From b9708a7c3cfaf5767992a2b15180e7b85c459242 Mon Sep 17 00:00:00 2001 From: "Eran (ev672n), Vosk" Date: Tue, 7 Aug 2018 14:15:05 +0300 Subject: adding the dcae dt code Adding DCAE-dt code Change-Id: Id6b779db9d24e10825fb97ad5fd46f41e65e6738 Issue-ID: SDC-1614 Signed-off-by: Eran (ev672n), Vosk --- .bowerrc | 5 + .editorconfig | 21 + .gitignore | 34 + .maven-dockerignore | 1 + Dockerfile | 26 + Gruntfile.js | 644 + README.md | 29 + __test__/user-mapping.test.js | 41 + app/VNF_List.json | 1 + app/WEB-INF/jetty-web.xml | 8 + app/WEB-INF/rewrite.config | 2 + app/WEB-INF/web.xml | 10 + app/_dcaeapp.xml | 45 + app/app.config.js | 65 + app/app.constants.js | 20 + app/app.controller.js | 17 + app/app.module.js | 29 + app/app.route.js | 72 + app/app.run.js | 59 + app/comp-fe/asdc-catalog.js | 165 + app/comp-fe/catalog.css | 248 + app/comp-fe/catalog.html | 57 + app/comp-fe/catalog.js | 89 + app/comp-fe/composition.css | 626 + app/comp-fe/composition.js | 3004 +++ app/comp-fe/config.js | 3 + app/comp-fe/cors_http_server.py | 13 + app/comp-fe/elements | 1 + app/comp-fe/httpserv.js | 32 + app/comp-fe/icecat.html | 67 + app/comp-fe/img/3net.png | Bin 0 -> 32114 bytes app/comp-fe/img/3netg.png | Bin 0 -> 31927 bytes app/comp-fe/img/collnode.png | Bin 0 -> 6565 bytes app/comp-fe/img/dbnode.png | Bin 0 -> 2783 bytes app/comp-fe/img/death.png | Bin 0 -> 80676 bytes app/comp-fe/img/dummy.svg | 1 + app/comp-fe/img/extnode.png | Bin 0 -> 4780 bytes app/comp-fe/img/gamma.png | Bin 0 -> 12375 bytes app/comp-fe/img/msnode.png | Bin 0 -> 2914 bytes app/comp-fe/img/sanode.png | Bin 0 -> 7621 bytes app/comp-fe/img/srcnode.png | Bin 0 -> 5512 bytes app/comp-fe/js/bootstrap-notify.min.js | 2 + app/comp-fe/js/bootstrap.js | 2317 ++ app/comp-fe/js/circular-json.js | 2 + app/comp-fe/js/d3.js | 16673 ++++++++++++ app/comp-fe/js/d3.min.js | 5 + app/comp-fe/js/react.min.js | 16 + app/comp-fe/js/underscore-min.js | 6 + app/comp-fe/js/underscore-min.map | 0 app/comp-fe/js/underscore.js | 1276 + app/comp-fe/styles/bootstrap.css | 6584 +++++ app/core/header/header.controller.js | 15 + app/core/header/header.module.js | 13 + .../header/layouts/content-with-header/header.html | 36 + .../header/layouts/content-with-header/header.less | 5 + .../layouts/horizontal-navigation/header.html | 14 + .../layouts/horizontal-navigation/header.less | 53 + app/core/layouts/content-only/content-only.html | 7 + app/core/layouts/content-only/content-only.less | 3 + .../content-with-header/content-with-header.html | 5 + .../content-with-header/content-with-header.less | 3 + .../content-with-navigation.html | 15 + .../content-with-navigation.less | 4 + .../full-page-with-header.html | 30 + .../full-page-with-header.less | 167 + .../header-navigation-content.html | 11 + .../header-navigation-content.less | 3 + .../layouts/horizontal-navigation/navigation.html | 4 + .../layouts/horizontal-navigation/navigation.less | 26 + app/core/navigation/navigation.controller.js | 41 + app/core/navigation/navigation.module.js | 15 + app/dcaeapp.xml | 125 + app/favicon.png | Bin 0 -> 6364 bytes app/grep-logs/AIC-grep.txt | 4 + app/grep-logs/amdocs-grep.txt | 0 app/grep.sh | 53 + app/index.html | 194 + app/main/dashboard/about/about.controller.js | 16 + app/main/dashboard/about/about.html | 2 + app/main/dashboard/about/about.less | 5 + app/main/dashboard/about/about.module.js | 24 + app/main/dashboard/dcaedt/dcae.less | 1376 + app/main/dashboard/dcaedt/dcaedt.controller.js | 519 + app/main/dashboard/dcaedt/dcaedt.factory.js | 27 + app/main/dashboard/dcaedt/dcaedt.html | 69 + app/main/dashboard/dcaedt/dcaedt.module.js | 148 + app/main/dashboard/dcaedt/dcaedt.values.js | 6 + app/main/dashboard/dcaedt/dcaedt_artifact.html | 18 + app/main/dashboard/dcaedt/dcaedt_composition.html | 158 + app/main/dashboard/dcaedt/dcaedt_general.html | 202 + .../dashboard/dcaedt/dcaedt_general_service.html | 274 + app/main/dashboard/dcaedt/dcaedt_general_vnf.html | 228 + app/main/dashboard/dcaedt/dcaedt_import.html | 61 + app/main/dashboard/dcaedt/dcaedt_self_serve.html | 74 + app/main/dashboard/dcaedt/dcaedt_services.html | 79 + app/main/dashboard/dcaedt/leftMenu.html | 22 + app/main/dashboard/home/home.controller.js | 16 + app/main/dashboard/home/home.html | 1 + app/main/dashboard/home/home.less | 5 + app/main/dashboard/home/home.module.js | 25 + app/main/errors/404.html | 152 + app/main/main.controller.js | 22 + app/my-lib.js | 238 + app/my-lib.js.map | 1 + app/node.exe.stackdump | 7 + app/prodHtml/index.html | 206 + app/punch-outs.js | 16 + app/robots.txt | 4 + app/sdc-pubsub.js | 285 + app/services/cache.service.js | 37 + app/services/users.service.js | 33 + app/sh.exe.stackdump | 7 + app/styles/app.css | 25513 +++++++++++++++++++ app/styles/app.less | 23 + app/styles/catalog.css | 223 + app/styles/images/Add.png | Bin 0 -> 731 bytes app/styles/images/att_logo.png | Bin 0 -> 2827 bytes app/styles/images/import.png | Bin 0 -> 409 bytes app/styles/images/import.svg | 39 + app/styles/images/sprites/sprite-global-old.png | Bin 0 -> 84465 bytes app/styles/images/sprites/sprite-global.png | Bin 0 -> 83986 bytes app/styles/images/sprites/sprite-product-icons.png | Bin 0 -> 132122 bytes .../images/sprites/sprite-resource-icons.png | Bin 0 -> 496742 bytes .../images/sprites/sprite-services-icons.png | Bin 0 -> 127233 bytes app/styles/images/sprites/tlv-sprite.png | Bin 0 -> 14677 bytes app/styles/mixins.less | 217 + app/styles/mixins_old.less | 555 + app/styles/sdc.less | 18385 +++++++++++++ app/styles/sprite-resource-icons.less | 268 + app/styles/sprite-services-icons.less | 66 + app/styles/sprite.less | 225 + app/styles/tlv-sprite.less | 138 + app/styles/variables.less | 43 + bower.json | 24 + deploy.sh | 15 + docker/chef-solo/cookbooks/dcae-dt/.gitignore | 20 + docker/chef-solo/cookbooks/dcae-dt/.kitchen.yml | 16 + docker/chef-solo/cookbooks/dcae-dt/README.md | 4 + .../cookbooks/dcae-dt/attributes/default.rb | 19 + .../cookbooks/dcae-dt/files/default/keystore | Bin 0 -> 4255 bytes .../cookbooks/dcae-dt/files/default/truststore | Bin 0 -> 4255 bytes docker/chef-solo/cookbooks/dcae-dt/metadata.rb | 7 + .../cookbooks/dcae-dt/recipes/dcae_dt_setup.rb | 69 + .../cookbooks/dcae-dt/recipes/jetty_setup.rb | 86 + .../default/dcae-application.properties.erb | 4 + .../templates/default/dcae-logback-spring.erb | 342 + .../dcae-dt/templates/default/http-ini.erb | 29 + .../dcae-dt/templates/default/https-ini.erb | 29 + .../dcae-dt/templates/default/ssl-ini.erb | 90 + docker/chef-solo/environments/.keep | 0 docker/chef-solo/roles/dcae-dt.json | 18 + docker/chef-solo/solo.json | 4 + docker/chef-solo/solo.rb | 16 + docker/scripts/set_dockerfile_and_pom.pl | 62 + docker/set_user.sh | 20 + docker/startup.sh | 19 + package-lock.json | 15372 +++++++++++ package.json | 61 + pom.xml | 445 + run.sh | 9 + src/main/java/org/onap/sdc/dcae/FeApp.java | 76 + .../dcae/controller/health/HealthController.java | 72 + .../sdc/dcae/controller/proxy/DcaeProxyOld.java | 164 + .../sdc/dcae/controller/proxy/DcaeProxyTest.java | 29 + test/.jshintrc | 18 + test/karma.conf.js | 76 + test/spec/controllers/main.js | 23 + webpack.config.js | 31 + 168 files changed, 100489 insertions(+) create mode 100644 .bowerrc create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .maven-dockerignore create mode 100644 Dockerfile create mode 100644 Gruntfile.js create mode 100644 README.md create mode 100644 __test__/user-mapping.test.js create mode 100644 app/VNF_List.json create mode 100644 app/WEB-INF/jetty-web.xml create mode 100644 app/WEB-INF/rewrite.config create mode 100644 app/WEB-INF/web.xml create mode 100644 app/_dcaeapp.xml create mode 100644 app/app.config.js create mode 100644 app/app.constants.js create mode 100644 app/app.controller.js create mode 100644 app/app.module.js create mode 100644 app/app.route.js create mode 100644 app/app.run.js create mode 100644 app/comp-fe/asdc-catalog.js create mode 100644 app/comp-fe/catalog.css create mode 100644 app/comp-fe/catalog.html create mode 100644 app/comp-fe/catalog.js create mode 100644 app/comp-fe/composition.css create mode 100644 app/comp-fe/composition.js create mode 100644 app/comp-fe/config.js create mode 100644 app/comp-fe/cors_http_server.py create mode 100644 app/comp-fe/elements create mode 100644 app/comp-fe/httpserv.js create mode 100644 app/comp-fe/icecat.html create mode 100644 app/comp-fe/img/3net.png create mode 100644 app/comp-fe/img/3netg.png create mode 100644 app/comp-fe/img/collnode.png create mode 100644 app/comp-fe/img/dbnode.png create mode 100644 app/comp-fe/img/death.png create mode 100644 app/comp-fe/img/dummy.svg create mode 100644 app/comp-fe/img/extnode.png create mode 100644 app/comp-fe/img/gamma.png create mode 100644 app/comp-fe/img/msnode.png create mode 100644 app/comp-fe/img/sanode.png create mode 100644 app/comp-fe/img/srcnode.png create mode 100644 app/comp-fe/js/bootstrap-notify.min.js create mode 100644 app/comp-fe/js/bootstrap.js create mode 100644 app/comp-fe/js/circular-json.js create mode 100644 app/comp-fe/js/d3.js create mode 100644 app/comp-fe/js/d3.min.js create mode 100644 app/comp-fe/js/react.min.js create mode 100644 app/comp-fe/js/underscore-min.js create mode 100644 app/comp-fe/js/underscore-min.map create mode 100644 app/comp-fe/js/underscore.js create mode 100644 app/comp-fe/styles/bootstrap.css create mode 100644 app/core/header/header.controller.js create mode 100644 app/core/header/header.module.js create mode 100644 app/core/header/layouts/content-with-header/header.html create mode 100644 app/core/header/layouts/content-with-header/header.less create mode 100644 app/core/header/layouts/horizontal-navigation/header.html create mode 100644 app/core/header/layouts/horizontal-navigation/header.less create mode 100644 app/core/layouts/content-only/content-only.html create mode 100644 app/core/layouts/content-only/content-only.less create mode 100644 app/core/layouts/content-with-header/content-with-header.html create mode 100644 app/core/layouts/content-with-header/content-with-header.less create mode 100755 app/core/layouts/content-with-navigation/content-with-navigation.html create mode 100755 app/core/layouts/content-with-navigation/content-with-navigation.less create mode 100644 app/core/layouts/full-page-with-header/full-page-with-header.html create mode 100644 app/core/layouts/full-page-with-header/full-page-with-header.less create mode 100644 app/core/layouts/header-navigation-content/header-navigation-content.html create mode 100644 app/core/layouts/header-navigation-content/header-navigation-content.less create mode 100644 app/core/navigation/layouts/horizontal-navigation/navigation.html create mode 100644 app/core/navigation/layouts/horizontal-navigation/navigation.less create mode 100644 app/core/navigation/navigation.controller.js create mode 100644 app/core/navigation/navigation.module.js create mode 100644 app/dcaeapp.xml create mode 100644 app/favicon.png create mode 100644 app/grep-logs/AIC-grep.txt create mode 100644 app/grep-logs/amdocs-grep.txt create mode 100755 app/grep.sh create mode 100644 app/index.html create mode 100644 app/main/dashboard/about/about.controller.js create mode 100644 app/main/dashboard/about/about.html create mode 100644 app/main/dashboard/about/about.less create mode 100644 app/main/dashboard/about/about.module.js create mode 100644 app/main/dashboard/dcaedt/dcae.less create mode 100644 app/main/dashboard/dcaedt/dcaedt.controller.js create mode 100644 app/main/dashboard/dcaedt/dcaedt.factory.js create mode 100644 app/main/dashboard/dcaedt/dcaedt.html create mode 100644 app/main/dashboard/dcaedt/dcaedt.module.js create mode 100644 app/main/dashboard/dcaedt/dcaedt.values.js create mode 100644 app/main/dashboard/dcaedt/dcaedt_artifact.html create mode 100644 app/main/dashboard/dcaedt/dcaedt_composition.html create mode 100644 app/main/dashboard/dcaedt/dcaedt_general.html create mode 100644 app/main/dashboard/dcaedt/dcaedt_general_service.html create mode 100644 app/main/dashboard/dcaedt/dcaedt_general_vnf.html create mode 100644 app/main/dashboard/dcaedt/dcaedt_import.html create mode 100644 app/main/dashboard/dcaedt/dcaedt_self_serve.html create mode 100644 app/main/dashboard/dcaedt/dcaedt_services.html create mode 100644 app/main/dashboard/dcaedt/leftMenu.html create mode 100644 app/main/dashboard/home/home.controller.js create mode 100644 app/main/dashboard/home/home.html create mode 100644 app/main/dashboard/home/home.less create mode 100644 app/main/dashboard/home/home.module.js create mode 100644 app/main/errors/404.html create mode 100644 app/main/main.controller.js create mode 100644 app/my-lib.js create mode 100644 app/my-lib.js.map create mode 100644 app/node.exe.stackdump create mode 100644 app/prodHtml/index.html create mode 100644 app/punch-outs.js create mode 100644 app/robots.txt create mode 100644 app/sdc-pubsub.js create mode 100644 app/services/cache.service.js create mode 100644 app/services/users.service.js create mode 100644 app/sh.exe.stackdump create mode 100644 app/styles/app.css create mode 100755 app/styles/app.less create mode 100644 app/styles/catalog.css create mode 100644 app/styles/images/Add.png create mode 100755 app/styles/images/att_logo.png create mode 100644 app/styles/images/import.png create mode 100644 app/styles/images/import.svg create mode 100644 app/styles/images/sprites/sprite-global-old.png create mode 100644 app/styles/images/sprites/sprite-global.png create mode 100644 app/styles/images/sprites/sprite-product-icons.png create mode 100644 app/styles/images/sprites/sprite-resource-icons.png create mode 100644 app/styles/images/sprites/sprite-services-icons.png create mode 100644 app/styles/images/sprites/tlv-sprite.png create mode 100755 app/styles/mixins.less create mode 100644 app/styles/mixins_old.less create mode 100644 app/styles/sdc.less create mode 100644 app/styles/sprite-resource-icons.less create mode 100644 app/styles/sprite-services-icons.less create mode 100755 app/styles/sprite.less create mode 100644 app/styles/tlv-sprite.less create mode 100755 app/styles/variables.less create mode 100644 bower.json create mode 100644 deploy.sh create mode 100644 docker/chef-solo/cookbooks/dcae-dt/.gitignore create mode 100644 docker/chef-solo/cookbooks/dcae-dt/.kitchen.yml create mode 100644 docker/chef-solo/cookbooks/dcae-dt/README.md create mode 100644 docker/chef-solo/cookbooks/dcae-dt/attributes/default.rb create mode 100644 docker/chef-solo/cookbooks/dcae-dt/files/default/keystore create mode 100644 docker/chef-solo/cookbooks/dcae-dt/files/default/truststore create mode 100644 docker/chef-solo/cookbooks/dcae-dt/metadata.rb create mode 100644 docker/chef-solo/cookbooks/dcae-dt/recipes/dcae_dt_setup.rb create mode 100644 docker/chef-solo/cookbooks/dcae-dt/recipes/jetty_setup.rb create mode 100644 docker/chef-solo/cookbooks/dcae-dt/templates/default/dcae-application.properties.erb create mode 100644 docker/chef-solo/cookbooks/dcae-dt/templates/default/dcae-logback-spring.erb create mode 100644 docker/chef-solo/cookbooks/dcae-dt/templates/default/http-ini.erb create mode 100644 docker/chef-solo/cookbooks/dcae-dt/templates/default/https-ini.erb create mode 100644 docker/chef-solo/cookbooks/dcae-dt/templates/default/ssl-ini.erb create mode 100644 docker/chef-solo/environments/.keep create mode 100644 docker/chef-solo/roles/dcae-dt.json create mode 100644 docker/chef-solo/solo.json create mode 100644 docker/chef-solo/solo.rb create mode 100644 docker/scripts/set_dockerfile_and_pom.pl create mode 100755 docker/set_user.sh create mode 100644 docker/startup.sh create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 pom.xml create mode 100644 run.sh create mode 100644 src/main/java/org/onap/sdc/dcae/FeApp.java create mode 100644 src/main/java/org/onap/sdc/dcae/controller/health/HealthController.java create mode 100644 src/main/java/org/onap/sdc/dcae/controller/proxy/DcaeProxyOld.java create mode 100644 src/test/org/onap/sdc/dcae/controller/proxy/DcaeProxyTest.java create mode 100644 test/.jshintrc create mode 100644 test/karma.conf.js create mode 100644 test/spec/controllers/main.js create mode 100644 webpack.config.js diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 0000000..e98c83d --- /dev/null +++ b/.bowerrc @@ -0,0 +1,5 @@ +{ + "directory": "bower_components", + "proxy":"http://one.proxy.att.com:8080", + "https-proxy":"http://one.proxy.att.com:8080" +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..1215de4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + + +[*] + +# Change these settings to your own preference +indent_style = space +indent_size = 4 + +# We recommend you to keep these unchanged +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9bd2ce8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +.tmp/* +.tmp_imploded/* +bower_components/* +app/bower_components/* +node_modules/* +dist/* +.tmp_imploded/fonts/glyphicons-halflings-regular.svg +app/app.env.js +.project +.idea/* +.vscode/ +target/* +.settings* +.classpath +/*.war +/node/* +/src/main/webapp/comp-fe/* +/src/main/webapp/*.png +/src/main/webapp/* +!/src/main/webapp/META-INF/MANIFAST.MF +!/src/main/webapp/WEB-INF/config/dcae-fe/* +*.iml + +# intelij idea IDE +*.iml + + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +/target/ diff --git a/.maven-dockerignore b/.maven-dockerignore new file mode 100644 index 0000000..07fa861 --- /dev/null +++ b/.maven-dockerignore @@ -0,0 +1 @@ +target/docker/ diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..9c2fe6a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +FROM dockercentral.it.att.com:5100/com.att.sdc/base_sdc-jetty:1.2.0-SNAPSHOT-latest + +COPY docker/chef-solo /var/opt/dcae-dt/chef-solo/ + +COPY docker/startup.sh /var/opt/dcae-dt/ + +ADD target/dcae-dt.war ${JETTY_BASE}/webapps/ + +USER root + +RUN mkdir -p /opt/logs/dcae-dt + +COPY docker/set_user.sh /tmp/set_user.sh + +RUN sh -x /tmp/set_user.sh && rm -f /tmp/set_user.sh + +RUN chown -R jetty:jetty ${JETTY_BASE}/webapps /var/opt/dcae-dt /opt/logs /var/lib/jetty + +RUN chmod 770 /var/opt/dcae-dt/startup.sh + +EXPOSE 8186 9446 + +USER jetty + +ENTRYPOINT [ "/var/opt/dcae-dt/startup.sh" ] + diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..d9d90d8 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,644 @@ +// Generated on 2016-05-30 using generator-angular 0.15.1 +'use strict'; + +// # Globbing for performance reasons we're only matching one level down: +// 'test/spec/{,*/}*.js' use this if you want to recursively match all +// subfolders: 'test/spec/**/*.js' + +module.exports = function (grunt) { + + // Time how long tasks take. Can help when optimizing build times + require('time-grunt')(grunt); + + // Automatically load required Grunt tasks + require('jit-grunt')(grunt, { + useminPrepare: 'grunt-usemin', + ngtemplates: 'grunt-angular-templates', + cdnify: 'grunt-google-cdn', + ngconstant: 'grunt-ng-constant', + mkdir: 'grunt-mkdir', + preprocess: 'grunt-preprocess' + }); + + // Configurable paths for the application + var appConfig = { + app: require('./bower.json').appPath || 'app', + tmp: { + exploded: '.tmp', + imploded: '.tmp_imploded' + }, + dist: { + exploded: 'dist/exploded', + imploded: 'dist/imploded', + war: 'dist/war' + } + }; + + // Define the configuration for all the tasks + grunt.initConfig({ + + // Project settings + yeoman: appConfig, + + // Watches files for changes and runs tasks based on the changed files + watch: { + bower: { + files: ['bower.json'], + tasks: ['wiredep'] + }, + js: { + files: ['<%= yeoman.app %>/main/{,*/}*.js'], + tasks: [ + 'newer:jshint:all', 'newer:jscs:all' + ], + options: { + livereload: '<%= connect.options.livereload %>' + } + }, + injector: { + files: [ + 'app/styles/*.less', 'app/core/**/*.less', 'app/main/**/*.less' + ], + taskd: ['injector'] + }, + less: { + files: ['app/**/*.less'], + tasks: ['less:development'], + options: { + nospawn: true + } + }, + styles: { + files: ['<%= yeoman.app %>/main/{,*/}*.css'], + tasks: ['newer:copy:styles', 'postcss'] + }, + gruntfile: { + files: ['Gruntfile.js'] + }, + options: { + livereload: true + }, + livereload: { + options: { + livereload: '<%= connect.options.livereload %>' + }, + files: ['<%= yeoman.app %>/{,*/}*.html', '<%= yeoman.app %>/styles/app.css', '<%= yeoman.app %>/styles/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'] + } + }, + + /* + concat: { + options: { + stripBanners: true + }, + exploded: { + dest: '<%= yeoman.tmp.exploded %>' + } + }, + */ + + ngconstant: { + // Options for all targets + options: { + space: ' ', + wrap: '"use strict";\n\n {\%= __ngModule %}', + name: 'dcaeApp.env' + }, + // Environment targets + dev: { + options: { + dest: '<%= yeoman.app %>/app.env.js' + }, + constants: { + ENV: { + name: 'development', + apiBase: 'http://localhost:8080/', + host: 'http://localhost:8446/', + catalogImport: '/comp-fe/', + catalogPrefix: 'http://localhost:8446', + cookieUser: 'ym903w', + ruleEditorUrl: 'http://localhost:4200' + } + } + }, + exploded: { + options: { + dest: '<%= yeoman.app %>/app.env.js' + }, + constants: { + ENV: { + name: 'production', + apiBase: '/dcae/dcaeProxyOld/', + host: '/dcae/dcaeProxyOld/', + catalogImport: '/dcae/comp-fe/', + catalogPrefix: '/dcae/dcaeProxyOld/', + cookieUser: 'le056g', + ruleEditorUrl: '/rule_engine' + } + } + } + }, + + // The actual grunt server settings + connect: { + options: { + port: 9000, + // Change this to '0.0.0.0' to access the server from outside. + hostname: 'localhost', + livereload: true + }, + livereload: { + options: { + open: true, + middleware: function (connect) { + return [ + //connect.static('.tmp'), + connect().use('/bower_components', connect.static('./bower_components')), + connect().use('/app/styles', connect.static('./app/styles')), + connect.static(appConfig.app) + ]; + } + } + }, + test: { + options: { + port: 9001, + middleware: function (connect) { + return [ + connect.static('<%= yeoman.tmp.exploded %>'), + connect.static('test'), + connect().use('/bower_components', connect.static('./bower_components')), + connect.static(appConfig.app) + ]; + } + } + }, + exploded: { + options: { + open: true, + base: '<%= yeoman.dist.exploded %>' + } + } + }, + + // app.less contains all the less from all places, convert it to CSS + less: { + development: { + files: { + 'app/styles/app.css': 'app/styles/app.less' + } + }, + production: { + files: { + '<%= yeoman.tmp.exploded %>/styles/app.css': 'app/styles/app.less' + } + } + }, + + injector: { + options: {}, + // Inject all project less into app.less + less: { + options: { + transform: function (filePath) { + filePath = filePath.replace('/app/styles/', '../styles/'); + filePath = filePath.replace('/app/main/', '../main/'); + filePath = filePath.replace('/app/core/', '../core/'); + return '@import \'' + filePath + '\';'; + }, + starttag: '// injector:less', + endtag: '// endinjector:less' + }, + files: { + 'app/styles/app.less': ['app/styles/*.less', 'app/core/**/*.less', 'app/main/**/*.less', '!app/styles/app.less'] + } + } + }, + + // Make sure there are no obvious mistakes + jshint: { + options: { + jshintrc: '.jshintrc', + reporter: require('jshint-stylish') + }, + all: { + src: ['Gruntfile.js', '<%= yeoman.app %>/main/{,*/}*.js'] + }, + test: { + options: { + jshintrc: 'test/.jshintrc' + }, + src: ['test/spec/{,*/}*.js'] + } + }, + + // Make sure code styles are up to par + jscs: { + options: { + config: '.jscsrc', + verbose: true + }, + all: { + src: ['Gruntfile.js', '<%= yeoman.app %>/main/{,*/}*.js'] + }, + test: { + src: ['test/spec/{,*/}*.js'] + } + }, + + // Empties folders to start fresh + clean: { + exploded: { + files: [ + { + dot: true, + src: ['<%= yeoman.tmp.exploded %>', '<%= yeoman.dist.exploded %>/{,*/}*', '!<%= yeoman.dist.exploded %>/.git{,*/}*'] + } + ] + }, + imploded: { + files: [ + { + dot: true, + src: ['<%= yeoman.dist.imploded %>'] + } + ] + }, + html: { + files: [ + { + dot: true, + src: ['<%= yeoman.dist.exploded %>/index.html'] + } + ] + }, + server: '<%= yeoman.tmp.exploded %>' + }, + + // Add vendor prefixed styles + postcss: { + options: { + processors: [require('autoprefixer-core')({browsers: ['last 1 version']})] + }, + server: { + options: { + map: true + }, + files: [ + { + expand: true, + cwd: '<%= yeoman.tmp.exploded %>/styles/', + src: '{,*/}*.css', + dest: '<%= yeoman.tmp.exploded %>/styles/' + } + ] + }, + exploded: { + files: [ + { + expand: true, + cwd: '<%= yeoman.tmp.exploded %>/styles/', + src: '{,*/}*.css', + dest: '<%= yeoman.tmp.exploded %>/styles/' + } + ] + } + }, + + // Automatically inject Bower components into the app + wiredep: { + app: { + src: ['<%= yeoman.app %>/index.html'], + ignorePath: /\.\.\// + } + }, + + // Renames files for browser caching purposes + filerev: { + exploded: { + src: ['<%= yeoman.dist.exploded %>/scripts/{,*/}*.js', '<%= yeoman.dist.exploded %>/styles/{,*/}*.css', '<%= yeoman.dist.exploded %>/styles/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', '<%= yeoman.dist.exploded %>/styles/fonts/*'] + } + }, + + // Reads HTML for usemin blocks to enable smart builds that automatically + // concat, minify and revision files. Creates configurations in memory so + // additional tasks can operate on them + useminPrepare: { + html: '<%= yeoman.app %>/index.html', + options: { + dest: '<%= yeoman.dist.exploded %>', + flow: { + html: { + steps: { + js: [ + 'concat', 'uglifyjs' + ], + css: ['cssmin'] + }, + post: {} + } + } + } + }, + + // Performs rewrites based on filerev and the useminPrepare configuration + usemin: { + html: ['<%= yeoman.dist.exploded %>/{,*/}*.html'], + css: ['<%= yeoman.dist.exploded %>/styles/{,*/}*.css'], + js: ['<%= yeoman.dist.exploded %>/scripts/{,*/}*.js'], + options: { + assetsDirs: [ + '<%= yeoman.dist.exploded %>', '<%= yeoman.dist.exploded %>/styles/images', '<%= yeoman.dist.exploded %>/styles' + ], + patterns: { + js: [ + [/(images\/[^''""]*\.(png|jpg|jpeg|gif|webp|svg))/g, 'Replacing references to images'] + ] + } + } + }, + + imagemin: { + exploded: { + files: [ + { + expand: true, + cwd: '<%= yeoman.app %>/styles/images', + src: '**/*.{png,jpg,jpeg,gif}', + dest: '<%= yeoman.dist.exploded %>/styles/images' + } + ] + } + }, + + svgmin: { + exploded: { + files: [ + { + expand: true, + cwd: '<%= yeoman.app %>/styles/images', + src: '{,*/}*.svg', + dest: '<%= yeoman.dist.exploded %>/styles/images' + } + ] + } + }, + + htmlmin: { + exploded: { + options: { + collapseWhitespace: true, + conservativeCollapse: true, + collapseBooleanAttributes: true, + removeCommentsFromCDATA: true + }, + files: [ + { + expand: true, + cwd: '<%= yeoman.dist.exploded %>', + src: ['*.html'], + dest: '<%= yeoman.dist.exploded %>' + } + ] + } + }, + + ngtemplates: { + exploded: { + options: { + module: 'dcaeApp', + htmlmin: '<%= htmlmin.exploded.options %>', + usemin: 'scripts/scripts.js' + }, + cwd: '<%= yeoman.app %>', + src: [ + 'main/**/*.html', 'core/**/*.html', 'comp-fe/**/*.html' + ], + dest: '<%= yeoman.tmp.exploded %>/templateCache.js' + } + }, + + // ng-annotate tries to make the code safe for minification automatically by + // using the Angular long form for dependency injection. + ngAnnotate: { + exploded: { + files: [ + { + expand: true, + cwd: '<%= yeoman.tmp.exploded %>/concat/scripts', + src: '*.js', + dest: '<%= yeoman.tmp.exploded %>/concat/scripts' + } + ] + } + }, + + // Replace Google CDN references + cdnify: { + exploded: { + html: ['<%= yeoman.dist.exploded %>/*.html'] + } + }, + + // Copies remaining files to places other tasks can use + copy: { + exploded: { + files: [ + { + expand: true, + dot: true, + cwd: '<%= yeoman.app %>', + dest: '<%= yeoman.dist.exploded %>', + src: ['*.{ico,png,txt}', '*.html', 'styles/images/{,*/}*.{webp}', 'styles/fonts/{,*/}*.*'] + }, { + expand: true, + cwd: '<%= yeoman.tmp.exploded %>/images', + dest: '<%= yeoman.dist.exploded %>/styles/images', + src: ['generated/*'] + }, { + expand: true, + cwd: 'bower_components/bootstrap/dist', + src: 'fonts/*', + dest: '<%= yeoman.dist.exploded %>' + }, { + expand: true, + cwd: '<%= yeoman.app %>', + src: ['WEB-INF/*'], + dest: '<%= yeoman.dist.exploded %>/' + }, { + expand: true, + cwd: '<%= yeoman.app %>', + src: ['dcae.xml'], + dest: '<%= yeoman.dist.exploded %>/' + } + ] + }, + styles: { + expand: true, + cwd: '<%= yeoman.app %>/styles', + dest: '<%= yeoman.tmp.exploded %>/styles/', + src: '{,*/}*.css' + }, + tmpImploded: { + expand: true, + cwd: '<%= yeoman.dist.exploded %>', + dest: '<%= yeoman.tmp.imploded %>', + src: '**/*' + }, + copyComposition: { + expand: true, + cwd: '<%= yeoman.app %>', + dest: '<%= yeoman.dist.imploded %>', + src: 'comp-fe/**/*' + }, + copyProject: { + expand: true, + cwd: '<%= yeoman.app %>', + dest: '<%= yeoman.dist.exploded %>', + src: ['**/*'] + }, + copyIndex: { + expand: true, + cwd: '<%= yeoman.app %>/prodHtml', + dest: '<%= yeoman.dist.exploded %>', + src: ['**/*'] + }, + copyComposition2: { + expand: true, + cwd: '<%= yeoman.app %>', + dest: '<%= yeoman.dist.exploded %>', + src: 'comp-fe/**/*' + }, + imploded: { + expand: true, + cwd: '<%= yeoman.dist.exploded %>', + dest: '<%= yeoman.dist.imploded %>', + src: ['dcae.xml', 'WEB-INF/**'] + } + }, + + // Run some tasks in parallel to speed up the build process + concurrent: { + server: [ + 'less:development', 'copy:styles' + ], + test: ['copy:styles'], + exploded: [ + 'less:production', 'copy:styles', 'imagemin', 'svgmin' + ], + style: ['less:production'] + }, + + mkdir: { + all: { + options: { + create: ['<%= yeoman.dist.exploded %>/WEB-INF'] + } + }, + dist: { + options: { + create: ['<%= yeoman.dist %>'] + } + }, + imploded: { + options: { + create: ['<%= yeoman.dist.imploded %>', '<%= yeoman.tmp.imploded %>'] + } + } + }, + + preprocess: { + options: { + inline: true, + context: { + DEBUG: false + } + }, + /*html : { + src : [ + '<%= yeoman.dist %>/index.html', + '<%= yeoman.dist %>/views/*.html' + ] + },*/ + js: { + src: '<%= yeoman.tmp.exploded %>/concat/scripts/*.js' + } + } + + }); + + grunt.registerTask('serve', 'Compile then start a connect web server', function (target) { + if (target === 'dist') { + return grunt + .task + .run(['build', 'connect:exploded:keepalive']); + } + + grunt + .task + .run([ + 'clean:server', // Delete .tmp folder + 'ngconstant:dev', // Configure constants + 'wiredep', // Automatically inject Bower components into the app + 'injector', // Inject the less files to app.less + 'concurrent:server', // Run some tasks in parallel to speed up the build process, need to see what the task run. + 'postcss:server', // Add vendor prefixed styles + 'connect:livereload', + 'watch' + ]); + }); + + grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) { + grunt + .log + .warn('The `server` task has been deprecated. Use `grunt serve` to start a server.'); + grunt + .task + .run(['serve:' + target]); + }); + + grunt.registerTask('test', ['clean:server', 'wiredep', 'concurrent:test', 'postcss', 'connect:test']); + + grunt.registerTask('build', [ + 'clean:exploded', + 'ngconstant:exploded', + 'wiredep', + 'injector', + 'concurrent:exploded', + 'useminPrepare', + 'postcss', + 'ngtemplates', + 'concat', + 'preprocess:js', + 'ngAnnotate', + //'mkdir', + 'copy:exploded', + //'cdnify', + 'cssmin', + 'uglify', + 'mkdir:imploded', + 'clean:imploded', + 'copy:tmpImploded', // Copy the files before changing their names + 'copy:imploded', // Copy the WEB-INF folder and dcae.xml + 'filerev', // This will change the name of the files for caching. + 'usemin', + 'copy:copyComposition' + //'htmlmin' + ]); + + grunt.registerTask('build2', [ + 'clean:exploded', + 'ngconstant:exploded', + 'wiredep', + 'injector', + 'concurrent:style', + 'postcss', + // 'useminPrepare', 'postcss', 'ngtemplates', 'concat', 'preprocess:js', + // 'ngAnnotate', 'mkdir', + 'copy:copyProject', + 'clean:html', + 'copy:copyIndex' + ]); + + grunt.registerTask('default', ['newer:jshint', 'newer:jscs', 'test', 'build']); +}; diff --git a/README.md b/README.md new file mode 100644 index 0000000..a56fda6 --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# DCAE Designer FE + + +## Java + +### Build +Server: `mvn clean install –Pserver` + +Local: `mvn clean install -Plocal` + +### Run +`mvn -Plocal spring-boot:run` + +### Build and Run locally +`mvn clean install -Plocal spring-boot:run` + + +## Javascript + +This project is generated with [yo angular generator](https://github.com/yeoman/generator-angular) +version 0.15.1. + +### Setup +After cloning project execute the following commands in the project directory: +1. `npm run setup` + +### Build & development + +Run `npm run build` for building and `npm run run-local` for preview. diff --git a/__test__/user-mapping.test.js b/__test__/user-mapping.test.js new file mode 100644 index 0000000..8fdd613 --- /dev/null +++ b/__test__/user-mapping.test.js @@ -0,0 +1,41 @@ +var _ = require('underscore'); + +var input = []; + +function monitoringTemplateProtocol(input) { + var nodeTypes = input; + if (nodeTypes.length < 2) { + if (nodeTypes[0] == 'FOI collector' || nodeTypes[0] == 'syslog') { + return nodeTypes[0]; + } else { + return 'other'; + } + } else { + var match = _.difference(nodeTypes, ["map", "enrich", "supplement"]); + return match.length > 0 ? 'other' : 'SNMP'; + } +} + +beforeEach(() => { + input = []; +}) + +test('should return FOI', () => { + input.push('FOI collector'); + expect(monitoringTemplateProtocol(input)).toBe('FOI collector'); +}) +test('should return Syslog', () => { + input.push('syslog'); + expect(monitoringTemplateProtocol(input)).toBe('syslog'); +}) +test('should return SNMP', () => { + input.push('map'); + input.push('enrich'); + input.push('supplement'); + input = _.shuffle(input); + expect(monitoringTemplateProtocol(input)).toBe('SNMP'); +}) +test('should return other', () => { + input.push('west'); + expect(monitoringTemplateProtocol(input)).toBe('other'); +}) diff --git a/app/VNF_List.json b/app/VNF_List.json new file mode 100644 index 0000000..973e17f --- /dev/null +++ b/app/VNF_List.json @@ -0,0 +1 @@ +[{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Network Elements","normalizedName":"network elements","uniqueId":"resourceNewCategory.generic.network elements","icons":["network","connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.cp.nodes.heat.contrailV2.VirtualMachineInterface","tosca.nodes.network.Port","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Bindable":[{"uniqueId":"d9155aa5-4b34-4389-ad93-273ca975ff5c.binding","name":"binding","capability":"tosca.capabilities.network.Bindable","relationship":"tosca.relationships.network.BindsTo","ownerId":"d9155aa5-4b34-4389-ad93-273ca975ff5c","minOccurrences":"1","maxOccurrences":"1"}],"tosca.capabilities.network.Linkable":[{"uniqueId":"d9155aa5-4b34-4389-ad93-273ca975ff5c.link","name":"link","capability":"tosca.capabilities.network.Linkable","relationship":"tosca.relationships.network.LinksTo","ownerId":"d9155aa5-4b34-4389-ad93-273ca975ff5c","minOccurrences":"1","maxOccurrences":"1"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"com.att.d2.resource.cp.nodes.heat.contrailV2.VirtualMachineInterface","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"network","description":"Represents a network interface. The interfaces are defined with specific MAC addresses and ports.","tags":["ContrailV2VirtualMachineInterface"],"allVersions":{"1.0":"68d6a493-0cba-4b20-ae0e-339608f21702"},"uniqueId":"68d6a493-0cba-4b20-ae0e-339608f21702","invariantUUID":"c3eec7ee-fa43-4297-a5c6-156b5bdaf5c3","highestVersion":true,"systemName":"Contrailv2virtualmachineinterface","uuid":"b9df9b1c-56d0-47dc-a0bf-56ca03d2e08f","lifecycleState":"CERTIFIED","name":"ContrailV2VirtualMachineInterface"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Infrastructure","normalizedName":"infrastructure","uniqueId":"resourceNewCategory.generic.infrastructure","icons":["connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["tosca.nodes.LoadBalancer","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Endpoint.Public":[{"uniqueId":"capability.83d96c94-694c-4e36-a57d-6b795f511d52.client","name":"client","type":"tosca.capabilities.Endpoint.Public","capabilitySources":["tosca.nodes.LoadBalancer","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Endpoint.port_name","type":"string","required":false,"definition":false,"password":false,"name":"port_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.protocol","type":"string","required":false,"definition":false,"defaultValue":"tcp","password":false,"name":"protocol","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.port","type":"PortDef","required":false,"definition":false,"password":false,"name":"port","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.Public.floating","type":"boolean","required":false,"definition":false,"defaultValue":"false","description":"indicates that the public address should be allocated from a pool of floating IPs that are associated with the network.\n","password":false,"name":"floating","parentUniqueId":"tosca.capabilities.Endpoint.Public"},{"uniqueId":"tosca.capabilities.Endpoint.initiator","type":"string","required":false,"definition":false,"defaultValue":"source","password":false,"constraints":[{"validValues":["source","target","peer"]}],"name":"initiator","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.Public.network_name","required":false,"definition":false,"defaultValue":"PUBLIC","password":false,"name":"network_name","parentUniqueId":"tosca.capabilities.Endpoint.Public"},{"uniqueId":"tosca.capabilities.Endpoint.secure","type":"boolean","required":false,"definition":false,"defaultValue":"false","password":false,"name":"secure","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.ports","type":"map","required":false,"definition":false,"schema":{"property":{"type":"PortSpec","required":false,"definition":true,"password":false}},"password":false,"constraints":[{}],"name":"ports","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.Public.dns_name","type":"string","required":false,"definition":false,"description":"The optional name to register with DNS","password":false,"name":"dns_name","parentUniqueId":"tosca.capabilities.Endpoint.Public"},{"uniqueId":"tosca.capabilities.Endpoint.url_path","type":"string","required":false,"definition":false,"password":false,"name":"url_path","parentUniqueId":"tosca.capabilities.Endpoint"}],"ownerId":"83d96c94-694c-4e36-a57d-6b795f511d52","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Endpoint":[{"uniqueId":"83d96c94-694c-4e36-a57d-6b795f511d52.application","name":"application","capability":"tosca.capabilities.Endpoint","relationship":"tosca.relationships.RoutesTo","ownerId":"83d96c94-694c-4e36-a57d-6b795f511d52","minOccurrences":"1","maxOccurrences":"1"}],"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"tosca.nodes.LoadBalancer","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"loadBalancer","description":"Represents logical function that be used in conjunction with a Floating Address to distribute an applications traffic (load) across a number of instances of the application (e.g., for a clustered or scaled application).","tags":["LoadBalancer"],"allVersions":{"1.0":"83d96c94-694c-4e36-a57d-6b795f511d52"},"uniqueId":"83d96c94-694c-4e36-a57d-6b795f511d52","invariantUUID":"b81bd65f-ebee-4af4-8d85-22f6e9b46081","highestVersion":true,"systemName":"Loadbalancer","uuid":"b8f31045-bac3-4332-87a0-06be09d628ee","lifecycleState":"CERTIFIED","name":"LoadBalancer"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Database","normalizedName":"database","uniqueId":"resourceNewCategory.generic.database","icons":["database"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["tosca.nodes.Database","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Endpoint.Database":[{"uniqueId":"capability.64740fbf-2aff-4c5e-9a40-b5b52ad3192c.database_endpoint","name":"database_endpoint","type":"tosca.capabilities.Endpoint.Database","capabilitySources":["tosca.nodes.Database","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Endpoint.port_name","type":"string","required":false,"definition":false,"password":false,"name":"port_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.protocol","type":"string","required":false,"definition":false,"defaultValue":"tcp","password":false,"name":"protocol","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.port","type":"PortDef","required":false,"definition":false,"password":false,"name":"port","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.initiator","type":"string","required":false,"definition":false,"defaultValue":"source","password":false,"constraints":[{"validValues":["source","target","peer"]}],"name":"initiator","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.network_name","type":"string","required":false,"definition":false,"defaultValue":"PRIVATE","password":false,"name":"network_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.ports","type":"map","required":false,"definition":false,"schema":{"property":{"type":"PortSpec","required":false,"definition":true,"password":false}},"password":false,"constraints":[{}],"name":"ports","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.secure","type":"boolean","required":false,"definition":false,"defaultValue":"false","password":false,"name":"secure","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.url_path","type":"string","required":false,"definition":false,"password":false,"name":"url_path","parentUniqueId":"tosca.capabilities.Endpoint"}],"ownerId":"64740fbf-2aff-4c5e-9a40-b5b52ad3192c","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Container":[{"uniqueId":"64740fbf-2aff-4c5e-9a40-b5b52ad3192c.host","name":"host","capability":"tosca.capabilities.Container","node":"tosca.nodes.DBMS","relationship":"tosca.relationships.HostedOn","ownerId":"64740fbf-2aff-4c5e-9a40-b5b52ad3192c","minOccurrences":"1","maxOccurrences":"1"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"tosca.nodes.Database","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"defaulticon","description":"Represents a logical database that can be managed and hosted by a DBMS node.","tags":["Database"],"allVersions":{"1.0":"64740fbf-2aff-4c5e-9a40-b5b52ad3192c"},"uniqueId":"64740fbf-2aff-4c5e-9a40-b5b52ad3192c","invariantUUID":"c260600f-3c16-4827-8fda-4771fefaef88","highestVersion":true,"systemName":"Database","uuid":"079d2d89-a65a-45e1-ac57-1a54d1381b07","lifecycleState":"CERTIFIED","name":"Database"},{"categories":[{"name":"Network Connectivity","normalizedName":"network connectivity","uniqueId":"resourceNewCategory.network connectivity","subcategories":[{"name":"Virtual Links","normalizedName":"virtual links","uniqueId":"resourceNewCategory.network connectivity.virtual links","icons":["vl"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.vl.VL","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Endpoint":[{"uniqueId":"capability.9ac40e15-9b54-4681-b7a9-df4942c88fe9.end_point","name":"end_point","type":"tosca.capabilities.Endpoint","capabilitySources":["com.att.d2.resource.vl.VL","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Endpoint.port_name","type":"string","required":false,"definition":false,"password":false,"name":"port_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.protocol","type":"string","required":false,"definition":false,"defaultValue":"tcp","password":false,"name":"protocol","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.port","type":"PortDef","required":false,"definition":false,"password":false,"name":"port","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.initiator","type":"string","required":false,"definition":false,"defaultValue":"source","password":false,"constraints":[{"validValues":["source","target","peer"]}],"name":"initiator","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.network_name","type":"string","required":false,"definition":false,"defaultValue":"PRIVATE","password":false,"name":"network_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.ports","type":"map","required":false,"definition":false,"schema":{"property":{"type":"PortSpec","required":false,"definition":true,"password":false}},"password":false,"constraints":[{}],"name":"ports","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.secure","type":"boolean","required":false,"definition":false,"defaultValue":"false","password":false,"name":"secure","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.url_path","type":"string","required":false,"definition":false,"password":false,"name":"url_path","parentUniqueId":"tosca.capabilities.Endpoint"}],"ownerId":"9ac40e15-9b54-4681-b7a9-df4942c88fe9","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Linkable":[{"uniqueId":"capability.9ac40e15-9b54-4681-b7a9-df4942c88fe9.virtual_linkable","name":"virtual_linkable","type":"tosca.capabilities.network.Linkable","capabilitySources":["com.att.d2.resource.vl.VL","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"9ac40e15-9b54-4681-b7a9-df4942c88fe9","minOccurrences":"1","maxOccurrences":"UNBOUNDED"},{"uniqueId":"capability.beb1c610-9ab1-4187-b0ef-b2cfe2c077cb.link","name":"link","type":"tosca.capabilities.network.Linkable","capabilitySources":["com.att.d2.resource.vl.VL","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"beb1c610-9ab1-4187-b0ef-b2cfe2c077cb","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VL","toscaResourceName":"com.att.d2.resource.vl.VL","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"network","description":" Virtual link (VL) describes the basic topology of the connectivity as well as other required parameters (e.g. bandwidth and QoS class). ","tags":["VL"],"allVersions":{"1.0":"9ac40e15-9b54-4681-b7a9-df4942c88fe9"},"uniqueId":"9ac40e15-9b54-4681-b7a9-df4942c88fe9","invariantUUID":"9eba5e83-43ca-4906-a372-58747469ca40","highestVersion":true,"systemName":"Vl","uuid":"912ed6a3-b19f-4a6e-bee3-23b2894d727b","lifecycleState":"CERTIFIED","name":"VL"},{"categories":[{"name":"Network Connectivity","normalizedName":"network connectivity","uniqueId":"resourceNewCategory.network connectivity","subcategories":[{"name":"Virtual Links","normalizedName":"virtual links","uniqueId":"resourceNewCategory.network connectivity.virtual links","icons":["vl"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.vl.ELine","com.att.d2.resource.vl.VL","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Endpoint":[{"uniqueId":"capability.9ac40e15-9b54-4681-b7a9-df4942c88fe9.end_point","name":"end_point","type":"tosca.capabilities.Endpoint","capabilitySources":["com.att.d2.resource.vl.ELine","com.att.d2.resource.vl.VL","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Endpoint.port_name","type":"string","required":false,"definition":false,"password":false,"name":"port_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.protocol","type":"string","required":false,"definition":false,"defaultValue":"tcp","password":false,"name":"protocol","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.port","type":"PortDef","required":false,"definition":false,"password":false,"name":"port","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.initiator","type":"string","required":false,"definition":false,"defaultValue":"source","password":false,"constraints":[{"validValues":["source","target","peer"]}],"name":"initiator","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.network_name","type":"string","required":false,"definition":false,"defaultValue":"PRIVATE","password":false,"name":"network_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.ports","type":"map","required":false,"definition":false,"schema":{"property":{"type":"PortSpec","required":false,"definition":true,"password":false}},"password":false,"constraints":[{}],"name":"ports","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.secure","type":"boolean","required":false,"definition":false,"defaultValue":"false","password":false,"name":"secure","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.url_path","type":"string","required":false,"definition":false,"password":false,"name":"url_path","parentUniqueId":"tosca.capabilities.Endpoint"}],"ownerId":"9ac40e15-9b54-4681-b7a9-df4942c88fe9","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Linkable":[{"uniqueId":"capability.2b1ffc78-2730-4ea3-8ca5-a5c24669fac3.virtual_linkable","name":"virtual_linkable","type":"tosca.capabilities.network.Linkable","capabilitySources":["com.att.d2.resource.vl.ELine","com.att.d2.resource.vl.VL","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"2b1ffc78-2730-4ea3-8ca5-a5c24669fac3","minOccurrences":"0","maxOccurrences":"2"},{"uniqueId":"capability.beb1c610-9ab1-4187-b0ef-b2cfe2c077cb.link","name":"link","type":"tosca.capabilities.network.Linkable","capabilitySources":["com.att.d2.resource.vl.ELine","com.att.d2.resource.vl.VL","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"beb1c610-9ab1-4187-b0ef-b2cfe2c077cb","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"com.att.d2.resource.vl.ELine","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"network","description":"Thenode represents an E-Line virtual link entity.","tags":["VL ELINE"],"allVersions":{"1.0":"2b1ffc78-2730-4ea3-8ca5-a5c24669fac3"},"uniqueId":"2b1ffc78-2730-4ea3-8ca5-a5c24669fac3","invariantUUID":"3cfb7b78-94f1-4f75-8919-eaff5e00c4b1","highestVersion":true,"systemName":"VlEline","uuid":"f76221fd-c8d8-415f-9a0b-f7b38367468a","lifecycleState":"CERTIFIED","name":"VL ELINE"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Network Elements","normalizedName":"network elements","uniqueId":"resourceNewCategory.generic.network elements","icons":["network","connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.vl.nodes.heat.network.contrail.VirtualNetwork","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Linkable":[{"uniqueId":"capability.beb1c610-9ab1-4187-b0ef-b2cfe2c077cb.link","name":"link","type":"tosca.capabilities.network.Linkable","capabilitySources":["com.att.d2.resource.vl.nodes.heat.network.contrail.VirtualNetwork","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"beb1c610-9ab1-4187-b0ef-b2cfe2c077cb","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VL","toscaResourceName":"com.att.d2.resource.vl.nodes.heat.network.contrail.VirtualNetwork","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"network","description":"Represents a network service with optional subnets and advanced configurations.","tags":["ContrailVirtualNetwork"],"allVersions":{"1.0":"9032003c-75b5-41be-ac10-196928bdeadd"},"uniqueId":"9032003c-75b5-41be-ac10-196928bdeadd","invariantUUID":"de5a5448-4b9f-4401-ada5-18f80119cbe1","highestVersion":true,"systemName":"Contrailvirtualnetwork","uuid":"9d5c9e8b-5f66-4bf8-ac7a-0d4db8a61028","lifecycleState":"CERTIFIED","name":"ContrailVirtualNetwork"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Network Elements","normalizedName":"network elements","uniqueId":"resourceNewCategory.generic.network elements","icons":["network","connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.vl.nodes.heat.network.neutron.Net","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Linkable":[{"uniqueId":"capability.beb1c610-9ab1-4187-b0ef-b2cfe2c077cb.link","name":"link","type":"tosca.capabilities.network.Linkable","capabilitySources":["com.att.d2.resource.vl.nodes.heat.network.neutron.Net","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"beb1c610-9ab1-4187-b0ef-b2cfe2c077cb","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VL","toscaResourceName":"com.att.d2.resource.vl.nodes.heat.network.neutron.Net","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"network","description":"Represents a network service with optional subnets and advanced configurations.","tags":["NeutronNet"],"allVersions":{"1.0":"6146f136-b9fd-46d2-b6d4-ecb3744f4b4a"},"uniqueId":"6146f136-b9fd-46d2-b6d4-ecb3744f4b4a","invariantUUID":"b5c51697-409f-4622-995e-f76a8a32d241","highestVersion":true,"systemName":"Neutronnet","uuid":"a2532042-193f-4c45-9611-07dd14977e57","lifecycleState":"CERTIFIED","name":"NeutronNet"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Network Elements","normalizedName":"network elements","uniqueId":"resourceNewCategory.generic.network elements","icons":["network","connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["tosca.nodes.network.Port","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Bindable":[{"uniqueId":"d9155aa5-4b34-4389-ad93-273ca975ff5c.binding","name":"binding","capability":"tosca.capabilities.network.Bindable","relationship":"tosca.relationships.network.BindsTo","ownerId":"d9155aa5-4b34-4389-ad93-273ca975ff5c","minOccurrences":"1","maxOccurrences":"1"}],"tosca.capabilities.network.Linkable":[{"uniqueId":"d9155aa5-4b34-4389-ad93-273ca975ff5c.link","name":"link","capability":"tosca.capabilities.network.Linkable","relationship":"tosca.relationships.network.LinksTo","ownerId":"d9155aa5-4b34-4389-ad93-273ca975ff5c","minOccurrences":"1","maxOccurrences":"1"}]},"abstract":false,"resourceType":"CP","toscaResourceName":"tosca.nodes.network.Port","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"port","description":"Represents a logical entity that associates between Compute and Network normative types.","tags":["Port"],"allVersions":{"1.0":"d9155aa5-4b34-4389-ad93-273ca975ff5c"},"uniqueId":"d9155aa5-4b34-4389-ad93-273ca975ff5c","invariantUUID":"3912d7d0-3f29-461f-8ff1-98ffa9897fbb","highestVersion":true,"systemName":"Port","uuid":"dc904303-9a3a-4ccc-aeaa-81dad91a63c2","lifecycleState":"CERTIFIED","name":"Port"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Network Elements","normalizedName":"network elements","uniqueId":"resourceNewCategory.generic.network elements","icons":["network","connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.vl.nodes.heat.network.contrailV2.VirtualNetwork","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Linkable":[{"uniqueId":"capability.beb1c610-9ab1-4187-b0ef-b2cfe2c077cb.link","name":"link","type":"tosca.capabilities.network.Linkable","capabilitySources":["com.att.d2.resource.vl.nodes.heat.network.contrailV2.VirtualNetwork","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"beb1c610-9ab1-4187-b0ef-b2cfe2c077cb","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Attachment":[{"uniqueId":"capability.463022c0-556e-4e1d-b44b-cdf734e609b6.attachment","name":"attachment","type":"tosca.capabilities.Attachment","capabilitySources":["com.att.d2.resource.vl.nodes.heat.network.contrailV2.VirtualNetwork","tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"463022c0-556e-4e1d-b44b-cdf734e609b6","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VL","toscaResourceName":"com.att.d2.resource.vl.nodes.heat.network.contrailV2.VirtualNetwork","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"network","description":"Represents a network service with optional subnets and advanced configurations for contrail V2.","tags":["ContrailV2VirtualNetwork"],"allVersions":{"1.0":"463022c0-556e-4e1d-b44b-cdf734e609b6"},"uniqueId":"463022c0-556e-4e1d-b44b-cdf734e609b6","invariantUUID":"8b2119d7-d9c6-4342-a116-10a2c0672b9d","highestVersion":true,"systemName":"Contrailv2virtualnetwork","uuid":"10db5e25-dfe9-4df5-aff1-04d789da6040","lifecycleState":"CERTIFIED","name":"ContrailV2VirtualNetwork"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Infrastructure","normalizedName":"infrastructure","uniqueId":"resourceNewCategory.generic.infrastructure","icons":["connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.vfc.nodes.heat.cinder.Volume","tosca.nodes.BlockStorage","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Attachment":[{"uniqueId":"capability.918d4e2a-4f52-40b6-b6e3-e0fccd9bd88d.attachment","name":"attachment","type":"tosca.capabilities.Attachment","capabilitySources":["com.att.d2.resource.vfc.nodes.heat.cinder.Volume","tosca.nodes.BlockStorage","tosca.nodes.Root"],"properties":[],"ownerId":"918d4e2a-4f52-40b6-b6e3-e0fccd9bd88d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"com.att.d2.resource.vfc.nodes.heat.cinder.Volume","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"objectStorage","description":"Represents a server-local block storage device that provides persistent storage to guest virtual machines. ","tags":["CinderVolume"],"allVersions":{"1.0":"0a8fad75-58d8-4a02-ad5a-71c44bcef002"},"uniqueId":"0a8fad75-58d8-4a02-ad5a-71c44bcef002","invariantUUID":"cc646996-be13-4e13-9bb0-d89acbc23fe5","highestVersion":true,"systemName":"Cindervolume","uuid":"c43afcf2-a4ad-462f-986f-7c1a4c37aa33","lifecycleState":"CERTIFIED","name":"CinderVolume"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Infrastructure","normalizedName":"infrastructure","uniqueId":"resourceNewCategory.generic.infrastructure","icons":["connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["tosca.nodes.BlockStorage","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Attachment":[{"uniqueId":"capability.918d4e2a-4f52-40b6-b6e3-e0fccd9bd88d.attachment","name":"attachment","type":"tosca.capabilities.Attachment","capabilitySources":["tosca.nodes.BlockStorage","tosca.nodes.Root"],"properties":[],"ownerId":"918d4e2a-4f52-40b6-b6e3-e0fccd9bd88d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"tosca.nodes.BlockStorage","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"objectStorage","description":"Represents a server-local block storage device (i.e., not shared) offering evenly sized blocks of data from which raw storage volumes can be created.","tags":["BlockStorage"],"allVersions":{"1.0":"918d4e2a-4f52-40b6-b6e3-e0fccd9bd88d"},"uniqueId":"918d4e2a-4f52-40b6-b6e3-e0fccd9bd88d","invariantUUID":"43be48e7-5dc3-4095-9e64-0a08be63e64e","highestVersion":true,"systemName":"Blockstorage","uuid":"b8baf25c-02e9-476a-babe-fe9415119bb0","lifecycleState":"CERTIFIED","name":"BlockStorage"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Rules","normalizedName":"rules","uniqueId":"resourceNewCategory.generic.rules","icons":["networkrules","securityrules"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.vfc.rules.nodes.heat.network.contrailV2.NetworkRules","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Attachment":[{"uniqueId":"cfd69b33-27b8-4f50-aa06-cb7fe977e508.network","name":"network","capability":"tosca.capabilities.Attachment","node":"tosca.nodes.network.Network","relationship":"com.att.d2.relationships.AttachesTo","ownerId":"cfd69b33-27b8-4f50-aa06-cb7fe977e508","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"com.att.d2.resource.vfc.rules.nodes.heat.network.contrailV2.NetworkRules","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"networkrules","description":"Configuration of policy rules to be applied over the network for contrail V2.","tags":["ContrailV2NetworkRules"],"allVersions":{"1.0":"cfd69b33-27b8-4f50-aa06-cb7fe977e508"},"uniqueId":"cfd69b33-27b8-4f50-aa06-cb7fe977e508","invariantUUID":"cdc1f9d5-b077-4b0e-b266-93780907d697","highestVersion":true,"systemName":"Contrailv2networkrules","uuid":"f756b4bb-ab5a-4ff6-92a4-1891f179f13a","lifecycleState":"CERTIFIED","name":"ContrailV2NetworkRules"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Infrastructure","normalizedName":"infrastructure","uniqueId":"resourceNewCategory.generic.infrastructure","icons":["connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["tosca.nodes.ObjectStorage","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Endpoint":[{"uniqueId":"capability.5f460fab-d37f-4e4e-982c-b992950b68e4.storage_endpoint","name":"storage_endpoint","type":"tosca.capabilities.Endpoint","capabilitySources":["tosca.nodes.ObjectStorage","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Endpoint.port_name","type":"string","required":false,"definition":false,"password":false,"name":"port_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.protocol","type":"string","required":false,"definition":false,"defaultValue":"tcp","password":false,"name":"protocol","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.port","type":"PortDef","required":false,"definition":false,"password":false,"name":"port","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.initiator","type":"string","required":false,"definition":false,"defaultValue":"source","password":false,"constraints":[{"validValues":["source","target","peer"]}],"name":"initiator","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.network_name","type":"string","required":false,"definition":false,"defaultValue":"PRIVATE","password":false,"name":"network_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.ports","type":"map","required":false,"definition":false,"schema":{"property":{"type":"PortSpec","required":false,"definition":true,"password":false}},"password":false,"constraints":[{}],"name":"ports","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.secure","type":"boolean","required":false,"definition":false,"defaultValue":"false","password":false,"name":"secure","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.url_path","type":"string","required":false,"definition":false,"password":false,"name":"url_path","parentUniqueId":"tosca.capabilities.Endpoint"}],"ownerId":"5f460fab-d37f-4e4e-982c-b992950b68e4","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"tosca.nodes.ObjectStorage","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"objectStorage","description":"Represents storage that provides the ability to store data as objects (or BLOBs of data) without consideration for the underlying filesystem or devices.","tags":["ObjectStorage"],"allVersions":{"1.0":"5f460fab-d37f-4e4e-982c-b992950b68e4"},"uniqueId":"5f460fab-d37f-4e4e-982c-b992950b68e4","invariantUUID":"c5e9022e-f687-4d39-96e1-d1301f76ad0f","highestVersion":true,"systemName":"Objectstorage","uuid":"f57eee7d-8a88-4788-b90b-10ac3dab87f2","lifecycleState":"CERTIFIED","name":"ObjectStorage"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Infrastructure","normalizedName":"infrastructure","uniqueId":"resourceNewCategory.generic.infrastructure","icons":["connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.vfc.nodes.heat.contrail.Compute","tosca.nodes.Compute","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Scalable":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.scalable","name":"scalable","type":"tosca.capabilities.Scalable","capabilitySources":["com.att.d2.resource.vfc.nodes.heat.contrail.Compute","tosca.nodes.Compute","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Scalable.min_instances","type":"integer","required":false,"definition":false,"defaultValue":"1","password":false,"name":"min_instances","parentUniqueId":"tosca.capabilities.Scalable"},{"uniqueId":"tosca.capabilities.Scalable.max_instances","type":"integer","required":false,"definition":false,"defaultValue":"1","password":false,"name":"max_instances","parentUniqueId":"tosca.capabilities.Scalable"},{"uniqueId":"tosca.capabilities.Scalable.default_instances","type":"integer","required":false,"definition":false,"password":false,"name":"default_instances","parentUniqueId":"tosca.capabilities.Scalable"}],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Bindable":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.binding","name":"binding","type":"tosca.capabilities.network.Bindable","capabilitySources":["com.att.d2.resource.vfc.nodes.heat.contrail.Compute","tosca.nodes.Compute","tosca.nodes.Root"],"properties":[],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Container":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.host","name":"host","type":"tosca.capabilities.Container","validSourceTypes":["tosca.nodes.SoftwareComponent"],"capabilitySources":["com.att.d2.resource.vfc.nodes.heat.contrail.Compute","tosca.nodes.Compute","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Container.num_cpus","type":"integer","required":false,"definition":false,"password":false,"constraints":[{}],"name":"num_cpus","parentUniqueId":"tosca.capabilities.Container"},{"uniqueId":"tosca.capabilities.Container.disk_size","type":"scalar-unit.size","required":false,"definition":false,"password":false,"constraints":[{}],"name":"disk_size","parentUniqueId":"tosca.capabilities.Container"},{"uniqueId":"tosca.capabilities.Container.cpu_frequency","type":"scalar-unit.frequency","required":false,"definition":false,"password":false,"constraints":[{}],"name":"cpu_frequency","parentUniqueId":"tosca.capabilities.Container"},{"uniqueId":"tosca.capabilities.Container.mem_size","type":"scalar-unit.size","required":false,"definition":false,"password":false,"constraints":[{}],"name":"mem_size","parentUniqueId":"tosca.capabilities.Container"}],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Endpoint.Admin":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.endpoint","name":"endpoint","type":"tosca.capabilities.Endpoint.Admin","capabilitySources":["com.att.d2.resource.vfc.nodes.heat.contrail.Compute","tosca.nodes.Compute","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Endpoint.port_name","type":"string","required":false,"definition":false,"password":false,"name":"port_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.protocol","type":"string","required":false,"definition":false,"defaultValue":"tcp","password":false,"name":"protocol","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.port","type":"PortDef","required":false,"definition":false,"password":false,"name":"port","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.initiator","type":"string","required":false,"definition":false,"defaultValue":"source","password":false,"constraints":[{"validValues":["source","target","peer"]}],"name":"initiator","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.network_name","type":"string","required":false,"definition":false,"defaultValue":"PRIVATE","password":false,"name":"network_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.Admin.secure","required":false,"definition":false,"defaultValue":"true","password":false,"name":"secure","parentUniqueId":"tosca.capabilities.Endpoint.Admin"},{"uniqueId":"tosca.capabilities.Endpoint.ports","type":"map","required":false,"definition":false,"schema":{"property":{"type":"PortSpec","required":false,"definition":true,"password":false}},"password":false,"constraints":[{}],"name":"ports","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.url_path","type":"string","required":false,"definition":false,"password":false,"name":"url_path","parentUniqueId":"tosca.capabilities.Endpoint"}],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.OperatingSystem":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.os","name":"os","type":"tosca.capabilities.OperatingSystem","capabilitySources":["com.att.d2.resource.vfc.nodes.heat.contrail.Compute","tosca.nodes.Compute","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.OperatingSystem.distribution","type":"string","required":false,"definition":false,"password":false,"name":"distribution","parentUniqueId":"tosca.capabilities.OperatingSystem"},{"uniqueId":"tosca.capabilities.OperatingSystem.type","type":"string","required":false,"definition":false,"password":false,"name":"type","parentUniqueId":"tosca.capabilities.OperatingSystem"},{"uniqueId":"tosca.capabilities.OperatingSystem.version","type":"version","required":false,"definition":false,"password":false,"name":"version","parentUniqueId":"tosca.capabilities.OperatingSystem"},{"uniqueId":"tosca.capabilities.OperatingSystem.architecture","type":"string","required":false,"definition":false,"password":false,"name":"architecture","parentUniqueId":"tosca.capabilities.OperatingSystem"}],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Attachment":[{"uniqueId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df.local_storage","name":"local_storage","capability":"tosca.capabilities.Attachment","node":"tosca.nodes.BlockStorage","relationship":"tosca.relationships.AttachesTo","ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"com.att.d2.resource.vfc.nodes.heat.contrail.Compute","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"compute","description":"Represents a virtual machine for contrail service template. The information provided will be used to create a VM that matches characteristics.","tags":["ContrailCompute"],"allVersions":{"1.0":"c5bf3167-c9ed-4b9f-9441-b15f35ed46a8"},"uniqueId":"c5bf3167-c9ed-4b9f-9441-b15f35ed46a8","invariantUUID":"c518561a-d615-4e30-9dbe-ef80d5f872d3","highestVersion":true,"systemName":"Contrailcompute","uuid":"13b4c8de-6e91-47e8-9c81-11267fc87140","lifecycleState":"CERTIFIED","name":"ContrailCompute"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Network Elements","normalizedName":"network elements","uniqueId":"resourceNewCategory.generic.network elements","icons":["network","connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.cp.nodes.heat.network.contrail.Port","tosca.nodes.network.Port","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Bindable":[{"uniqueId":"d9155aa5-4b34-4389-ad93-273ca975ff5c.binding","name":"binding","capability":"tosca.capabilities.network.Bindable","relationship":"tosca.relationships.network.BindsTo","ownerId":"d9155aa5-4b34-4389-ad93-273ca975ff5c","minOccurrences":"1","maxOccurrences":"1"}],"tosca.capabilities.network.Linkable":[{"uniqueId":"d9155aa5-4b34-4389-ad93-273ca975ff5c.link","name":"link","capability":"tosca.capabilities.network.Linkable","relationship":"tosca.relationships.network.LinksTo","ownerId":"d9155aa5-4b34-4389-ad93-273ca975ff5c","minOccurrences":"1","maxOccurrences":"1"}]},"abstract":false,"resourceType":"CP","toscaResourceName":"com.att.d2.resource.cp.nodes.heat.network.contrail.Port","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"port","description":"Represents a logical entity that associates between Compute and Network normative types for contrail.","tags":["ContrailPort"],"allVersions":{"1.0":"19b2381e-2c81-4af7-a4e7-432e08511080"},"uniqueId":"19b2381e-2c81-4af7-a4e7-432e08511080","invariantUUID":"38cd1e97-a231-47a4-9708-c156ec4ff3ff","highestVersion":true,"systemName":"Contrailport","uuid":"c0d8827b-73f4-4caf-b066-2b52d021c9bd","lifecycleState":"CERTIFIED","name":"ContrailPort"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Infrastructure","normalizedName":"infrastructure","uniqueId":"resourceNewCategory.generic.infrastructure","icons":["connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Linkable":[{"uniqueId":"capability.beb1c610-9ab1-4187-b0ef-b2cfe2c077cb.link","name":"link","type":"tosca.capabilities.network.Linkable","capabilitySources":["tosca.nodes.network.Network","tosca.nodes.Root"],"properties":[],"ownerId":"beb1c610-9ab1-4187-b0ef-b2cfe2c077cb","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VL","toscaResourceName":"tosca.nodes.network.Network","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"network","description":"Represents a simple , logical network service.","tags":["Network"],"allVersions":{"1.0":"beb1c610-9ab1-4187-b0ef-b2cfe2c077cb"},"uniqueId":"beb1c610-9ab1-4187-b0ef-b2cfe2c077cb","invariantUUID":"d5c648fa-45ed-4b88-a8ab-652935e4f057","highestVersion":true,"systemName":"Network","uuid":"23e889ac-3f14-4d02-8a5e-f0b01ae15a80","lifecycleState":"CERTIFIED","name":"Network"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Rules","normalizedName":"rules","uniqueId":"resourceNewCategory.generic.rules","icons":["networkrules","securityrules"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.vfc.rules.nodes.heat.network.neutron.SecurityRules","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Attachment":[{"uniqueId":"1d99d23a-f4c9-4ae9-86e9-b5220d1b6a1c.port","name":"port","capability":"tosca.capabilities.Attachment","node":"com.att.d2.resource.cp.nodes.heat.network.neutron.Port","relationship":"com.att.d2.relationships.AttachesTo","ownerId":"1d99d23a-f4c9-4ae9-86e9-b5220d1b6a1c","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"com.att.d2.resource.vfc.rules.nodes.heat.network.neutron.SecurityRules","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"securityrules","description":"Configuration of policy rules to be applied on ports.","tags":["SecurityRules"],"allVersions":{"1.0":"1d99d23a-f4c9-4ae9-86e9-b5220d1b6a1c"},"uniqueId":"1d99d23a-f4c9-4ae9-86e9-b5220d1b6a1c","invariantUUID":"de579566-d993-4476-98f9-d2c7cc4dad33","highestVersion":true,"systemName":"Securityrules","uuid":"eadd27a9-0143-4891-8157-97ad5a4f646b","lifecycleState":"CERTIFIED","name":"SecurityRules"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Rules","normalizedName":"rules","uniqueId":"resourceNewCategory.generic.rules","icons":["networkrules","securityrules"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.vfc.rules.nodes.heat.network.contrail.NetworkRules","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Attachment":[{"uniqueId":"d08fa295-350c-4a17-b873-7fd082cde3ee.network","name":"network","capability":"tosca.capabilities.Attachment","node":"tosca.nodes.network.Network","relationship":"com.att.d2.relationships.AttachesTo","ownerId":"d08fa295-350c-4a17-b873-7fd082cde3ee","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"com.att.d2.resource.vfc.rules.nodes.heat.network.contrail.NetworkRules","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"networkrules","description":"Configuration of policy rules to be applied over the network.","tags":["ContrailNetworkRules"],"allVersions":{"1.0":"d08fa295-350c-4a17-b873-7fd082cde3ee"},"uniqueId":"d08fa295-350c-4a17-b873-7fd082cde3ee","invariantUUID":"4feedb8c-b91a-4c60-a167-a07a3b6a0142","highestVersion":true,"systemName":"Contrailnetworkrules","uuid":"af14fa4e-fa2a-4dd2-bc58-f382ee3e862c","lifecycleState":"CERTIFIED","name":"ContrailNetworkRules"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Network Elements","normalizedName":"network elements","uniqueId":"resourceNewCategory.generic.network elements","icons":["network","connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.cp.nodes.heat.network.neutron.Port","tosca.nodes.network.Port","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Bindable":[{"uniqueId":"d9155aa5-4b34-4389-ad93-273ca975ff5c.binding","name":"binding","capability":"tosca.capabilities.network.Bindable","relationship":"tosca.relationships.network.BindsTo","ownerId":"d9155aa5-4b34-4389-ad93-273ca975ff5c","minOccurrences":"1","maxOccurrences":"1"}],"tosca.capabilities.network.Linkable":[{"uniqueId":"d9155aa5-4b34-4389-ad93-273ca975ff5c.link","name":"link","capability":"tosca.capabilities.network.Linkable","relationship":"tosca.relationships.network.LinksTo","ownerId":"d9155aa5-4b34-4389-ad93-273ca975ff5c","minOccurrences":"1","maxOccurrences":"1"}]},"abstract":false,"resourceType":"CP","toscaResourceName":"com.att.d2.resource.cp.nodes.heat.network.neutron.Port","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"port","description":"Represents a logical entity that associates between Compute and Network normative types.","tags":["NeutronPort"],"allVersions":{"1.0":"5d97d7ab-99fb-464d-bd25-3bc8e8d1d74e"},"uniqueId":"5d97d7ab-99fb-464d-bd25-3bc8e8d1d74e","invariantUUID":"146a2b90-176a-4f09-a8c6-64af71c092f1","highestVersion":true,"systemName":"Neutronport","uuid":"de6a888e-ae2b-4f58-b31d-91162d611b63","lifecycleState":"CERTIFIED","name":"NeutronPort"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Infrastructure","normalizedName":"infrastructure","uniqueId":"resourceNewCategory.generic.infrastructure","icons":["connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["tosca.nodes.Compute","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Scalable":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.scalable","name":"scalable","type":"tosca.capabilities.Scalable","capabilitySources":["tosca.nodes.Compute","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Scalable.min_instances","type":"integer","required":false,"definition":false,"defaultValue":"1","password":false,"name":"min_instances","parentUniqueId":"tosca.capabilities.Scalable"},{"uniqueId":"tosca.capabilities.Scalable.max_instances","type":"integer","required":false,"definition":false,"defaultValue":"1","password":false,"name":"max_instances","parentUniqueId":"tosca.capabilities.Scalable"},{"uniqueId":"tosca.capabilities.Scalable.default_instances","type":"integer","required":false,"definition":false,"password":false,"name":"default_instances","parentUniqueId":"tosca.capabilities.Scalable"}],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Bindable":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.binding","name":"binding","type":"tosca.capabilities.network.Bindable","capabilitySources":["tosca.nodes.Compute","tosca.nodes.Root"],"properties":[],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Container":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.host","name":"host","type":"tosca.capabilities.Container","validSourceTypes":["tosca.nodes.SoftwareComponent"],"capabilitySources":["tosca.nodes.Compute","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Container.num_cpus","type":"integer","required":false,"definition":false,"password":false,"constraints":[{}],"name":"num_cpus","parentUniqueId":"tosca.capabilities.Container"},{"uniqueId":"tosca.capabilities.Container.disk_size","type":"scalar-unit.size","required":false,"definition":false,"password":false,"constraints":[{}],"name":"disk_size","parentUniqueId":"tosca.capabilities.Container"},{"uniqueId":"tosca.capabilities.Container.cpu_frequency","type":"scalar-unit.frequency","required":false,"definition":false,"password":false,"constraints":[{}],"name":"cpu_frequency","parentUniqueId":"tosca.capabilities.Container"},{"uniqueId":"tosca.capabilities.Container.mem_size","type":"scalar-unit.size","required":false,"definition":false,"password":false,"constraints":[{}],"name":"mem_size","parentUniqueId":"tosca.capabilities.Container"}],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Endpoint.Admin":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.endpoint","name":"endpoint","type":"tosca.capabilities.Endpoint.Admin","capabilitySources":["tosca.nodes.Compute","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Endpoint.port_name","type":"string","required":false,"definition":false,"password":false,"name":"port_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.protocol","type":"string","required":false,"definition":false,"defaultValue":"tcp","password":false,"name":"protocol","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.port","type":"PortDef","required":false,"definition":false,"password":false,"name":"port","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.initiator","type":"string","required":false,"definition":false,"defaultValue":"source","password":false,"constraints":[{"validValues":["source","target","peer"]}],"name":"initiator","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.network_name","type":"string","required":false,"definition":false,"defaultValue":"PRIVATE","password":false,"name":"network_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.Admin.secure","required":false,"definition":false,"defaultValue":"true","password":false,"name":"secure","parentUniqueId":"tosca.capabilities.Endpoint.Admin"},{"uniqueId":"tosca.capabilities.Endpoint.ports","type":"map","required":false,"definition":false,"schema":{"property":{"type":"PortSpec","required":false,"definition":true,"password":false}},"password":false,"constraints":[{}],"name":"ports","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.url_path","type":"string","required":false,"definition":false,"password":false,"name":"url_path","parentUniqueId":"tosca.capabilities.Endpoint"}],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.OperatingSystem":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.os","name":"os","type":"tosca.capabilities.OperatingSystem","capabilitySources":["tosca.nodes.Compute","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.OperatingSystem.distribution","type":"string","required":false,"definition":false,"password":false,"name":"distribution","parentUniqueId":"tosca.capabilities.OperatingSystem"},{"uniqueId":"tosca.capabilities.OperatingSystem.type","type":"string","required":false,"definition":false,"password":false,"name":"type","parentUniqueId":"tosca.capabilities.OperatingSystem"},{"uniqueId":"tosca.capabilities.OperatingSystem.version","type":"version","required":false,"definition":false,"password":false,"name":"version","parentUniqueId":"tosca.capabilities.OperatingSystem"},{"uniqueId":"tosca.capabilities.OperatingSystem.architecture","type":"string","required":false,"definition":false,"password":false,"name":"architecture","parentUniqueId":"tosca.capabilities.OperatingSystem"}],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Attachment":[{"uniqueId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df.local_storage","name":"local_storage","capability":"tosca.capabilities.Attachment","node":"tosca.nodes.BlockStorage","relationship":"tosca.relationships.AttachesTo","ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"tosca.nodes.Compute","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"compute","description":"Represents a real or virtual machine or server. Information specified on the Compute node will be used to find the machine that fits the given requirements in the cloud available machines. If no sizing information are specified the cloud provider default machine will be used. It is strongly recommended to specify the required CPUs and memory at least.","tags":["Compute"],"allVersions":{"1.0":"c30f3b4c-d28c-4e46-8954-2de6b00c21df"},"uniqueId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","invariantUUID":"8888d83c-b053-46ab-a28e-7ed1bbb1da5b","highestVersion":true,"systemName":"Compute","uuid":"9cecb2a4-5588-4256-a69d-0aff871c0b13","lifecycleState":"CERTIFIED","name":"Compute"},{"categories":[{"name":"Generic","normalizedName":"generic","uniqueId":"resourceNewCategory.generic","subcategories":[{"name":"Infrastructure","normalizedName":"infrastructure","uniqueId":"resourceNewCategory.generic.infrastructure","icons":["connector"]}]}],"componentType":"RESOURCE","capabilities":{"tosca.capabilities.Node":[{"uniqueId":"capability.f1086d06-92ab-4ab8-9565-5aa1118ed76d.feature","name":"feature","type":"tosca.capabilities.Node","capabilitySources":["com.att.d2.resource.vfc.nodes.heat.nova.Server","tosca.nodes.Compute","tosca.nodes.Root"],"properties":[],"ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Scalable":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.scalable","name":"scalable","type":"tosca.capabilities.Scalable","capabilitySources":["com.att.d2.resource.vfc.nodes.heat.nova.Server","tosca.nodes.Compute","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Scalable.min_instances","type":"integer","required":false,"definition":false,"defaultValue":"1","password":false,"name":"min_instances","parentUniqueId":"tosca.capabilities.Scalable"},{"uniqueId":"tosca.capabilities.Scalable.max_instances","type":"integer","required":false,"definition":false,"defaultValue":"1","password":false,"name":"max_instances","parentUniqueId":"tosca.capabilities.Scalable"},{"uniqueId":"tosca.capabilities.Scalable.default_instances","type":"integer","required":false,"definition":false,"password":false,"name":"default_instances","parentUniqueId":"tosca.capabilities.Scalable"}],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.network.Bindable":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.binding","name":"binding","type":"tosca.capabilities.network.Bindable","capabilitySources":["com.att.d2.resource.vfc.nodes.heat.nova.Server","tosca.nodes.Compute","tosca.nodes.Root"],"properties":[],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Container":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.host","name":"host","type":"tosca.capabilities.Container","validSourceTypes":["tosca.nodes.SoftwareComponent"],"capabilitySources":["com.att.d2.resource.vfc.nodes.heat.nova.Server","tosca.nodes.Compute","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Container.num_cpus","type":"integer","required":false,"definition":false,"password":false,"constraints":[{}],"name":"num_cpus","parentUniqueId":"tosca.capabilities.Container"},{"uniqueId":"tosca.capabilities.Container.disk_size","type":"scalar-unit.size","required":false,"definition":false,"password":false,"constraints":[{}],"name":"disk_size","parentUniqueId":"tosca.capabilities.Container"},{"uniqueId":"tosca.capabilities.Container.cpu_frequency","type":"scalar-unit.frequency","required":false,"definition":false,"password":false,"constraints":[{}],"name":"cpu_frequency","parentUniqueId":"tosca.capabilities.Container"},{"uniqueId":"tosca.capabilities.Container.mem_size","type":"scalar-unit.size","required":false,"definition":false,"password":false,"constraints":[{}],"name":"mem_size","parentUniqueId":"tosca.capabilities.Container"}],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Endpoint.Admin":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.endpoint","name":"endpoint","type":"tosca.capabilities.Endpoint.Admin","capabilitySources":["com.att.d2.resource.vfc.nodes.heat.nova.Server","tosca.nodes.Compute","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.Endpoint.port_name","type":"string","required":false,"definition":false,"password":false,"name":"port_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.protocol","type":"string","required":false,"definition":false,"defaultValue":"tcp","password":false,"name":"protocol","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.port","type":"PortDef","required":false,"definition":false,"password":false,"name":"port","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.initiator","type":"string","required":false,"definition":false,"defaultValue":"source","password":false,"constraints":[{"validValues":["source","target","peer"]}],"name":"initiator","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.network_name","type":"string","required":false,"definition":false,"defaultValue":"PRIVATE","password":false,"name":"network_name","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.Admin.secure","required":false,"definition":false,"defaultValue":"true","password":false,"name":"secure","parentUniqueId":"tosca.capabilities.Endpoint.Admin"},{"uniqueId":"tosca.capabilities.Endpoint.ports","type":"map","required":false,"definition":false,"schema":{"property":{"type":"PortSpec","required":false,"definition":true,"password":false}},"password":false,"constraints":[{}],"name":"ports","parentUniqueId":"tosca.capabilities.Endpoint"},{"uniqueId":"tosca.capabilities.Endpoint.url_path","type":"string","required":false,"definition":false,"password":false,"name":"url_path","parentUniqueId":"tosca.capabilities.Endpoint"}],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.OperatingSystem":[{"uniqueId":"capability.c30f3b4c-d28c-4e46-8954-2de6b00c21df.os","name":"os","type":"tosca.capabilities.OperatingSystem","capabilitySources":["com.att.d2.resource.vfc.nodes.heat.nova.Server","tosca.nodes.Compute","tosca.nodes.Root"],"properties":[{"uniqueId":"tosca.capabilities.OperatingSystem.distribution","type":"string","required":false,"definition":false,"password":false,"name":"distribution","parentUniqueId":"tosca.capabilities.OperatingSystem"},{"uniqueId":"tosca.capabilities.OperatingSystem.type","type":"string","required":false,"definition":false,"password":false,"name":"type","parentUniqueId":"tosca.capabilities.OperatingSystem"},{"uniqueId":"tosca.capabilities.OperatingSystem.version","type":"version","required":false,"definition":false,"password":false,"name":"version","parentUniqueId":"tosca.capabilities.OperatingSystem"},{"uniqueId":"tosca.capabilities.OperatingSystem.architecture","type":"string","required":false,"definition":false,"password":false,"name":"architecture","parentUniqueId":"tosca.capabilities.OperatingSystem"}],"ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"1","maxOccurrences":"UNBOUNDED"}]},"requirements":{"tosca.capabilities.Node":[{"uniqueId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d.dependency","name":"dependency","capability":"tosca.capabilities.Node","node":"tosca.nodes.Root","relationship":"tosca.relationships.DependsOn","ownerId":"f1086d06-92ab-4ab8-9565-5aa1118ed76d","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}],"tosca.capabilities.Attachment":[{"uniqueId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df.local_storage","name":"local_storage","capability":"tosca.capabilities.Attachment","node":"tosca.nodes.BlockStorage","relationship":"tosca.relationships.AttachesTo","ownerId":"c30f3b4c-d28c-4e46-8954-2de6b00c21df","minOccurrences":"0","maxOccurrences":"UNBOUNDED"}]},"abstract":false,"resourceType":"VFC","toscaResourceName":"com.att.d2.resource.vfc.nodes.heat.nova.Server","vendorName":"ATT (Tosca)","vendorRelease":"1.0.0.wd03","version":"1.0","icon":"defaulticon","description":"Represents a real or virtual machine or server. Information specified on the Compute node will be used to find the machine that fits the given requirements in the cloud available machines. If no sizing information are specified the cloud provider default machine will be used. It is strongly recommended to specify the required CPUs and memory at least.","tags":["NovaServer"],"allVersions":{"1.0":"99b21d27-f578-48c7-93a2-5a28e2b5f751"},"uniqueId":"99b21d27-f578-48c7-93a2-5a28e2b5f751","invariantUUID":"8dccd960-a2af-493d-957e-f8a820675ff2","highestVersion":true,"systemName":"Novaserver","uuid":"77855454-a0e1-4f46-b063-0c8b89e43782","lifecycleState":"CERTIFIED","name":"NovaServer"}] \ No newline at end of file diff --git a/app/WEB-INF/jetty-web.xml b/app/WEB-INF/jetty-web.xml new file mode 100644 index 0000000..ba9f083 --- /dev/null +++ b/app/WEB-INF/jetty-web.xml @@ -0,0 +1,8 @@ + + + + + /dcae + diff --git a/app/WEB-INF/rewrite.config b/app/WEB-INF/rewrite.config new file mode 100644 index 0000000..90893bb --- /dev/null +++ b/app/WEB-INF/rewrite.config @@ -0,0 +1,2 @@ +RewriteRule ^.*\..*$ - [L] +RewriteRule ^.*$ /index.html [L] diff --git a/app/WEB-INF/web.xml b/app/WEB-INF/web.xml new file mode 100644 index 0000000..8ba3dc1 --- /dev/null +++ b/app/WEB-INF/web.xml @@ -0,0 +1,10 @@ + + + + DCAE_FE + + + diff --git a/app/_dcaeapp.xml b/app/_dcaeapp.xml new file mode 100644 index 0000000..2af7bd4 --- /dev/null +++ b/app/_dcaeapp.xml @@ -0,0 +1,45 @@ + + + + + + + /dcae + /dcae.war + + + + org.eclipse.jetty.websocket.jsr356 + true + + + + + 2048 + + + + + + + + Test Realm + /etc/realm.properties + + + + + + + + true + + + true + + + + diff --git a/app/app.config.js b/app/app.config.js new file mode 100644 index 0000000..952c221 --- /dev/null +++ b/app/app.config.js @@ -0,0 +1,65 @@ +(function () { + 'use strict'; + + angular + .module('dcaeApp') + .factory('httpRequestInterceptor', function ($injector, $rootScope) { + var httpRequestInterceptor = { + request: function (config) { + // Send the user only for API requests + var userId = ""; + if ($rootScope.baseURL.indexOf('localhost') !== -1) { + // if (config.url.indexOf($rootScope.baseURL) !== -1) { + config.headers = config.headers || {}; + userId = 'ym903w'; + // userId = $injector .get('Sdc.Services.CookieService') .getUserId(); + var user = { + userId: userId + }; + if (user) { + config.headers['USER_ID'] = user.userId; + } + // } + } else { + config.headers = config.headers || {}; + var user = { + userId: window.userId + }; + userId = window.userId; + // var user = { userId: $rootScope.cookieUser }; userId = + // $rootScope.cookieUser; + if (user) { + config.headers['USER_ID'] = user.userId; + console.log('Your User is:', user.userId); + } else { + console.log('Error look on your grunt file you dont have a user set'); + } + + } + $rootScope.userId = userId; + return config; + } + }; + return httpRequestInterceptor; + }) + .config(config); + + function config($httpProvider) { + + // Ask for cross domain from the sever (need to allow this in server). + $httpProvider.defaults.useXDomain = true; + delete $httpProvider.defaults.headers.common['X-Requested-With']; + + $httpProvider + .interceptors + .push('httpRequestInterceptor'); + + // HTTP Interceptor definition + /*$httpProvider.interceptors.push('httpRequestInterceptor'); + $httpProvider.interceptors.push('httpResponseInterceptor'); + $httpProvider.interceptors.push('httpRequestErrorInterceptor'); + $httpProvider.interceptors.push('httpResponseErrorInterceptor');*/ + + } + +})(); diff --git a/app/app.constants.js b/app/app.constants.js new file mode 100644 index 0000000..274edcb --- /dev/null +++ b/app/app.constants.js @@ -0,0 +1,20 @@ +(function () { + 'use strict'; + + angular + .module('dcaeApp') + .constant("dcaeConstants", { + + params: { + "param1": "param1", + "param2": "param2", + "param3": "param3" + }, + + more: { + "more1": "more1", + "more2": "mroe2" + } + + }); +})(); diff --git a/app/app.controller.js b/app/app.controller.js new file mode 100644 index 0000000..94e79a1 --- /dev/null +++ b/app/app.controller.js @@ -0,0 +1,17 @@ +(function () { + + 'use strict'; + + angular + .module('dcaeApp') + .controller('AppController', AppController); + + function AppController($state, + $timeout, + $rootScope) { + + var vm = this; + + } + +})(); diff --git a/app/app.module.js b/app/app.module.js new file mode 100644 index 0000000..47507e6 --- /dev/null +++ b/app/app.module.js @@ -0,0 +1,29 @@ +(function () { + + 'use strict'; + + angular + .module('dcaeApp', [ + + // Core + 'ui.router', + 'dcaeApp.env', + + // Modules + 'dcaeApp.header', + 'dcaeApp.navigation', + 'dcaeApp.main', + 'dcaeApp.dashboard.home', + 'dcaeApp.dashboard.about', + 'dcaeApp.dashboard.dcae', + + // Services + 'dcaeApp.services.cacheService', + 'dcaeApp.services.users' + + // Interceptors + + // Main pages + + ]); +})(); diff --git a/app/app.route.js b/app/app.route.js new file mode 100644 index 0000000..ee2a161 --- /dev/null +++ b/app/app.route.js @@ -0,0 +1,72 @@ +(function () { + + 'use strict'; + + angular + .module('dcaeApp') + .config(routeConfig); + + function routeConfig($stateProvider, $urlRouterProvider, dcaeConstants) { + + //$urlRouterProvider.otherwise('/dcae/home'); + + var layoutStyle = 'contentOnly'; + + var layouts = { + contentWithHeaderAndNavigation: { + main: 'core/layouts/header-navigation-content/header-navigation-content.html', + header: 'core/header/layouts/horizontal-navigation/header.html', + navigation: 'core/navigation/layouts/horizontal-navigation/navigation.html' + }, + contentOnly: { + main: 'core/layouts/content-only/content-only.html', + header: '', + navigation: '' + }, + contentWithHeader: { + main: 'core/layouts/content-with-header/content-with-header.html', + header: 'header/layouts/content-with-header/header.html', + navigation: '' + } + }; + + // @if DEBUG + // Note: this section is removed when running grunt. + // If you want to run the application as standalone from the dist folder you need to remove: if DEBUG and endif and build the grunt again. + $stateProvider.state('dcae', { + url: '/dcae', + views: { + 'dcae@': { + template: '
' + } + } + }); + // @endif + + // State definitions + $stateProvider + .state('dcae.app', { + parent: 'dcae', + abstract: true, + views: { + // This is the main view (defined in the hosting application) + 'main@dcae': { + templateUrl: layouts[layoutStyle].main, + controller: 'MainController as vm' + }/*, + + // According to the view used in "main@" we have another 3 views in main: 'header@app', 'navigation@app' and 'content@app' (defined in each page module) + 'header@dcae.app': { // View inside the main + templateUrl: layouts[layoutStyle].header, + controller: 'HeaderController as vm' + }, + 'navigation@dcae.app': { // View inside the main + templateUrl: layouts[layoutStyle].navigation, + controller: 'NavigationController as vm' + }*/ + } + }); + + } + +})(); diff --git a/app/app.run.js b/app/app.run.js new file mode 100644 index 0000000..8be7ad1 --- /dev/null +++ b/app/app.run.js @@ -0,0 +1,59 @@ +(function () { + + 'use strict'; + + angular + .module('dcaeApp') + .run(runBlock); + + function runBlock($rootScope, $timeout, $state, cacheService, ENV) { + + $rootScope.user = {}; + + // Show loading circle + var stateChangeStartEvent = $rootScope.$on('$stateChangeStart', function () { + $rootScope.loadingProgress = true; + }); + + // Hide loading circle + var stateChangeSuccessEvent = $rootScope.$on('$stateChangeSuccess', function () { + $timeout(function () { + $rootScope.loadingProgress = false; + }); + }); + + // Store state in the root scope for easy access + $rootScope.state = $state; + + // Cleanup + $rootScope.$on('$destroy', function () { + stateChangeStartEvent(); + stateChangeSuccessEvent(); + }); + + // Load configuration + $rootScope.baseURL = ENV.apiBase; + window.host = ENV.host; + $rootScope.catalogImport = ENV.catalogImport; + window.catalogImport = ENV.catalogImport; + window.catalogPrefix = ENV.catalogPrefix; + $rootScope.cookieUser = ENV.cookieUser; + window.ruleEditorUrl = ENV.ruleEditorUrl; + // debugger; + + cacheService.set('configuration', { + "urls": { + "auth": { + "login": $rootScope.baseURL + "dcaeApp/v1/engmgr/login", + "register": $rootScope.baseURL + "dcaeApp/v1/engmgr/signup" + } + } + }); + + /*$rootScope.$on('$stateChangeStart', function(e, to, toP, from, fromP) { + to.views['item-'+toP.itemId+'@home'] = to.views['item-:itemId@home']; + delete to.views['item-:itemId@home']; + });*/ + + } +})(); diff --git a/app/comp-fe/asdc-catalog.js b/app/comp-fe/asdc-catalog.js new file mode 100644 index 0000000..334a6d7 --- /dev/null +++ b/app/comp-fe/asdc-catalog.js @@ -0,0 +1,165 @@ +var log = log || function (x, y) { + var args = ["asdc-catalog:"].concat(Array.prototype.slice.call(arguments, 0)); + console.log.apply(console, args); +} + +setTimeout(function () { + sbox = document.getElementById('searchbox'); + if (sbox) { + sbox.onkeypress = function (e) { + if (!e) e = window.event; + var keyCode = e.keyCode || e.which; + if (keyCode == '13') { + dosearch(sbox.value); + return false; + } + }; + } +}, 1000); + +function dosearch() { + input = document.getElementById("searchbox"); + catalogbyname(".*(" + input.value + ").*"); +} + +var catalogprefix = window.catalogPrefix; + +function elements() { + // log("elements"); + var url = "/catalog"; + xhrget(url, + function (req) { + d3.select("#elementquery").remove(); + var res = JSON.parse(req); + var list = d3.select("#catalogitemlist"); + res.elements.map(function (item) { + (function () { + var div = list.append("div"); + var name = item.name; + div.classed("folder", true) + .html("" + name + "") + .append("br"); + div.on("click", function () { + div.on("click", null); // once only + items(item, div); + }); + })(); + }); + }); +} + +function items(item, parent) { + + var items = item.items; + items.map(function (item) { + var _item = item; + (function () { + var div = parent.append("div"); + var name = _item.name; + log("ITEM", name, _item); + + div.classed("item", true) + .attr('data-tests-id', name) + .html(name); + + parent.append("div").style("clear", "both").style("height", 0); + div.on("click", function () { + dropdata(_item); + }); + + div.attr("draggable", true) + .classed("draggable", true); + div.node().addEventListener('dragstart', function (e) { + e.dataTransfer.effectAllowed = 'move'; + e.dataTransfer.setData('product', JSON.stringify(_item)); + }); + })(); + }); + +} + +function catalogitem(id, fn) { + var nn = 0; + var url = "/" + id + "/model"; + log("catalogitem:", url); + xhrget(url, function (resp) { + var x = JSON.parse(resp); + if (!_.isEmpty(x.error)) { + log("catalogitem error", x.error); + return; + } + if (_.isEmpty(x.data)) { + log("catalogitem NO DATA"); + return; + } + + x = x.data; // HACK + + var model = x.model; + log("catalogitem", model.nodes); + + if (!x.models) { + log("HACK models"); + x.models = [x.model]; + } + + nn += model.nodes.length; + model.nodes.map(function (n) { + catalogtype(id, n.type, function (resp) { + var ti = JSON.parse(resp); + n.typeinfo = ti; + + // patch things up (HACK) + log("HACK typeinfo"); + n.typeinfo = n.typeinfo.data.type; + if (!n.typeinfo.requirements) + n.typeinfo.requirements = []; + if (!n.typeinfo.capabilities) + n.typeinfo.capabilities = []; + + if (--nn == 0) + fn(x); + }); + }); + }); +} + +function catalogitem00(id, fn) { + var nn = 0; + var url = "/" + id + "/model"; + log("catalogitem:", url); + xhrget(url, function (resp) { + var x = JSON.parse(resp); + var model = x.data.model; + //model.id = id; + model.name = "foo"; // HACK + log("catalogitem", id, x, model); + fn(model); + }); +} + +function xhrget(url, callback) { + var req = new XMLHttpRequest; + console.log(url); + // debugger; + url = catalogprefix + url; + // if (!(url.startsWith("https://") || url.startsWith("http://"))) + // url = catalogprefix + url; + // console.log(url); + req.open("GET", url, true); // asynchronous request + req.onreadystatechange = function (x) { + if (req.readyState === 4) + callback(req.responseText); + }; + req.send(null); +} + +function catalogtype(id, type, fn) { + var url = "/" + id + "/type/" + type + "/"; + xhrget(url, function (resp) { + //log("catalogtype", id, type, resp); + fn(resp); + }); +} + +setTimeout(elements, 500); diff --git a/app/comp-fe/catalog.css b/app/comp-fe/catalog.css new file mode 100644 index 0000000..5d674e3 --- /dev/null +++ b/app/comp-fe/catalog.css @@ -0,0 +1,248 @@ +.product { + font-size: 140%; +} + +#catalog { + width: auto; + overflow: hidden; + height: 100%; + font-family: helvetica; //font-weight: 200; +} + +#catalogitemlist { + display: inline-block; + overflow-x: hidden; + max-height: 95%; + width: 360px; + pointer-events: all; //margin-top: 10px; + margin: 4px; + padding: 6px; + border: 1px solid rgba(50, 50, 50, 0.5); //border-radius: 11px; + //background: rgba(238,238,238,0.4); + transition: 1s; + overflow: scroll; + max-height: 800px; +} + +#catalogitemlist:hover { + //background: rgba(238,238,238,0.9); +} + +.big-btn { + width: 100%; +} + +.catalogitems { + overflow-y: visible; + overflow-x: hidden; +} + +.catalogitem { + display: unset; + margin: 5px; //width: 320px; + padding: 15px; + padding-left: 15px; + padding-bottom: 15px; //border-radius: 10px; + border: 1px dotted rgba(50, 50, 50, 0.5); + overflow-x: hidden; +} + +.catalogitem:hover { + border: 1px dotted rgba(50, 50, 50, 0.5); +} + +.inflight { + transform: scale(.5); +} + +.template { + padding-left: 15px; +} + +.node { + margin-left: 10px; + padding: 2px; + border-radius: 8px; +} + +.node:hover { + background-color: rgba(0, 0, 0, 0.15); +} + +.nodebody { + padding-left: 15px; +} + +.propinput { + padding-left: 15px; +} + +.notes { + display: inline-block; + vertical-align: top; + text-align: left; + font-size: 16px; + padding-left: 8px; + width: 300px; +} + +.dotbox { + width: 300px; + margin: 4px; + outline: 1px dotted rgba(50, 50, 50, 0.5); +} + +.nodebox { + max-width: 310px; + margin: 4px; + margin-left: 15px; + overflow: hidden; + line-spacing: 1.1; +} + +.dcae-label { + display: inline-block; + width: 100px; + text-align: left top; +} + +.dragover { + background-color: gray; +} + +.dcae-input { + color: black; + border: 1px dotted rgba(50, 50, 50, 0.5); + background-color: rgba(0, 0, 0, 0); + font-size: 100%; + font-family: Raleway; +} + +.dcae-input:focus { + outline: 1px solid rgba(50, 50, 50, 0.5); +} + +#dragcover { + z-index: -1; + position: absolute; + left: 0; + bottom: 0; + width: 600; + height: 600; + -webkit-transform: scale(0.3); + -webkit-transform-origin: bottom left; + padding: 4px; + overflow: hidden; + background: #eeeeee; +} + +#dragdiv { + z-index: -2; + position: absolute; + left: 0; + bottom: 0; + width: 600px; + height: auto; + -webkit-transform: scale(0.3); + -webkit-transform-origin: bottom left; + padding: 4px; + overflow: hidden; +} + +#dragtext { + font-size: 350%; +} + +#innerdragdiv { + width: 380px; + height: auto; + margin-left: 30px; + border-radius: 15; + overflow: hidden; +} + +#top { + font-size: 200%; +} + +#search { + font-size: 120%; + position: absolute; + left: 10px; + max-width: 900px; //height: 400px; + line-height: 2.3; + overflow-x: visible; + margin: 0 auto; +} + +body::-webkit-scrollbar { + width: 1px; +} + +#searchfield { + display: block; + float: left; +} + +#searchitems { + display: block; + float: left; + pointer-events: all; + height: auto; + width: auto; + max-width: 400px; + max-height: 300px; + padding: 4px; + margin-left: 12px; + overflow-x: hidden; + overflow-y: auto; + line-height: 2; + background: #eeeeee; + box-shadow: 4px 4px 50px rgba(0, 0, 0, 1); +} + +#searchbox { + font-family: Raleway; + pointer-events: all; + margin-bottom: 10px; +} + +.searchitem { + pointer-events: all; + margin: 2px; + padding: 5px; + outline: 1px dotted rgba(50, 50, 50, 0.5); +} + +.searchitem:hover { + outline: 1px solid rgba(50, 50, 50, 0.5); +} + +.folder { + margin: 5px; //width: 320px; + padding: 15px; + padding-left: 15px; + padding-bottom: 15px; //border-radius: 10px; + outline: 1px dotted rgba(50, 50, 50, 0.5); + overflow-x: hidden; +} + +.folder:hover { + outline: 2px solid rgba(50, 50, 50, 0.5); //background: rgba(255,0,0,0.2); +} + +.draggable { + //background: rgba(0,0,0,0.1); +} + +.item.draggable:hover { + outline: 1px solid rgba(0, 0, 0, 0.8); //background: rgba(255,255,255,0.6); +} + +.item { + padding: 2px; + margin: 1px; + margin-left: 20px; + display: inline-block; + outline: 1px solid rgba(0, 0, 0, 0); +} diff --git a/app/comp-fe/catalog.html b/app/comp-fe/catalog.html new file mode 100644 index 0000000..f0d80b2 --- /dev/null +++ b/app/comp-fe/catalog.html @@ -0,0 +1,57 @@ + + + + + + + + + + + + +
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+ + + + diff --git a/app/comp-fe/catalog.js b/app/comp-fe/catalog.js new file mode 100644 index 0000000..dc7006e --- /dev/null +++ b/app/comp-fe/catalog.js @@ -0,0 +1,89 @@ +setTimeout(function () { + sbox = document.getElementById('searchbox'); + sbox.onkeypress = function (e) { + if (!e) e = window.event; + var keyCode = e.keyCode || e.which; + if (keyCode == '13') { + dosearch(sbox.value); + return false; + } + }; + +}, 1000); + +function dosearch() { + input = document.getElementById("searchbox"); + catalogbyname(".*(" + input.value + ").*"); +} + +var catalogprefix = ""; + +function catalogbyname(pattern) { + xhrget(catalogprefix + "/byname?" + pattern, + function (req) { + var res = JSON.parse(req); + var list = d3.select("#catalogitemlist"); + res.result.map(function (item) { + var div = list.append("div"); + + (function () { + div.classed("catalogitem", true) + .attr("draggable", true) + .html(item.name) + .append("br"); + div.node().addEventListener('dragstart', function (e) { + var _item = item; + e.dataTransfer.effectAllowed = 'move'; + e.dataTransfer.setData('product', JSON.stringify(_item)); + }); + + })(); + + }); + }); +} + +function catalogitem(id, fn) { + var nn = 0; + xhrget(catalogprefix + "/itembyid?" + id, function (resp) { + var x = JSON.parse(resp); + if (x.models && x.models.length > 0) { + x.models.map(function (w) { + nn += w.nodes.length; + w.nodes.map(function (n) { + if (n.id == 0) { // dummy node special case + if (--nn == 0) + fn(x); + } else { + xhrget(catalogprefix + "/type?" + n.type.name, function (resp) { + var ti = JSON.parse(resp); + n.typeinfo = ti; + if (--nn == 0) + fn(x); + }); + } + }); + }); + } else { + fn(x); + } + }); +} + +function catalogtype(typename, fn) { + xhrget(catalogprefix + "/type?" + typename, fn); +} + +/* e.g. + catalogtype(n.type.name, function(resp) { + var ti = JSON.parse(resp); + n.typeinfo = ti; + addnode(n); + }); + */ + + +function log(x, y) { + var args = ["catalog:"].concat(Array.prototype.slice.call(arguments, 0)); + console.log.apply(console, args); +} diff --git a/app/comp-fe/composition.css b/app/comp-fe/composition.css new file mode 100644 index 0000000..2431858 --- /dev/null +++ b/app/comp-fe/composition.css @@ -0,0 +1,626 @@ +body { + overflow: hidden; +} + +#icecat { + width: 100%; + height: 100%; + overflow: hidden; +} + +.product { + padding: 5px; + margin: 5px; + background: rgba(0,0,0,0.05); + border-radius: 10px; +} +#products { + position:absolute; + top:10px; + left:0px; + width:140px; + height:200px; + font-size: 10px; + background: rgba(0,0,0,0); + z-index: 10; +} +#productlist { + position:absolute; + top:0; +} +.part { + padding: 2px; + margin: 3px; + margin-left: 5px; + background: rgba(0,0,0,0.1); + display: table; +} +.part span { + //background: rgba(0,0,0,0.1); +} +.part:hover { + outline: 1px solid black; +} + +.partnode { + padding: 2px; + margin-left: 10px; +} +.partnode span { + padding: 1px; + background: rgba(0,0,0,0.1); +} +.partnode span:hover { + background: rgba(200,100,100,0.3); +} + +.compositionbody { + margin:0; + padding:0; + font-size: 14px; + //font-family: Raleway; + font-family: helvetica; + color: black; + //overflow-x: hidden; + //overflow-y: hidden; + //position:fixed; + //text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5); + background: rgba(255, 255, 255, 0); + + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -o-user-select: none; + user-select: none; +} + +#compositioncontainer { + //position:absolute; + overflow:hidden; + width: 100%; height: 100%; + user-select: none; +} +#under { + z-index:-10; + background: rgba(0,0,0,0); + position:absolute; + width: 100%; + height: 100%; + overflow: hidden; + margin: 0; + padding: 0; +} +#overlay { + z-index:1; + background: rgba(0,0,0,0); + position:absolute; + width: 100%; + height: 100%; + overflow: hidden; + margin: 0; padding: 0; + pointer-events: none; +} +svg { + pointer-events: all; + overflow: visible; +} + +.node { + //fill: rgba(190,190,190,0.8); + fill: #ccc; + //fill-opacity: .6; + text-shadow: 1px 1px 3px rgba(0,0,0,0.5); + stroke: rgba(0,0,0,0.2); +} + +.node:hover { + stroke: rgba(0,0,0,0.5); +} +.nodeport { + //visibility:hidden; + text-shadow: none; + //text-color: rgba(0,0,0,0.4); + //fill-opacity: 1; + //transform: scale(1); +} +.nodeport:hover { + //fill: #f00; +} + +.nodeporttext { + transition: .5s; + text-anchor: middle; + //font: 12px Raleway; + //font: 12px helvetica; + font-size: 12px; + font-family:helvetica; + pointer-events: none; + //stroke: rgba(0,0,0,0.3); + fill: rgba(0,0,0,0.6); + text-color: rgba(0,0,0,0.6); + //stroke-opacity: 0.7; + //opacity: 0.8; +} +.nodeporttext:hover { + font-size: 14px; +} + +.hidden { + visibility: hidden; +} +.srcport { +} +.srcport:hover { + //fill: rgba(0,0,255,0.5); +} + +.capabilityport { + fill: #beb; +} +.requirementport { + fill: #ebb; +} + +.targetport { + //visibility: hidden; +} +.targeting:hover .nodeportcircle { + visibility: visible; +} + +.targetcircle { + stroke: rgba(0,0,0,0); + fill: rgba(0,0,0,0); + fill: none; +} +.targeting:hover .targetcircle { + fill: rgba(0,0,0,0.2); + stroke: rgba(0,0,0,0.5); + stroke-width: .5; + visibility: visible; + -webkit-animation: pulsate 1s ease-out 0s infinite alternate; + animation: pulsate 1s ease-out 0s infinite alternatedil; +} +@keyframes pulsate { + 0% {transform: scale(0.9); opacity: 0.0;} + 50% {opacity: 0.8;} + 100% {transform: scale(2); opacity: 0.0;} +} + +#catalogdiv { + position:absolute; + top: 5px; + right: 5px; + transform: scale(0.7); + transform-origin: top right; +} + +.type-select{ + width: 90%; + display: block; + margin: 10px auto; + height: 45px; + line-height: 40px; + padding: 0 5px; + font-size: 22px; + border: 2px solid #68c6e9; +} + +.pendingquery { + font-style: italic; + margin-left: 20px; + -webkit-animation: pending 1s ease-out 0s infinite alternatedil; + animation: pending 1s ease-out 0s infinite alternatedil; +} +@keyframes pending { + 0% { opacity: 1.0;} + 50% {opacity: 0.5;} + 100% {opacity: 1.0;} +} + +.svgtext { + text-anchor: middle; + //font: 12px Raleway; + font: 12px helvetica; + stroke: rgba(0,0,0,0.6); + pointer-events: none; +} +.relation { + fill-opacity: 0; + stroke-width: 10; + stroke-opacity: 0.4; + stroke-linecap: round; + stroke: #777; + //transition: .5s; +} +.relation:hover { + stroke: #555; +} +.pending { + stroke-dasharray: 10,25; +} +.tmprelation { + fill-opacity: 0; + stroke-width: 10; + stroke-opacity: 0.6; + stroke-linecap: round; + stroke: #777; + pointer-events: none; + stroke-dasharray: 10,20; + //transition: .5s; +} +.fixed { +} +#minutiae { + width: 150; + height: 15; + border: 1px solid rgba(50,50,50,0.5); + background: rgba(238,238,238,0.2); + border-radius: 5px; + transition: height 1s, width 2s; + transition-delay: 5s; + transform-origin: bottom right; + padding: 4px; + margin: 4px; + margin-bottom: 10px; + overflow: hidden; + position:absolute; + right: 5; + bottom: 40; +} +#minutiae:hover { + transition-delay: 0s; + width: 200; + height: 300; + transform: scale(1); + background: rgba(238,238,238,0.8); + pointer-events: all; +} +#project { + position:absolute; + bottom: 4; + left: 4; +} +iiinput { + color: black; + border: 1px dotted rgba(50,50,50,0.5); + background-color: rgba(0,0,0,0); +} +iiinput:focus { + outline: 1px solid rgba(50,50,50,0.5); +} +.nodetext { + padding:2px; + font: 13px helvetica; + text-align: center; + display: table-cell; + vertical-align: middle; + /*border-radius: 10px;*/ +} +.nodetypetext { + font-size: 7px; + /*text-shadow: none;*/ +} + +.confignode { + /*visibility: hidden;*/ + pointer-events: all; + font-size: 60%; + background: #8ac6fb; + padding: 0.3rem; + border-radius: 28px; +} +.nodetext:hover .confignode { + visibility: visible; +} +.confignode:hover { + visibility: visible; + background: rgba(255,100,100,0.5); +} +#configeditor { + font-family: helvetica; + font-size: 12px; + padding: 5px; + position:absolute; + z-index:10; + width: 100%; + height: 600px; + visibility: hidden; + border-radius: 5px; + background: rgba(238,238,238,0.9); + box-shadow: 4px 4px 50px rgba(0,0,0,1); + transition: .2s; + pointer-events: all; + transform-origin: top left; + border-radius: 5px; + overflow: hidden; + bottom: 0px; + right: 0px; + top: 0; + left: 0; + margin-left: auto; + margin-right: auto; + +} +#configstuff { + width: 100%; + height: 564px; + overflow: hidden; +} + +.configbutton{ + background: #009fdb; + font-family: Arial; + color: #ffffff; + font-size: 14px; + padding: 5px 15px 5px 15px; + margin: 0.1rem; + float: right; + height: 100%; + cursor: pointer; + border-radius: 5px; +} + +.config-fotter { + position:absolute; + height: 39px; + left: 0px; + bottom: 0px; + width: 100%; +} + +.config-fotter .btn { + float: right; + margin-right: 5px; +} + +.btn.btn-primary { + background-color: #009fdb; + border-color: #009fdb; +} + +.btn.btn-default { + color: #009fdb; + border-color: #009fdb; +} + +.btn.btn-default:hover { + color: #009fdb; + border-color: #009fdb; +} + +.modal-footer { + background-color: #f8f8f8; + border: none !important; +} + +.modal-header .modal-header-info { + border-top: solid 3px #009fdb; + margin-top: 10px; + margin-bottom: 0px; +} + +.modal-header .modal-header-error { + border-top: solid 3px #cf2a2a; + margin-top: 10px; + margin-bottom: 0px; +} + +.modal-header { + border: none !important; +} + +#problem { + padding: 5px; + position:absolute; + width: 100px; + height: 50px; + visibility: hidden; + border-radius: 10px; + background: rgba(238,238,238,0.9); + box-shadow: 4px 4px 50px rgba(0,0,0,1); + transition: .2s; + pointer-events: all; + transform-origin: top left; + font-size: 20px; + vertical-align: middle; + text-align: center; +} + + +#bottombar { + width: 100%; + position:fixed; + bottom:0px; + text-align: center; + transform: scale(.3); + opacity: 0; +} +#viewclasses { + z-index: 2; + display:inline-block; + text-align: center; + background: rgba(0,0,0,0.2); + padding: 4px; + padding-left: 10px; + border-radius: 4px; +} +.viewclass { + margin-right: 20px; + margin-left: 20px; + padding: 2px; + border: 1px solid rgba(50,50,50,0.5); + border-radius: 3px; +} +.viewclass:hover { + outline: 2px solid rgba(50,50,50,0.5); +} +.activeview { + background: rgba(125,125,125,0.9); +} + +.faded { + transition: 1s; + opacity: 0.15; +} + + +.asc_nodes_Router_CPE { + fill: #cbb; +} + +.asc_nodes_Link_CPE_CPE_site2site { + fill: #bcb; +} + +.asc_nodes_Feature_Data_Gamma_Link_Data { + fill: #bbc; +} + + +.asc_nodes_Feature_Firewall { + fill: green; +} + +.asc_nodes_Feature_Switch { + fill: green; +} + +.asc_nodes_Feature_Link { + fill: green; +} + +.asc_nodes_Feature_ { + fill: @asc_nodes_Feature_ +} + +.asc_nodes_Router_Gateway_Internet { + fill: #ccb; +} + +.asc_nodes_Link_CPE_Gateway_mis { + fill: #bcc; +} + +.asc_nodes_NOD { + fill: #bcc; +} +.asc_nodes_VPN { + fill: #cbc; +} +.asc_nodes_Site { + fill: #bcb; +} + +.asc_nodes_VIG { + fill: #cbb; +} +.asc_nodes_AppServer { + fill: #bbc; +} + +.fabulous { + stroke: rgba(0,255,0,0.5); + stroke-width: 10px; +} + +.dragpart { + font-size: 30px; + position: absolute; +} + +.highlight { + fill: #44c8f5; + background-color: #f2f2f2; +} +#editNodeProperties { + padding: 5px; + position:absolute; + z-index:10; + width: 500px; + visibility: hidden; + border-radius: 5px; + background: rgba(238,238,238,0.9); + box-shadow: 4px 4px 50px rgba(0,0,0,1); + transition: .2s; + pointer-events: all; + transform-origin: top left; + transform: scale(.001); + border-radius: 3px; + vertical-align:middle; +} +#editNodePropertiesHeaderBoard { + position:relative; + background-color:FloralWhite; + border-radius:10px; + margin-bottom:5px; +} +#editNodePropertiesHeader { + display:inline-block; + width:90%; + text-align:center; + font-size:125%; + margin-left:15px; +} +.editNodePropertyLabel { + display:inline-block; + width:35%; + text-align:right; + margin-right:0.5em; +} +.editNodePropertyValue { + display:inline-block; + width:60%; + text-align:left; +} +.editNodePolicyLabel { + display:inline-block; + width:50%; + text-align:right; + margin-right:0.5em; +} +.editNodePolicyValue { + display:inline-block; + width:45%; + text-align:left; +} +.rule-editor-btn { + cursor: pointer; + width: auto; + font-size: 16px; + margin-left: 2px; + color: #999999; +} +.rule-editor-btn:hover { + color: #009fdb; +} +.rule-editor-modal .modal-header { + position: absolute; + border-bottom: none; + width: 100%; +} + +@keyframes pulse-info { + 0% { + -moz-box-shadow: 0 0 0 0 rgba(104, 198, 233, 0.9); + box-shadow: 0 0 0 0 rgba(104, 198, 233, 0.9); + } + 70% { + -moz-box-shadow: 0 0 0 10px rgba(104, 198, 233, 0); + box-shadow: 0 0 0 10px rgba(104, 198, 233, 0); + } + 100% { + -moz-box-shadow: 0 0 0 0 rgba(104, 198, 233, 0); + box-shadow: 0 0 0 0 rgba(104, 198, 233, 0); + } +} + +.pulse-info { + animation: pulse-info 1.5s infinite; +} + +.mandatory { + font-size: 34px; + position: absolute; + color: red; +} \ No newline at end of file diff --git a/app/comp-fe/composition.js b/app/comp-fe/composition.js new file mode 100644 index 0000000..be03f5d --- /dev/null +++ b/app/comp-fe/composition.js @@ -0,0 +1,3004 @@ +(function () { + /** + * workaround to register events only once + * and get just the inner-event + */ + var eventMap = {}; + window.addEventListener('message', function (event) { + var innerEvent = event.data; + var handler = eventMap[innerEvent.type]; + if (handler instanceof Function) { + handler(innerEvent.data); + } + }); + + /** + * Use this function to register to post message events + */ + window.registerPostMessageEvent = function (type, handler) { + eventMap[type] = handler; + }; +})(); + +function alertNoFlowTypeSelected() { + $('#selected-type-mt') + .addClass('pulse-info') + .on('change', function (event) { + $(event.target).removeClass('pulse-info'); + }) + alertError('Please select the flow type to continue'); +} + +var CompositionEditor = function () { + var componentId = document + .getElementById('iframe') + .getAttribute('componentid'); + var userId = document + .getElementById('iframe') + .getAttribute('user_id'); + var readOnlyComponent = document + .getElementById('iframe') + .getAttribute('readOnlyComponent'); + var curcomp = { + cid: null, + //1806 US374595 save flow type in cdump + flowType: null, + version: 0, + nodes: [], + relations: [], + inputs: [], + outputs: [] + }; + window.d3Data = curcomp; + curcomp.cid = componentId; + this.curcomp = curcomp; + + var flowTypes = window.flowTypes; + var typeSelect = document.getElementById("selected-type-mt"); + + if (flowTypes.length > 0) { + flowTypes + .forEach(function (flowType) { + var myOption = document.createElement("option"); + myOption.text = flowType; + myOption.value = flowType; + typeSelect.add(myOption); + }); + } + + typeSelect + .addEventListener("change", function () { + curcomp.flowType = typeSelect.value; + }); + + document + .getElementById("savebtn") + .setAttribute("data-tests-id", "SaveButton"); + document + .getElementById("savebtn") + .setAttribute("disabled", "true"); + document + .getElementById("savebtn") + .setAttribute("style", "opacity:0.5"); + + if (readOnlyComponent == 'true') { + var componentUser = document + .getElementById('iframe') + .getAttribute('componentUser'); + alertError("The resource is already checked out by user: " + componentUser); + } else { + document + .getElementById("savebtn") + .removeAttribute("disabled"); + document + .getElementById("savebtn") + .setAttribute("style", "opacity:1"); + } + + document + .getElementById("savebtn") + .addEventListener("click", function () { + var mt = $('#selected-type-mt').val(); + if (!mt) { + alertNoFlowTypeSelected(); + return; + } + compController.saveComposition(curcomp); + }); + + var vfni = document + .getElementById('iframe') + .getAttribute('vnfiname'); + + // document.getElementById("submitbtn").setAttribute("data-tests-id", + // "SubmitButton"); if (!(vfni !== null && vfni !== "") || readOnlyComponent == + // 'true') { // + // document.getElementById("submitbtn").setAttribute("disabled", "true"); // + // document.getElementById("submitbtn").setAttribute("style", "opacity:0.5"); } + // else { document.getElementById("submitbtn").addEventListener("click", + // function () { var mt = $('#selected-type-mt').val(); if (mt + // == null) { alertNoFlowTypeSelected(); return; } + // console.log('entered submitbtn eventlistener'); var component_Id = + // document.getElementById('iframe').getAttribute('componentid'); var + // serviceuuid = document.getElementById('iframe').getAttribute('serviceuuid'); + // var vnfiname = + // document.getElementById('iframe').getAttribute('vnfiname'); + // compController.createBlueprint(component_Id, serviceuuid, vnfiname, mt); }); + // //console.log(x); } + + function log(x, y) { + var args = ["composition:"].concat(Array.prototype.slice.call(arguments, 0)); + console + .log + .apply(console, args); + } + + function simulateclick(x, y, target) { + target = target || document.body; + var e = document.createEvent("MouseEvent"); + e.initMouseEvent("click", true, true, window, 1, 0, 0, x, y, false, false, false, false, 0, null); + target.dispatchEvent(e); + } + + function addcss(id, text) { + var head = document.getElementsByTagName("head")[0]; + var style = document.createElement("style"); + style.id = id; + style.type = "text/css"; + style.innerHTML = text; + + // if style with this id exists, remove it + try { + var styles = head.getElementsByTagName("style"); + if (styles) + _.each(styles, function (x) { + if (x.id == id) + head.removeChild(x); + } + ); + } + catch (e) { + log(e); + } + head.appendChild(style); + return style; + } + + function parentmsg(s) { + return parent.postMessage(s, '*'); + } + + var msgid = 0; + + function basemsg(action) { + return { + "action": action, + "channelID": "ice-to-cart", + "id": msgid++, + "timestamp": new Date() + }; + } + + function uuid() { + function s4() { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1); + } + + return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4(); + } + + function parsequery(s) { + s = s.substring(s.indexOf('?') + 1).split('&'); + var params = {}, + pair; + // march and parse + for (var i = s.length - 1; i >= 0; i--) { + pair = s[i].split('='); + params[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]); + } + return params; + } + + var cid = "NULL"; + + function getCompositionError(error) { + console.error("unable to get composition: %o", error); + } + + function init(cid) { + log("init"); + cid = cid || uuid(); + log("cid", cid); + curcomp.cid = cid; + console.log("get composition is called "); + $ + .get(window.configOptions.backend_url + "getComposition/" + cid) + .then(function (resData) { + if (resData && resData.successResponse) { + try { + var composition = JSON.parse(resData.successResponse); + composition.cid = cid; + onCompositionEvent("initend"); + restoregraph(composition); + } catch (error) { + getCompositionError(error); + } + } else { + document.dispatchEvent(new CustomEvent('noComposition')); + } + }) + .fail(getCompositionError); + + deletebutton(); + } + + function deletebutton() { + d3 + .select("#compositiondiv") + .append("div") + .style("position", "absolute") + .style("bottom", "30px") + .style("right", "5px") + .style("background", "rgba(255,0,0,0.3)") + .html("toggle node deletion") + .on("click", function (d) { + if (d3.selectAll(".deletenode").style("visibility") == "hidden") + d3.selectAll(".deletenode").style("visibility", "visible"); + else + d3 + .selectAll(".deletenode") + .style("visibility", "hidden"); + } + ); + } + + function getcdump(cid) { + var pe = svg.style("pointer-events"); + + log("suspend pointer-events"); + svg.style("pointer-events", "none"); + + // fallback in case xhrget doesn't reset svg pointer events + setTimeout(function () { + if (svg.style("pointer-events") != pe) { + log("restore pointer-events fallback"); + svg.style("pointer-events", pe); + } + }, 2000); + + return new Promise(function (resolve, reject) { + xhrget("/cdump?cid=" + cid, function (resp) { + log("restore pointer-events"); + if (svg.style("pointer-events") != "none") // assert? + log("wtf pointer-events"); + svg.style("pointer-events", pe); + try { + resolve(JSON.parse(resp)); + } catch (e) { + reject({"exception": e, "response": resp}); + } + }); + }); + } + + function compositionreadonly(val) { + if (val == undefined) + val = true; + if (val) + svg.style("pointer-events", "none"); + else + svg.style("pointer-events", "all"); + return svg.style("pointer-events"); + } + + function restoregraph(c) { + if (!c.nodes) + return; + + curcomp.cid = c.cid; + rc = c; + + c + .nodes + .forEach(function (n) { + addnode(n, 0, 0, n.ndata); + }); + c + .relations + .forEach(function (r) { + var m = r.meta; + addlink(m.n1, m.n2, m.p1, m.p2, true); + }); + sortinterfaces(); // HACK + //1806 US374595 flowType saved to cdump + if (c.flowType && _.contains(flowTypes, c.flowType)) { + typeSelect.value = c.flowType; + curcomp.flowType = typeSelect.value; + } else { + console.log(c.flowType + " not in flowTypes DDL") + } + } + + function postcompimg() { + log("postcompimg"); + /*xhrpostraw("/compimg?cid="+cid, serialsvg(), + function(resp) { log("compimg", resp); }, + "image/svg");*/ + } + + function commitcomposition(callback) { + console.log("commitcomposition"); + /*xhrpost("/composition.commit?cid="+cid, {}, + function(resp) { + callback(resp); + });*/ + } + + function jsonparse(x) { + try { + return JSON.parse(x); + } catch (e) { + log("jsonparse", x, e); + throw e; + } + } + + function template(id, fn) { + /*xhrget("/template?" + id, function(resp) { + var tp = JSON.parse(resp); + if (! tp.nodes) { + log("template:oops", tp); + fn(null); + } + var nn = tp.nodes.length; + if (nn == 0) + fn(tp); + else { + tp.nodes.map(function(n) { + if (n.id == 0) { // dummy node special case + if (--nn == 0) + fn(tp); + } else { + xhrget("/type?" + n.type.name, function(resp) { + var ti = JSON.parse(resp); + n.typeinfo = ti; + if (--nn == 0) + fn(tp); + }); + } + }); + } + });*/ + } + + function template0(id, fn) { + /*xhrget("/template?" + id, function(resp) { + var tp = JSON.parse(resp); + fn(tp); + });*/ + } + + function addtemplate(id) { + template(id, addcomp); + } + + function addproduct(prod, x, y) { + log("addproduct", prod); + if (prod.offer) { + clearComposition(); + } + catalogitem(prod.uuid, function (p) { + log("addproduct p", p); + + // HACK -- this can't be right + log("HACK node.id", prod.uuid); + p + .model + .nodes + .forEach(function (n) { + n.id = prod.uuid; + }); + + if (p.models && p.models.length > 0) { + // addcomp + p + .models + .map(function (w) { + dropdata(w, x || bw / 2, y || bh / 2); + }); + } + onCompositionEvent("added.product.to.composition", prod); + }); + } + + function setnodeproperties(nid, properties) { + /*xhrpost("/composition.setnodeproperties?cid="+cid, {"nid":nid, "properties":_.clone(properties)}, + function(resp) { + });*/ + } + + function setnodepolicies(nid, policies) { + /*xhrpost("/composition.setnodepolicies?cid="+cid, {"nid":nid, "policies":_.clone(policies)}, + function(resp) { + });*/ + } + + function deepclone(x) { + return JSON.parse(JSON.stringify(x)); + } + + var gensym = (function () { + var n = 0; + return function (x) { + var t = new Date().getTime(); + return (x || "g") + "." + t + "." + n++; + }; + })(); + + var xhrprefix = configOptions.backend_url; + + function xhrgetBE(url, callback) { + var req = new XMLHttpRequest; + if (!(url.startsWith("https://") || url.startsWith("http://"))) + url = xhrprefix + url; + req.open("GET", url, true); // asynchronous request + req.onreadystatechange = function (x) { + if (req.readyState === 4) + callback(req.responseText); + }; + req.send(null); + } + + function xhrget(url, callback) { + var req = new XMLHttpRequest; + if (!(url.startsWith("https://") || url.startsWith("http://"))) + url = xhrprefix + url; + req.open("GET", url, true); // asynchronous request + req.onreadystatechange = function (x) { + if (req.readyState === 4) + callback(req.responseText); + }; + req.send(null); + } + + function xhrgetsync(url, callback) { + var req = new XMLHttpRequest; + if (!(url.startsWith("https://") || url.startsWith("http://"))) + url = xhrprefix + url; + req.open("GET", url, false); + req.onreadystatechange = function (x) { + if (req.readyState === 4) + callback(req.responseText); + }; + req.send(null); + } + + callback = function (responseText) { + // write your own handler here. + console.log('result from http://localhost:8446/saveComposition/ac297d4d-0199-458f-99ff-2a6ff6' + + 'ed849a \n' + responseText); + }; + + /** + * Callback function of AJAX request if the request fails. + */ + failCallback = function () { + // write your own failure handler here. + console.log('AJAXRequest failure!'); + }; + + var apiService = new ApiService(xhrprefix, userId); + var compController = new CompController(apiService); + + function xhrpost(url, obj, callback, type, async) { + var req = new XMLHttpRequest; + if (!(url.startsWith("https://") || url.startsWith("http://"))) + url = xhrprefix + url; + req.open("POST", url, true); // asynchronous request + req.setRequestHeader("Content-Type", type || "application/json;charset=UTF-8"); + req.setRequestHeader('USER_ID', userId); + + req.onreadystatechange = function (x) { + if (req.readyState === 4) + callback(req.responseText); + }; + try { + req.send(JSON.stringify(obj)); + } catch (e) { + if (e.name == "TypeError") + req.send(JSON.stringify(obj)); + else + throw(e); + } + } + + function xhrpostraw(url, obj, callback, type) { + var req = new XMLHttpRequest; + if (!(url.startsWith("https://") || url.startsWith("http://"))) + url = xhrprefix + url; + req.open("POST", url, true); + req.setRequestHeader("Content-Type", type || "text/plain"); + req.setRequestHeader('USER_ID', userId); + + req.onreadystatechange = function (x) { + if (req.readyState === 4) + callback(req.responseText); + }; + req.send(obj); + } + + var bw = document + .getElementById("compositioncontainer") + .clientWidth; + var bh = document + .getElementById("compositioncontainer") + .clientHeight; + + // initially setting linkdistance to smaller value will help layout sort out + // edge crossings + var force = d3 + .layout + .force() + .gravity(.9) + .charge(-3000) + .linkDistance(500) + .linkStrength(1) + .size([bw, bh]); + + setTimeout(function () { + init(componentId); + }); + + function unfix() { + force + .nodes() + .forEach(function (n) { + n.fixed = false; + }); + } + + function fix() { + force + .nodes() + .forEach(function (n) { + n.fixed = true; + }); + } + + function resize() { + bw = document + .getElementById("compositioncontainer") + .clientWidth; + bh = document + .getElementById("compositioncontainer") + .clientHeight; + svg + .attr("width", bw) + .attr("height", bh); + force.size([ + bw - 30, + bh - 30 + ]); + force.start(); + } + + var rev = 0; + + var svg = d3 + .select("#compositioncontainer") + .append("svg:svg") + .style("overflow", "visible") + .attr("width", bw) + .attr("height", bh); + + var undergraph = svg.append("svg:g"); + var graph = svg.append("svg:g"); + var edgegroup = graph.append("svg:g"); + + function bbox(sel) { // arg is d3 svg selection + return sel[0][0].getBBox(); + } + + function clamp(d) { + var pad = 120; // HACK + var x1 = pad, + y1 = pad, + x2 = bw - pad, + y2 = bh - pad; + if (d.x < x1) + d.x = x1; + if (d.y < y1) + d.y = y1; + if (d.x > x2) + d.x = x2; + if (d.y > y2) + d.y = y2; + return d; + } + + function circleclamp(d) { + var p2 = 2 * Math.PI; + if (d.a < 0) + d.a += p2; + if (d.a > p2) + d.a -= p2; + return d; + } + + function tick() { + if (force.alpha() < .05) // chill + force.alpha(0); + graph + .selectAll(".node") + .attr("transform", function (d) { + clamp(d); + + // (d.x > 350) { d.x = 350; } break; + // case 2: if (d.x < bw - 350) { d.x = bw - 350; + // } break; } } HACK for vLAN nodes in uCPE + var modelName = d + .model + .name + .toUpperCase() + .replace(/-/g, " "); + if (modelName.match(/\bVPN\sFACING\b/) || modelName.match(/\bINTERNET\sFACING\b/)) { + if (d.y > 130) + d.y = 130; + } + else if (modelName.match(/\bLAN\sFACING\b/)) { + if (d.y < bh - 130) + d.y = bh - 130; + } + else if (modelName.match(/\bNM\sVLAN\b/)) { + if (d.x < bw - 150) + d.x = bw - 150; + } + else if (modelName.match(/\bOAM\sVLAN\b/)) { + if (d.x > 150) + d.x = 150; + } + // END TODO + + return "translate(" + d.x + "," + d.y + ")"; + }); + d3 + .selectAll(".relation") + .attr("d", epath); + d3 + .selectAll(".nodeport") + .attr("transform", function (d) { + circleclamp(d); + if (d.link) { + if (d.link.srcport == d) + n1 = d.link.source, + n2 = d.link.target; + else + n1 = d.link.target, + n2 = d.link.source; + var p1 = { + x: n1.x, + y: n1.y + }, + p2 = { + x: n2.x, + y: n2.y + }; + var dx = n2.x - n1.x, + dy = n2.y - n1.y; + d.a = Math.atan2(dx, dy); + circleclamp(d); + var p = nodeboundarypoint(p1, p2, d.parent.name); + d.x = p.x - d.parent.x; + d.y = p.y - d.parent.y; + } else { + if (d.parent.ports.length > 1) { + d + .parent + .ports + .forEach(function (x) { + if (d != x && Math.abs(x.a - d.a) < 0.8) { + d.a += x.a > d.a + ? -.02 + : .02; + } + }); + } + var p1 = { + x: d.parent.x, + y: d.parent.y + }, + p2 = { + x: d.parent.x + 100 * Math.sin(d.a), + y: d.parent.y + 100 * Math.cos(d.a) + }; + var p = nodeboundarypoint(p1, p2, d.parent.name); + d.x = p.x - d.parent.x; + d.y = p.y - d.parent.y; + } + return "translate(" + d.x + "," + d.y + ")"; + }); + } + + force.on("tick", tick); + + // p1 inside, p2 outside + function nodeboundarypoint(p1, p2, nodename) { + if ((Math.abs(p1.x - p2.x) + Math.abs(p1.y - p2.y)) < 0.2) { + return p1; + } + if (typeof document.elementsFromPoint === 'function') { + var mp = { + x: (p1.x + p2.x) / 2, + y: (p1.y + p2.y) / 2 + }; + var r = svg + .node() + .getBoundingClientRect(); + var n = document + .elementsFromPoint(mp.x + r.left, mp.y + r.top) + .find(function (x) { + var d = d3 + .select(x) + .datum(); + return d3 + .select(x) + .classed("nodebody") && d && d.name == nodename; + }); + if (n) + p1 = mp; + else + p2 = mp; + return nodeboundarypoint(p1, p2, nodename); + } + // ... here when no function document.elementsFromPoint (FF <46) ... -- put on + // circle + var r = 30; + var dx = p2.x - p1.x, + dy = p2.y - p1.y; + if (!dx) { + if (r < Math.abs(dy)) { + p1.y += r * Math.sign(dy); + } else { + p1.y += dy; + } + return p1; + } + + alpha = Math.atan2(dx, dy); + p1.x += r * Math.sin(alpha); + p1.y += r * Math.cos(alpha); + return p1; + } + + var hitrect = svg + .node() + .createSVGRect(); + hitrect.height = 1; + hitrect.width = 1; + + // ffs, chrome's svg.getIntersectionList uses bbox for intersection + function nodeboundarypoint0(p1, p2, node) { + if ((Math.abs(p1.x - p2.x) + Math.abs(p1.y - p2.y)) < 0.5) + return p1; + else { + var n, + mp = { + x: (p1.x + p2.x) / 2, + y: (p1.y + p2.y) / 2 + }; + hitrect.x = mp.x; + hitrect.y = mp.y; + var hits = svg + .node() + .getIntersectionList(hitrect, null); + if (hits) { + function itol(x) { + var v, + r = [], + i = 0; + while (v = x.item(i++)) + r.push(v); + return r; + } + + hits = itol(hits); + n = hits.find(function (x) { + var d = d3 + .select(x) + .datum(); + return d3 + .select(x) + .classed("nodebody") && d && d.name == node; + }); + } + if (n) + p1 = mp; + else + p2 = mp; + return nodeboundarypoint0(p1, p2, node); + } + } + + function abs(n) { + return n < 0 + ? -n + : n; + } + + function rand(n) { + n = n || 1.0; + return (Math.random() * n) - n / 2; + } + + function elt(selection) { + return selection[0][0]; + } + + function nameof(x) { + return x + ? x.name + : "..."; + } + + function dnode(name) { + return force + .nodes() + .find(function (n) { + return n.model.name === name; + }); + } + + function dlink(name) { + return force + .links() + .filter(function (l) { + return l.source.model.name === name || l.target.model.name === name; + }); + } + + function matchnodetype(n, tname) { + return ((n.type.name === tname) || (n.typeinfo && n.typeinfo.hierarchy && n.typeinfo.hierarchy.find(function (t) { + return t.name === tname; + }))); + } + + // "transactions" for composition operations + var logtxn = false; + var incompositiontxn = false; + + function txn(name, fn) { + if (incompositiontxn) // already in transaction + return fn(); + else { + try { + if (logtxn) + log("TXN.begin", name); + incompositiontxn = true; + return fn(); + } finally { + incompositiontxn = false; + if (logtxn) + log("TXN.end", name); + onCompositionEvent("composition.done"); + } + } + } + + function addnode(model, x, y, ndata) { + return txn("addnode", function () { + return _addnode(model, x, y, ndata); + }); + } + + function _addnode(model, x, y, ndata) { + var hasdata = !!ndata; + + curmodel = model; + + if (!ndata) { + ndata = { + name: gensym("n"), + label: model.name, + x: x, + y: y, + px: x - 1, + py: y - 1, + ports: [], + radius: 30 + }; + + if (matchnodetype(model, "tosca.nodes.network.Port")) + ndata.radius = 10; + + if (model.name === "CPE") + ndata.radius = 80; + } + + //log("node", model.name, ndata.x, ndata.y, ndata.fixed); + + ndata.x = ndata.x || bw / 2 + rand(100); + ndata.y = ndata.y || bh / 2 + rand(100); + ndata.px = ndata.x - 1; + ndata.py = ndata.y - 1; + + ndata.ports = ndata.ports || []; + ndata.label = model.name; + + model = _.clone(model); + model.nid = ndata.name; + + var node = _.extend({}, model, {ndata: ndata}); + curcomp + .nodes + .push(deepclone(node)); + + if (!hasdata) { + /*xhrpost("/composition.addnode?cid="+cid, node, + function(resp) { + }); + + xhrpost("/composition.savecomp?cid="+cid, curcomp, + function(resp) { + });*/ + + onCompositionEvent("composition.add.node", model); + } + ndata.model = model; + + force + .nodes() + .push(ndata); + var nodes = force.nodes(); + + var gnode = graph + .selectAll(".node") + .data(nodes, function (d) { + return d.name; + }); + + var n = gnode + .enter() + .append("g") + .attr("id", model.nid.replace(/\W/g, "_")) + // this must come first, because ?? .attr("class", "node draggable") + .classed("node", true) + .classed("draggable", true) + .attr("draggable", "true") + .classed(model.type.name.replace(/\W/g, "_"), true) + .attr("transform", function (d) { + if (!d.x || isNaN(d.x)) + d.x = bw / 2 + rand(100); + if (!d.y || isNaN(d.y)) + d.y = bh / 2 + rand(100); + return "translate(" + d.x + "," + d.y + ")"; + }) + .on("click", function (d) { + if (d3.event.metaKey || d3.event.ctrlKey) + removenode(d); + } + ); + + rendernode(n); + + n.call(force.drag().on("dragstart", function (d) { + d3 + .select(this) + .classed("fixed", d.fixed = true); + })); + + function rti(n, name) { + return n + .typeinfo + .requirements + .find(function (tr) { + return tr.name === r.name; + }) + } + + if (!model.typeinfo) + model.typeinfo = {}; // dummy node special case + + if (model.requirements) { + model.requirements = dedup(model.requirements); + model + .requirements + .forEach(function (x) { + if (x.name == "host") // CCD hack + return; + ndata + .ports + .push({ + name: x.name, + parent: ndata, + ptype: "req", + id: uuid(), + portinfo: _.clone(x) + }); + }); + + model + .requirements + .forEach(function (r) { + r.ti = model + .typeinfo + .requirements + .find(function (tr) { + return tr.name == r.name; + }); + }); + } + // this may become uneccessary(?) (serban: type info now merged with + // requirements/capabilities) + if (model.typeinfo.requirements) { + model.typeinfo.requirements = dedup(model.typeinfo.requirements); + model + .typeinfo + .requirements + .forEach(function (x) { + var port = ndata + .ports + .find(function (y) { + return y.name == x.name && y.ptype == "req"; + }); + if (port) + port.portinfo = _.extend(_.clone(x), port.portinfo); // this should never happen + else { + if (x.name == "host") // CCD hack + return; + log("UNEXPECTED TYPEINFO", x.name); + } + }); + } + + if (model.capabilities) { + model.capabilities = dedup(model.capabilities); + model + .capabilities + .forEach(function (x) { + ndata + .ports + .push({ + name: x.name, + parent: ndata, + ptype: "cap", + id: uuid(), + portinfo: _.clone(x) + }); + }); + + model + .capabilities + .forEach(function (c) { + c.ti = model + .typeinfo + .capabilities + .find(function (tc) { + return tc.name == c.name; + }); + }); + } + + if (model.typeinfo.capabilities) { + model.typeinfo.capabilities = dedup(model.typeinfo.capabilities); + model + .typeinfo + .capabilities + .forEach(function (x) { + var port = ndata + .ports + .find(function (y) { + return y.name == x.name && y.ptype == "cap"; + }); + if (port) + port.portinfo = _.extend(_.clone(x), port.portinfo); // this should never happen + else { + log("UNEXPECTED TYPEINFO", x.name); + } + }); + } + addports(n); + + force.start(); + + return ndata; + } + + // pin lans and wans in lexicographic order + function sortinterfaces() { + // var rx = [/^WAN/, /^LAN/]; for (var i in rx) { var x = 200; + // d3.selectAll(".node") .filter(function (d) { return + // d.label.match(rx[i]); }) .sort(function (a, b) { return + // a.label > b.label; }) .each(function (d) { d.x = d.px = x; + // x += 100; d.fixed = true; }); } + } + + var _nd = []; + + function updatenodes() { + var nd = force + .nodes() + .map(function (d) { + var f = { + nid: d.name, + x: d.x, + y: d.y, + px: d.px, + py: d.py, + radius: d.radius, + fixed: true + }; + f.ndata = _.clone(f); + f.ndata.name = d.name; + return f; + }); + + // only consider x,y values in computing sameness + function same(a, b) { + return a.every(function (c) { + return b.some(function (d) { + return c.x == d.x && c.y == d.y; + }); + }); + } + + if (!same(nd, _nd)) { + log("updatenodes...changed"); + onCompositionEvent("after.loaded.composition"); + } else { + log("updatenodes...stable"); + } + _nd = nd; + } + + force.on("end", updatenodes); + + function pp(x) { + return JSON.stringify(x, null, 2); + } + + function str(x) { + return JSON.stringify(x); + } + + function dedup(a) { + var r = []; + a.forEach(function (x) { + if (!r.find(function (y) { + return x.name == y.name; + })) + r.push(x) + }); + return r; + } + + function addport(n, name, ptype, portinfo) { + n + .each(function (d) { + d + .ports + .push({ + name: name || gensym(), + parent: d, + ptype: ptype, + portinfo: portinfo, + id: uuid() + }); + }); + addports(n); + } + + var iconbase = "/images/ice/"; + iconbase = "/img/"; + + var icons = {}; + + function ngon(node, n, offset) { + offset = offset || 0; + //var offset = n == 4 ? Math.PI/4 : 0; + var r = node + .datum() + .radius * (1 + 1 / n), + p = []; + for (var i = 0; i < n; i++) { + // offset is so squares are squared :/ + var a = (i * Math.PI * 2) / n + offset; + p.push(r * Math.sin(a)); + p.push(r * Math.cos(a)); + } + return node + .append("svg:polygon") + .classed("nodebody", true) + .attr("points", p.join(",")); + } + + var compositionDraggingType; + + function allowDropByType(event, type) { + if (compositionDraggingType === type) { + event.preventDefault(); + event.dataTransfer.dropEffect = 'copy'; + return true; + } + return false; + } + + /* DEAD CODE? + // handle dropping location data on a node + function dropLocation(event,that) { + compositionDraggingType = null; + var locText = event.dataTransfer.getData('location'); + if (locText === '') {return;} + if (event.stopPropagation) {event.stopPropagation();} + + var nodeData = d3.select(that).datum(); + log("dropLocation",locText,nodeData); + + var loc = shoppingCart.locations.findByKey(Location.genKey(JSON.parse(locText))); + log("dropLocation loc",loc); + closeNodePropertiesEditor(); + setLocationOnSite(nodeData.model,loc); + d3.select(that).select("#confignode").html(function(d) {return getShortPropertyValues(d.model);}); + } + */ + + // var getShortPropertyValues = getShortPropertyValues || function(x) { return + // "{property values}" }; + var getShortPropertyValues = getShortPropertyValues || function (x) { + return "" + }; + + var cpe; + + function renderucpe() { + cpe = undergraph + .append("svg:rect") + .classed("ucpecontainer", true) + .attr("width", bw - 200) + .attr("height", bh - 100) + .attr("x", 100) + .attr("y", 50) + .attr("rx", 20) + .attr("ry", 20) + .attr("stroke", "black") + .attr("stroke-width", 5) + .attr("fill", "rgba(0,0,0,0.1)") + .style("opacity", 0.2); + } + + function rendernode(n) { + var type = n + .datum() + .model + .type + .name; + var model = n + .datum() + .model; + + // HACK + if (matchnodetype(n.datum().model, "tosca.nodes.network.Port")) { + ngon(n, 4); + return; + } + + n + .append("svg:rect") + .classed("nodebody", true) + /* + .attr("width", 70) + .attr("height", 44) + .attr("x", -35) + .attr("y", -22) + */ + .attr("width", 90) + .attr("height", 64) + .attr("x", -45) + .attr("y", -32) + .attr("rx", 5) + .attr("ry", 5); + + n.classed(type.replace(/\W/g, "_"), true); + n.classed(n.datum().model.name.replace(/\W/g, "_"), true); + + var w = 150, + h = 50; // node width, height + + // n.append("g") .attr("transform", "translate(" + (-(w / 2 - 15)) + "," + + // (-(h / 2 - 5)) + ")") .append("foreignObject") .attr({ width: + // 100, height: 50, fill: '#7413E8', 'class': + // 'svg-tooltip' }) .append('xhtml:div') .append('div') + // .html(function (d) { return squishnodename(d.label) }) .append("div") + // .attr({ width: 50, height: 50, fill: 'red', color: + // 'green' }) .style("pointer-events", "all") .style("cursor", + // "pointer") .html("config") .on("click", function (d) { if + // (d3.event.metaKey || d3.event.ctrlKey) { return; } if + // (typeof editNodeProperties === 'function') { editNodeProperties(this); } + // else { configeditor(d3.select(this), d.model); } }); + + n + .append("g") + .attr("transform", "translate(" + (-(w / 2 - 15)) + "," + (-(h / 2 - 5)) + ")") + .append("foreignObject") + .attr("width", (w - 10) + "px") + .attr("height", (h + 60) + "px") + .append("xhtml:div") + .classed("compositionbody", true) + //.classed(type.replace(/\./g,"_"), true) + .classed("nodetext", true) + .style("width", (w - 30) + "px") + .style("height", (h - 20) + "px") + .style("pointer-events", function () { + return (type == "asc.nodes.Site" + ? null + : "none"); + }) + .attr("ondragover", function () { + return (type == "asc.nodes.Site" + ? "allowDropByType(event,'location');" + : null); + }) + .attr("ondrop", function () { + return (type == "asc.nodes.Site" + ? "dropLocation(event,this);" + : null); + }) + .html(function (d) { + var icon = icons[d.model.type.name]; + if (!icon) { + if (d.model.typeinfo && d.model.typeinfo.hierarchy) { + var h = d.model.typeinfo.hierarchy; + for (i in h) { + var type = h[i].name; + if (icon = icons[type]) + break; + } + } + } + if (icon) + icon = iconbase + icon; + else + icon = window.location.origin + iconbase + "3net.png"; + icon = "dcae/comp-fe/img/death.png"; + if (propertynameval(d.model.properties, "designer_name")) { + // return "" + "
" + + // "
" + propertynameval(d.model.properties, "designer_name") + + // "
"; + } else { + //return "" + "
" + + return "
" + + // "" + "
" + + "" + squishnodename(d.label) + "
"; + } + }) + // .append("span") .attr("id", "confignode") .attr("class", "confignode") + // .style("pointer-events", "all") .style("cursor", "pointer") .html(function(d) + // {return getShortPropertyValues(d.model);}) .html("config") .on("click", + // function (d) { if (d3.event.metaKey || d3.event.ctrlKey) { return; } + // if (typeof editNodeProperties === 'function') { editNodeProperties(this); + // } else { if ($('#selected-type-mt').val() == null) { + // alertNoFlowTypeSelected(); } else { var self = this; + // compController.saveComposition(curcomp) .then(function () { + // d.model.uniqeId = d.name; configeditor(d3.select(self), + // d.model); }); } } }); node delete button + var del = n + .append("g") + .classed("deletenode", true) + .attr("transform", "translate(0,-10)") + .style("visibility", "hidden"); + + del + .append("svg:ellipse") + .attr("rx", 10) + .attr("ry", 10) + .attr("fill", "red") + .attr("opacity", 0.7) + .on("click", function (d) { + if (d3.select(this).style("visibility") != "hidden") + removenode(d); + } + ); + + del + .append("svg:text") + .attr("dominant-baseline", "middle") + .attr("text-anchor", "middle") + .style("color", "black") + .style("pointer-events", "none") + .text(function (d) { + return "X"; + }) + + } + + var propertyeditor = propertyeditor || null; + + function propertynameval(props, name) { + var p = props && props.find(function (x) { + return x.name == name; + }); + return p && p.assignment + ? p.assignment.value + : null; + } + + function configeditor(selection, model) { + var x = selection[0][0] + var r = x.getBoundingClientRect(); + var e = document.getElementById("configeditor"); + var stuff = d3.select(e.children[0]); + + var cfg = d3 + .select("#configstuff") + .html("properties for " + model.name + ":"); + var props = cfg + .append("form") + .attr("id", "cfgform") + .style("display", "table") + .style("overflow-y", "auto") + .style("overflow-x", "hidden") + .style("padding-left", "10px") + .style("width", "100%"); + + mm = model; + model + .properties + .forEach(function (p) { + var row = props + .append("div") + .style("line-height", "25px") + .style("height", "45px") + .style("display", "table-row"); + + row + .append("label") + .style("display", "table-cell") + .html(p.name); + row + .append("input") + .style("display", "table-cell") + .style("width", "90%") + .attr("type", "text") + .attr("name", p.name) + .attr("value", function () { + return p.value && !_.isObject(p.value) + ? p.value + : null; + }); + + if (window.isRuleEditorActive) { + row + .append('span') + .attr({"class": "glyphicon glyphicon-cog rule-editor-btn"}) + .on('click', function () { + var self = this; + var reModel = $('#rule-editor-modal'); + openRuleEditor(); + + function openRuleEditor() { + var $propInput = $(self) + .parent() + .find('input'); + var flowType = $('#selected-type-mt').val(); + var data = { + vfcmtUuid: curcomp.cid, + nodeName: model.name, + nodeId: model.uniqeId, + fieldName: p.name, + userId: userId, + flowType: flowType + }; + window.registerPostMessageEvent('disable-loader', function () { + $('#modal-loader').hide(); + }); + window.registerPostMessageEvent('exit', function (jsonResult) { + reModel.modal('hide'); + if (jsonResult !== null) { + try { + JSON.parse(jsonResult); // verifing that jsonResult is a valid json + p.value = jsonResult; // updating model + $propInput.val(p.value); // updating view + } catch (err) { + alert('Internal Error: unable to parse rule-editor value'); + } + } + }); + reModel + .find('iframe') + .attr({ + src: window.ruleEditorUrl + '?' + $.param(data), + style: 'display: none' + }) + .load(function (event) { + $(event.target).attr({style: 'display: block'}); + }); + + reModel.modal({backdrop: 'static', keyboard: false}); + $('#modal-loader').show(); + } + }); + } + + }); + + d3 + .select("#configset") + .on("click", function () { + eatform(model); + }); + + props + .append("div") + .style("display", "table-column"); + props + .append("div") + .style("display", "table-column") + .style("width", "70%"); + + e.style.left = r.left; + e.style.top = r.top; + e.style.visibility = "visible"; + e.style.transform = "scale(1)"; + } + + function eatform(model) { + d3 + .select("#cfgform") + .selectAll("input") + .each(function () { + var i = d3.select(this), + name = i.attr("name"), + val = i.property("value"); + if (val) { + // debugger; + var p = model + .properties + .find(function (x) { + return x.name == name; + }); + p.value = val; + log("forminput", name, val); + } + curcomp + .nodes + .forEach(function (node) { + if (node.nid == model.uniqeId) { + var copy = model + .properties + .map(function (a) { + return Object.assign({}, a); + }); + node.properties = copy; + } + }); + }); + configclose(); + } + + function configclose(x) { + var e = document.getElementById("configeditor"); + e.style.transform = "scale(.001)"; + } + + function selectucpe() { + return graph + .select(".node") + .filter(function (d) { + return d.label === "ucpe"; + }); + } + + function removeucpe() { + selectucpe().each(removenode); + } + + function removenode(d) { + return txn("removenode", function () { + return _removenode(d); + }); + } + + function _removenode(d) { + curcomp.nodes = curcomp + .nodes + .filter(function (n) { + return n.nid != d.name; + }); + + console.log("before: ", curcomp.nodes); + + onCompositionEvent("composition.remove.node", {nid: d.name}); + + if (d.label === "ucpe") { + // cpe implementation is such a hack + cpe.remove(); + return; + } + + _ + .values(d.ports) + .map(function (x) { + if (x.link) + removelink(x.link); + } + ); + nodes = _.without(force.nodes(), d); + graph + .selectAll(".node") + .data(nodes, function (d) { + return d.name; + }) + .exit() + .remove(); + force + .nodes(nodes) + .start(); + + } + + function addports(n) { + var port = n + .selectAll(".nodeport") + .data(function (d) { + return d.ports; + }, function (p) { + return p.id; + }) + //.filter(function(d) { return d.name != "host"; }) + .enter(); + + var pg = port + .append("g") + .attr("class", "nodeport") + .attr("name", function (d) { + return d.name; + }) + .attr("transform", function (d) { + var pp = d.parent.ports; + d.a = rand() * Math.PI * 2; + d.x = d.parent.radius * Math.sin(d.a); + d.y = d.parent.radius * Math.cos(d.a); + return "translate(" + d.x + "," + d.y + ")"; + }); + + pg + .append("svg:circle") + .classed("targetcircle", true) + .attr("r", 5); + + var pc = pg + .append("svg:circle") + .attr("class", function (d) { + var rtype = "nuh"; + if (d.ptype === "cap") { + if (d.portinfo) { + if (d.portinfo.type) + rtype = d.portinfo.type.name; + if (d.portinfo.target) + rtype = d.portinfo.target.name; + } + else { + rtype = "null"; + } + } else { + try { + rtype = d.portinfo.capability.name; + } catch (e) { + log("oops", d, d.parent.model.name); + } + } + if (rtype.name) { + log("HACK rtype", rtype); + rtype = rtype.name; + } + if (rtype) + rtype = rtype.replace(/\W/g, "_"); + else + log("NULL RTYPE", d); + return (d.ptype == "cap" + ? "capabilityport" + : "requirementport") + " " + rtype; + }) + .classed("srcport", true) + .attr("r", 5) + .attr("port", function (d) { + return d.name; + }); + + pg + .append("svg:text") + .attr("class", "nodeporttext") + .attr("transform", "scale(.75)") + .attr("dominant-baseline", "middle") + .style("pointer-events", "none") + .text(function (d) { + return squishportname(d.name); + }); + + pc.on("click", function (d) { + log("pc.onclick", d); + var port = d3.select(this); + if (d3.selectAll(".tmprelation").empty()) + startedge(port, d); + else + targetclick(port, d); + } + ); + + pc.on("mouseenter", function (d) { + var self = d3.select(this); + var t = d3 + .select(self.node().parentNode) + .select("text"); + t.style("font-size", "15px"); + //t.style("stroke", "black"); + }); + pc.on("mouseleave", function (d) { + var self = d3.select(this); + var t = d3 + .select(self.node().parentNode) + .select("text"); + t.style("font-size", "12px"); + //t.style("font-size", "inherit"); t.style("stroke", "rgba(0,0,0,0.3)"); + }); + + pc.on("touchstart", function (d) { + d3 + .event + .preventDefault(); + var t = d3.event.touches[0], + x = t.clientX, + y = t.clientY; + var port = d3.select(this); + if (d3.selectAll(".tmprelation").empty()) { + force.stop(); + startedge(port, d); + } else { + force.resume(); + targetclick(port, d); + } + }); + + pg.classed("targetport", true); + + return pg; + } + + //hacks + function squishportname(s) { + return s + .replace(/_connection$/, "") + .replace(/_input$/, "") + .replace(/_output$/, "") + .replace(/network/, "net"); + } + + function squishnodename(s) { + return s + .replace(/network/, "net") + .replace(/_analytics$/, "") + .replace(/customer/, "cust"); + } + + function portclick(d) { + var port = d3.select(this); + if (d3.selectAll(".tmprelation").empty()) + startedge(port, d); + else + targetclick(port, d); + } + + function addlink(n1, n2, p1, p2, restoring) { + return txn("addlink", function () { + return _addlink(n1, n2, p1, p2, restoring); + }); + } + + function _addlink(n1, n2, p1, p2, restoring) { + var nodes = force.nodes(); + var links = force.links(); + //p1 = p1 || gensym(); p2 = p2 || gensym(); + + n1 = typeof n1 === "object" + ? n1 + : _.findWhere(nodes, {name: n1}); + n2 = typeof n2 === "object" + ? n2 + : _.findWhere(nodes, {name: n2}); + + if (!n1 || !n2) { + // hostedOn exceptional case log("addlink?", n1, n2, p1, p2); + return [n1, n2]; + } + + var sp, + tp; + try { + sp = n1 + .ports + .find(function (p) { + return p.name == p1 && (!p.link || !p.link.name); + }); + tp = n2 + .ports + .find(function (p) { + return p.name == p2 && (!p.link || !p.link.name); + }); + } catch (e) { + log(e, n1, n2); + } + + if (sp == null) { + // port is already linked, so we'll duplicate it (unless occurrences exceeded) + var xp = n1 + .ports + .find(function (p) { + return p.name == p1 + }); + sp = _.clone(xp); + sp.link = null; + sp.id = uuid(); + n1 + .ports + .push(sp); + addports(d3.selectAll(".node").filter(function (n) { + return n1.name == n.name; + })); + } + + if (tp == null) { + // port is already linked, so we'll duplicate it (unless occurrences exceeded) + var xp = n2 + .ports + .find(function (p) { + return p.name == p2 + }); + tp = _.clone(xp); + tp.link = null; + tp.id = uuid(); + n2 + .ports + .push(tp); + addports(d3.selectAll(".node").filter(function (n) { + return n2.name == n.name; + })); + } + + // if port allows multiple occurrences, duplicate it (weak test on occurrences + // is a hack) + + if (sp.portinfo.occurrences == null || sp.portinfo.occurrences[1] > 1) { + var nx = d3 + .selectAll(".node") + .filter(function (n) { + return n1.name == n.name; + }); + addport(nx, sp.name, sp.ptype, sp.portinfo); + } + + if (tp.portinfo.occurrences == null || tp.portinfo.occurrences[1] > 1) { + var nx = d3 + .selectAll(".node") + .filter(function (n) { + return n2.name == n.name; + }); + addport(nx, tp.name, tp.ptype, tp.portinfo); + } + + /* + // hack -- add port for relations with multiple occurrences + //log("addlink", sp.type, sp.name, tp.type, tp.name); + if (sp.ptype == "cap" && sp.name == "access_conn") { + var nx = d3.selectAll(".node").filter(function(n) { return n1.name == n.name; }); + addport (nx, "access_conn", "cap", sp.portinfo); + } + if (tp.ptype == "cap" && tp.name == "access_conn") { + var nx = d3.selectAll(".node").filter(function(n) { return n2.name == n.name; }); + addport (nx, "access_conn", "cap", tp.portinfo); + } + */ + + var link = { + name: gensym("lnk"), + source: n1, + target: n2, + srcport: sp, + targetport: tp, + pending: true + }; + + sp.link = link; + tp.link = link; + + links.push(link); + + var ln = edgegroup + .selectAll(".relation") + .data(links, function (d) { + return d.name; + }); + ln + .enter() + .insert("svg:path") + .classed("relation", true) + .classed("pending", true) + .attr("d", epath) + .on("click", function (d) { + if (d3.event.metaKey || d3.event.ctrlKey) + removelink(d); + } + ); + ln + .exit() + .remove(); + + setTimeout(function () { + edgegroup + .selectAll(".pending") + .classed("pending", false) + .each(function (d) { + d.pending = false; + }); + }, 1000); + + var meta = { + n1: n1.name, + n2: n2.name, + p1: p1, + p2: p2 + }; + + function findrelationship(n, p) { + var r = n.typeinfo.requirements && n + .typeinfo + .requirements + .find(function (x) { + return x.name == p; + }); + return r && r.relationship && [n.name, r.relationship.name, r.name]; + } + + meta.relationship = findrelationship(n1.model, p1) || findrelationship(n2.model, p2); + + var relation = { + rid: link.name, + n1: n1.name, + name1: n1.model.name, + n2: n2.name, + name2: n2.model.name, + meta: meta + }; + curcomp + .relations + .push(deepclone(relation)); + + if (!restoring) { + /*xhrpost("/composition.addrelation?cid="+cid, relation, + function(resp) { + }); + + xhrpost("/composition.savecomp?cid="+cid, curcomp, + function(resp) { + });*/ + + } + + force.start(); + + return link; + } + + function removelink(d) { + return txn("removelink", function () { + return _removelink(d); + }); + } + + function removelink(d) { + /*xhrpost("/composition.deleterelation?cid="+cid, {rid: d.name}, + function(resp) { + });*/ + + curcomp.relations = curcomp + .relations + .filter(function (r) { + r.rid != d.name + }); + /*xhrpost("/composition.savecomp?cid="+cid, curcomp, + function(resp) { + });*/ + + var links = _.without(force.links(), d); + edgegroup + .selectAll(".relation") + .data(links, function (d) { + return d.name; + }) + .exit() + .remove(); + force + .links(links) + .start(); + d.srcport.link = null; + d.targetport.link = null; + } + + var srcport = false; + + function startedge(port, d) { + log("startedge", d); + d = port.datum(); // ?? + var type, + rtype; + try { + if (d.ptype == "cap") { + rtype = d.portinfo.type.name; + type = "requirementport"; + } else { + rtype = d.portinfo.capability.name; + //rtype = d.portinfo.target.name; // MAYBE?? + type = "capabilityport"; + } + } catch (e) { + log("startedge-error", e, d); + } + if (rtype.name) { + log("HACK rtype", rtype); + rtype = rtype.name; + } + if (rtype) + rtype = rtype.replace(/\./g, "_"); + else + log("NULL RTYPE"); + d3 + .selectAll("." + rtype + "." + type) + .filter(function (c) { + return c.parent != d.parent; + }) // same node + .filter(function (c) { + return !c.link; + }) // already linked + .classed("fabulous", true); + + var mx = port[0][0].getScreenCTM(); + x = mx.e; + y = mx.f; + + srcport = port; // global + + d3 + .selectAll(".targetport") + .classed("targeting", true); + + var link = { + source: d.parent, + target: { + x: x, + y: y + }, + srcport: d, + targetport: { + x: 5, + y: 5 + } + }; + srcport.each(function (d) { + d.link = link; + }); + + var tmp = graph + .selectAll(".tmprelation") + .data([link]) + .enter() + .insert("svg:path") + .attr("class", "tmprelation") + .attr("d", tpath); + + d3 + .select("#compositioncontainer") + .on("mousemove", function () { + var m = d3.mouse(this); + link.target.x = m[0]; + link.target.y = m[1]; + tick(); + tmp.attr("d", tpath); + }) + .on("touchmove", function () { + d3 + .event + .preventDefault(); + var m = d3.mouse(this); + link.target.x = m[0]; + link.target.y = m[1]; + tick(); + tmp.attr("d", tpath); + }) + .on("mouseup", function () { + // will miss target click event if this is immediate + setTimeout(function () { + if (srcport) + srcport.each(function (d) { + d.link = null; + }); + srcport = false; // HACK + d3 + .selectAll(".targeting") + .classed("targeting", false); + d3 + .select("#compositioncontainer") + .on("mousemove", null) + .on("mouseup", null); + tmp.remove(); + d3 + .selectAll(".fabulous") + .classed("fabulous", false); + }, 1); + }); + } + + function targetclick(tport, d) { + d3 + .selectAll(".tmprelation") + .remove(); + d3 + .selectAll(".fabulous") + .classed("fabulous", false); // DRY + + if (srcport) { + var tp = tport.attr("port"); + var sp = srcport.attr("port"); + var spd = srcport.datum(), + tpd = tport.datum(); + + //log("targetclick", spd, tpd); + var stype = spd.ptype == "cap" + ? spd.portinfo.type.name + : spd.portinfo.capability.name; + var ttype = tpd.ptype == "cap" + ? tpd.portinfo.type.name + : tpd.portinfo.capability.name; + // var stype = spd.type == "cap" ? spd.portinfo.type.name : + // spd.portinfo.target.name; var ttype = tpd.type == "cap" ? + // tpd.portinfo.type.name : tpd.portinfo.target.name; log("target", + // "stype="+stype, "ttype="+str(ttype)); + + var name = d.label; + + if (spd.ptype != tpd.ptype && stype == ttype) + log("MATCH ", d); + else { + log("NOMATCH", d); + var mx = tport[0][0].getScreenCTM(); // fun! + var x = mx.e, + y = mx.f; + d3 + .select("#problem") + .style("left", x) + .style("top", y) + .style("visibility", "visible") + .html("node/type mismatch"); + setTimeout(function () { + d3 + .select("#problem") + .style("visibility", "hidden"); + }, 3000); + return; + } + + // match success... + var port = d3.select(tport[0][0].parentNode); + port.classed("boundport", true); + port.classed("targetport", false); + var sp = srcport.datum(), + tp = tport.datum(); + addlink(sp.parent, tp.parent, sp.name, tp.name); + srcport = false; + } + } + + var edgelink = function () { + var curvature = .5; + + function link(d) { + var spx = d.srcport.x, + spy = d.srcport.y, + tpx = d.targetport.x, + tpy = d.targetport.y; + + var x0 = d.source.x + spx, + x1 = d.target.x + tpx, + y0 = d.source.y + spy, + y1 = d.target.y + tpy, + + xi = d3.interpolateNumber(x0, x1), + yi = d3.interpolateNumber(y0, y1), + x2 = xi(curvature), + y2 = yi(curvature), + x3 = xi(1 - curvature), + y3 = yi(1 - curvature); + + // if (isNaN(spx)) log("edgelink", d); fix curvature depending on whether port + // is on side, top, or bottom log(":: " + tpy + ", " + spy); + /* + if (tpy == 0) y3 = y1; + if (spy == 0) y2 = y0; + if (tpy != 0) x3 = x1; + if (spy != 0) x2 = x0; + */ + y3 = y1; + y2 = y0; + + return "M" + x0 + "," + y0 + "C" + x2 + "," + y2 + " " + x3 + "," + y3 + " " + x1 + "," + y1; + } + + link.curvature = function (_) { + if (!arguments.length) + return curvature; + curvature = +_; + return link; + }; + + return link; + }; + + var epath = edgelink(); + var tpath = edgelink(); + + epath.curvature(0.3); + + function node(name) { + return cc + .nodes + .find(function (n) { + return n.name == name; + }); + } + + function hascapability(n, cap) { + return n.capabilities && n + .capabilities + .find(function (c) { + return c.name == cap; + }); + } + + function addcomp(c, x, y) { + return txn("addcomp", function () { + return _addcomp(c, x, y); + }); + } + + function _addcomp(c, x, y) { + x = x || 0; + y = y || 0; + + log("addcomp", c); + cc = c; + + var nodes = {}; + var links = []; + var newnodes = []; + + if (!c.outputs) + c.outputs = []; // dummy node special case + if (!c.inputs) + c.inputs = []; + + var outputs = c.outputs; + outputs.forEach(function (o) { + o.value = jsonparse(o.value); + }); + + var inputs = c.inputs; + + c + .nodes + .forEach(function (n) { + + n = _.clone(n); + + outputs.forEach(function (o) { + _ + .values(o) + .forEach(function (a) { + _ + .values(a) + .forEach(function (m) { + if (m.forEach) { + m + .forEach(function (y) { + if (n.name == y) { + n.output = o; + } + }); + } + }); + }); + }); + + if (c.policies) { + c + .policies + .forEach(function (po) { + if (!po.targets) { + return; + } + po + .targets + .some(function (potarget) { + if (n.name != potarget) { + return false; + } + log("ASSIGN POLICY", potarget, po); + if (!n.policies) { + n.policies = []; + } + var policy = JSON.parse(JSON.stringify(po)); + n + .policies + .push(policy); + return true; + }); + }); + } + + onCompositionEvent("init.properties.on.node", n); + // debugger; + if (n.properties) { + n + .properties + .forEach(function (p) { + if (!p.value && p.assignment) { + p.value = p.assignment.value || p["default"]; + if (!p.value && p.assignment.input) { + p.value = p.assignment.input["default"]; + } + //log("assignment value", p.name, p.value); + } + }); + } + + inputs + .forEach(function (i) { + // debugger; + if (n.properties) + n.properties.forEach(function (p) { + if (p.name == i.name && !p.value) { + p.value = i['default']; + log("INPUT", p.name, p.value); + } + }); + } + ); + + var d = addnode(n, x, y); + newnodes.push(d); + + nodes[n.name] = d; + d.model = n; + x += 50; + y += rand(50); + }); + + log(c.name); + log("inputs", inputs); + log("outputs", outputs); + + //if (inputs && inputs.length > 0) + /*xhrpost("/composition.addinputs?cid="+cid, inputs);*/ + //if (outputs && outputs.length > 0) + /*xhrpost("/composition.addoutputs?cid="+cid, outputs);*/ + + c + .nodes + .forEach(function (n) { + if (n.requirements) { + n + .requirements + .forEach(function (req) { + var tn = c + .nodes + .find(function (x) { // target node + return req.node == x.name; + }); + if (tn) { + // find target capability from requirement + var tc = tn + .typeinfo + .capabilities + .find(function (cap) { + return req.capability.name === cap.type.name; + }); + if (tc) + links.push({ + n1: nodes[n.name], + sp: req.name, + n2: nodes[tn.name], + tp: tc.name + }); + } + }); + } + }); + + links.forEach(function (x) { + addlink(x.n1, x.n2, x.sp, x.tp); + }); + sortinterfaces(); // HACK + return newnodes; + } + + function unfade() { + d3 + .selectAll(".node") + .classed("faded", false); + } + + var dropzone1 = d3 + .select("#compositioncontainer") + .node(); + + dropzone1.addEventListener('dragover', function (e) { + if (e.preventDefault) + e.preventDefault(); + + //e.dataTransfer.dropEffect = 'move'; return allowDropByType(e,'product'); + return true; + }); + + dropzone1.addEventListener('dragenter', function (e) { + e.preventDefault(); + this.className = "over"; // assumes react + }); + + dropzone1.addEventListener('dragleave', function (e) { + this.className = ""; + }); + + function droplistener(e) { + compositionDraggingType = null; + + e.preventDefault(); + e.stopPropagation(); + + var data = JSON.parse(e.dataTransfer.getData('product')); + + dropdata(data, e.clientX, e.clientY); + } + + dropzone1.addEventListener('drop', droplistener); + + var catalogprefix = catalogprefix || ""; + + function dropdata(data, x, y) { + //log("DROPDATA",data); + if (data.nodes) { + log("dropdata", 1); + // assuming incoming data blob is a composition template + fixcomp(data, function (c) { + var nodes = addcomp(c, x, y); + }); + } else if (data.product) { // DEAD? + log("dropdata", 2); + addproduct(data.product, x, y); + } else if (data.uuid) { // self-contained catalog interface + log("dropdata", 3); + addproduct(data, x, y); + } else { + log("dropdata", 4); + // it's a single node + var n = data; + if (n.id == 0) { // dummy node special case + n.type = { + name: "NOTYPE" + }; + addnode(n); + } else { + // replace with catalogtype TODO + if (x.type && x.type.name) { + xhrget(catalogprefix + "/type?" + n.type.name, function (resp) { + var ti = JSON.parse(resp); + n.typeinfo = ti; + addnode(n); + }); + } else { + addnode(n); + } + } + } + return false; + } + + // query type info for each node + function fixcomp(c, fn) { + var nn = c.nodes.length; + c + .nodes + .map(function (n) { + if (n.id === 0) { // dummy node special case + n.type = { + name: "NOTYPE" + }; + if (--nn == 0) + fn(c); + } + else { + // replace with catalogtype TODO HACK n.type into n.type.name + if (typeof n.type == "string") + n.type = { + name: n.type + }; + if (!n.name) + n.name = "foo"; + catalogtype(n.id, n.type.name, function (resp) { + var ti = JSON.parse(resp); + if (n.typeinfo) + log("fixcomp - already have typeinfo"); + else + n.typeinfo = ti; + if (--nn == 0) + fn(c); + } + ); + } + }); + } + + function fixcomp0(c, fn) { + var nn = c.nodes.length; + c + .nodes + .map(function (n) { + if (n.id == 0) { // dummy node special case + n.type = { + name: "NOTYPE" + }; + if (--nn == 0) + fn(c); + } + else { + // replace with catalogtype TODO + xhrget(catalogprefix + "/type?" + n.type.name, function (resp) { + var ti = JSON.parse(resp); + n.typeinfo = ti; + if (--nn == 0) + fn(c); + } + ); + } + }); + } + + function setcomposition(c) { + c = JSON.parse(c); + d3 + .select("#composition") + .html("\"" + c.name + "\"
(" + c.description + ")
" + c.composition + "
"); + } + + // stolen from bostock + function wrap(text, width) { + text + .each(function () { + var text = d3.select(this), + words = text + .text() + .split(/\s+/) + .reverse(), + word, + line = [], + lineNumber = 0, + lineHeight = 1.1, // ems + y = text.attr("y"), + dy = parseFloat(text.attr("dy")), + tspan = text + .text(null) + .append("tspan") + .attr("x", 0) + .attr("y", y) + .attr("dy", dy + "em"); + while (word = words.pop()) { + line.push(word); + tspan.text(line.join(" ")); + if (tspan.node().getComputedTextLength() > width) { + line.pop(); + tspan.text(line.join(" ")); + line = [word]; + tspan = text + .append("tspan") + .attr("x", 0) + .attr("y", y) + .attr("dy", ++lineNumber * lineHeight + dy + "em") + .text(word); + } + } + }); + } + + // filters go in defs element + var defs = svg.append("defs"); + + var filter = defs + .append("filter") + .attr("id", "drop-shadow") + .attr("x", "-50%") + .attr("y", "-50%") + .attr("width", "200%") + .attr("height", "200%"); + + // SourceAlpha refers to opacity of graphic that this filter will be applied to + // convolve that with a Gaussian with standard deviation 3 and store result in + // blur + filter + .append("feGaussianBlur") + .attr("in", "SourceAlpha") + .attr("stdDeviation", 7) + .attr("result", "blur"); + + // translate output of Gaussian blur to the right and downwards with 2px store + // result in offsetBlur + filter + .append("feOffset") + .attr("in", "blur") + .attr("dx", 2) + .attr("dy", 2) + .attr("result", "offsetBlur"); + + // overlay original SourceGraphic over translated blurred opacity by using + // feMerge filter. Order of specifying inputs is important! + var feMerge = filter.append("feMerge"); + + feMerge + .append("feMergeNode") + .attr("in", "offsetBlur") + feMerge + .append("feMergeNode") + .attr("in", "SourceGraphic"); + + function _serialsvg() { + svg + .append("style") + .html(css); // stick the stylesheet in + return new XMLSerializer().serializeToString(svg[0][0]); + // + } + + function serialsvg() { + // no, clone is poison var s = clone(svg); + s = svg; + // s.append("style").html(css); // stick the stylesheet in + return new XMLSerializer().serializeToString(s.node()); + // + } + + function clone(s) { + var n = s.node(); + return d3.select(n.parentNode.insertBefore(n.cloneNode(true), n.nextSibling)); + } + + // EXTERNAL / OUTBOUND APIs window.addEventListener('load', function(){ + // },false); + + if (typeof ascIceServerGet == 'function') { + xhrget = function (url, callback) { + console.log("ascIceServerGet", url); + ascIceServerGet(url, function (responseText) { + if (callback) + callback(responseText); + } + ); + } + xhrpost = function (url, obj, callback, type) { + console.log("ascIceServerPost", url, obj, type); + ascIceServerPost(url, JSON.stringify(obj), function (responseText) { + if (callback) + callback(responseText); + } + , type); + } + + xhrpostraw = function (url, obj, callback, type) { + // console.log("ascIceServerPost raw", url, obj, type); + ascIceServerPost(url, obj, function (responseText) { + if (callback) + callback(responseText); + } + , type || "text/plain"); + } + } + + function onCompositionEvent(compositionEvent, compositionElement) { + if (typeof onEventFromComposition === 'function') { + onEventFromComposition(compositionEvent, compositionElement); + } + } + + function setCompositionDropZone(type, yesno) { + compositionDraggingType = (yesno === true + ? type + : null); + switch (type) { + case 'product': + d3 + .select("#compositiondiv") + .selectAll(".compositioncontainer") + .classed("highlight", !!yesno); + break; + case 'location': + d3 + .select("#compositiondiv") + .selectAll(".asc_nodes_Site") + .classed("highlight", !!yesno); + break; + } + } + + function clearComposition() { + graph + .selectAll(".node") + .each(function (d) { + removenode(d); + }); + } + + var composition_version = { + revision: "revision: 2568", + lastmod: "last modified: Thu Sep 21 13:22:37 2017" + }; + + // log(composition_version); extern + window.xhrget = xhrget; + window.configclose = configclose; + window.dropdata = dropdata; + + // log("starting composition inside " + window.location.host + " " + + // JSON.stringify(composition_version)); + +}; + +setTimeout(function () { + window.comp = new CompositionEditor(); + $('#composition-loader').hide(); +}, 2000); + +// +// ─── CONTROLLERS +// ──────────────────────────────────────────────────────────────── +// + +/** + * Represents a controller that connects DOM operations with services. Comp(ostion)Controller + * @param {ApiService} apiService - service that handles api calls + * @requires jquery + * @requires bootstrap-modal + */ +function CompController(apiService) { + + /* Private members */ + + var self = this, + loaderElement = $('#composition-loader'); + + /* Public members */ + + /** + * Saves a given composition, up to 3 attempts are made in case of failure + * UI interactions: + * - loader showing until request returns + * - notification on success + * - modal on failure + * @param {Object} composition + */ + self.saveComposition = function (composition) { + loaderElement.show(); + return attempt(3, function () { + return apiService.saveComposition(composition.cid, composition); + }) + .then(function (response) { + console.log(response); + composition.cid = response.uuid; + notifySuccess('Composition saved', 'saveMsg'); + }) + .fail(function (jqXHR) { + console.error('SaveComposition failed %o', jqXHR.responseJSON.notes); + var tempError = Object + .keys(jqXHR.responseJSON.requestError) + .map(function (key) { + return jqXHR.responseJSON.requestError[key]; + }); + var message = (jqXHR.responseJSON !== undefined) + ? tempError[0].formattedErrorMessage // use response when it's not in JSON format + : 'Internal server error - unable to save composition.'; + alertError(message); + }) + .always(function () { + loaderElement.hide(); + window + .sdc + .notify('ACTION_COMPLETED'); + }); + }; + + /** + * Creates a blueprint + * UI interactions: + * - loader showing until request returns + * - notification on success + * - modal on failure + * @param {String} component_Id + * @param {String} serviceuuid + * @param {String} vnfiname + * @param {String} mt - flow-type + */ + self.createBlueprint = function (component_Id, serviceuuid, vnfiname, mt) { + loaderElement.show(); + apiService + .createBlueprint(component_Id, serviceuuid, vnfiname, mt) + .then(function (response) { + console.log('create blueprint response body: %o', response); + notifySuccess('Blueprint Created', 'submitMsg'); + }) + .fail(function (jqXHR) { + console.error('Create blueprint failed %o', jqXHR.responseJSON.notes); + var tempError = Object + .keys(jqXHR.responseJSON.requestError) + .map(function (key) { + return jqXHR.responseJSON.requestError[key]; + }); + var message = (jqXHR.responseJSON !== undefined) + ? tempError[0].formattedErrorMessage + // use response when it's not in JSON format + : 'Internal server error: unable to create blueprint'; + alertError(message); + }) + .always(function () { + loaderElement.hide(); + }); + }; + +} + +// +// ─── SERVICES +// ─────────────────────────────────────────────────────────────────── +// + +/** + * Represents a service that handles api calls + * (!) Do not make any UI interactions or DOM changes in this context - use the controller for that + * @constructor + * @param {String} baseUrl + * @param {String} userId + */ +function ApiService(baseUrl, userId) { + + /* Private members */ + + var self = this, + headers = { + 'Content-Type': 'text/plain;charset=UTF-8', + 'Access-Control-Allow-Origin': '*', + 'USER_ID': userId + }; + + function post(path, data) { + var deferred = $.Deferred(); + $.ajax({ + type: 'POST', + url: baseUrl + path, + data: JSON.stringify(data), + headers: headers + }) + .then(function () { + // connect deferred with ajax on success + return deferred + .resolve + .apply(null, arguments); + }) + .fail(function (jqXHR) { + // when no response show server-unavilable + jqXHR.responseText = jqXHR.responseText || 'Server Unavailable'; + // connect deferred with ajax on failure + return deferred.reject(jqXHR); + }); + return deferred; + } + + /* Public members */ + + self.saveComposition = function (cid, data) { + return post('/saveComposition/' + cid, data); + }; + + self.createBlueprint = function (componentId, serviceUuid, vfniName, mt) { + var path = ['/createBluePrint', componentId, serviceUuid, vfniName, mt].join('/'); + return post(path, null); + }; +} + +// +// ─── UTILS +// ────────────────────────────────────────────────────────────────────── +// + +/** + * Attempt to perform an given action (deferredFunc) + * @param {Integer} maxAttempts - maximum number of retries + * @param {Function} deferredFunc - function that returns deferred object (jquery promise object) + * @returns {jquery Deferred object} - see api at https://api.jquery.com/category/deferred-object/ + * @requires jquery + * @example + * // prints 'error' if GET request to 'http://some-url' failed 3 times + * // prints 'success' if one of the attempts was successful + * attempt(3, () => $.get('http://some-url')) + * .then(() => console.log('success')) + * .fail(() => console.log('error')) + */ +function attempt(maxAttempts, deferredFunc) { + var promise = $.Deferred(), + errorArgs = null; + + function recurse(attemptsLeft) { + if (attemptsLeft < 1) { + // fail when no more attempts left + promise + .reject + .apply(null, errorArgs); + } else { + deferredFunc() + .then(function () { + return promise + .resolve + .apply(null, arguments); + }) + .fail(function () { + errorArgs = arguments; + recurse(attemptsLeft - 1); // retry on fail + }); + } + } + + recurse(maxAttempts); + return promise; +} + +/** + * Displays success notification on the bottom of the screen + * Will auto-close after 5 secs + * @param {String} message + * @param {String} testId - id for selenium tests + * @requires jquery + * @requires remarkable-bootstrap-notify + */ +function notifySuccess(message, testId) { + var template = $('') + .attr('data-tests-id', testId) + .text(message) + .prop('outerHTML') // stringify the element + + $.notify({ + // options + message: template, + icon: 'glyphicon glyphicon-ok' // v icon + }, { + // settings + type: 'success', + delay: 5000, // auto-close after 5sec + placement: { + from: 'bottom' + } + }); +} + +/** + * Displays alert modal + * @param {String} message + * @requires bootstrap + */ +function alertError(message) { + $('#alert-modal') + .modal('show') + .find('.modal-body') + .text(message); +} diff --git a/app/comp-fe/config.js b/app/comp-fe/config.js new file mode 100644 index 0000000..210fbe4 --- /dev/null +++ b/app/comp-fe/config.js @@ -0,0 +1,3 @@ +configOptions = { + backend_url: window.host +} diff --git a/app/comp-fe/cors_http_server.py b/app/comp-fe/cors_http_server.py new file mode 100644 index 0000000..8a54500 --- /dev/null +++ b/app/comp-fe/cors_http_server.py @@ -0,0 +1,13 @@ +#! /usr/bin/env python + +from SimpleHTTPServer import SimpleHTTPRequestHandler, test + + +class CORSHTTPRequestHandler(SimpleHTTPRequestHandler): + + def end_headers(self): + self.send_header('Access-Control-Allow-Origin', '*') + super(CORSHTTPRequestHandler, self).end_headers(self) + +if __name__ == '__main__': + test(HandlerClass=CORSHTTPRequestHandler) \ No newline at end of file diff --git a/app/comp-fe/elements b/app/comp-fe/elements new file mode 100644 index 0000000..2c5d56d --- /dev/null +++ b/app/comp-fe/elements @@ -0,0 +1 @@ +{"id":null,"timestamp":0,"data":{},"error":{"exception":"java.lang.RuntimeException: Failed to retrieve resources","message":"Catalog API failed"}} \ No newline at end of file diff --git a/app/comp-fe/httpserv.js b/app/comp-fe/httpserv.js new file mode 100644 index 0000000..11bbef4 --- /dev/null +++ b/app/comp-fe/httpserv.js @@ -0,0 +1,32 @@ +var http = require("http"); +var url = require("url"); +var fs = require("fs"); + +http.createServer(function(req, resp) { + var file = url.parse(req.url).pathname.substring(1); + + console.log(file); + if (!fs.existsSync(file)) { + resp.writeHead(404, file + " foundn't"); + return resp.end(); + } + + try { + fs.readFile(file, function(err, file) { + if (err) { + throw err; + } else { + resp.writeHead(200, + { 'Access-Control-Allow-Origin' : '*', + 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS, PUT, PATCH, DELETE', + 'Access-Control-Allow-Headers': 'X-Requested-With,content-type', + 'Access-Control-Allow-Credentials': true }); + resp.write(file); + resp.end(); + } + }); + } catch(e) { + resp.writeHead(500,e); + resp.end(); + } +}).listen(8999); diff --git a/app/comp-fe/icecat.html b/app/comp-fe/icecat.html new file mode 100644 index 0000000..e4057a1 --- /dev/null +++ b/app/comp-fe/icecat.html @@ -0,0 +1,67 @@ + + +
+
+
+
*
+ +
+ +
+
+
[catalog elements]
+
+
+
+ + +
+
+
+ +
+ + + +
+ + + + + diff --git a/app/comp-fe/img/3net.png b/app/comp-fe/img/3net.png new file mode 100644 index 0000000..436d324 Binary files /dev/null and b/app/comp-fe/img/3net.png differ diff --git a/app/comp-fe/img/3netg.png b/app/comp-fe/img/3netg.png new file mode 100644 index 0000000..0b0cf9a Binary files /dev/null and b/app/comp-fe/img/3netg.png differ diff --git a/app/comp-fe/img/collnode.png b/app/comp-fe/img/collnode.png new file mode 100644 index 0000000..ca395d1 Binary files /dev/null and b/app/comp-fe/img/collnode.png differ diff --git a/app/comp-fe/img/dbnode.png b/app/comp-fe/img/dbnode.png new file mode 100644 index 0000000..2d3cc8c Binary files /dev/null and b/app/comp-fe/img/dbnode.png differ diff --git a/app/comp-fe/img/death.png b/app/comp-fe/img/death.png new file mode 100644 index 0000000..748fbf8 Binary files /dev/null and b/app/comp-fe/img/death.png differ diff --git a/app/comp-fe/img/dummy.svg b/app/comp-fe/img/dummy.svg new file mode 100644 index 0000000..108c43f --- /dev/null +++ b/app/comp-fe/img/dummy.svg @@ -0,0 +1 @@ +
site
[configure]
net_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accesssite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_host

site
[configure]
net_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accesssite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_host

vpn
[configure]
net_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacevpn_hostvpn_hostvpn_hostvpn_hostvpn_hostvpn_hostvpn_hostvpn_hostvpn_hostvpn_hostvpn_hostnet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interface

server
[configure]
site_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_host

vig
[configure]
vpn_hostvpn_hostvpn_hostvpn_hostvpn_hostvpn_hostvpn_hostvpn_hostvpn_host

server
[configure]
site_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_hostsite_host

NOD
[configure]
net_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_interfacenet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_accessnet_access
diff --git a/app/comp-fe/img/extnode.png b/app/comp-fe/img/extnode.png new file mode 100644 index 0000000..cdad92c Binary files /dev/null and b/app/comp-fe/img/extnode.png differ diff --git a/app/comp-fe/img/gamma.png b/app/comp-fe/img/gamma.png new file mode 100644 index 0000000..66db810 Binary files /dev/null and b/app/comp-fe/img/gamma.png differ diff --git a/app/comp-fe/img/msnode.png b/app/comp-fe/img/msnode.png new file mode 100644 index 0000000..a669f4d Binary files /dev/null and b/app/comp-fe/img/msnode.png differ diff --git a/app/comp-fe/img/sanode.png b/app/comp-fe/img/sanode.png new file mode 100644 index 0000000..b55d09c Binary files /dev/null and b/app/comp-fe/img/sanode.png differ diff --git a/app/comp-fe/img/srcnode.png b/app/comp-fe/img/srcnode.png new file mode 100644 index 0000000..b5c8ab4 Binary files /dev/null and b/app/comp-fe/img/srcnode.png differ diff --git a/app/comp-fe/js/bootstrap-notify.min.js b/app/comp-fe/js/bootstrap-notify.min.js new file mode 100644 index 0000000..f5ad385 --- /dev/null +++ b/app/comp-fe/js/bootstrap-notify.min.js @@ -0,0 +1,2 @@ +/* Project: Bootstrap Growl = v3.1.3 | Description: Turns standard Bootstrap alerts into "Growl-like" notifications. | Author: Mouse0270 aka Robert McIntosh | License: MIT License | Website: https://github.com/mouse0270/bootstrap-growl */ +!function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t("object"==typeof exports?require("jquery"):jQuery)}(function(t){function e(e,i,n){var i={content:{message:"object"==typeof i?i.message:i,title:i.title?i.title:"",icon:i.icon?i.icon:"",url:i.url?i.url:"#",target:i.target?i.target:"-"}};n=t.extend(!0,{},i,n),this.settings=t.extend(!0,{},s,n),this._defaults=s,"-"==this.settings.content.target&&(this.settings.content.target=this.settings.url_target),this.animations={start:"webkitAnimationStart oanimationstart MSAnimationStart animationstart",end:"webkitAnimationEnd oanimationend MSAnimationEnd animationend"},"number"==typeof this.settings.offset&&(this.settings.offset={x:this.settings.offset,y:this.settings.offset}),this.init()}var s={element:"body",position:null,type:"info",allow_dismiss:!0,newest_on_top:!1,showProgressbar:!1,placement:{from:"top",align:"right"},offset:20,spacing:10,z_index:1031,delay:5e3,timer:1e3,url_target:"_blank",mouse_over:null,animate:{enter:"animated fadeInDown",exit:"animated fadeOutUp"},onShow:null,onShown:null,onClose:null,onClosed:null,icon_type:"class",template:''};String.format=function(){for(var t=arguments[0],e=1;e .progress-bar').removeClass("progress-bar-"+t.settings.type),t.settings.type=i[e],this.$ele.addClass("alert-"+i[e]).find('[data-notify="progressbar"] > .progress-bar').addClass("progress-bar-"+i[e]);break;case"icon":var n=this.$ele.find('[data-notify="icon"]');"class"==t.settings.icon_type.toLowerCase()?n.removeClass(t.settings.content.icon).addClass(i[e]):(n.is("img")||n.find("img"),n.attr("src",i[e]));break;case"progress":var a=t.settings.delay-t.settings.delay*(i[e]/100);this.$ele.data("notify-delay",a),this.$ele.find('[data-notify="progressbar"] > div').attr("aria-valuenow",i[e]).css("width",i[e]+"%");break;case"url":this.$ele.find('[data-notify="url"]').attr("href",i[e]);break;case"target":this.$ele.find('[data-notify="url"]').attr("target",i[e]);break;default:this.$ele.find('[data-notify="'+e+'"]').html(i[e])}var o=this.$ele.outerHeight()+parseInt(t.settings.spacing)+parseInt(t.settings.offset.y);t.reposition(o)},close:function(){t.close()}}},buildNotify:function(){var e=this.settings.content;this.$ele=t(String.format(this.settings.template,this.settings.type,e.title,e.message,e.url,e.target)),this.$ele.attr("data-notify-position",this.settings.placement.from+"-"+this.settings.placement.align),this.settings.allow_dismiss||this.$ele.find('[data-notify="dismiss"]').css("display","none"),(this.settings.delay<=0&&!this.settings.showProgressbar||!this.settings.showProgressbar)&&this.$ele.find('[data-notify="progressbar"]').remove()},setIcon:function(){"class"==this.settings.icon_type.toLowerCase()?this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon):this.$ele.find('[data-notify="icon"]').is("img")?this.$ele.find('[data-notify="icon"]').attr("src",this.settings.content.icon):this.$ele.find('[data-notify="icon"]').append('Notify Icon')},styleURL:function(){this.$ele.find('[data-notify="url"]').css({backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)",height:"100%",left:"0px",position:"absolute",top:"0px",width:"100%",zIndex:this.settings.z_index+1}),this.$ele.find('[data-notify="dismiss"]').css({position:"absolute",right:"10px",top:"5px",zIndex:this.settings.z_index+2})},placement:function(){var e=this,s=this.settings.offset.y,i={display:"inline-block",margin:"0px auto",position:this.settings.position?this.settings.position:"body"===this.settings.element?"fixed":"absolute",transition:"all .5s ease-in-out",zIndex:this.settings.z_index},n=!1,a=this.settings;switch(t('[data-notify-position="'+this.settings.placement.from+"-"+this.settings.placement.align+'"]:not([data-closing="true"])').each(function(){return s=Math.max(s,parseInt(t(this).css(a.placement.from))+parseInt(t(this).outerHeight())+parseInt(a.spacing))}),1==this.settings.newest_on_top&&(s=this.settings.offset.y),i[this.settings.placement.from]=s+"px",this.settings.placement.align){case"left":case"right":i[this.settings.placement.align]=this.settings.offset.x+"px";break;case"center":i.left=0,i.right=0}this.$ele.css(i).addClass(this.settings.animate.enter),t.each(Array("webkit","moz","o","ms",""),function(t,s){e.$ele[0].style[s+"AnimationIterationCount"]=1}),t(this.settings.element).append(this.$ele),1==this.settings.newest_on_top&&(s=parseInt(s)+parseInt(this.settings.spacing)+this.$ele.outerHeight(),this.reposition(s)),t.isFunction(e.settings.onShow)&&e.settings.onShow.call(this.$ele),this.$ele.one(this.animations.start,function(){n=!0}).one(this.animations.end,function(){t.isFunction(e.settings.onShown)&&e.settings.onShown.call(this)}),setTimeout(function(){n||t.isFunction(e.settings.onShown)&&e.settings.onShown.call(this)},600)},bind:function(){var e=this;if(this.$ele.find('[data-notify="dismiss"]').on("click",function(){e.close()}),this.$ele.mouseover(function(){t(this).data("data-hover","true")}).mouseout(function(){t(this).data("data-hover","false")}),this.$ele.data("data-hover","false"),this.settings.delay>0){e.$ele.data("notify-delay",e.settings.delay);var s=setInterval(function(){var t=parseInt(e.$ele.data("notify-delay"))-e.settings.timer;if("false"===e.$ele.data("data-hover")&&"pause"==e.settings.mouse_over||"pause"!=e.settings.mouse_over){var i=(e.settings.delay-t)/e.settings.delay*100;e.$ele.data("notify-delay",t),e.$ele.find('[data-notify="progressbar"] > div').attr("aria-valuenow",i).css("width",i+"%")}t<=-e.settings.timer&&(clearInterval(s),e.close())},e.settings.timer)}},close:function(){var e=this,s=parseInt(this.$ele.css(this.settings.placement.from)),i=!1;this.$ele.data("closing","true").addClass(this.settings.animate.exit),e.reposition(s),t.isFunction(e.settings.onClose)&&e.settings.onClose.call(this.$ele),this.$ele.one(this.animations.start,function(){i=!0}).one(this.animations.end,function(){t(this).remove(),t.isFunction(e.settings.onClosed)&&e.settings.onClosed.call(this)}),setTimeout(function(){i||(e.$ele.remove(),e.settings.onClosed&&e.settings.onClosed(e.$ele))},600)},reposition:function(e){var s=this,i='[data-notify-position="'+this.settings.placement.from+"-"+this.settings.placement.align+'"]:not([data-closing="true"])',n=this.$ele.nextAll(i);1==this.settings.newest_on_top&&(n=this.$ele.prevAll(i)),n.each(function(){t(this).css(s.settings.placement.from,e),e=parseInt(e)+parseInt(s.settings.spacing)+t(this).outerHeight()})}}),t.notify=function(t,s){var i=new e(this,t,s);return i.notify},t.notifyDefaults=function(e){return s=t.extend(!0,{},s,e)},t.notifyClose=function(e){"undefined"==typeof e||"all"==e?t("[data-notify]").find('[data-notify="dismiss"]').trigger("click"):t('[data-notify-position="'+e+'"]').find('[data-notify="dismiss"]').trigger("click")}}); \ No newline at end of file diff --git a/app/comp-fe/js/bootstrap.js b/app/comp-fe/js/bootstrap.js new file mode 100644 index 0000000..1c88b71 --- /dev/null +++ b/app/comp-fe/js/bootstrap.js @@ -0,0 +1,2317 @@ +/*! + * Bootstrap v3.3.4 (http://getbootstrap.com) + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +if (typeof jQuery === 'undefined') { + throw new Error('Bootstrap\'s JavaScript requires jQuery') +} + ++function ($) { + 'use strict'; + var version = $.fn.jquery.split(' ')[0].split('.') + if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) { + throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher') + } +}(jQuery); + +/* ======================================================================== + * Bootstrap: transition.js v3.3.4 + * http://getbootstrap.com/javascript/#transitions + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/) + // ============================================================ + + function transitionEnd() { + var el = document.createElement('bootstrap') + + var transEndEventNames = { + WebkitTransition : 'webkitTransitionEnd', + MozTransition : 'transitionend', + OTransition : 'oTransitionEnd otransitionend', + transition : 'transitionend' + } + + for (var name in transEndEventNames) { + if (el.style[name] !== undefined) { + return { end: transEndEventNames[name] } + } + } + + return false // explicit for ie8 ( ._.) + } + + // http://blog.alexmaccaw.com/css-transitions + $.fn.emulateTransitionEnd = function (duration) { + var called = false + var $el = this + $(this).one('bsTransitionEnd', function () { called = true }) + var callback = function () { if (!called) $($el).trigger($.support.transition.end) } + setTimeout(callback, duration) + return this + } + + $(function () { + $.support.transition = transitionEnd() + + if (!$.support.transition) return + + $.event.special.bsTransitionEnd = { + bindType: $.support.transition.end, + delegateType: $.support.transition.end, + handle: function (e) { + if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments) + } + } + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: alert.js v3.3.4 + * http://getbootstrap.com/javascript/#alerts + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // ALERT CLASS DEFINITION + // ====================== + + var dismiss = '[data-dismiss="alert"]' + var Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.VERSION = '3.3.4' + + Alert.TRANSITION_DURATION = 150 + + Alert.prototype.close = function (e) { + var $this = $(this) + var selector = $this.attr('data-target') + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7 + } + + var $parent = $(selector) + + if (e) e.preventDefault() + + if (!$parent.length) { + $parent = $this.closest('.alert') + } + + $parent.trigger(e = $.Event('close.bs.alert')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + // detach from parent, fire event then clean up data + $parent.detach().trigger('closed.bs.alert').remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent + .one('bsTransitionEnd', removeElement) + .emulateTransitionEnd(Alert.TRANSITION_DURATION) : + removeElement() + } + + + // ALERT PLUGIN DEFINITION + // ======================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.alert') + + if (!data) $this.data('bs.alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + var old = $.fn.alert + + $.fn.alert = Plugin + $.fn.alert.Constructor = Alert + + + // ALERT NO CONFLICT + // ================= + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + // ALERT DATA-API + // ============== + + $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: button.js v3.3.4 + * http://getbootstrap.com/javascript/#buttons + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // BUTTON PUBLIC CLASS DEFINITION + // ============================== + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Button.DEFAULTS, options) + this.isLoading = false + } + + Button.VERSION = '3.3.4' + + Button.DEFAULTS = { + loadingText: 'loading...' + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + var $el = this.$element + var val = $el.is('input') ? 'val' : 'html' + var data = $el.data() + + state = state + 'Text' + + if (data.resetText == null) $el.data('resetText', $el[val]()) + + // push to event loop to allow forms to submit + setTimeout($.proxy(function () { + $el[val](data[state] == null ? this.options[state] : data[state]) + + if (state == 'loadingText') { + this.isLoading = true + $el.addClass(d).attr(d, d) + } else if (this.isLoading) { + this.isLoading = false + $el.removeClass(d).removeAttr(d) + } + }, this), 0) + } + + Button.prototype.toggle = function () { + var changed = true + var $parent = this.$element.closest('[data-toggle="buttons"]') + + if ($parent.length) { + var $input = this.$element.find('input') + if ($input.prop('type') == 'radio') { + if ($input.prop('checked') && this.$element.hasClass('active')) changed = false + else $parent.find('.active').removeClass('active') + } + if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change') + } else { + this.$element.attr('aria-pressed', !this.$element.hasClass('active')) + } + + if (changed) this.$element.toggleClass('active') + } + + + // BUTTON PLUGIN DEFINITION + // ======================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.button') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.button', (data = new Button(this, options))) + + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + var old = $.fn.button + + $.fn.button = Plugin + $.fn.button.Constructor = Button + + + // BUTTON NO CONFLICT + // ================== + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + // BUTTON DATA-API + // =============== + + $(document) + .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + Plugin.call($btn, 'toggle') + e.preventDefault() + }) + .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) { + $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type)) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: carousel.js v3.3.4 + * http://getbootstrap.com/javascript/#carousel + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // CAROUSEL CLASS DEFINITION + // ========================= + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.paused = null + this.sliding = null + this.interval = null + this.$active = null + this.$items = null + + this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this)) + + this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element + .on('mouseenter.bs.carousel', $.proxy(this.pause, this)) + .on('mouseleave.bs.carousel', $.proxy(this.cycle, this)) + } + + Carousel.VERSION = '3.3.4' + + Carousel.TRANSITION_DURATION = 600 + + Carousel.DEFAULTS = { + interval: 5000, + pause: 'hover', + wrap: true, + keyboard: true + } + + Carousel.prototype.keydown = function (e) { + if (/input|textarea/i.test(e.target.tagName)) return + switch (e.which) { + case 37: this.prev(); break + case 39: this.next(); break + default: return + } + + e.preventDefault() + } + + Carousel.prototype.cycle = function (e) { + e || (this.paused = false) + + this.interval && clearInterval(this.interval) + + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + + return this + } + + Carousel.prototype.getItemIndex = function (item) { + this.$items = item.parent().children('.item') + return this.$items.index(item || this.$active) + } + + Carousel.prototype.getItemForDirection = function (direction, active) { + var activeIndex = this.getItemIndex(active) + var willWrap = (direction == 'prev' && activeIndex === 0) + || (direction == 'next' && activeIndex == (this.$items.length - 1)) + if (willWrap && !this.options.wrap) return active + var delta = direction == 'prev' ? -1 : 1 + var itemIndex = (activeIndex + delta) % this.$items.length + return this.$items.eq(itemIndex) + } + + Carousel.prototype.to = function (pos) { + var that = this + var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active')) + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid" + if (activeIndex == pos) return this.pause().cycle() + + return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos)) + } + + Carousel.prototype.pause = function (e) { + e || (this.paused = true) + + if (this.$element.find('.next, .prev').length && $.support.transition) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + + this.interval = clearInterval(this.interval) + + return this + } + + Carousel.prototype.next = function () { + if (this.sliding) return + return this.slide('next') + } + + Carousel.prototype.prev = function () { + if (this.sliding) return + return this.slide('prev') + } + + Carousel.prototype.slide = function (type, next) { + var $active = this.$element.find('.item.active') + var $next = next || this.getItemForDirection(type, $active) + var isCycling = this.interval + var direction = type == 'next' ? 'left' : 'right' + var that = this + + if ($next.hasClass('active')) return (this.sliding = false) + + var relatedTarget = $next[0] + var slideEvent = $.Event('slide.bs.carousel', { + relatedTarget: relatedTarget, + direction: direction + }) + this.$element.trigger(slideEvent) + if (slideEvent.isDefaultPrevented()) return + + this.sliding = true + + isCycling && this.pause() + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)]) + $nextIndicator && $nextIndicator.addClass('active') + } + + var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid" + if ($.support.transition && this.$element.hasClass('slide')) { + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + $active + .one('bsTransitionEnd', function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { + that.$element.trigger(slidEvent) + }, 0) + }) + .emulateTransitionEnd(Carousel.TRANSITION_DURATION) + } else { + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger(slidEvent) + } + + isCycling && this.cycle() + + return this + } + + + // CAROUSEL PLUGIN DEFINITION + // ========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.carousel') + var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option) + var action = typeof option == 'string' ? option : options.slide + + if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + var old = $.fn.carousel + + $.fn.carousel = Plugin + $.fn.carousel.Constructor = Carousel + + + // CAROUSEL NO CONFLICT + // ==================== + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + + // CAROUSEL DATA-API + // ================= + + var clickHandler = function (e) { + var href + var $this = $(this) + var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 + if (!$target.hasClass('carousel')) return + var options = $.extend({}, $target.data(), $this.data()) + var slideIndex = $this.attr('data-slide-to') + if (slideIndex) options.interval = false + + Plugin.call($target, options) + + if (slideIndex) { + $target.data('bs.carousel').to(slideIndex) + } + + e.preventDefault() + } + + $(document) + .on('click.bs.carousel.data-api', '[data-slide]', clickHandler) + .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler) + + $(window).on('load', function () { + $('[data-ride="carousel"]').each(function () { + var $carousel = $(this) + Plugin.call($carousel, $carousel.data()) + }) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: collapse.js v3.3.4 + * http://getbootstrap.com/javascript/#collapse + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // COLLAPSE PUBLIC CLASS DEFINITION + // ================================ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, Collapse.DEFAULTS, options) + this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' + + '[data-toggle="collapse"][data-target="#' + element.id + '"]') + this.transitioning = null + + if (this.options.parent) { + this.$parent = this.getParent() + } else { + this.addAriaAndCollapsedClass(this.$element, this.$trigger) + } + + if (this.options.toggle) this.toggle() + } + + Collapse.VERSION = '3.3.4' + + Collapse.TRANSITION_DURATION = 350 + + Collapse.DEFAULTS = { + toggle: true + } + + Collapse.prototype.dimension = function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + Collapse.prototype.show = function () { + if (this.transitioning || this.$element.hasClass('in')) return + + var activesData + var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing') + + if (actives && actives.length) { + activesData = actives.data('bs.collapse') + if (activesData && activesData.transitioning) return + } + + var startEvent = $.Event('show.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + if (actives && actives.length) { + Plugin.call(actives, 'hide') + activesData || actives.data('bs.collapse', null) + } + + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + .addClass('collapsing')[dimension](0) + .attr('aria-expanded', true) + + this.$trigger + .removeClass('collapsed') + .attr('aria-expanded', true) + + this.transitioning = 1 + + var complete = function () { + this.$element + .removeClass('collapsing') + .addClass('collapse in')[dimension]('') + this.transitioning = 0 + this.$element + .trigger('shown.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + var scrollSize = $.camelCase(['scroll', dimension].join('-')) + + this.$element + .one('bsTransitionEnd', $.proxy(complete, this)) + .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize]) + } + + Collapse.prototype.hide = function () { + if (this.transitioning || !this.$element.hasClass('in')) return + + var startEvent = $.Event('hide.bs.collapse') + this.$element.trigger(startEvent) + if (startEvent.isDefaultPrevented()) return + + var dimension = this.dimension() + + this.$element[dimension](this.$element[dimension]())[0].offsetHeight + + this.$element + .addClass('collapsing') + .removeClass('collapse in') + .attr('aria-expanded', false) + + this.$trigger + .addClass('collapsed') + .attr('aria-expanded', false) + + this.transitioning = 1 + + var complete = function () { + this.transitioning = 0 + this.$element + .removeClass('collapsing') + .addClass('collapse') + .trigger('hidden.bs.collapse') + } + + if (!$.support.transition) return complete.call(this) + + this.$element + [dimension](0) + .one('bsTransitionEnd', $.proxy(complete, this)) + .emulateTransitionEnd(Collapse.TRANSITION_DURATION) + } + + Collapse.prototype.toggle = function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + Collapse.prototype.getParent = function () { + return $(this.options.parent) + .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]') + .each($.proxy(function (i, element) { + var $element = $(element) + this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element) + }, this)) + .end() + } + + Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) { + var isOpen = $element.hasClass('in') + + $element.attr('aria-expanded', isOpen) + $trigger + .toggleClass('collapsed', !isOpen) + .attr('aria-expanded', isOpen) + } + + function getTargetFromTrigger($trigger) { + var href + var target = $trigger.attr('data-target') + || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7 + + return $(target) + } + + + // COLLAPSE PLUGIN DEFINITION + // ========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.collapse') + var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option) + + if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false + if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.collapse + + $.fn.collapse = Plugin + $.fn.collapse.Constructor = Collapse + + + // COLLAPSE NO CONFLICT + // ==================== + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + // COLLAPSE DATA-API + // ================= + + $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) { + var $this = $(this) + + if (!$this.attr('data-target')) e.preventDefault() + + var $target = getTargetFromTrigger($this) + var data = $target.data('bs.collapse') + var option = data ? 'toggle' : $this.data() + + Plugin.call($target, option) + }) + +}(jQuery); + +/* ======================================================================== + * Bootstrap: dropdown.js v3.3.4 + * http://getbootstrap.com/javascript/#dropdowns + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // DROPDOWN CLASS DEFINITION + // ========================= + + var backdrop = '.dropdown-backdrop' + var toggle = '[data-toggle="dropdown"]' + var Dropdown = function (element) { + $(element).on('click.bs.dropdown', this.toggle) + } + + Dropdown.VERSION = '3.3.4' + + Dropdown.prototype.toggle = function (e) { + var $this = $(this) + + if ($this.is('.disabled, :disabled')) return + + var $parent = getParent($this) + var isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) { + // if mobile we use a backdrop because click events don't delegate + $('