You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2014/03/31 23:23:43 UTC

[3/9] merging upstream

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/09611d5b/portal/js/usergrid-dev.min.js
----------------------------------------------------------------------
diff --cc portal/js/usergrid-dev.min.js
index 87fd017,af849c2..0e96767
--- a/portal/js/usergrid-dev.min.js
+++ b/portal/js/usergrid-dev.min.js
@@@ -4512,6 -4511,6 +4511,19760 @@@
          $templateCache.put("users/users-tabs.html", "\n" + "\n" + "\n");
          $templateCache.put("users/users.html", '<div class="content-page">\n' + "\n" + '  <page-title title=" Users" icon="&#128100;"></page-title>\n' + '  <bsmodal id="newUser"\n' + '           title="Create New User"\n' + '           close="hideModal"\n' + '           closelabel="Cancel"\n' + '           buttonid="users"\n' + '           extrabutton="newUserDialog"\n' + '           extrabuttonlabel="Create"\n' + "           ng-cloak>\n" + "    <fieldset>\n" + '      <div class="control-group">\n' + '        <label for="new-user-username">Username</label>\n' + "\n" + '        <div class="controls">\n' + '          <input type="text" required ng-model="$parent.newUser.newusername" ng-pattern="usernameRegex" ng-attr-title="{{usernameRegexDescription}}"  name="username" id="new-user-username" class="input-xlarge" ug-validate/>\n' + '          <p class="help-block hide"></p>\n' + "        </div>\n" + "      </div>\n" + '      <div class="control-group">\n' + '        <label for="new-u
 ser-fullname">Full name</label>\n' + "\n" + '        <div class="controls">\n' + '          <input type="text" required  ng-attr-title="{{nameRegexDescription}}" ng-pattern="nameRegex" ng-model="$parent.newUser.name" name="name" id="new-user-fullname" class="input-xlarge" ug-validate/>\n' + "\n" + '          <p class="help-block hide"></p>\n' + "        </div>\n" + "      </div>\n" + '      <div class="control-group">\n' + '        <label for="new-user-email">Email</label>\n' + "\n" + '        <div class="controls">\n' + '          <input type="email" required  ng-model="$parent.newUser.email" pattern="emailRegex"   ng-attr-title="{{emailRegexDescription}}"  name="email" id="new-user-email" class="input-xlarge" ug-validate/>\n' + "\n" + '          <p class="help-block hide"></p>\n' + "        </div>\n" + "      </div>\n" + '      <div class="control-group">\n' + '        <label for="new-user-password">Password</label>\n' + "\n" + '        <div class="controls">\n' + '          <inpu
 t type="password" required ng-pattern="passwordRegex"  ng-attr-title="{{passwordRegexDescription}}" ng-model="$parent.newUser.newpassword" name="password" id="new-user-password" ug-validate\n' + '                 class="input-xlarge"/>\n' + "\n" + '          <p class="help-block hide"></p>\n' + "        </div>\n" + "      </div>\n" + '      <div class="control-group">\n' + '        <label for="new-user-re-password">Confirm password</label>\n' + "\n" + '        <div class="controls">\n' + '          <input type="password" required ng-pattern="passwordRegex"  ng-attr-title="{{passwordRegexDescription}}" ng-model="$parent.newUser.repassword" name="re-password" id="new-user-re-password" ug-validate\n' + '                 class="input-xlarge"/>\n' + "\n" + '          <p class="help-block hide"></p>\n' + "        </div>\n" + "      </div>\n" + "    </fieldset>\n" + "  </bsmodal>\n" + "\n" + '  <bsmodal id="deleteUser"\n' + '           title="Delete User"\n' + '           close="hideModal"
 \n' + '           closelabel="Cancel"\n' + '           extrabutton="deleteUsersDialog"\n' + '           extrabuttonlabel="Delete"\n' + '           buttonid="deleteusers"\n' + "           ng-cloak>\n" + "    <p>Are you sure you want to delete the user(s)?</p>\n" + "  </bsmodal>\n" + "\n" + '  <section class="row-fluid">\n' + '    <div class="span3 user-col">\n' + "\n" + '        <div class="button-toolbar span12">\n' + '          <a title="Select All" class="btn btn-primary toolbar select-all" ng-show="hasUsers" ng-click="selectAllEntities(usersCollection._list,this,\'usersSelected\',true)" ng-model="usersSelected"> <i class="pictogram">&#8863;</i></a>\n' + '          <button title="Delete" class="btn btn-primary toolbar" ng-disabled="!hasUsers || !valueSelected(usersCollection._list)" ng-click="showModal(\'deleteUser\')" id="delete-user-button"><i class="pictogram">&#9749;</i></button>\n' + '          <button title="Add" class="btn btn-primary toolbar" ng-click="showModal(\'newUser\
 ')" id="new-user-button" ng-attr-id="new-user-button"><i class="pictogram">&#59136;</i></button>\n' + "        </div>\n" + '        <ul class="user-list">\n' + '          <li ng-class="selectedUser._data.uuid === user._data.uuid ? \'selected\' : \'\'" ng-repeat="user in usersCollection._list" ng-click="selectUser(user._data.uuid)">\n' + "            <input\n" + '                type="checkbox"\n' + "                id=\"user-{{user.get('username')}}-checkbox\"\n" + "                ng-value=\"user.get('uuid')\"\n" + '                ng-checked="master"\n' + '                ng-model="user.checked"\n' + "                >\n" + "              <a href=\"javaScript:void(0)\"  id=\"user-{{user.get('username')}}-link\" >{{user.get('username')}}</a>\n" + '              <span ng-if="user.name" class="label">Display Name:</span>{{user.name}}\n' + "          </li>\n" + "        </ul>\n" + "\n" + '        <div style="padding: 10px 5px 10px 5px">\n' + '          <button class="btn btn-primary t
 oolbar" ng-click="getPrevious()" style="display:{{previous_display}}">< Previous\n' + "          </button>\n" + '          <button class="btn btn-primary toolbar" ng-click="getNext()" style="display:{{next_display}}; float:right;">Next >\n' + "          </button>\n" + "        </div>\n" + "\n" + "    </div>\n" + "\n" + '    <div class="span9 tab-content" ng-show="hasUsers">\n' + '      <div class="menu-toolbar">\n' + '        <ul class="inline">\n' + '          <li class="tab" ng-class="currentUsersPage.route === \'/users/profile\' ? \'selected\' : \'\'"><a class="btn btn-primary toolbar" ng-click="selectUserPage(\'/users/profile\')"><i class="pictogram">&#59170;</i>Profile</a></li>\n' + '          <li class="tab" ng-class="currentUsersPage.route === \'/users/groups\' ? \'selected\' : \'\'"><a class="btn btn-primary toolbar" ng-click="selectUserPage(\'/users/groups\')"><i class="pictogram">&#128101;</i>Groups</a></li>\n' + '          <li class="tab" ng-class="currentUsersPage.route 
 === \'/users/activities\' ? \'selected\' : \'\'"><a class="btn btn-primary toolbar" ng-click="selectUserPage(\'/users/activities\')"><i class="pictogram">&#59194;</i>Activities</a></li>\n' + '          <li class="tab" ng-class="currentUsersPage.route === \'/users/feed\' ? \'selected\' : \'\'"><a class="btn btn-primary toolbar" ng-click="selectUserPage(\'/users/feed\')"><i class="pictogram">&#128196;</i>Feed</a></li>\n' + '          <li class="tab" ng-class="currentUsersPage.route === \'/users/graph\' ? \'selected\' : \'\'"><a class="btn btn-primary toolbar" ng-click="selectUserPage(\'/users/graph\')"><i class="pictogram">&#9729;</i>Graph</a></li>\n' + '          <li class="tab" ng-class="currentUsersPage.route === \'/users/roles\' ? \'selected\' : \'\'"><a class="btn btn-primary toolbar" ng-click="selectUserPage(\'/users/roles\')"><i class="pictogram">&#127758;</i>Roles &amp; Permissions</a></li>\n' + "        </ul>\n" + "      </div>\n" + '      <span ng-include="currentUsersPage.t
 emplate"></span>\n' + "    </div>\n" + "  </section>\n" + "</div>");
      } ]);
