Repository: ambari Updated Branches: refs/heads/trunk 5c204d86a -> f3aa618f9
AMBARI-8603 add updates page for ambari-web admin page. (ababiichuk) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/f3aa618f Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/f3aa618f Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/f3aa618f Branch: refs/heads/trunk Commit: f3aa618f9a87088e90b5199b9f7828bc19a85755 Parents: 5c204d8 Author: aBabiichuk <ababiic...@cybervisiontech.com> Authored: Tue Dec 9 16:02:18 2014 +0200 Committer: aBabiichuk <ababiic...@cybervisiontech.com> Committed: Tue Dec 9 16:02:18 2014 +0200 ---------------------------------------------------------------------- .../data/stack_versions/repo_versions_all.json | 449 +++++++++++++++++++ .../data/stack_versions/stack_version_all.json | 2 + ambari-web/app/assets/test/tests.js | 1 + ambari-web/app/controllers.js | 1 + .../stack_versions/repo_versions_controller.js | 92 ++++ .../stack_versions/stack_versions_controller.js | 2 +- .../app/mappers/repository_version_mapper.js | 49 +- ambari-web/app/mappers/stack_version_mapper.js | 6 +- ambari-web/app/routes/main.js | 9 + ambari-web/app/styles/application.less | 2 +- .../main/admin/stack_versions/repo_versions.hbs | 86 ++++ .../admin/stack_versions/stack_versions.hbs | 2 +- ambari-web/app/utils/ajax/ajax.js | 8 +- ambari-web/app/views.js | 2 + .../app/views/main/admin/stack_versions/menu.js | 51 +++ .../admin/stack_versions/repo_version_view.js | 129 ++++++ ambari-web/app/views/main/menu.js | 2 +- .../repo_versions_controller_test.js | 79 ++++ 18 files changed, 938 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/assets/data/stack_versions/repo_versions_all.json ---------------------------------------------------------------------- diff --git a/ambari-web/app/assets/data/stack_versions/repo_versions_all.json b/ambari-web/app/assets/data/stack_versions/repo_versions_all.json new file mode 100644 index 0000000..a96993c --- /dev/null +++ b/ambari-web/app/assets/data/stack_versions/repo_versions_all.json @@ -0,0 +1,449 @@ +{ + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions?fields=*,operatingSystems/*,operatingSystems/repositories/*", + "items" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/1", + "RepositoryVersions" : { + "display_name" : "HDP-2.2", + "id" : 1, + "repository_version" : "2.2", + "stack_name" : "HDP", + "stack_version" : "2.2", + "upgrade_pack" : "" + }, + "operating_systems" : [ ] + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/2", + "RepositoryVersions" : { + "display_name" : "HDP 2.2.0", + "id" : 2, + "repository_version" : "2.2.0.1-885", + "stack_name" : "HDP", + "stack_version" : "2.2", + "upgrade_pack" : "upgrade-2.2" + }, + "operating_systems" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/2/operating_systems/redhat6", + "OperatingSystems" : { + "os_type" : "redhat6", + "repository_version_id" : 2, + "stack_name" : "HDP", + "stack_version" : "2.2" + }, + "repositories" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/2/operating_systems/redhat6/repositories/HDP-2.2", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-2.2", + "repo_name" : "HDP", + "repository_version_id" : 2, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/2/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-UTILS-1.1.0.20", + "repo_name" : "HDP-UTILS", + "repository_version_id" : 2, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + } + ] + } + ] + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/3", + "RepositoryVersions" : { + "display_name" : "HDP 2.2.1", + "id" : 3, + "repository_version" : "2.2.1.1-885", + "stack_name" : "HDP", + "stack_version" : "2.2", + "upgrade_pack" : "upgrade-2.2" + }, + "operating_systems" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/3/operating_systems/redhat6", + "OperatingSystems" : { + "os_type" : "redhat6", + "repository_version_id" : 3, + "stack_name" : "HDP", + "stack_version" : "2.2" + }, + "repositories" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/3/operating_systems/redhat6/repositories/HDP-2.2", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-2.2", + "repo_name" : "HDP", + "repository_version_id" : 3, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/3/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-UTILS-1.1.0.20", + "repo_name" : "HDP-UTILS", + "repository_version_id" : 3, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + } + ] + } + ] + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/4", + "RepositoryVersions" : { + "display_name" : "HDP 2.2.2", + "id" : 4, + "repository_version" : "2.2.2.1-885", + "stack_name" : "HDP", + "stack_version" : "2.2", + "upgrade_pack" : "upgrade-2.2" + }, + "operating_systems" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/4/operating_systems/redhat6", + "OperatingSystems" : { + "os_type" : "redhat6", + "repository_version_id" : 4, + "stack_name" : "HDP", + "stack_version" : "2.2" + }, + "repositories" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/4/operating_systems/redhat6/repositories/HDP-2.2", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-2.2", + "repo_name" : "HDP", + "repository_version_id" : 4, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/4/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-UTILS-1.1.0.20", + "repo_name" : "HDP-UTILS", + "repository_version_id" : 4, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + } + ] + } + ] + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/5", + "RepositoryVersions" : { + "display_name" : "HDP 2.2.3", + "id" : 5, + "repository_version" : "2.2.3.1-885", + "stack_name" : "HDP", + "stack_version" : "2.2", + "upgrade_pack" : "upgrade-2.2" + }, + "operating_systems" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/5/operating_systems/redhat6", + "OperatingSystems" : { + "os_type" : "redhat6", + "repository_version_id" : 5, + "stack_name" : "HDP", + "stack_version" : "2.2" + }, + "repositories" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/5/operating_systems/redhat6/repositories/HDP-2.2", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-2.2", + "repo_name" : "HDP", + "repository_version_id" : 5, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/5/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-UTILS-1.1.0.20", + "repo_name" : "HDP-UTILS", + "repository_version_id" : 5, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + } + ] + } + ] + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/6", + "RepositoryVersions" : { + "display_name" : "HDP 2.2.4", + "id" : 6, + "repository_version" : "2.2.4.1-885", + "stack_name" : "HDP", + "stack_version" : "2.2", + "upgrade_pack" : "upgrade-2.2" + }, + "operating_systems" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/6/operating_systems/redhat6", + "OperatingSystems" : { + "os_type" : "redhat6", + "repository_version_id" : 6, + "stack_name" : "HDP", + "stack_version" : "2.2" + }, + "repositories" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/6/operating_systems/redhat6/repositories/HDP-2.2", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-2.2", + "repo_name" : "HDP", + "repository_version_id" : 6, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/6/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-UTILS-1.1.0.20", + "repo_name" : "HDP-UTILS", + "repository_version_id" : 6, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + } + ] + } + ] + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/7", + "RepositoryVersions" : { + "display_name" : "HDP 2.2.5", + "id" : 7, + "repository_version" : "2.2.5.1-885", + "stack_name" : "HDP", + "stack_version" : "2.2", + "upgrade_pack" : "upgrade-2.2" + }, + "operating_systems" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/7/operating_systems/redhat6", + "OperatingSystems" : { + "os_type" : "redhat6", + "repository_version_id" : 7, + "stack_name" : "HDP", + "stack_version" : "2.2" + }, + "repositories" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/7/operating_systems/redhat6/repositories/HDP-2.2", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-2.2", + "repo_name" : "HDP", + "repository_version_id" : 7, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/7/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-UTILS-1.1.0.20", + "repo_name" : "HDP-UTILS", + "repository_version_id" : 7, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + } + ] + } + ] + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/8", + "RepositoryVersions" : { + "display_name" : "HDP 2.2.6", + "id" : 8, + "repository_version" : "2.2.6.1-885", + "stack_name" : "HDP", + "stack_version" : "2.2", + "upgrade_pack" : "upgrade-2.2" + }, + "operating_systems" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/8/operating_systems/redhat6", + "OperatingSystems" : { + "os_type" : "redhat6", + "repository_version_id" : 8, + "stack_name" : "HDP", + "stack_version" : "2.2" + }, + "repositories" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/8/operating_systems/redhat6/repositories/HDP-2.2", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-2.2", + "repo_name" : "HDP", + "repository_version_id" : 8, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/8/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-UTILS-1.1.0.20", + "repo_name" : "HDP-UTILS", + "repository_version_id" : 8, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + } + ] + } + ] + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/9", + "RepositoryVersions" : { + "display_name" : "HDP 2.2.7", + "id" : 9, + "repository_version" : "2.2.7.1-885", + "stack_name" : "HDP", + "stack_version" : "2.2", + "upgrade_pack" : "upgrade-2.2" + }, + "operating_systems" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/9/operating_systems/redhat6", + "OperatingSystems" : { + "os_type" : "redhat6", + "repository_version_id" : 9, + "stack_name" : "HDP", + "stack_version" : "2.2" + }, + "repositories" : [ + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/9/operating_systems/redhat6/repositories/HDP-2.2", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-2.2", + "repo_name" : "HDP", + "repository_version_id" : 9, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + }, + { + "href" : "http://162.216.149.241:8080/api/v1/stacks/HDP/versions/2.2/repository_versions/9/operating_systems/redhat6/repositories/HDP-UTILS-1.1.0.20", + "Repositories" : { + "base_url" : "http://s3.amazonaws.com/dev.hortonworks.com/HDP/centos5/2.x/updates/2.2.0.0", + "default_base_url" : "", + "latest_base_url" : "", + "mirrors_list" : "", + "os_type" : "redhat6", + "repo_id" : "HDP-UTILS-1.1.0.20", + "repo_name" : "HDP-UTILS", + "repository_version_id" : 9, + "stack_name" : "HDP", + "stack_version" : "2.2" + } + } + ] + } + ] + } + ] +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/assets/data/stack_versions/stack_version_all.json ---------------------------------------------------------------------- diff --git a/ambari-web/app/assets/data/stack_versions/stack_version_all.json b/ambari-web/app/assets/data/stack_versions/stack_version_all.json index ea68a2f..932ae8a 100644 --- a/ambari-web/app/assets/data/stack_versions/stack_version_all.json +++ b/ambari-web/app/assets/data/stack_versions/stack_version_all.json @@ -6,6 +6,7 @@ "ClusterStackVersions" : { "cluster_name" : "1", "id" : 1, + "repository_version" : 1, "stack" : "HDP", "state" : "CURRENT", "version" : "2.2", @@ -83,6 +84,7 @@ "ClusterStackVersions" : { "cluster_name" : "1", "id" : 2, + "repository_version" : 2, "stack" : "HDP", "state" : "INSTALLED", "version" : "2.2", http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/assets/test/tests.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js index fdd95c3..38e13f6 100644 --- a/ambari-web/app/assets/test/tests.js +++ b/ambari-web/app/assets/test/tests.js @@ -53,6 +53,7 @@ var files = ['test/init_model_test', 'test/controllers/main/alerts/manage_alert_notifications_controller_test', 'test/controllers/main/admin/stack_and_upgrade_controller_test', 'test/controllers/main/admin/stack_version/stack_version_details_controller_test', + 'test/controllers/main/admin/stack_version/repo_versions_controller_test', 'test/controllers/main/admin/serviceAccounts_controller_test', 'test/controllers/main/admin/highAvailability_controller_test', 'test/controllers/main/admin/highAvailability/progress_controller_test', http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/controllers.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js index faa96d6..7e30431 100644 --- a/ambari-web/app/controllers.js +++ b/ambari-web/app/controllers.js @@ -53,6 +53,7 @@ require('controllers/main/admin/highAvailability/resourceManager/step3_controlle require('controllers/main/admin/highAvailability/resourceManager/step4_controller'); require('controllers/main/admin/stack_and_upgrade_controller'); require('controllers/main/admin/stack_upgrade_controller'); +require('controllers/main/admin/stack_versions/repo_versions_controller'); require('controllers/main/admin/stack_versions/stack_versions_controller'); require('controllers/main/admin/stack_versions/stack_version_details_controller'); require('controllers/main/admin/serviceAccounts_controller'); http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/controllers/main/admin/stack_versions/repo_versions_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/admin/stack_versions/repo_versions_controller.js b/ambari-web/app/controllers/main/admin/stack_versions/repo_versions_controller.js new file mode 100644 index 0000000..3204249 --- /dev/null +++ b/ambari-web/app/controllers/main/admin/stack_versions/repo_versions_controller.js @@ -0,0 +1,92 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var App = require('app'); + +App.RepoVersionsController = Em.ArrayController.extend({ + name: 'repoVersionsController', + + content: function () { + return App.RepositoryVersion.find().filterProperty('stackVersion', null); + }.property('dataIsLoaded'), + dataIsLoaded: false, + mockUrl: '/data/stack_versions/repo_versions_all.json', + realUrl: function () { + return App.get('apiPrefix') + App.get('stackVersionURL') + '/repository_versions?fields=*,operatingSystems/*,operatingSystems/repositories/*'; + }.property('App.stackVersionURL'), + /** + * load all data components required by repo version table + * @return {*} + */ + load: function () { + this.set('dataIsLoaded', false); + var dfd = $.Deferred(); + var self = this; + this.loadRepoVersionsToModel().done(function () { + self.set('dataIsLoaded', true); + dfd.resolve(); + }); + return dfd.promise(); + }, + + /** + * get repo versions from server and push it to model + * @return {*} + */ + loadRepoVersionsToModel: function (isUpdate) { + var dfd = $.Deferred(); + var self = this; + App.get('router.mainStackVersionsController').loadStackVersionsToModel().done(function () { + App.HttpClient.get(self.getUrl(isUpdate), App.repoVersionMapper, { + complete: function () { + dfd.resolve(); + } + }); + }); + + return dfd.promise(); + }, + + getUrl: function (isUpdate) { + return App.get('testMode') ? this.get('mockUrl') : + isUpdate ? this.get('realUpdateUrl') : this.get('realUrl'); + }, + + installRepoVersion: function (event) { + var repo = event.context; + var data = { + ClusterStackVersions: { + stack: repo.get('stackVersionType'), + version: repo.get('stackVersionNumber'), + repository_version: repo.get('repositoryVersion') + }, + id: repo.get('id') + }; + App.ajax.send({ + name: 'admin.stack_version.install.repo_version', + sender: this, + data: data, + success: 'installStackVersionSuccess' + }); + }, + + installStackVersionSuccess: function (data, opt, params) { + var stackVersion = App.StackVersion.find().findProperty('repositoryVersion.id', params.id); + App.router.transitionTo('main.admin.adminStackVersions.version', stackVersion); + } +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/controllers/main/admin/stack_versions/stack_versions_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/admin/stack_versions/stack_versions_controller.js b/ambari-web/app/controllers/main/admin/stack_versions/stack_versions_controller.js index 726739d..3f6e713 100644 --- a/ambari-web/app/controllers/main/admin/stack_versions/stack_versions_controller.js +++ b/ambari-web/app/controllers/main/admin/stack_versions/stack_versions_controller.js @@ -30,7 +30,7 @@ App.MainStackVersionsController = Em.ArrayController.extend({ return App.apiPrefix + '/clusters/' + App.get('clusterName') + '/stack_versions?fields=*,repository_versions/*,repository_versions/operatingSystems/repositories/*'; }.property('App.clusterName'), realUpdateUrl: function () { - return App.apiPrefix + '/clusters/' + App.get('clusterName') + '/stack_versions?fields=*,repository_versions/*,repository_versions/operatingSystems/repositories/*'; + return App.apiPrefix + '/clusters/' + App.get('clusterName') + '/stack_versions?fields=ClusterStackVersions/*'; //TODO return App.apiPrefix + '/clusters/' + App.get('clusterName') + '/stack_versions?fields=ClusterStackVersions/state,ClusterStackVersions/host_states&minimal_response=true'; }.property('App.clusterName'), http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/mappers/repository_version_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/repository_version_mapper.js b/ambari-web/app/mappers/repository_version_mapper.js index ecb914e..5d42fd8 100644 --- a/ambari-web/app/mappers/repository_version_mapper.js +++ b/ambari-web/app/mappers/repository_version_mapper.js @@ -64,7 +64,7 @@ App.repoVersionMapper = App.QuickDataMapper.create({ stack_version : 'Repositories.stack_version' }, - map: function (json) { + map: function (json, loadAll) { var modelRepoVersions = this.get('modelRepoVersions'); var modelOperatingSystems = this.get('modelOperatingSystems'); var modelRepositories = this.get('modelRepositories'); @@ -75,29 +75,32 @@ App.repoVersionMapper = App.QuickDataMapper.create({ if (json && json.items) { json.items.forEach(function (item) { - var repo = item; - var osArray = []; - - if (Em.get(item, 'operating_systems')) { - item.operating_systems.forEach(function (os) { - os.id = item.RepositoryVersions.repository_version + os.OperatingSystems.os_type; - os.repository_version_id = repo.id; - var repoArray = []; - if (Em.get(os, 'repositories')) { - os.repositories.forEach(function(repo) { - repo.id = repo.Repositories.repo_id + os.id; - repo.operating_system_id = os.id; - repoArray.pushObject(repo); - resultRepo.push(this.parseIt(repo, this.get('modelRepository'))); - }, this); - } - os.repositories = repoArray; - osArray.pushObject(os); - resultOS.push(this.parseIt(os, this.get('modelOS'))); - }, this); + if (loadAll || !App.StackVersion.find().someProperty('repositoryVersion.id', item.RepositoryVersions.id.toString())) { + var repo = item; + var osArray = []; + //TODO leave onr property name after api will be fixed + var operatingSystems = Em.get(item, 'operating_systems') || Em.get(item, 'operatingSystems'); + if (operatingSystems) { + operatingSystems.forEach(function (os) { + os.id = item.RepositoryVersions.repository_version + os.OperatingSystems.os_type; + os.repository_version_id = repo.id; + var repoArray = []; + if (Em.get(os, 'repositories')) { + os.repositories.forEach(function (repo) { + repo.id = repo.Repositories.repo_id + os.id; + repo.operating_system_id = os.id; + repoArray.pushObject(repo); + resultRepo.push(this.parseIt(repo, this.get('modelRepository'))); + }, this); + } + os.repositories = repoArray; + osArray.pushObject(os); + resultOS.push(this.parseIt(os, this.get('modelOS'))); + }, this); + } + repo.operating_systems = osArray; + resultRepoVersion.push(this.parseIt(repo, this.get('modelRepoVersion'))); } - repo.operating_systems = osArray; - resultRepoVersion.push(this.parseIt(repo, this.get('modelRepoVersion'))); }, this); } App.store.commit(); http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/mappers/stack_version_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/stack_version_mapper.js b/ambari-web/app/mappers/stack_version_mapper.js index 5ef49bd..c8169ba 100644 --- a/ambari-web/app/mappers/stack_version_mapper.js +++ b/ambari-web/app/mappers/stack_version_mapper.js @@ -43,11 +43,11 @@ App.stackVersionMapper = App.QuickDataMapper.create({ if (json && json.items) { json.items.forEach(function (item) { var stack = item.ClusterStackVersions; - if (item.repository_versions[0]) { - stack.repository_version_id = item.repository_versions[0].RepositoryVersions.id; + stack.repository_version_id = item.ClusterStackVersions.repository_version; + if (item.repository_versions && item.repository_versions[0]) { item.repository_versions[0].RepositoryVersions.stackVersionId = item.ClusterStackVersions.id; resultStack.push(this.parseIt(stack, this.get('modelStack'))); - App.repoVersionMapper.map({"items": item.repository_versions }); + App.repoVersionMapper.map({"items": item.repository_versions }, true); } }, this); } http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/routes/main.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js index 4fde39f..34edf7e 100644 --- a/ambari-web/app/routes/main.js +++ b/ambari-web/app/routes/main.js @@ -535,6 +535,15 @@ module.exports = Em.Route.extend({ connectOutlets: function (router, stackVersion) { router.get('mainAdminController').connectOutlet('mainStackVersionsDetails', stackVersion); } + }), + update: Em.Route.extend({ + route: '/updates', + connectOutlets: function (router) { + if(App.get('supports.stackUpgrade')) { + router.set('mainAdminController.category', "stackVersions"); + router.get('mainAdminController').connectOutlet('repoVersions'); + } + } }) }), adminAdvanced: Em.Route.extend({ http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/styles/application.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less index c38b987..ef6f618 100644 --- a/ambari-web/app/styles/application.less +++ b/ambari-web/app/styles/application.less @@ -5008,7 +5008,7 @@ ul.inline li { } } -#stack_versions { +#stack_versions, #repository_versions { .table { thead { background: none repeat scroll 0 0 #F8F8F8; http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/templates/main/admin/stack_versions/repo_versions.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/admin/stack_versions/repo_versions.hbs b/ambari-web/app/templates/main/admin/stack_versions/repo_versions.hbs new file mode 100644 index 0000000..1a48016 --- /dev/null +++ b/ambari-web/app/templates/main/admin/stack_versions/repo_versions.hbs @@ -0,0 +1,86 @@ +{{! +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +}} +{{view App.StackVersionMenuView}} +<div id="repository_versions"> + <table class="table advanced-header-table table-bordered table-striped"> + <thead> + {{#view view.sortView classNames="label-row" contentBinding="view.filteredContent"}} + {{view view.parentView.repoNameSort}} + {{view view.parentView.repoVersionSort}} + {{view view.parentView.osSort}} + <th class="action-col">Actions</th> + {{/view}} + + <tr class="filter-row"> + <th class="first repo-name-filter">{{view view.repoNameFilterView}}</th> + <th class="repo-version-filter">{{view view.repoVersionFilterView}}</th> + <th class="os-type-filter">{{view view.osFilterView}}</th> + <th></th> + </tr> + </thead> + <tbody class="services-menu"> + {{#if view.pageContent}} + {{#each item in view.pageContent}} + {{#view view.RepositoryVersionView contentBinding="item"}} + <td class="first repo-name"> + <span>{{view.content.repositoryVersion}}</span> + </td> + <td class="repo-display-name"> + <span>{{view.content.displayName}}</span> + </td> + <td class="os-types"> + <a href="#" class="os-expander" {{action toggleOs target="view"}}> + <span {{bindAttr class="view.isOsCollapsed:icon-caret-right:icon-caret-down"}}></span> + {{view.content.operatingSystems.length}} {{pluralize view.content.operatingSystems.length singular="t:common.os" plural="t:common.oss"}} + </a> + + <div id="stack-{{view.content.repositoryVersion}}" class="operating-systems"> + {{{view.labels}}} + </div> + </td> + <td class="repo-version-install"> + <a href="#" class="btn btn-success" {{action installRepoVersion view.content target="controller"}}>{{t common.install}}</a> + </td> + {{/view}} + {{/each}} + {{else}} + <tr> + <td class="first empty-table" colspan="4"> + {{t dashboard.configHistory.table.empty}} + </td> + </tr> + + {{/if}} + </tbody> + </table> + + <div class="page-bar"> + <div class="filtered-info span4"> + <label>{{view.filteredContentInfo}} - <a {{action clearFilters target="view"}} + href="#">{{t tableView.filters.clearAllFilters}}</a></label> + </div> + <div class="items-on-page"> + <label>{{t common.show}}: {{view view.rowsPerPageSelectView selectionBinding="view.displayLength"}}</label> + </div> + <div class="info">{{view.paginationInfo}}</div> + <div class="paging_two_button"> + {{view view.paginationLeft}} + {{view view.paginationRight}} + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/templates/main/admin/stack_versions/stack_versions.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/admin/stack_versions/stack_versions.hbs b/ambari-web/app/templates/main/admin/stack_versions/stack_versions.hbs index 41edf1e..dd6a99d 100644 --- a/ambari-web/app/templates/main/admin/stack_versions/stack_versions.hbs +++ b/ambari-web/app/templates/main/admin/stack_versions/stack_versions.hbs @@ -15,7 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. }} - +{{view App.StackVersionMenuView}} <div id="stack_versions"> <table class="table advanced-header-table table-bordered table-striped"> <thead> http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/utils/ajax/ajax.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js index 6f00a5c..a84f2dd 100644 --- a/ambari-web/app/utils/ajax/ajax.js +++ b/ambari-web/app/utils/ajax/ajax.js @@ -1346,13 +1346,13 @@ var urls = { 'mock': '/data/stack_versions/stack_version_all.json' }, 'admin.stack_version.install.repo_version': { - 'type': 'POST', - 'real': 'clusters/{clusterName}/requests', + 'real': '/clusters/{clusterName}/stack_versions', 'format': function (data) { return { type: 'POST', - dataType: 'text', - data: data.data + data: JSON.stringify({ + ClusterStackVersions: data.ClusterStackVersions + }) } }, 'mock': '' http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/views.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js index f7dae7e..5a06af8 100644 --- a/ambari-web/app/views.js +++ b/ambari-web/app/views.js @@ -106,6 +106,8 @@ require('views/main/admin/stack_upgrade'); require('views/main/admin/stack_upgrade/upgrade_version_box_view'); require('views/main/admin/stack_upgrade/upgrade_task_view'); require('views/main/admin/stack_and_upgrade_view'); +require('views/main/admin/stack_versions/menu'); +require('views/main/admin/stack_versions/repo_version_view'); require('views/main/admin/stack_versions/stack_version_view'); require('views/main/admin/stack_versions/stack_version_details_view'); require('views/main/admin/advanced'); http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/views/main/admin/stack_versions/menu.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/admin/stack_versions/menu.js b/ambari-web/app/views/main/admin/stack_versions/menu.js new file mode 100644 index 0000000..7117a1a --- /dev/null +++ b/ambari-web/app/views/main/admin/stack_versions/menu.js @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var App = require('app'); + +App.StackVersionMenuView = Em.CollectionView.extend({ + tagName: 'ul', + classNames: ["nav", "nav-tabs"], + content:function(){ + var menuItems = [ + { label: 'Installed', routing:'versions', url:"versions", active:"active"}, + { label: 'Updates', routing:'updates', url:"versions/updates"} + ]; + return menuItems; + }.property(), + + init: function(){ this._super(); this.activateView(); }, + + activateView:function () { + $.each(this._childViews, function () { + this.set('active', (document.URL.endsWith(this.get('content.routing')) ? "active" : "")); + }); + }.observes('App.router.location.lastSetURL'), + + deactivateChildViews: function() { + $.each(this._childViews, function(){ + this.set('active', ""); + }); + }, + + itemViewClass: Em.View.extend({ + classNameBindings: ["active"], + active: "", + template: Ember.Handlebars.compile('<a href="#/main/admin/{{unbound view.content.url}}"> {{unbound view.content.label}}</a>') + }) +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/views/main/admin/stack_versions/repo_version_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/admin/stack_versions/repo_version_view.js b/ambari-web/app/views/main/admin/stack_versions/repo_version_view.js new file mode 100644 index 0000000..c613a35 --- /dev/null +++ b/ambari-web/app/views/main/admin/stack_versions/repo_version_view.js @@ -0,0 +1,129 @@ +/** Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var App = require('app'); +var filters = require('views/common/filter_view'); +var sort = require('views/common/sort_view'); + +App.RepoVersionsView = App.TableView.extend({ + templateName: require('templates/main/admin/stack_versions/repo_versions'), + + content: function () { + return this.get('controller.content'); + }.property('controller.content'), + + /** + * return filtered number of all content number information displayed on the page footer bar + * @returns {String} + */ + filteredContentInfo: function () { + return this.t('tableView.filters.filteredConfigVersionInfo').format(this.get('filteredCount'), this.get('content.length')); + }.property('filteredCount', 'content.length'), + + /** + * associations between stack version property and column index + * @type {Array} + */ + colPropAssoc: function () { + var associations = []; + associations[1] = 'repositoryVersion'; + associations[2] = 'displayName'; + associations[3] = 'operatingSystems'; + return associations; + }.property(), + + sortView: sort.wrapperView, + repoNameSort: sort.fieldView.extend({ + column: 1, + name: 'repositoryVersion', + displayName: Em.I18n.t('admin.stackVersions.table.header.stack'), + type: 'version', + classNames: ['first'] + }), + repoVersionSort: sort.fieldView.extend({ + column: 2, + name: 'displayName', + displayName: Em.I18n.t('admin.stackVersions.table.header.version'), + type: 'version' + }), + osSort: sort.fieldView.extend({ + column: 3, + name: 'operatingSystems', + displayName: Em.I18n.t('admin.stackVersions.table.header.os') + }), + + repoNameFilterView: filters.createSelectView({ + column: 1, + fieldType: 'filter-input-width', + content: function () { + var names = this.get('parentView.content').mapProperty('repositoryVersion').uniq(); + return [ + { + value: '', + label: Em.I18n.t('common.all') + } + ].concat(names.map(function (name) { + return { + value: name, + label: name + } + })); + }.property('App.router.repoVersionsController.dataIsLoaded'), + onChangeValue: function () { + this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'select'); + } + }), + + repoVersionFilterView: filters.createTextView({ + column: 2, + fieldType: 'filter-input-width', + onChangeValue: function () { + this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'string'); + } + }), + + osFilterView: filters.createTextView({ + column: 3, + fieldType: 'filter-input-width', + onChangeValue: function () { + this.get('parentView').updateFilter(this.get('column'), this.get('value'), 'string'); + } + }), + + didInsertElement: function() { + this.get('controller').load(); + }, + + RepositoryVersionView: Em.View.extend({ + tagName: 'tr', + didInsertElement: function () { + App.tooltip(this.$("[rel='Tooltip']")); + this.set('isOsCollapsed', true); + }, + + toggleOs: function(event) { + this.set('isOsCollapsed', !this.get('isOsCollapsed')); + this.$('.operating-systems').toggle(); + }, + + labels: function() { + return this.get('content.operatingSystems') && + this.get('content.operatingSystems').getEach('osType').join("<br/>"); + }.property('content.operatingSystems.length') + }) + +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/app/views/main/menu.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/menu.js b/ambari-web/app/views/main/menu.js index 1df8379..509d416 100644 --- a/ambari-web/app/views/main/menu.js +++ b/ambari-web/app/views/main/menu.js @@ -131,7 +131,7 @@ App.MainMenuView = Em.CollectionView.extend({ }); if (App.get('supports.stackUpgrade')) { categories.push({ - name: 'adminStackVersions', + name: 'adminStackVersions.index', url: 'versions', label: Em.I18n.t('common.stack.versions') }); http://git-wip-us.apache.org/repos/asf/ambari/blob/f3aa618f/ambari-web/test/controllers/main/admin/stack_version/repo_versions_controller_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/admin/stack_version/repo_versions_controller_test.js b/ambari-web/test/controllers/main/admin/stack_version/repo_versions_controller_test.js new file mode 100644 index 0000000..0d979ae --- /dev/null +++ b/ambari-web/test/controllers/main/admin/stack_version/repo_versions_controller_test.js @@ -0,0 +1,79 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +var App = require('app'); +require('controllers/main/admin/stack_versions/repo_versions_controller'); +var repoVersionsController; + +describe('App.RepoVersionsController', function () { + + beforeEach(function () { + repoVersionsController = App.RepoVersionsController.create(); + }); + + describe('#installRepoVersion', function () { + beforeEach(function () { + sinon.stub(App.ajax, 'send', Em.K); + }); + afterEach(function () { + App.ajax.send.restore(); + }); + it("runs post request to create stack version", function () { + var repoVersion = Em.Object.create({ + stackVersionType: "HDP", + stackVersionNumber: "2.2", + repositoryVersion: "2.2.0.1" + }); + repoVersionsController.installRepoVersion({context: repoVersion}); + expect(App.ajax.send.getCall(0).args[0].data.ClusterStackVersions).to.deep.eql({ + "stack": "HDP", + "version": "2.2", + "repository_version": "2.2.0.1" + }); + }); + }); + + describe('#load', function () { + it('', function () { + sinon.stub(repoVersionsController, 'loadRepoVersionsToModel').returns({done: Em.K}); + repoVersionsController.load(); + expect(repoVersionsController.loadRepoVersionsToModel.calledOnce).to.be.true; + repoVersionsController.loadRepoVersionsToModel.restore(); + }); + }); + describe('#loadRepoVersionsToModel()', function () { + it('', function () { + sinon.stub(App.HttpClient, 'get', Em.K); + sinon.stub(repoVersionsController, 'getUrl', Em.K); + sinon.stub(App.get('router.mainStackVersionsController'), 'loadStackVersionsToModel', function() { return $.Deferred().resolve()}); + + repoVersionsController.loadRepoVersionsToModel(); + expect(App.HttpClient.get.calledOnce).to.be.true; + expect(repoVersionsController.getUrl.calledOnce).to.be.true; + expect(App.get('router.mainStackVersionsController').loadStackVersionsToModel.calledOnce).to.be.true; + + + App.get('router.mainStackVersionsController').loadStackVersionsToModel.restore(); + repoVersionsController.getUrl.restore(); + App.HttpClient.get.restore(); + }); + }); + + +}); \ No newline at end of file