++    (function(exports, global) {
++        global["true"] = exports;
++        "use strict";
++        var polyfills = function(window, Object) {
++            window.requestAnimFrame = function() {
++                return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback, element) {
++                    window.setTimeout(callback, 1e3 / 60);
++                };
++            }();
++            Object.defineProperty(Object.prototype, "clone", {
++                enumerable: false,
++                writable: true,
++                value: function() {
++                    var i, newObj = this instanceof Array ? [] : {};
++                    for (i in this) {
++                        if (i === "clone") {
++                            continue;
++                        }
++                        if (this[i] && typeof this[i] === "object") {
++                            newObj[i] = this[i].clone();
++                        } else {
++                            newObj[i] = this[i];
++                        }
++                    }
++                    return newObj;
++                }
++            });
++            Object.defineProperty(Object.prototype, "stringifyJSON", {
++                enumerable: false,
++                writable: true,
++                value: function() {
++                    return JSON.stringify(this, null, "	");
++                }
++            });
++        };
++        polyfills(window, Object);
++        var global = global || this;
++        var AppServices = AppServices || {};
++        global.AppServices = global.AppServices || AppServices;
++        AppServices.Constants = angular.module("appservices.constants", []);
++        AppServices.Services = angular.module("appservices.services", []);
++        AppServices.Controllers = angular.module("appservices.controllers", []);
++        AppServices.Filters = angular.module("appservices.filters", []);
++        AppServices.Directives = angular.module("appservices.directives", []);
++        AppServices.Performance = angular.module("appservices.performance", []);
++        AppServices.MAX = angular.module("appservices.max", []);
++        angular.module("appservices", [ "ngRoute", "ngResource", "ngSanitize", "ui.bootstrap", "angulartics", "angulartics.google.analytics", "appservices.filters", "appservices.services", "appservices.directives", "appservices.constants", "appservices.controllers", "appservices.max", "angular-intro" ]).config([ "$routeProvider", "$locationProvider", "$sceDelegateProvider", "$analyticsProvider", function($routeProvider, $locationProvider, $sceDelegateProvider, $analyticsProvider) {
++            $routeProvider.when("/org-overview", {
++                templateUrl: "org-overview/org-overview.html",
++                controller: "OrgOverviewCtrl"
++            }).when("/login", {
++                templateUrl: "login/login.html",
++                controller: "LoginCtrl"
++            }).when("/login/loading", {
++                templateUrl: "login/loading.html",
++                controller: "LoginCtrl"
++            }).when("/app-overview/summary", {
++                templateUrl: "app-overview/app-overview.html",
++                controller: "AppOverviewCtrl"
++            }).when("/getting-started/setup", {
++                templateUrl: "app-overview/getting-started.html",
++                controller: "GettingStartedCtrl"
++            }).when("/forgot-password", {
++                templateUrl: "login/forgot-password.html",
++                controller: "ForgotPasswordCtrl"
++            }).when("/register", {
++                templateUrl: "login/register.html",
++                controller: "RegisterCtrl"
++            }).when("/users", {
++                templateUrl: "users/users.html",
++                controller: "UsersCtrl"
++            }).when("/users/profile", {
++                templateUrl: "users/users-profile.html",
++                controller: "UsersProfileCtrl"
++            }).when("/users/groups", {
++                templateUrl: "users/users-groups.html",
++                controller: "UsersGroupsCtrl"
++            }).when("/users/activities", {
++                templateUrl: "users/users-activities.html",
++                controller: "UsersActivitiesCtrl"
++            }).when("/users/feed", {
++                templateUrl: "users/users-feed.html",
++                controller: "UsersFeedCtrl"
++            }).when("/users/graph", {
++                templateUrl: "users/users-graph.html",
++                controller: "UsersGraphCtrl"
++            }).when("/users/roles", {
++                templateUrl: "users/users-roles.html",
++                controller: "UsersRolesCtrl"
++            }).when("/groups", {
++                templateUrl: "groups/groups.html",
++                controller: "GroupsCtrl"
++            }).when("/groups/details", {
++                templateUrl: "groups/groups-details.html",
++                controller: "GroupsDetailsCtrl"
++            }).when("/groups/members", {
++                templateUrl: "groups/groups-members.html",
++                controller: "GroupsMembersCtrl"
++            }).when("/groups/activities", {
++                templateUrl: "groups/groups-activities.html",
++                controller: "GroupsActivitiesCtrl"
++            }).when("/groups/roles", {
++                templateUrl: "groups/groups-roles.html",
++                controller: "GroupsRolesCtrl"
++            }).when("/roles", {
++                templateUrl: "roles/roles.html",
++                controller: "RolesCtrl"
++            }).when("/roles/settings", {
++                templateUrl: "roles/roles-settings.html",
++                controller: "RolesSettingsCtrl"
++            }).when("/roles/users", {
++                templateUrl: "roles/roles-users.html",
++                controller: "RolesUsersCtrl"
++            }).when("/roles/groups", {
++                templateUrl: "roles/roles-groups.html",
++                controller: "RolesGroupsCtrl"
++            }).when("/data", {
++                templateUrl: "data/data.html",
++                controller: "DataCtrl"
++            }).when("/data/entity", {
++                templateUrl: "data/entity.html",
++                controller: "EntityCtrl"
++            }).when("/data/shell", {
++                templateUrl: "data/shell.html",
++                controller: "ShellCtrl"
++            }).when("/profile/organizations", {
++                templateUrl: "profile/organizations.html",
++                controller: "OrgCtrl"
++            }).when("/profile/profile", {
++                templateUrl: "profile/profile.html",
++                controller: "ProfileCtrl"
++            }).when("/profile", {
++                templateUrl: "profile/account.html",
++                controller: "AccountCtrl"
++            }).when("/activities", {
++                templateUrl: "activities/activities.html",
++                controller: "ActivitiesCtrl"
++            }).when("/shell", {
++                templateUrl: "shell/shell.html",
++                controller: "ShellCtrl"
++            }).when("/logout", {
++                templateUrl: "login/logout.html",
++                controller: "LogoutCtrl"
++            }).otherwise({
++                redirectTo: "/org-overview"
++            });
++            $locationProvider.html5Mode(false).hashPrefix("!");
++            $sceDelegateProvider.resourceUrlWhitelist([ "self", "http://apigee-internal-prod.jupiter.apigee.net/**", "http://apigee-internal-prod.mars.apigee.net/**", "https://appservices.apigee.com/**", "https://api.usergrid.com/**" ]);
++            $analyticsProvider.virtualPageviews(false);
++            $analyticsProvider.firstPageview(false);
++        } ]);
++        AppServices.Controllers.controller("ActivitiesCtrl", [ "ug", "$scope", "$rootScope", "$location", "$route", function(ug, $scope, $rootScope, $location, $route) {
++            $scope.$on("app-activities-received", function(evt, data) {
++                $scope.activities = data;
++                $scope.$apply();
++            });
++            $scope.$on("app-activities-error", function(evt, data) {
++                $rootScope.$broadcast("alert", "error", "Application failed to retreive activities data.");
++            });
++            ug.getActivities();
++        } ]);
++        "use strict";
++        AppServices.Controllers.controller("AppOverviewCtrl", [ "ug", "charts", "$scope", "$rootScope", "$log", function(ug, charts, $scope, $rootScope, $log) {
++            var createGradient = function(color1, color2) {
++                var perShapeGradient = {
++                    x1: 0,
++                    y1: 0,
++                    x2: 0,
++                    y2: 1
++                };
++                return {
++                    linearGradient: perShapeGradient,
++                    stops: [ [ 0, color1 ], [ 1, color2 ] ]
++                };
++            };
++            $scope.appOverview = {};
++            $scope.collections = [];
++            $scope.graph = "";
++            $scope.$on("top-collections-received", function(event, collections) {
++                var dataDescription = {
++                    bar1: {
++                        labels: [ "Total" ],
++                        dataAttr: [ "title", "count" ],
++                        colors: [ createGradient("rgba(36,151,212,0.6)", "rgba(119,198,240,0.6)") ],
++                        borderColor: "#1b97d1"
++                    }
++                };
++                $scope.collections = collections;
++                var arr = [];
++                for (var i in collections) {
++                    if (collections.hasOwnProperty(i)) {
++                        arr.push(collections[i]);
++                    }
++                }
++                $scope.appOverview = {};
++                if (!$rootScope.chartTemplate) {
++                    ug.httpGet(null, "js/charts/highcharts.json").then(function(success) {
++                        $rootScope.chartTemplate = success;
++                        $scope.appOverview.chart = angular.copy($rootScope.chartTemplate.pareto);
++                        $scope.appOverview.chart = charts.convertParetoChart(arr, $scope.appOverview.chart, dataDescription.bar1, "1h", "NOW");
++                        $scope.applyScope();
++                    }, function(fail) {
++                        $log.error("Problem getting chart template", fail);
++                    });
++                } else {
++                    $scope.appOverview.chart = angular.copy($rootScope.chartTemplate.pareto);
++                    $scope.appOverview.chart = charts.convertParetoChart(arr, $scope.appOverview.chart, dataDescription.bar1, "1h", "NOW");
++                    $scope.applyScope();
++                }
++            });
++            $scope.$on("app-initialized", function() {
++                ug.getTopCollections();
++            });
++            if ($rootScope.activeUI) {
++                ug.getTopCollections();
++            }
++        } ]);
++        "use strict";
++        AppServices.Controllers.controller("GettingStartedCtrl", [ "ug", "$scope", "$rootScope", "$location", "$timeout", "$anchorScroll", function(ug, $scope, $rootScope, $location, $timeout, $anchorScroll) {
++            $scope.collections = [];
++            $scope.graph = "";
++            $scope.clientID = "";
++            $scope.clientSecret = "";
++            var getKeys = function() {
++                return ug.jsonpRaw("credentials", "", {});
++            };
++            $scope.regenerateCredentialsDialog = function(modalId) {
++                $scope.orgAPICredentials = {
++                    client_id: "regenerating...",
++                    client_secret: "regenerating..."
++                };
++                ug.regenerateAppCredentials();
++                $scope.hideModal(modalId);
++            };
++            $scope.$on("app-creds-updated", function(event, credentials) {
++                if (credentials) {
++                    $scope.clientID = credentials.client_id;
++                    $scope.clientSecret = credentials.client_secret;
++                    if (!$scope.$$phase) {
++                        $scope.$apply();
++                    }
++                } else {
++                    setTimeout(function() {
++                        ug.getAppCredentials();
++                    }, 5e3);
++                }
++            });
++            ug.getAppCredentials();
++            $scope.contentTitle;
++            $scope.showSDKDetail = function(name) {
++                var introContainer = document.getElementById("intro-container");
++                if (name === "nocontent") {
++                    introContainer.style.height = "0";
++                    return true;
++                }
++                introContainer.style.opacity = .1;
++                introContainer.style.height = "0";
++                var timeout = 0;
++                if ($scope.contentTitle) {
++                    timeout = 500;
++                }
++                $timeout(function() {
++                    introContainer.style.height = "1000px";
++                    introContainer.style.opacity = 1;
++                }, timeout);
++                $scope.optionName = name;
++                $scope.contentTitle = name;
++                $scope.sdkLink = "http://apigee.com/docs/content/" + name + "-sdk-redirect";
++                $scope.docsLink = "http://apigee.com/docs/app-services/content/installing-apigee-sdk-" + name;
++                $scope.getIncludeURL = function() {
++                    return "app-overview/doc-includes/" + $scope.optionName + ".html";
++                };
++            };
++            $scope.scrollToElement = function(elem) {
++                $location.hash(elem);
++                $anchorScroll();
++                return false;
++            };
++        } ]);
++        "use strict";
++        AppServices.Controllers.controller("ChartCtrl", [ "$scope", "$location", function($scope, $location) {} ]);
++        "use strict";
++        AppServices.Directives.directive("chart", function($rootScope) {
++            return {
++                restrict: "E",
++                scope: {
++                    chartdata: "=chartdata"
++                },
++                template: "<div></div>",
++                replace: true,
++                controller: function($scope, $element) {},
++                link: function(scope, element, attrs) {
++                    scope.$watch("chartdata", function(chartdata, oldchartdata) {
++                        if (chartdata) {
++                            var chartsDefaults = {
++                                chart: {
++                                    renderTo: element[0],
++                                    type: attrs.type || null,
++                                    height: attrs.height || null,
++                                    width: attrs.width || null,
++                                    reflow: true,
++                                    animation: false,
++                                    zoomType: "x"
++                                }
++                            };
++                            if (attrs.type === "pie") {
++                                chartsDefaults.chart.margin = [ 0, 0, 0, 0 ];
++                                chartsDefaults.chart.spacingLeft = 0;
++                                chartsDefaults.chart.spacingRight = 0;
++                                chartsDefaults.chart.spacingTop = 0;
++                                chartsDefaults.chart.spacingBottom = 0;
++                                if (attrs.titleimage) {
++                                    chartdata.title.text = '<img src="' + attrs.titleimage + '">';
++                                }
++                                if (attrs.titleicon) {
++                                    chartdata.title.text = '<i class="pictogram ' + attrs.titleiconclass + '">' + attrs.titleicon + "</i>";
++                                }
++                                if (attrs.titlecolor) {
++                                    chartdata.title.style.color = attrs.titlecolor;
++                                }
++                                if (attrs.titleimagetop) {
++                                    chartdata.title.style.marginTop = attrs.titleimagetop;
++                                }
++                                if (attrs.titleimageleft) {
++                                    chartdata.title.style.marginLeft = attrs.titleimageleft;
++                                }
++                            }
++                            if (attrs.type === "line") {
++                                chartsDefaults.chart.marginTop = 30;
++                                chartsDefaults.chart.spacingTop = 50;
++                            }
++                            if (attrs.type === "column") {
++                                chartsDefaults.chart.marginBottom = 80;
++                            }
++                            if (attrs.type === "area") {
++                                chartsDefaults.chart.spacingLeft = 0;
++                                chartsDefaults.chart.spacingRight = 0;
++                                chartsDefaults.chart.marginLeft = 0;
++                                chartsDefaults.chart.marginRight = 0;
++                            }
++                            Highcharts.setOptions({
++                                global: {
++                                    useUTC: false
++                                },
++                                chart: {
++                                    style: {
++                                        fontFamily: "marquette-light, Helvetica, Arial, sans-serif"
++                                    }
++                                }
++                            });
++                            if (attrs.type === "line") {
++                                var xAxis1 = chartdata.xAxis[0];
++                                if (!xAxis1.labels.formatter) {
++                                    xAxis1.labels.formatter = new Function(attrs.xaxislabel);
++                                }
++                                if (!xAxis1.labels.step) {
++                                    xAxis1.labels.step = attrs.xaxisstep;
++                                }
++                            }
++                            if (chartdata.tooltip) {
++                                if (typeof chartdata.tooltip.formatter === "string") {
++                                    chartdata.tooltip.formatter = new Function(chartdata.tooltip.formatter);
++                                }
++                            }
++                            renderChart(chartsDefaults, chartdata);
++                        }
++                    }, true);
++                }
++            };
++        });
++        function renderChart(chartsDefaults, chartdata, attrs) {
++            var newSettings = {};
++            $.extend(true, newSettings, chartsDefaults, chartdata);
++            var chart = new Highcharts.Chart(newSettings);
++        }
++        AppServices.Services.factory("charts", function() {
++            var lineChart, areaChart, paretoChart, pieChart, pieCompare, xaxis, seriesIndex;
++            return {
++                convertLineChart: function(chartData, chartTemplate, dataDescription, settings, currentCompare) {
++                    lineChart = chartTemplate;
++                    if (typeof chartData[0] === "undefined") {
++                        chartData[0] = {};
++                        chartData[0].datapoints = [];
++                    }
++                    var dataPoints = chartData[0].datapoints, dPLength = dataPoints.length, label;
++                    if (currentCompare === "YESTERDAY") {
++                        seriesIndex = dataDescription.dataAttr.length;
++                        label = "Yesterday ";
++                    } else if (currentCompare === "LAST_WEEK") {
++                        seriesIndex = dataDescription.dataAttr.length;
++                        label = "Last Week ";
++                    } else {
++                        lineChart = chartTemplate;
++                        seriesIndex = 0;
++                        lineChart.series = [];
++                        label = "";
++                    }
++                    xaxis = lineChart.xAxis[0];
++                    xaxis.categories = [];
++                    if (settings.xaxisformat) {
++                        xaxis.labels.formatter = new Function(settings.xaxisformat);
++                    }
++                    if (settings.step) {
++                        xaxis.labels.step = settings.step;
++                    }
++                    for (var i = 0; i < dPLength; i++) {
++                        var dp = dataPoints[i];
++                        xaxis.categories.push(dp.timestamp);
++                    }
++                    if (chartData.length > 1) {
++                        for (var l = 0; l < chartData.length; l++) {
++                            if (chartData[l].chartGroupName) {
++                                dataPoints = chartData[l].datapoints;
++                                lineChart.series[l] = {};
++                                lineChart.series[l].data = [];
++                                lineChart.series[l].name = chartData[l].chartGroupName;
++                                lineChart.series[l].yAxis = 0;
++                                lineChart.series[l].type = "line";
++                                lineChart.series[l].color = dataDescription.colors[i];
++                                lineChart.series[l].dashStyle = "solid";
++                                lineChart.series[l].yAxis.title.text = dataDescription.yAxisLabels;
++                                plotData(l, dPLength, dataPoints, dataDescription.detailDataAttr, true);
++                            }
++                        }
++                    } else {
++                        var steadyCounter = 0;
++                        for (var i = seriesIndex; i < dataDescription.dataAttr.length + (seriesIndex > 0 ? seriesIndex : 0); i++) {
++                            var yAxisIndex = dataDescription.multiAxis ? steadyCounter : 0;
++                            lineChart.series[i] = {};
++                            lineChart.series[i].data = [];
++                            lineChart.series[i].name = label + dataDescription.labels[steadyCounter];
++                            lineChart.series[i].yAxis = yAxisIndex;
++                            lineChart.series[i].type = "line";
++                            lineChart.series[i].color = dataDescription.colors[i];
++                            lineChart.series[i].dashStyle = "solid";
++                            lineChart.yAxis[yAxisIndex].title.text = dataDescription.yAxisLabels[dataDescription.yAxisLabels > 1 ? steadyCounter : 0];
++                            steadyCounter++;
++                        }
++                        plotData(seriesIndex, dPLength, dataPoints, dataDescription.dataAttr, false);
++                    }
++                    function plotData(counter, dPLength, dataPoints, dataAttrs, detailedView) {
++                        for (var i = 0; i < dPLength; i++) {
++                            var dp = dataPoints[i];
++                            var localCounter = counter;
++                            for (var j = 0; j < dataAttrs.length; j++) {
++                                if (typeof dp === "undefined") {
++                                    lineChart.series[localCounter].data.push([ i, 0 ]);
++                                } else {
++                                    lineChart.series[localCounter].data.push([ i, dp[dataAttrs[j]] ]);
++                                }
++                                if (!detailedView) {
++                                    localCounter++;
++                                }
++                            }
++                        }
++                    }
++                    return lineChart;
++                },
++                convertAreaChart: function(chartData, chartTemplate, dataDescription, settings, currentCompare) {
++                    areaChart = angular.copy(areaChart);
++                    if (typeof chartData[0] === "undefined") {
++                        chartData[0] = {};
++                        chartData[0].datapoints = [];
++                    }
++                    var dataPoints = chartData[0].datapoints, dPLength = dataPoints.length, label;
++                    if (currentCompare === "YESTERDAY") {
++                        seriesIndex = dataDescription.dataAttr.length;
++                        label = "Yesterday ";
++                    } else if (currentCompare === "LAST_WEEK") {
++                        seriesIndex = dataDescription.dataAttr.length;
++                        label = "Last Week ";
++                    } else {
++                        areaChart = chartTemplate;
++                        seriesIndex = 0;
++                        areaChart.series = [];
++                        label = "";
++                    }
++                    xaxis = areaChart.xAxis[0];
++                    xaxis.categories = [];
++                    if (settings.xaxisformat) {
++                        xaxis.labels.formatter = new Function(settings.xaxisformat);
++                    }
++                    if (settings.step) {
++                        xaxis.labels.step = settings.step;
++                    }
++                    for (var i = 0; i < dPLength; i++) {
++                        var dp = dataPoints[i];
++                        xaxis.categories.push(dp.timestamp);
++                    }
++                    if (chartData.length > 1) {
++                        for (var l = 0; l < chartData.length; l++) {
++                            if (chartData[l].chartGroupName) {
++                                dataPoints = chartData[l].datapoints;
++                                areaChart.series[l] = {};
++                                areaChart.series[l].data = [];
++                                areaChart.series[l].fillColor = dataDescription.areaColors[l];
++                                areaChart.series[l].name = chartData[l].chartGroupName;
++                                areaChart.series[l].yAxis = 0;
++                                areaChart.series[l].type = "area";
++                                areaChart.series[l].pointInterval = 1;
++                                areaChart.series[l].color = dataDescription.colors[l];
++                                areaChart.series[l].dashStyle = "solid";
++                                areaChart.series[l].yAxis.title.text = dataDescription.yAxisLabels;
++                                plotData(l, dPLength, dataPoints, dataDescription.detailDataAttr, true);
++                            }
++                        }
++                    } else {
++                        var steadyCounter = 0;
++                        for (var i = seriesIndex; i < dataDescription.dataAttr.length + (seriesIndex > 0 ? seriesIndex : 0); i++) {
++                            var yAxisIndex = dataDescription.multiAxis ? steadyCounter : 0;
++                            areaChart.series[i] = {};
++                            areaChart.series[i].data = [];
++                            areaChart.series[i].fillColor = dataDescription.areaColors[i];
++                            areaChart.series[i].name = label + dataDescription.labels[steadyCounter];
++                            areaChart.series[i].yAxis = yAxisIndex;
++                            areaChart.series[i].type = "area";
++                            areaChart.series[i].pointInterval = 1;
++                            areaChart.series[i].color = dataDescription.colors[i];
++                            areaChart.series[i].dashStyle = "solid";
++                            areaChart.yAxis[yAxisIndex].title.text = dataDescription.yAxisLabels[dataDescription.yAxisLabels > 1 ? steadyCounter : 0];
++                            steadyCounter++;
++                        }
++                        plotData(seriesIndex, dPLength, dataPoints, dataDescription.dataAttr, false);
++                    }
++                    function plotData(counter, dPLength, dataPoints, dataAttrs, detailedView) {
++                        for (var i = 0; i < dPLength; i++) {
++                            var dp = dataPoints[i];
++                            var localCounter = counter;
++                            for (var j = 0; j < dataAttrs.length; j++) {
++                                if (typeof dp === "undefined") {
++                                    areaChart.series[localCounter].data.push(0);
++                                } else {
++                                    areaChart.series[localCounter].data.push(dp[dataAttrs[j]]);
++                                }
++                                if (!detailedView) {
++                                    localCounter++;
++                                }
++                            }
++                        }
++                    }
++                    return areaChart;
++                },
++                convertParetoChart: function(chartData, chartTemplate, dataDescription, settings, currentCompare) {
++                    paretoChart = chartTemplate;
++                    if (typeof chartData === "undefined") {
++                        chartData = [];
++                    }
++                    var label, cdLength = chartData.length, compare = false, allParetoOptions = [], stackedBar = false;
++                    seriesIndex = 0;
++                    function getPreviousData() {
++                        for (var i = 0; i < chartTemplate.series[0].data.length; i++) {
++                            allParetoOptions.push(chartTemplate.xAxis.categories[i]);
++                        }
++                    }
++                    if (typeof dataDescription.dataAttr[1] === "object") {
++                        stackedBar = true;
++                    }
++                    if (currentCompare === "YESTERDAY") {
++                        label = "Yesterday ";
++                        compare = true;
++                        if (stackedBar) {
++                            seriesIndex = dataDescription.dataAttr[1].length;
++                        }
++                        getPreviousData();
++                    } else if (currentCompare === "LAST_WEEK") {
++                        label = "Last Week ";
++                        compare = true;
++                        if (stackedBar) {
++                            seriesIndex = dataDescription.dataAttr[1].length;
++                        }
++                        seriesIndex = getPreviousData();
++                    } else {
++                        compare = false;
++                        label = "";
++                        paretoChart.xAxis.categories = [];
++                        paretoChart.series = [];
++                        paretoChart.series[0] = {};
++                        paretoChart.series[0].data = [];
++                        paretoChart.legend.enabled = false;
++                    }
++                    paretoChart.plotOptions.series.borderColor = dataDescription.borderColor;
++                    if (compare && !stackedBar) {
++                        paretoChart.series[1] = {};
++                        paretoChart.series[1].data = [];
++                        for (var i = 0; i < allParetoOptions.length; i++) {
++                            paretoChart.series[1].data.push(0);
++                        }
++                        paretoChart.legend.enabled = true;
++                    }
++                    for (var i = 0; i < cdLength; i++) {
++                        var bar = chartData[i];
++                        if (!compare) {
++                            paretoChart.xAxis.categories.push(bar[dataDescription.dataAttr[0]]);
++                            if (typeof dataDescription.dataAttr[1] === "object") {
++                                createStackedBar(dataDescription, paretoChart, paretoChart.series.length);
++                            } else {
++                                paretoChart.series[0].data.push(bar[dataDescription.dataAttr[1]]);
++                                paretoChart.series[0].name = dataDescription.labels[0];
++                                paretoChart.series[0].color = dataDescription.colors[0];
++                            }
++                        } else {
++                            var newLabel = bar[dataDescription.dataAttr[0]], newValue = bar[dataDescription.dataAttr[1]], previousIndex = allParetoOptions.indexOf(newLabel);
++                            if (previousIndex > -1) {
++                                if (typeof dataDescription.dataAttr[1] === "object") {
++                                    createStackedBar(dataDescription, paretoChart, paretoChart.series.length);
++                                } else {
++                                    paretoChart.series[1].data[previousIndex] = newValue;
++                                    paretoChart.series[1].name = label !== "" ? label + " " + dataDescription.labels[0] : dataDescription.labels[0];
++                                    paretoChart.series[1].color = dataDescription.colors[1];
++                                }
++                            } else {}
++                        }
++                    }
++                    function createStackedBar(dataDescription, paretoChart, startingPoint) {
++                        paretoChart.plotOptions = {
++                            series: {
++                                shadow: false,
++                                borderColor: dataDescription.borderColor,
++                                borderWidth: 1
++                            },
++                            column: {
++                                stacking: "normal",
++                                dataLabels: {
++                                    enabled: true,
++                                    color: Highcharts.theme && Highcharts.theme.dataLabelsColor || "white"
++                                }
++                            }
++                        };
++                        var start = dataDescription.dataAttr[1].length, steadyCounter = 0, stackName = label;
++                        if (compare) {
++                            paretoChart.legend.enabled = true;
++                        }
++                        for (var f = seriesIndex; f < start + seriesIndex; f++) {
++                            if (!paretoChart.series[f]) {
++                                paretoChart.series[f] = {
++                                    data: []
++                                };
++                            }
++                            paretoChart.series[f].data.push(bar[dataDescription.dataAttr[1][steadyCounter]]);
++                            paretoChart.series[f].name = label !== "" ? label + " " + dataDescription.labels[steadyCounter] : dataDescription.labels[steadyCounter];
++                            paretoChart.series[f].color = dataDescription.colors[f];
++                            paretoChart.series[f].stack = label;
++                            steadyCounter++;
++                        }
++                    }
++                    return paretoChart;
++                },
++                convertPieChart: function(chartData, chartTemplate, dataDescription, settings, currentCompare) {
++                    var label, cdLength = chartData.length, compare = false;
++                    pieChart = chartTemplate;
++                    if (currentCompare === "YESTERDAY") {
++                        label = "Yesterday ";
++                        compare = false;
++                    } else if (currentCompare === "LAST_WEEK") {
++                        label = "Last Week ";
++                        compare = false;
++                    } else {
++                        compare = false;
++                        pieChart.series[0].data = [];
++                        if (pieChart.series[0].dataLabels) {
++                            if (typeof pieChart.series[0].dataLabels.formatter === "string") {
++                                pieChart.series[0].dataLabels.formatter = new Function(pieChart.series[0].dataLabels.formatter);
++                            }
++                        }
++                    }
++                    pieChart.plotOptions.pie.borderColor = dataDescription.borderColor;
++                    if (compare) {
++                        pieChart.series[1].data = [];
++                        if (pieChart.series[1].dataLabels) {
++                            if (typeof pieChart.series[1].dataLabels.formatter === "string") {
++                                pieChart.series[1].dataLabels.formatter = new Function(pieChart.series[1].dataLabels.formatter);
++                            }
++                        }
++                    }
++                    var tempArray = [];
++                    for (var i = 0; i < cdLength; i++) {
++                        var pie = chartData[i];
++                        tempArray.push({
++                            name: pie[dataDescription.dataAttr[0]],
++                            y: pie[dataDescription.dataAttr[1]],
++                            color: ""
++                        });
++                    }
++                    sortJsonArrayByProperty(tempArray, "name");
++                    for (var i = 0; i < tempArray.length; i++) {
++                        tempArray[i].color = dataDescription.colors[i];
++                    }
++                    if (!compare) {
++                        pieChart.series[0].data = tempArray;
++                    } else {
++                        pieChart.series[1].data = tempArray;
++                    }
++                    return pieChart;
++                }
++            };
++            function sortJsonArrayByProperty(objArray, prop, direction) {
++                if (arguments.length < 2) throw new Error("sortJsonArrayByProp requires 2 arguments");
++                var direct = arguments.length > 2 ? arguments[2] : 1;
++                if (objArray && objArray.constructor === Array) {
++                    var propPath = prop.constructor === Array ? prop : prop.split(".");
++                    objArray.sort(function(a, b) {
++                        for (var p in propPath) {
++                            if (a[propPath[p]] && b[propPath[p]]) {
++                                a = a[propPath[p]];
++                                b = b[propPath[p]];
++                            }
++                        }
++                        a = a.match(/^\d+$/) ? +a : a;
++                        b = b.match(/^\d+$/) ? +b : b;
++                        return a < b ? -1 * direct : a > b ? 1 * direct : 0;
++                    });
++                }
++            }
++        });
++        $(".sessions-bar").sparkline([ 3, 5, 6, 3, 4, 5, 6, 7, 8, 4, 3, 5, 6, 3, 4, 5, 6, 7, 8, 4, 3, 5, 6, 3, 4, 5, 6, 7, 8, 4, 3, 5, 6, 3, 4, 5, 6, 7, 8, 4, 3, 5, 6, 3, 4, 5, 6, 7, 8, 4, 3, 5, 6, 3, 4, 5, 6, 7, 8, 1 ], {
++            type: "bar",
++            barColor: "#c5c5c5",
++            width: "800px",
++            height: 100,
++            barWidth: 12,
++            barSpacing: "1px"
++        });
++        "use strict";
++        AppServices.Controllers.controller("DataCtrl", [ "ug", "$scope", "$rootScope", "$location", function(ug, $scope, $rootScope, $location) {
++            var init = function() {
++                $scope.verb = "GET";
++                $scope.display = "";
++                $scope.queryBodyDetail = {};
++                $scope.queryBodyDisplay = "none";
++                $scope.queryLimitDisplay = "block";
++                $scope.queryStringDisplay = "block";
++                $scope.entitySelected = {};
++                $scope.newCollection = {};
++                $rootScope.queryCollection = {};
++                $scope.data = {};
++                $scope.data.queryPath = "";
++                $scope.data.queryBody = '{ "name":"value" }';
++                $scope.data.searchString = "";
++                $scope.data.queryLimit = "";
++            };
++            var runQuery = function(verb) {
++                $scope.loading = true;
++                var queryPath = $scope.removeFirstSlash($scope.data.queryPath || "");
++                var searchString = $scope.data.searchString || "";
++                var queryLimit = $scope.data.queryLimit || "";
++                var body = JSON.parse($scope.data.queryBody || "{}");
++                if (verb == "POST" && $scope.validateJson(true)) {
++                    ug.runDataPOSTQuery(queryPath, body);
++                } else if (verb == "PUT" && $scope.validateJson(true)) {
++                    ug.runDataPutQuery(queryPath, searchString, queryLimit, body);
++                } else if (verb == "DELETE") {
++                    ug.runDataDeleteQuery(queryPath, searchString, queryLimit);
++                } else {
++                    ug.runDataQuery(queryPath, searchString, queryLimit);
++                }
++            };
++            $scope.$on("top-collections-received", function(event, collectionList) {
++                $scope.loading = false;
++                var ignoredCollections = [ "events" ];
++                ignoredCollections.forEach(function(ignoredCollection) {
++                    collectionList.hasOwnProperty(ignoredCollection) && delete collectionList[ignoredCollection];
++                });
++                $scope.collectionList = collectionList;
++                $scope.queryBoxesSelected = false;
++                if (!$scope.queryPath) {
++                    $scope.loadCollection("/" + collectionList[Object.keys(collectionList).sort()[0]].name);
++                }
++                $scope.applyScope();
++            });
++            $scope.$on("error-running-query", function(event) {
++                $scope.loading = false;
++                runQuery("GET");
++                $scope.applyScope();
++            });
++            $scope.$on("entity-deleted", function(event) {
++                $scope.deleteLoading = false;
++                $rootScope.$broadcast("alert", "success", "Entities deleted sucessfully");
++                $scope.queryBoxesSelected = false;
++                $scope.checkNextPrev();
++                $scope.applyScope();
++            });
++            $scope.$on("entity-deleted-error", function(event) {
++                $scope.deleteLoading = false;
++                runQuery("GET");
++                $scope.applyScope();
++            });
++            $scope.$on("collection-created", function() {
++                $scope.newCollection.name = "";
++            });
++            $scope.$on("query-received", function(event, collection) {
++                $scope.loading = false;
++                $rootScope.queryCollection = collection;
++                ug.getIndexes($scope.data.queryPath);
++                $scope.setDisplayType();
++                $scope.checkNextPrev();
++                $scope.applyScope();
++                $scope.queryBoxesSelected = false;
++            });
++            $scope.$on("indexes-received", function(event, indexes) {
++                var fred = indexes;
++            });
++            $scope.$on("app-changed", function() {
++                init();
++            });
++            $scope.setDisplayType = function() {
++                $scope.display = "generic";
++            };
++            $scope.deleteEntitiesDialog = function(modalId) {
++                $scope.deleteLoading = false;
++                $scope.deleteEntities($rootScope.queryCollection, "entity-deleted", "error deleting entity");
++                $scope.hideModal(modalId);
++            };
++            $scope.newCollectionDialog = function(modalId) {
++                if ($scope.newCollection.name) {
++                    ug.createCollection($scope.newCollection.name);
++                    ug.getTopCollections();
++                    $rootScope.$broadcast("alert", "success", "Collection created successfully.");
++                    $scope.hideModal(modalId);
++                } else {
++                    $rootScope.$broadcast("alert", "error", "You must specify a collection name.");
++                }
++            };
++            $scope.addToPath = function(uuid) {
++                $scope.data.queryPath = "/" + $rootScope.queryCollection._type + "/" + uuid;
++            };
++            $scope.isDeep = function(item) {
++                return Object.prototype.toString.call(item) === "[object Object]";
++            };
++            $scope.loadCollection = function(type) {
++                $scope.data.queryPath = "/" + type.substring(1, type.length);
++                $scope.data.searchString = "";
++                $scope.data.queryLimit = "";
++                $scope.data.body = '{ "name":"value" }';
++                $scope.selectGET();
++                $scope.applyScope();
++                $scope.run();
++            };
++            $scope.selectGET = function() {
++                $scope.queryBodyDisplay = "none";
++                $scope.queryLimitDisplay = "block";
++                $scope.queryStringDisplay = "block";
++                $scope.verb = "GET";
++            };
++            $scope.selectPOST = function() {
++                $scope.queryBodyDisplay = "block";
++                $scope.queryLimitDisplay = "none";
++                $scope.queryStringDisplay = "none";
++                $scope.verb = "POST";
++            };
++            $scope.selectPUT = function() {
++                $scope.queryBodyDisplay = "block";
++                $scope.queryLimitDisplay = "block";
++                $scope.queryStringDisplay = "block";
++                $scope.verb = "PUT";
++            };
++            $scope.selectDELETE = function() {
++                $scope.queryBodyDisplay = "none";
++                $scope.queryLimitDisplay = "block";
++                $scope.queryStringDisplay = "block";
++                $scope.verb = "DELETE";
++            };
++            $scope.validateJson = function(skipMessage) {
++                var queryBody = $scope.data.queryBody;
++                try {
++                    queryBody = JSON.parse(queryBody);
++                } catch (e) {
++                    $rootScope.$broadcast("alert", "error", "JSON is not valid");
++                    return false;
++                }
++                queryBody = JSON.stringify(queryBody, null, 2);
++                !skipMessage && $rootScope.$broadcast("alert", "success", "JSON is valid");
++                $scope.data.queryBody = queryBody;
++                return true;
++            };
++            $scope.saveEntity = function(entity) {
++                if (!$scope.validateJson()) {
++                    return false;
++                }
++                var queryBody = entity._json;
++                queryBody = JSON.parse(queryBody);
++                $rootScope.selectedEntity.set();
++                $rootScope.selectedEntity.set(queryBody);
++                $rootScope.selectedEntity.set("type", entity._data.type);
++                $rootScope.selectedEntity.set("uuid", entity._data.uuid);
++                $rootScope.selectedEntity.save(function(err, data) {
++                    if (err) {
++                        $rootScope.$broadcast("alert", "error", "error: " + data.error_description);
++                    } else {
++                        $rootScope.$broadcast("alert", "success", "entity saved");
++                    }
++                });
++            };
++            $scope.run = function() {
++                $rootScope.queryCollection = "";
++                var verb = $scope.verb;
++                runQuery(verb);
++            };
++            $scope.hasProperty = function(prop) {
++                var retval = false;
++                if (typeof $rootScope.queryCollection._list !== "undefined") {
++                    angular.forEach($rootScope.queryCollection._list, function(value, key) {
++                        if (!retval) {
++                            if (value._data[prop]) {
++                                retval = true;
++                            }
++                        }
++                    });
++                }
++                return retval;
++            };
++            $scope.resetNextPrev = function() {
++                $scope.previous_display = "none";
++                $scope.next_display = "none";
++            };
++            $scope.checkNextPrev = function() {
++                $scope.resetNextPrev();
++                if ($rootScope.queryCollection.hasPreviousPage()) {
++                    $scope.previous_display = "default";
++                }
++                if ($rootScope.queryCollection.hasNextPage()) {
++                    $scope.next_display = "default";
++                }
++            };
++            $scope.selectEntity = function(uuid) {
++                $rootScope.selectedEntity = $rootScope.queryCollection.getEntityByUUID(uuid);
++                $scope.addToPath(uuid);
++            };
++            $scope.getJSONView = function(entity) {
++                var tempjson = entity.get();
++                var queryBody = JSON.stringify(tempjson, null, 2);
++                queryBody = JSON.parse(queryBody);
++                delete queryBody.metadata;
++                delete queryBody.uuid;
++                delete queryBody.created;
++                delete queryBody.modified;
++                delete queryBody.type;
++                $scope.queryBody = JSON.stringify(queryBody, null, 2);
++            };
++            $scope.getPrevious = function() {
++                $rootScope.queryCollection.getPreviousPage(function(err) {
++                    if (err) {
++                        $rootScope.$broadcast("alert", "error", "error getting previous page of data");
++                    }
++                    $scope.checkNextPrev();
++                    $scope.applyScope();
++                });
++            };
++            $scope.getNext = function() {
++                $rootScope.queryCollection.getNextPage(function(err) {
++                    if (err) {
++                        $rootScope.$broadcast("alert", "error", "error getting next page of data");
++                    }
++                    $scope.checkNextPrev();
++                    $scope.applyScope();
++                });
++            };
++            init();
++            $rootScope.queryCollection = $rootScope.queryCollection || {};
++            $rootScope.selectedEntity = {};
++            if ($rootScope.queryCollection && $rootScope.queryCollection._type) {
++                $scope.loadCollection($rootScope.queryCollection._type);
++                $scope.setDisplayType();
++            }
++            ug.getTopCollections();
++            $scope.resetNextPrev();
++        } ]);
++        "use strict";
++        AppServices.Controllers.controller("EntityCtrl", [ "ug", "$scope", "$rootScope", "$location", function(ug, $scope, $rootScope, $location) {
++            if (!$rootScope.selectedEntity) {
++                $location.path("/data");
++                return;
++            }
++            $scope.entityUUID = $rootScope.selectedEntity.get("uuid");
++            $scope.entityType = $rootScope.selectedEntity.get("type");
++            var tempjson = $rootScope.selectedEntity.get();
++            var queryBody = JSON.stringify(tempjson, null, 2);
++            queryBody = JSON.parse(queryBody);
++            delete queryBody.metadata;
++            delete queryBody.uuid;
++            delete queryBody.created;
++            delete queryBody.modified;
++            delete queryBody.type;
++            $scope.queryBody = JSON.stringify(queryBody, null, 2);
++            $scope.validateJson = function() {
++                var queryBody = $scope.queryBody;
++                try {
++                    queryBody = JSON.parse(queryBody);
++                } catch (e) {
++                    $rootScope.$broadcast("alert", "error", "JSON is not valid");
++                    return false;
++                }
++                queryBody = JSON.stringify(queryBody, null, 2);
++                $rootScope.$broadcast("alert", "success", "JSON is valid");
++                $scope.queryBody = queryBody;
++                return true;
++            };
++            $scope.saveEntity = function() {
++                if (!$scope.validateJson()) {
++                    return false;
++                }
++                var queryBody = $scope.queryBody;
++                queryBody = JSON.parse(queryBody);
++                $rootScope.selectedEntity.set();
++                $rootScope.selectedEntity.set(queryBody);
++                $rootScope.selectedEntity.set("type", $scope.entityType);
++                $rootScope.selectedEntity.set("uuid", $scope.entityUUID);
++                $rootScope.selectedEntity.save(function(err, data) {
++                    if (err) {
++                        $rootScope.$broadcast("alert", "error", "error: " + data.error_description);
++                    } else {
++                        $rootScope.$broadcast("alert", "success", "entity saved");
++                    }
++                });
++            };
++        } ]);
++        "use strict";
++        AppServices.Directives.directive("balloon", [ "$window", "$timeout", function($window, $timeout) {
++            return {
++                restrict: "ECA",
++                scope: "=",
++                template: "" + '<div class="baloon {{direction}}" ng-transclude>' + "</div>",
++                replace: true,
++                transclude: true,
++                link: function linkFn(scope, lElement, attrs) {
++                    scope.direction = attrs.direction;
++                    var runScroll = true;
++                    var windowEl = angular.element($window);
++                    windowEl.on("scroll", function() {
++                        if (runScroll) {
++                            lElement.addClass("fade-out");
++                            $timeout(function() {
++                                lElement.addClass("hide");
++                            }, 1e3);
++                            runScroll = false;
++                        }
++                    });
++                }
++            };
++        } ]);
++        "use strict";
++        AppServices.Directives.directive("bsmodal", [ "$rootScope", function($rootScope) {
++            return {
++                restrict: "ECA",
++                scope: {
++                    title: "@title",
++                    buttonid: "=buttonid",
++                    footertext: "=footertext",
++                    closelabel: "=closelabel"
++                },
++                transclude: true,
++                templateUrl: "dialogs/modal.html",
++                replace: true,
++                link: function linkFn(scope, lElement, attrs, parentCtrl) {
++                    scope.title = attrs.title;
++                    scope.footertext = attrs.footertext;
++                    scope.closelabel = attrs.closelabel;
++                    scope.close = attrs.close;
++                    scope.extrabutton = attrs.extrabutton;
++                    scope.extrabuttonlabel = attrs.extrabuttonlabel;
++                    scope.buttonId = attrs.buttonid;
++                    scope.closeDelegate = function(attr) {
++                        scope.$parent[attr](attrs.id, scope);
++                    };
++                    scope.extraDelegate = function(attr) {
++                        if (scope.dialogForm.$valid) {
++                            console.log(parentCtrl);
++                            scope.$parent[attr](attrs.id);
++                        } else {
++                            $rootScope.$broadcast("alert", "error", "Please check your form input and resubmit.");
++                        }
++                    };
++                }
++            };
++        } ]);
++        "use strict";
++        AppServices.Controllers.controller("AlertCtrl", [ "$scope", "$rootScope", "$timeout", function($scope, $rootScope, $timeout) {
++            $scope.alertDisplay = "none";
++            $scope.alerts = [];
++            $scope.$on("alert", function(event, type, message, permanent) {
++                $scope.addAlert(type, message, permanent);
++            });
++            $scope.$on("clear-alerts", function(event, message) {
++                $scope.alerts = [];
++            });
++            $scope.addAlert = function(type, message, permanent) {
++                $scope.alertDisplay = "block";
++                $scope.alerts.push({
++                    type: type,
++                    msg: message
++                });
++                $scope.applyScope();
++                if (!permanent) {
++                    $timeout(function() {
++                        $scope.alerts.shift();
++                    }, 5e3);
++                }
++            };
++            $scope.closeAlert = function(index) {
++                $scope.alerts.splice(index, 1);
++            };
++        } ]);
++        "use strict";
++        AppServices.Directives.directive("alerti", [ "$rootScope", "$timeout", function($rootScope, $timeout) {
++            return {
++                restrict: "ECA",
++                scope: {
++                    type: "=type",
++                    closeable: "@closeable",
++                    index: "&index"
++                },
++                template: '<div class="alert" ng-class="type && \'alert-\' + type">' + '    <button ng-show="closeable" type="button" class="close" ng-click="closeAlert(index)">&times;</button>' + '    <i ng-if="type === \'warning\'" class="pictogram pull-left" style="font-size:3em;line-height:0.4">&#128165;</i>' + '    <i ng-if="type === \'info\'" class="pictogram pull-left">&#8505;</i>' + '    <i ng-if="type === \'error\'" class="pictogram pull-left">&#9889;</i>' + '    <i ng-if="type === \'success\'" class="pictogram pull-left">&#128077;</i>' + "<div ng-transclude></div>" + "</div>",
++                replace: true,
++                transclude: true,
++                link: function linkFn(scope, lElement, attrs) {
++                    $timeout(function() {
++                        lElement.addClass("fade-out");
++                    }, 4e3);
++                    lElement.click(function() {
++                        if (attrs.index) {
++                            scope.$parent.closeAlert(attrs.index);
++                        }
++                    });
++                    setTimeout(function() {
++                        lElement.addClass("alert-animate");
++                    }, 10);
++                }
++            };
++        } ]);
++        "use strict";
++        AppServices.Directives.directive("appswitcher", [ "$rootScope", function($rootScope) {
++            return {
++                restrict: "ECA",
++                scope: "=",
++                templateUrl: "global/appswitcher-template.html",
++                replace: true,
++                transclude: true,
++                link: function linkFn(scope, lElement, attrs) {
++                    var classNameOpen = "open";
++                    $("ul.nav li.dropdownContainingSubmenu").hover(function() {
++                        $(this).addClass(classNameOpen);
++                    }, function() {
++                        $(this).removeClass(classNameOpen);
++                    });
++                    $("#globalNav > a").mouseover(globalNavDetail);
++                    $("#globalNavDetail").mouseover(globalNavDetail);
++                    $("#globalNavSubmenuContainer ul li").mouseover(function() {
++                        $("#globalNavDetail > div").removeClass(classNameOpen);
++                        $("#" + this.getAttribute("data-globalNavDetail")).addClass(classNameOpen);
++                    });
++                    function globalNavDetail() {
++                        $("#globalNavDetail > div").removeClass(classNameOpen);
++                        $("#globalNavDetailApiPlatform").addClass(classNameOpen);
++                    }
++                }
++            };
++        } ]);
++        "use strict";
++        AppServices.Services.factory("help", function($rootScope, $http, $analytics) {
++            $rootScope.help = {};
++            $rootScope.help.helpButtonStatus = "Enable Help";
++            $rootScope.help.helpTooltipsEnabled = false;
++            $rootScope.help.clicked = false;
++            $rootScope.help.showHelpButtons = false;
++            var tooltipStartTime;
++            var helpStartTime;
++            var introjs_step;
++            $rootScope.help.sendTooltipGA = function(tooltipName) {
++                $analytics.eventTrack("tooltip - " + $rootScope.currentPath, {
++                    category: "App Services",
++                    label: tooltipName
++                });
++            };
++            $rootScope.help.toggleTooltips = function() {
++                if ($rootScope.help.helpTooltipsEnabled == false) {
++                    $rootScope.help.helpButtonStatus = "Disable Help";
++                    $rootScope.help.helpTooltipsEnabled = true;
++                    showHelpModal("tooltips");
++                } else {
++                    $rootScope.help.helpButtonStatus = "Enable Help";
++                    $rootScope.help.helpTooltipsEnabled = false;
++                }
++            };
++            $rootScope.help.IntroOptions = {
++                steps: [],
++                showStepNumbers: false,
++                exitOnOverlayClick: true,
++                exitOnEsc: true,
++                nextLabel: "Next",
++                prevLabel: "Back",
++                skipLabel: "Exit",
++                doneLabel: "Done"
++            };
++            $rootScope.$on("$routeChangeSuccess", function(event, current) {
++                var path = current.$$route ? current.$$route.originalPath : null;
++                if (path == "/org-overview") {
++                    $rootScope.help.showHelpButtons = true;
++                    getHelpJson(path).success(function(json) {
++                        var helpJson = json;
++                        setHelpStrings(helpJson);
++                        showHelpModal("tour");
++                    });
++                } else {
++                    $rootScope.help.showHelpButtons = false;
++                }
++            });
++            var showHelpModal = function(helpType) {
++                var shouldHelp = location.search.indexOf("noHelp") <= 0;
++                if (helpType == "tour" && !getHelpStatus(helpType)) {
++                    shouldHelp && $rootScope.showModal("introjs");
++                } else if (helpType == "tooltips" && !getHelpStatus(helpType)) {
++                    shouldHelp && $rootScope.showModal("tooltips");
++                }
++            };
++            var setHelpStrings = function(helpJson) {
++                $rootScope.help.IntroOptions.steps = helpJson.introjs;
++                angular.forEach(helpJson.tooltip, function(value, binding) {
++                    $rootScope[binding] = value;
++                });
++            };
++            $rootScope.help.introjs_StartEvent = function() {
++                helpStartTime = Date.now();
++                introjs_step = 1;
++            };
++            $rootScope.help.introjs_ExitEvent = function() {
++                var introjs_time = Math.round((Date.now() - helpStartTime) / 1e3);
++                $analytics.eventTrack("introjs timing - " + $rootScope.currentPath, {
++                    category: "App Services",
++                    label: introjs_time + "s"
++                });
++                $analytics.eventTrack("introjs exit - " + $rootScope.currentPath, {
++                    category: "App Services",
++                    label: "step" + introjs_step
++                });
++            };
++            $rootScope.help.introjs_ChangeEvent = function() {
++                introjs_step++;
++            };
++            var getHelpJson = function(path) {
++                return $http.jsonp("http://sdk.apigee.com.s3.amazonaws.com/portal_help" + path + "/helpJson.json?callback=JSON_CALLBACK");
++            };
++            var getHelpStatus = function(helpType) {
++                var status;
++                if (helpType == "tour") {
++                    status = localStorage.getItem("ftu_tour");
++                    localStorage.setItem("ftu_tour", "false");
++                } else if (helpType == "tooltips") {
++                    status = localStorage.getItem("ftu_tooltips");
++                    localStorage.setItem("ftu_tooltips", "false");
++                }
++                return status;
++            };
++        });
++        AppServices.Directives.directive("insecureBanner", [ "$rootScope", "ug", function($rootScope, ug) {
++            return {
++                restrict: "E",
++                transclude: true,
++                templateUrl: "global/insecure-banner.html",
++                link: function linkFn(scope, lElement, attrs) {
++                    scope.securityWarning = false;
++                    scope.$on("roles-received", function(evt, roles) {
++                        scope.securityWarning = false;
++                        if (!roles || !roles._list) return;
++                        roles._list.forEach(function(roleHolder) {
++                            var role = roleHolder._data;
++                            if (role.name.toUpperCase() === "GUEST") {
++                                roleHolder.getPermissions(function(err, data) {
++                                    if (!err) {
++                                        if (roleHolder.permissions) {
++                                            roleHolder.permissions.forEach(function(permission) {
++                                                if (permission.path.indexOf("/**") >= 0) {
++                                                    scope.securityWarning = true;
++                                                    scope.applyScope();
++                                                }
++                                            });
++                                        }
++                                    }
++                                });
++                            }
++                        });
++                    });
++                    var initialized = false;
++                    scope.$on("app-initialized", function() {
++                        !initialized && ug.getRoles();
++                        initialized = true;
++                    });
++                    scope.$on("app-changed", function() {
++                        scope.securityWarning = false;
++                        ug.getRoles();
++                    });
++                }
++            };
++        } ]);
++        "use strict";
++        AppServices.Constants.constant("configuration", {
++            ITEMS_URL: "global/temp.json"
++        });
++        "use strict";
++        AppServices.Controllers.controller("PageCtrl", [ "ug", "help", "utility", "$scope", "$rootScope", "$location", "$routeParams", "$q", "$route", "$log", "$analytics", function(ug, help, utility, $scope, $rootScope, $location, $routeParams, $q, $route, $log, $analytics) {
++            var initScopeVariables = function() {
++                $scope.loadingText = "Loading...";
++                $scope.use_sso = false;
++                $scope.newApp = {
++                    name: ""
++                };
++                $scope.getPerm = "";
++                $scope.postPerm = "";
++                $scope.putPerm = "";
++                $scope.deletePerm = "";
++                $scope.usersTypeaheadValues = [];
++                $scope.groupsTypeaheadValues = [];
++                $scope.rolesTypeaheadValues = [];
++                $rootScope.sdkActive = false;
++                $rootScope.demoData = false;
++                $scope.queryStringApplied = false;
++                $rootScope.autoUpdateTimer = Usergrid.config ? Usergrid.config.autoUpdateTimer : 61;
++                $rootScope.requiresDeveloperKey = Usergrid.config ? Usergrid.config.client.requiresDeveloperKey : false;
++                $rootScope.loaded = $rootScope.activeUI = false;
++                for (var key in Usergrid.regex) {
++                    $scope[key] = Usergrid.regex[key];
++                }
++                $scope.options = Usergrid.options;
++                var getQuery = function() {
++                    var result = {}, queryString = location.search.slice(1), re = /([^&=]+)=([^&]*)/g, m;
++                    while (m = re.exec(queryString)) {
++                        result[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
++                    }
++                    return result;
++                };
++                $scope.queryString = getQuery();
++            };
++            initScopeVariables();
++            $rootScope.urls = function() {
++                var urls = ug.getUrls($scope.queryString);
++                $scope.apiUrl = urls.apiUrl;
++                $scope.use_sso = urls.use_sso;
++                return urls;
++            };
++            $rootScope.gotoPage = function(path) {
++                $location.path(path);
++            };
++            var notRegistration = function() {
++                return "/forgot-password" !== $location.path() && "/register" !== $location.path();
++            };
++            var verifyUser = function() {
++                if ($location.path().slice(0, "/login".length) !== "/login") {
++                    $rootScope.currentPath = $location.path();
++                }
++                if ($routeParams.access_token && $routeParams.admin_email && $routeParams.uuid) {
++                    ug.set("token", $routeParams.access_token);
++                    ug.set("email", $routeParams.admin_email);
++                    ug.set("uuid", $routeParams.uuid);
++                    $location.search("access_token", null);
++                    $location.search("admin_email", null);
++                    $location.search("uuid", null);
++                }
++                ug.checkAuthentication(true);
++            };
++            $scope.profile = function() {
++                if ($scope.use_sso) {
++                    window.location = $rootScope.urls().PROFILE_URL + "?callback=" + encodeURIComponent($location.absUrl());
++                } else {
++                    $location.path("/profile");
++                }
++            };
++            $rootScope.showModal = function(id) {
++                $("#" + id).modal("show");
++            };
++            $rootScope.hideModal = function(id) {
++                $("#" + id).modal("hide");
++            };
++            $scope.deleteEntities = function(collection, successBroadcast, errorMessage) {
++                collection.resetEntityPointer();
++                var entitiesToDelete = [];
++                while (collection.hasNextEntity()) {
++                    var entity = collection.getNextEntity();
++                    var checked = entity.checked;
++                    if (checked) {
++                        entitiesToDelete.push(entity);
++                    }
++                }
++                var count = 0, success = false;
++                for (var i = 0; i < entitiesToDelete.length; i++) {
++                    var entity = entitiesToDelete[i];
++                    collection.destroyEntity(entity, function(err) {
++                        count++;
++                        if (err) {
++                            $rootScope.$broadcast("alert", "error", errorMessage);
++                            $rootScope.$broadcast(successBroadcast + "-error", err);
++                        } else {
++                            success = true;
++                        }
++                        if (count === entitiesToDelete.length) {
++                            success && $rootScope.$broadcast(successBroadcast);
++                            $scope.applyScope();
++                        }
++                    });
++                }
++            };
++            $scope.selectAllEntities = function(list, that, varName, setValue) {
++                varName = varName || "master";
++                var val = that[varName];
++                if (setValue == undefined) {
++                    setValue = true;
++                }
++                if (setValue) {
++                    that[varName] = val = !val;
++                }
++                list.forEach(function(entitiy) {
++                    entitiy.checked = val;
++                });
++            };
++            $scope.createPermission = function(type, entity, path, permissions) {
++                if (path.charAt(0) != "/") {
++                    path = "/" + path;
++                }
++                var ops = "";
++                var s = "";
++                if (permissions.getPerm) {
++                    ops = "get";
++                    s = ",";
++                }
++                if (permissions.postPerm) {
++                    ops = ops + s + "post";
++                    s = ",";
++                }
++                if (permissions.putPerm) {
++                    ops = ops + s + "put";
++                    s = ",";
++                }
++                if (permissions.deletePerm) {
++                    ops = ops + s + "delete";
++                    s = ",";
++                }
++                var permission = ops + ":" + path;
++                return permission;
++            };
++            $scope.formatDate = function(date) {
++                return new Date(date).toUTCString();
++            };
++            $scope.clearCheckbox = function(id) {
++                if ($("#" + id).attr("checked")) {
++                    $("#" + id).click();
++                }
++            };
++            $scope.removeFirstSlash = function(path) {
++                return path.indexOf("/") === 0 ? path.substring(1, path.length) : path;
++            };
++            $scope.applyScope = function(cb) {
++                cb = typeof cb === "function" ? cb : function() {};
++                if (!this.$$phase) {
++                    return this.$apply(cb);
++                } else {
++                    cb();
++                }
++            };
++            $scope.valueSelected = function(list) {
++                return list && list.some(function(item) {
++                    return item.checked;
++                });
++            };
++            $scope.sendHelp = function(modalId) {
++                ug.jsonpRaw("apigeeuihelpemail", "", {
++                    useremail: $rootScope.userEmail
++                }).then(function() {
++                    $rootScope.$broadcast("alert", "success", "Email sent. Our team will be in touch with you shortly.");
++                }, function() {
++                    $rootScope.$broadcast("alert", "error", "Problem Sending Email. Try sending an email to mobile@apigee.com.");
++                });
++                $scope.hideModal(modalId);
++            };
++            $scope.$on("users-typeahead-received", function(event, users) {
++                $scope.usersTypeaheadValues = users;
++                if (!$scope.$$phase) {
++                    $scope.$apply();
++                }
++            });
++            $scope.$on("groups-typeahead-received", function(event, groups) {
++                $scope.groupsTypeaheadValues = groups;
++                if (!$scope.$$phase) {
++                    $scope.$apply();
++                }
++            });
++            $scope.$on("roles-typeahead-received", function(event, roles) {
++                $scope.rolesTypeaheadValues = roles;
++                if (!$scope.$$phase) {
++                    $scope.$apply();
++                }
++            });
++            $scope.$on("checkAuthentication-success", function() {
++                sessionStorage.setItem("authenticateAttempts", 0);
++                $scope.loaded = true;
++                $rootScope.activeUI = true;
++                $scope.applyScope();
++                if (!$scope.queryStringApplied) {
++                    $scope.queryStringApplied = true;
++                    setTimeout(function() {
++                        if ($scope.queryString.org) {
++                            $rootScope.$broadcast("change-org", $scope.queryString.org);
++                        }
++                    }, 1e3);
++                }
++                $rootScope.$broadcast("app-initialized");
++            });
++            $scope.$on("checkAuthentication-error", function(args, err, missingData, email) {
++                $scope.loaded = true;
++                if (err && !$scope.use_sso && notRegistration()) {
++                    ug.logout();
++                    $location.path("/login");
++                    $scope.applyScope();
++                } else {
++                    if (missingData && notRegistration()) {
++                        if (!email && $scope.use_sso) {
++                            window.location = $rootScope.urls().LOGIN_URL + "?callback=" + encodeURIComponent($location.absUrl().split("?")[0]);
++                            return;
++                        }
++                        ug.reAuthenticate(email);
++                    }
++                }
++            });
++            $scope.$on("reAuthenticate-success", function(args, err, data, user, organizations, applications) {
++                sessionStorage.setItem("authenticateAttempts", 0);
++                $rootScope.$broadcast("loginSuccesful", user, organizations, applications);
++                $rootScope.$emit("loginSuccesful", user, organizations, applications);
++                $rootScope.$broadcast("checkAuthentication-success");
++                $scope.applyScope(function() {
++                    $scope.deferredLogin.resolve();
++                    $location.path("/org-overview");
++                });
++            });
++            var authenticateAttempts = parseInt(sessionStorage.getItem("authenticateAttempts") || 0);
++            $scope.$on("reAuthenticate-error", function() {
++                if ($scope.use_sso) {
++                    if (authenticateAttempts++ > 5) {
++                        $rootScope.$broadcast("alert", "error", "There is an issue with authentication. Please contact support.");
++                        return;
++                    }
++                    console.error("Failed to login via sso " + authenticateAttempts);
++                    sessionStorage.setItem("authenticateAttempts", authenticateAttempts);
++                    window.location = $rootScope.urls().LOGIN_URL + "?callback=" + encodeURIComponent($location.absUrl().split("?")[0]);
++                } else {
++                    if (notRegistration()) {
++                        ug.logout();
++                        $location.path("/login");
++                        $scope.applyScope();
++                    }
++                }
++            });
++            $scope.$on("loginSuccessful", function() {
++                $rootScope.activeUI = true;
++            });
++            $scope.$on("app-changed", function(args, oldVal, newVal, preventReload) {
++                if (newVal !== oldVal && !preventReload) {
++                    $route.reload();
++                }
++            });
++            $scope.$on("org-changed", function(args, oldOrg, newOrg) {
++                ug.getApplications();
++                $route.reload();
++            });
++            $scope.$on("app-settings-received", function(evt, data) {});
++            $scope.$on("request-times-slow", function(evt, averageRequestTimes) {
++                $rootScope.$broadcast("alert", "info", "We are experiencing performance issues on our server.  Please click Get Help for support if this continues.");
++            });
++            var lastPage = "";
++            $scope.$on("$routeChangeSuccess", function() {
++                verifyUser();
++                $scope.showDemoBar = $location.path().slice(0, "/performance".length) === "/performance";
++                if (!$scope.showDemoBar) {
++                    $rootScope.demoData = false;
++                }
++                setTimeout(function() {
++                    lastPage = "";
++                }, 50);
++                var path = window.location.pathname.replace("index-debug.html", "");
++                lastPage === "" && $analytics.pageTrack((path + $location.path()).replace("//", "/"));
++                lastPage = $location.path();
++            });
++            $scope.$on("applications-received", function(event, applications) {
++                $scope.applications = applications;
++                $scope.hasApplications = Object.keys(applications).length > 0;
++            });
++            ug.getAppSettings();
++            $rootScope.startFirstTimeUser = function() {
++                $rootScope.hideModal("introjs");
++                

<TRUNCATED>