[
  {
    "path": ".gitignore",
    "content": "bower_components/\nnode_modules/\ndist/\n.idea/\n.DS_Store\nTODO\nnpm-debug.log\n*.iml"
  },
  {
    "path": "README.md",
    "content": "# schema-registry-ui\n\n[![release](http://github-release-version.herokuapp.com/github/landoop/schema-registry-ui/release.svg?style=flat)](https://github.com/landoop/schema-registry-ui/releases/latest)\n[![docker](https://img.shields.io/docker/pulls/landoop/schema-registry-ui.svg?style=flat)](https://hub.docker.com/r/landoop/schema-registry-ui/)\n[![Join the chat at https://gitter.im/Landoop/support](https://img.shields.io/gitter/room/nwjs/nw.js.svg?maxAge=2592000)](https://gitter.im/Landoop/support?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\n\nThis is a web tool for the [confluentinc/schema-registry](https://github.com/confluentinc/schema-registry) in order to create / view / search / evolve / view history & configure **Avro** schemas of your Kafka cluster.\n\n## Live Demo\n[schema-registry-ui.demo.lenses.io](http://schema-registry-ui.demo.lenses.io)\n\n## Prerequisites\nYou will need schema-registry installed with CORS enabled.\n\nIn order to enable CORS, add in `/opt/confluent-3.x.x/etc/schema-registry/schema-registry.properties`\n\n```\naccess.control.allow.methods=GET,POST,PUT,OPTIONS\naccess.control.allow.origin=*\n```\nAnd then restart the [schema-registry] service\n\n##### Get the set up locally\nWe also provide the schema-registry and schema-registry-ui as part of the [fast-data-dev](https://github.com/Landoop/fast-data-dev) docker image for local development setup that also gives all the relevant backends. Just run:\n```\ndocker run -d --name=fast-data-dev -p 8081:8081 landoop/fast-data-dev\n```\nCheckout more about fast-data-dev docker container [here](https://github.com/Landoop/fast-data-dev)\n\n## Running it via Docker\n\nTo run it via the provided docker image:\n\n```\ndocker pull landoop/schema-registry-ui\ndocker run --rm -p 8000:8000 \\\n           -e \"SCHEMAREGISTRY_URL=http://confluent-schema-registry-host:port\" \\\n           landoop/schema-registry-ui\n```\n\nPlease see the [docker readme](https://github.com/Landoop/schema-registry-ui/tree/master/docker) for more information\nand how to enable various features or avoid CORS issues via the proxy flag.\n\n## Build from source\n\n```\n    git clone https://github.com/Landoop/schema-registry-ui.git\n    cd schema-registry-ui\n    npm install\n    npm start\n```\nWeb UI will be available at `http://localhost:8080`\n\n### Nginx config\n\nIf you use `nginx` to serve this ui, let angular manage routing with\n```\n    location / {\n        try_files $uri $uri/ /index.html =404;\n        root /folder-with-schema-registry-ui/;\n    }\n```\n\n### Setup Schema Registry clusters\n\nUse multiple schema registry clusters in `env.js` :\n```\nvar clusters = [\n   {\n       NAME:\"prod\",\n       // Schema Registry service URL (i.e. http://localhost:8081)\n       SCHEMA_REGISTRY: \"http://localhost:8081\", // https://schema-registry.demo.landoop.com\n       COLOR: \"#141414\", // optional\n       readonlyMode: true // optional\n     },\n     {\n       NAME:\"dev\",\n       SCHEMA_REGISTRY: \"http://localhost:8383\",\n       COLOR: \"red\", // optional\n       allowGlobalConfigChanges: true, // optional\n       //allowTransitiveCompatibilities: true        // if using a Confluent Platform release >= 3.1.1 uncomment this line\n     }\n  ];\n\n```\n* Use `COLOR` to set different header colors for each set up cluster.\n* Use `allowGlobalConfigChanges` to enable configuring Global Compatibility Level from the UI.\n* Use `allowTransitiveCompatibilities` to enable transitive compatibility levels. This is supported in SR >= 3.1.1\n* Use `allowSchemaDeletion` to enable schema deletion from the UI. This is supported in SR >= 3.3.0\n* Use `readonlyMode` to prevent any configuration or schema changes from the UI. It overwrites the previous parameters (`allowGlobalConfigChanges`, `allowSchemaDeletion`).\n\n## Changelog\n[Here](https://github.com/Landoop/schema-registry-ui/wiki/Changelog)\n\n## License\n\nThe project is licensed under the [BSL](http://www.landoop.com/bsl) license.\n\n## Relevant Projects\n\n* [kafka-topics-ui](https://github.com/Landoop/kafka-topics-ui), UI to browse Kafka data and work with Kafka Topics\n* [kafka-connect-ui](https://github.com/Landoop/kafka-connect-ui), Set up and manage connectors for multiple connect clusters\n* [fast-data-dev](https://github.com/Landoop/fast-data-dev), Docker for Kafka developers (schema-registry,kafka-rest,zoo,brokers,landoop)\n* [Landoop-On-Cloudera](https://github.com/Landoop/Landoop-On-Cloudera), Install and manage your kafka streaming-platform on you Cloudera CDH cluster\n\n\n\n<img src=\"http://www.landoop.com/images/landoop-dark.svg\" width=\"13\" /> www.landoop.com\n"
  },
  {
    "path": "docker/Caddyfile",
    "content": "0.0.0.0:8000\ntls off\n\nroot /schema-registry-ui\nlog stdout\n"
  },
  {
    "path": "docker/Dockerfile",
    "content": "FROM alpine\nMAINTAINER Marios Andreopoulos <marios@landoop.com>\n\nWORKDIR /\n# Add needed tools\nRUN apk add --no-cache ca-certificates wget \\\n    && echo \"progress = dot:giga\" | tee /etc/wgetrc\n\n# Add and Setup Caddy webserver\nRUN wget \"https://github.com/mholt/caddy/releases/download/v0.10.11/caddy_v0.10.11_linux_amd64.tar.gz\" -O /caddy.tgz \\\n    && mkdir caddy \\\n    && tar xzf caddy.tgz -C /caddy --no-same-owner \\\n    && rm -f /caddy.tgz\n\n# Add and Setup Schema-Registry-Ui\nENV SCHEMA_REGISTRY_UI_VERSION=\"0.9.5\"\nRUN wget \"https://github.com/Landoop/schema-registry-ui/releases/download/v.${SCHEMA_REGISTRY_UI_VERSION}/schema-registry-ui-${SCHEMA_REGISTRY_UI_VERSION}.tar.gz\" \\\n         -O /schema-registry-ui.tar.gz \\\n    && mkdir /schema-registry-ui \\\n    && tar xzf /schema-registry-ui.tar.gz -C /schema-registry-ui --no-same-owner \\\n    && rm -f /schema-registry-ui.tar.gz \\\n    && rm -f /schema-registry-ui/env.js \\\n    && ln -s /tmp/env.js /schema-registry-ui/env.js\n\n# Add configuration and runtime files\nADD Caddyfile /caddy/Caddyfile.template\nADD run.sh /\nRUN chmod +x /run.sh\n\nEXPOSE 8000\n\n\n# USER nobody:nogroup\nENTRYPOINT [\"/run.sh\"]\n"
  },
  {
    "path": "docker/README.md",
    "content": "## Schema Registry UI ##\n\n[![](https://images.microbadger.com/badges/image/landoop/schema-registry-ui.svg)](http://microbadger.com/images/landoop/schema-registry-ui)\n\nThis is a small docker image for Landoop's schema-registry-ui.\nIt serves the schema-registry-ui from port 8000 by default.\nA live version can be found at <https://schema-registry-ui.demo.lenses.io>\n\nThe software is stateless and the only necessary option is your Schema Registry\nURL.\n\nTo run it:\n\n    docker run --rm -p 8000:8000 \\\n               -e \"SCHEMAREGISTRY_URL=http://schema.registry.url\" \\\n               landoop/schema-registry-ui\n\nVisit http://localhost:8000 to see the UI.\n\n### Advanced Settings\n\nFour of the Schema Registry UI settings need to be enabled explicitly. These\nare:\n\n1. Support for global compatibility level configuration support —i.e change the\n   default compatibility level of your schema registry.\n2. Support for transitive compatibility levels (Schema Registry version 3.1.1 or better).\n3. Support for Schema deletion (Schema Registry version 3.3.0 or better).\n4. Support for readonly mode (overwrites settings for global compatibility configuration and schema deletion)\n\nThey are handled by the `ALLOW_GLOBAL`, `ALLOW_TRANSITIVE`, `ALLOW_DELETION` and `READONLY_MODE`\nenvironment variables. E.g:\n\n    docker run --rm -p 8000:8000 \\\n               -e \"SCHEMAREGISTRY_URL=http://schema.registry.url\" \\\n               -e ALLOW_GLOBAL=1 \\\n               -e ALLOW_TRANSITIVE=1 \\\n               -e ALLOW_DELETION=1 \\\n               -e READONLY_MODE=1 \\\n               landoop/schema-registry-ui\n\n    docker run --rm -p 8000:8000 \\\n               -e \"SCHEMAREGISTRY_URL=http://schema.registry.url\" \\\n               -e READONLY_MODE=1 \\\n               landoop/schema-registry-ui\n\n### Proxying Schema Registry\n\nIf you have CORS issues or want to pass through firewalls and maybe share your\nserver, we added the `PROXY` option. Run the container with `-e PROXY=true` and\nCaddy server will proxy the traffic to Schema Registry:\n\n    docker run --rm -p 8000:8000 \\\n               -e \"SCHEMAREGISTRY_URL=http://schema.registry.url\" \\\n               -e \"PROXY=true\" \\\n               landoop/schema-registry-ui\n\n> **Important**: When proxying, for the `SCHEMAREGISTRY_URL` you have to use an\n> IP address or a domain that can be resolved to it. **You can't use**\n> `localhost` even if you serve Schema Registry from your localhost. The reason\n> for this is that a docker container has its own network, so your _localhost_\n> is different from the container's _localhost_. As an example, if you are in\n> your home network and have an IP address of `192.168.5.65` and run Schema\n> Registry from your computer, instead of `http://127.0.0.1:8082` you must use\n> `http://192.168.5.65:8082`.\n\nIf your Schema Registry uses self-signed SSL certificates, you can use the\n`PROXY_SKIP_VERIFY=true` environment variable to instruct the proxy to\nnot verify the backend TLS certificate.\n\n## Configuration options\n\n### Schema Registry UI\n\nYou can control most of Kafka Topics UI settings via environment variables:\n\n * `SCHEMAREGISTRY_URL`\n * `ALLOW_GLOBAL=[true|false]` (default false)\n * `ALLOW_TRANSITIVE=[true|false]` (default false)\n * `ALLOW_DELETION=[true|false]` (default false).\n * `READONLY_MODE=[true|false]` (default false).\n\n## Docker Options\n\n- `PROXY=[true|false]`\n  \n  Whether to proxy Schema Registry endpoint via the internal webserver\n- `PROXY_SKIP_VERIFY=[true|false]`\n  \n  Whether to accept self-signed certificates when proxying Schema Registry\n  via https\n- `PORT=[PORT]`\n  \n  The port number to use for schema-registry-ui. The default is `8000`.\n  Usually the main reason for using this is when you run the\n  container with `--net=host`, where you can't use docker's publish\n  flag (`-p HOST_PORT:8000`).\n- `CADDY_OPTIONS=[OPTIONS]`\n  \n  The webserver that powers the image is Caddy. Via this variable\n  you can add options that will be appended to its configuration\n  (Caddyfile). Variables than span multiple lines are supported.\n  \n  As an example, you can set Caddy to not apply timeouts via:\n  \n      -e \"CADDY_OPTIONS=timeouts none\"\n  \n  Or you can set basic authentication via:\n  \n      -e \"CADDY_OPTIONS=basicauth / [USER] [PASS]\"\n  \n- `RELATIVE_PROXY_URL=[true|false]`\n  \n  When proxying Schema Registry, enabling this option will set the Schema\n  Registry endpoint in the UI as a relative URL. This can help when running\n  Schema Registry UI under a subpath of your server (e.g\n  `http://url:8000/sr-ui` instead of `http://url:8000/`).\n\n# Schema Registry Configuration\n\nIf you don't wish to proxy Schema Registry's api, you should permit CORS via setting\n`access.control.allow.methods=GET,POST,PUT,DELETE,OPTIONS` and\n`access.control.allow.origin=*`.\n\n# Logging\n\nIn the latest iterations, the container will print informational messages during\nstartup at stderr and web server logs at stdout. This way you may sent the logs\n(stdout) to your favorite log management solution.\n"
  },
  {
    "path": "docker/run.sh",
    "content": "#!/bin/sh\n\nPROXY_SKIP_VERIFY=\"${PROXY_SKIP_VERIFY:-false}\"\nINSECURE_PROXY=\"\"\nALLOW_GLOBAL=\"${ALLOW_GLOBAL:-false}\"\nALLOW_TRANSITIVE=\"${ALLOW_TRANSITIVE:-false}\"\nALLOW_DELETION=\"${ALLOW_DELETION:-false}\"\nREADONLY_MODE=\"${READONLY_MODE:-false}\"\nCADDY_OPTIONS=\"${CADDY_OPTIONS:-}\"\nRELATIVE_PROXY_URL=\"${RELATIVE_PROXY_URL:-false}\"\nPORT=\"${PORT:-8000}\"\n\n{\n    echo \"Landoop Schema Registry UI ${SCHEMA_REGISTRY_UI_VERSION}\"\n    echo \"Visit <https://github.com/Landoop/schema-registry-ui/tree/master/docker>\"\n    echo \"to find more about how you can configure this container.\"\n    echo\n\n    if echo \"$PROXY_SKIP_VERIFY\" | egrep -sq \"true|TRUE|y|Y|yes|YES|1\"; then\n        INSECURE_PROXY=insecure_skip_verify\n        echo \"Unsecure: won't verify proxy certicate chain.\"\n    fi\n\n    # fix for certain installations\n    cat /caddy/Caddyfile.template \\\n        | sed -e \"s/8000/$PORT/\" > /tmp/Caddyfile\n\n    if echo $PROXY | egrep -sq \"true|TRUE|y|Y|yes|YES|1\" \\\n            && [[ ! -z \"$SCHEMAREGISTRY_URL\" ]]; then\n        echo \"Enabling proxy.\"\n        cat <<EOF >>/tmp/Caddyfile\nproxy /api/schema-registry $SCHEMAREGISTRY_URL {\n    without /api/schema-registry\n    $INSECURE_PROXY\n}\nEOF\n        if echo \"$RELATIVE_PROXY_URL\" | egrep -sq \"true|TRUE|y|Y|yes|YES|1\"; then\n            SCHEMAREGISTRY_URL=api/schema-registry\n        else\n            SCHEMAREGISTRY_URL=/api/schema-registry\n        fi\n    fi\n\n    if echo \"$ALLOW_TRANSITIVE\" | egrep -sq \"true|TRUE|y|Y|yes|YES|1\"; then\n        TRANSITIVE_SETTING=\",allowTransitiveCompatibilities: true\"\n        echo \"Enabling transitive compatibility modes support.\"\n    fi\n\n    if echo \"$ALLOW_GLOBAL\" | egrep -sq \"true|TRUE|y|Y|yes|YES|1\"; then\n        GLOBAL_SETTING=\",allowGlobalConfigChanges: true\"\n        echo \"Enabling global compatibility level change support.\"\n    fi\n\n    if echo \"$ALLOW_DELETION\" | egrep -sq \"true|TRUE|y|Y|yes|YES|1\"; then\n        DELETION_SETTING=\",allowSchemaDeletion: true\"\n        echo \"Enabling schema deletion support.\"\n    fi\n\n    if echo \"$READONLY_MODE\" | egrep -sq \"true|TRUE|y|Y|yes|YES|1\"; then\n        READONLY_SETTING=\",readonlyMode: true\"\n        echo \"Enabling readonly mode.\"\n    fi\n\n    if [[ -z \"$SCHEMAREGISTRY_URL\" ]]; then\n        echo \"Schema Registry URL was not set via SCHEMAREGISTRY_URL environment variable.\"\n    else\n        echo \"Setting Schema Registry URL to $SCHEMAREGISTRY_URL.\"\n        cat <<EOF >/tmp/env.js\nvar clusters = [\n   {\n     NAME: \"default\",\n     SCHEMA_REGISTRY: \"$SCHEMAREGISTRY_URL\"\n     $GLOBAL_SETTING\n     $TRANSITIVE_SETTING\n     $DELETION_SETTING\n     $READONLY_SETTING\n   }\n]\nEOF\n    fi\n\n    if [[ -n \"${CADDY_OPTIONS}\" ]]; then\n        echo \"Applying custom options to Caddyfile\"\n        cat <<EOF >>/tmp/Caddyfile\n$CADDY_OPTIONS\nEOF\n    fi\n\n    # Here we emulate the output by Caddy. Why? Because we can't\n    # redirect caddy to stderr as the logging would also get redirected.\n    cat <<EOF\nNote: if you use a PORT lower than 1024, please note that schema-registry-ui can\nnow run under any user. In the future a non-root user may become the default.\nIn this case you will have to explicitly allow binding to such ports, either by\nsetting the root user or something like '--sysctl net.ipv4.ip_unprivileged_port_start=0'.\n\nActivating privacy features... done.\nhttp://0.0.0.0:$PORT\nEOF\n} 1>&2\n\nexec /caddy/caddy -conf /tmp/Caddyfile -quiet\n"
  },
  {
    "path": "env.js",
    "content": "var clusters = [\n  {\n    NAME: \"prod\",\n    // Schema Registry service URL (i.e. http://localhost:8081)\n    SCHEMA_REGISTRY: \"http://localhost:8081\", // https://schema-registry.demo.landoop.com\n    COLOR: \"#141414\", // optional\n    readonlyMode: true // optional\n  },\n  {\n    NAME: \"dev\",\n    SCHEMA_REGISTRY: \"http://localhost:8383\",\n    COLOR: \"red\", // optional\n    allowGlobalConfigChanges: true, // optional\n    allowSchemaDeletion: true  // Supported for Schema Registry version >= 3.3.0 \n    //allowTransitiveCompatibilities: true        // if using a Schema Registry release >= 3.1.1 uncomment this line\n  }\n];\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"schema-registry-ui\",\n  \"version\": \"0.9.5\",\n  \"description\": \"A user interface for Confluent's Schema Registry\",\n  \"readme\": \"README.md\",\n  \"dependencies\": {\n    \"angular\": \"1.5.9\",\n    \"angular-animate\": \"1.5.9\",\n    \"angular-aria\": \"1.5.9\",\n    \"angular-diff-match-patch\": \"^0.1.14\",\n    \"angular-json-tree\": \"^1.0.1\",\n    \"angular-material\": \"^1.0.9\",\n    \"angular-material-data-table\": \"^0.10.9\",\n    \"angular-route\": \"1.5.9\",\n    \"angular-sanitize\": \"1.5.9\",\n    \"angular-ui-ace\": \"0.2.3\",\n    \"angular-utils-pagination\": \"^0.11.1\",\n    \"brace\": \"^0.10.0\",\n    \"diff-match-patch\": \"^1.0.0\",\n    \"file-saver\": \"^1.3.3\",\n    \"font-awesome\": \"^4.6.3\",\n    \"jszip\": \"3.1.3\",\n    \"jszip-utils\": \"0.0.2\"\n  },\n  \"devDependencies\": {\n    \"babel-core\": \"^6.24.1\",\n    \"babel-loader\": \"^7.0.0\",\n    \"babel-plugin-transform-class-properties\": \"^6.24.1\",\n    \"babel-plugin-transform-decorators-legacy\": \"^1.3.4\",\n    \"babel-plugin-transform-object-rest-spread\": \"^6.23.0\",\n    \"babel-plugin-transform-runtime\": \"^6.23.0\",\n    \"babel-preset-es2015\": \"^6.24.1\",\n    \"babel-preset-stage-1\": \"^6.24.1\",\n    \"clean-webpack-plugin\": \"^0.1.16\",\n    \"copy-webpack-plugin\": \"^4.0.1\",\n    \"cross-env\": \"^5.0.1\",\n    \"css-loader\": \"^0.28.1\",\n    \"exports-loader\": \"^0.6.4\",\n    \"expose-loader\": \"^0.7.3\",\n    \"extract-text-webpack-plugin\": \"^2.1.0\",\n    \"file-loader\": \"^0.11.1\",\n    \"html-loader\": \"^0.4.5\",\n    \"html-webpack-plugin\": \"^2.28.0\",\n    \"imports-loader\": \"^0.7.1\",\n    \"style-loader\": \"^0.17.0\",\n    \"url-loader\": \"^0.5.8\",\n    \"webpack\": \"^2.5.1\",\n    \"webpack-dev-server\": \"^2.4.5\"\n  },\n  \"scripts\": {\n    \"start\": \"node ./node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node ./node_modules/webpack-dev-server/bin/webpack-dev-server --config webpack.config.js --progress\",\n    \"start-prod\": \"node ./node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=production node ./node_modules/webpack-dev-server/bin/webpack-dev-server --config webpack.config.js --progress\",\n    \"build-dev\": \"node ./node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=development node ./node_modules/webpack/bin/webpack --config webpack.config.js\",\n    \"build-prod\": \"node ./node_modules/cross-env/dist/bin/cross-env.js NODE_ENV=production node ./node_modules/webpack/bin/webpack --config webpack.config.js\",\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\",\n    \"postinstall\": \"\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/Landoop/schema-registry-ui.git\"\n  },\n  \"keywords\": [\n    \"schema\",\n    \"registry\",\n    \"kafka\",\n    \"avro\"\n  ],\n  \"author\": \"Landoop team\",\n  \"contributors\": [\n    {\n      \"name\": \"Christina Daskalaki\",\n      \"email\": \"christina@landoop.com\"\n    },\n    {\n      \"name\": \"Antonios Chalkiopoulos\",\n      \"email\": \"antonios@landoop.com\"\n    },\n    {\n      \"name\": \"Marios Andreopoulos\",\n      \"email\": \"marios@landoop.com\"\n    },\n    {\n      \"name\": \"John Glampedakis\",\n      \"email\": \"marios@landoop.com\"\n    }\n  ],\n  \"license\": \"BSL\",\n  \"bugs\": {\n    \"url\": \"https://github.com/Landoop/schema-registry-ui/issues\"\n  },\n  \"homepage\": \"https://github.com/Landoop/schema-registry-ui#readme\"\n}\n"
  },
  {
    "path": "src/app.js",
    "content": "'use strict';\n\n/**\n * Pulling in css libs\n */\nrequire('font-awesome/css/font-awesome.min.css');\nrequire('angular-material/angular-material.min.css');\nrequire('angular-material-data-table/dist/md-data-table.min.css');\nrequire('angular-json-tree/dist/angular-json-tree.css');\nrequire('./assets/css/styles.css');\n/**\n * Requiring in libs here for the time being\n * Going forward the require/import should be done in the file that needs it\n */\nrequire('expose-loader?diff_match_patch!diff-match-patch');\nwindow.DIFF_INSERT = require('exports-loader?DIFF_INSERT!diff-match-patch/index');\nwindow.DIFF_DELETE = require('exports-loader?DIFF_DELETE!diff-match-patch/index');\nwindow.DIFF_EQUAL = require('exports-loader?DIFF_EQUAL!diff-match-patch/index');\n\nrequire('jszip');\nrequire('jszip-utils');\n\nrequire('angular');\nrequire('angular-utils-pagination/dirPagination');\nrequire('angular-ui-ace');\nrequire('angular-route');\nrequire('angular-sanitize');\nrequire('angular-material');\nrequire('angular-animate');\nrequire('angular-aria');\nrequire('angular-material-data-table');\nrequire('angular-diff-match-patch');\nrequire('angular-json-tree');\n\n\nvar angularAPP = angular.module('angularAPP', [\n  'ui.ace',\n  'angularUtils.directives.dirPagination',\n  'ngRoute',\n  'ngMaterial',\n  'ngAnimate',\n  'ngAria',\n  'md.data.table',\n  'diff-match-patch',\n  'angular-json-tree',\n  'ngSanitize'\n]);\n\n/**\n *\n */\nrequire('./schema-registry');\nrequire('./factories');\n/**\n * Templates\n */\nvar homeTemplate = require('./schema-registry/home/home.html');\nvar newTemplate = require('./schema-registry/new/new.html');\nvar exportTemplate = require('./schema-registry/export/export.html');\nvar viewTemplate = require('./schema-registry/view/view.html');\nvar configTemplate = require('./schema-registry/config/config.html');\nvar listTemplate = require('./schema-registry/list/list.html');\nvar dirPaginationControlsTemplate = require('./schema-registry/pagination/dirPaginationControlsTemplate.html');\n\n\nvar HeaderCtrl = function ($rootScope, $scope, $location, $log, SchemaRegistryFactory, env) {\n\n  $scope.$on('$routeChangeSuccess', function () {\n    $rootScope.clusters = env.getClusters();\n    $scope.cluster = env.getSelectedCluster();\n    $scope.color = $scope.cluster.COLOR;\n  });\n\n  $scope.updateEndPoint = function (cluster) {\n    $rootScope.connectionFailure = false;\n    $location.path(\"/cluster/\" + cluster)\n  }\n};\n\nHeaderCtrl.$inject = ['$rootScope', '$scope', '$location', '$log', 'SchemaRegistryFactory', 'env'];\n\nangularAPP.controller('HeaderCtrl', HeaderCtrl);\n\n/* Custom directives */\n\nangularAPP.directive('validJson', function () {\n  return {\n    require: 'ngModel',\n    priority: 1000,\n    link: function (scope, elem, attrs, ngModel) {\n\n      // view to model\n      ngModel.$parsers.unshift(function (value) {\n        var valid = true,\n          obj;\n        try {\n          obj = JSON.parse(value);\n        } catch (ex) {\n          valid = false;\n        }\n        ngModel.$setValidity('validJson', valid);\n        return valid ? obj : undefined;\n      });\n\n      // model to view\n      ngModel.$formatters.push(function (value) {\n        return value;//JSON.stringify(value, null, '\\t');\n      });\n    }\n  };\n});\n\n\nangularAPP.filter('reverse', function () {\n  return function (items) {\n    return items.slice().reverse();\n  };\n});\n\n\nangularAPP.config(['$compileProvider', '$mdThemingProvider', '$routeProvider',\n  function ($compileProvider, $mdThemingProvider, $routeProvider) {\n    $compileProvider.aHrefSanitizationWhitelist(/^\\s*(https?|ftp|mailto|tel|file|blob):/);\n\n    $mdThemingProvider.theme('default')\n      .primaryPalette('blue-grey')\n      .accentPalette('blue')\n      .warnPalette('grey');\n\n    $routeProvider\n      .when('/', {\n        template: homeTemplate,\n        controller: 'HomeCtrl'\n      })\n      .when('/cluster/:cluster', {\n        template: homeTemplate,\n        controller: 'HomeCtrl'\n      })\n      .when('/cluster/:cluster/schema/new', {\n        template: newTemplate,\n        controller: 'NewSubjectCtrl as ctrl'\n      })\n      .when('/cluster/:cluster/export', {\n        template: exportTemplate,\n        controller: 'ExportSchemasCtrl'\n      })\n      .when('/cluster/:cluster/schema/:subject/version/:version', {\n        template: viewTemplate,\n        controller: 'SubjectsCtrl'\n      })\n      .otherwise({\n        redirectTo: '/'\n      });\n  }\n  // $locationProvider.html5Mode(true);\n]);\n\n\nangularAPP.run(['env', '$routeParams', '$rootScope', '$templateCache',\n  function loadRoute(env, $routeParams, $rootScope, $templateCache) {\n    $rootScope.$on('$routeChangeSuccess', function () {\n      env.setSelectedCluster($routeParams.cluster);\n    });\n\n    $templateCache.put('config.html', configTemplate);\n    $templateCache.put('list.html', listTemplate);\n    $templateCache.put('angularUtils.directives.dirPagination.template', dirPaginationControlsTemplate);\n  }\n]);\n"
  },
  {
    "path": "src/assets/css/styles.css",
    "content": "html, body {\n    height: 100%;\n    margin: 0;\n    padding: 0;\n    background-color: #F5F5F5;\n    font-size: 14px;\n    font-family: sans-serif;\n    -webkit-text-size-adjust: 100%;\n    -ms-text-size-adjust: 100%;\n}\n\na {\n    color: #337ab7;\n    text-decoration: none;\n}\n\n.ace_editor {\n    height: 460px;\n}\n\n.ace_gutter {\n    background: #f9f9f9 !important;\n}\n\n.searchSchemas {\n    border: 0;\n    margin: 10px auto;\n    display: block;\n    width: 100%;\n    height: 36px;\n    border-bottom: 1px solid #ddd;\n    outline: none;\n    text-indent: 15px;\n}\n\n.searchSchemas:focus, .searchSchemas:focused {\n    outline: none;\n}\n\nheader.header {\n    background-color: #141414;\n    min-height: 20px;\n    color: #ebebeb;\n    margin-bottom: 0;\n}\n\njson-tree .branch-preview {\n    overflow: hidden;\n    font-style: italic;\n    max-width: 90%;\n    height: 1.5em;\n    opacity: .7;\n}\n\n.header-section {\n    background-color: #4F6375;\n    color: #ebebeb;\n    border-bottom: 0 solid #2b3e50;\n    padding: 4px 0;\n    margin-bottom: 0;\n}\n\n.selectCluster {\n    margin: 7px 10px;\n    text-indent: 15px;\n    padding: 0;\n    line-height: 1.2;\n}\n\n.selectCluster md-select {\n    background: white;\n}\n\n.selectCluster md-select md-option,\n.selectCluster md-select md-select-value {\n    color: #333\n}\n\n.selectClusterLabel,\n.exportSchemas {\n    color: rgb(204, 204, 204);\n    font-size: 12px;\n    line-height: 44px;\n    padding-top: 0;\n    margin: 0;\n}\n\n.exportSchemas {\n    margin-right: 40px\n}\n\nmd-input-container.md-default-theme label.md-required:after, md-input-container label.md-required:after {\n    color: red;\n}\n\n.buttonGroup {\n    top: 66px;\n    text-align: right;\n    right: 0;\n    position: absolute;\n}\n\n.md-button.blue,\n.md-button.md-small.blue,\n.md-raised.md-primary.md-button.md-ink-ripple.blue {\n    background-color: rgb(65, 191, 236);\n    color: white;\n}\n\n.md-button.blue:hover,\n.md-button.md-small.blue:hover,\n.md-raised.md-primary.md-button.md-ink-ripple.blue:hover {\n    background-color: rgb(60, 178, 216);\n}\n\n.md-button.md-small.green,\n.md-raised.md-primary.md-button.md-ink-ripple.green,\n.md-primary.md-button.green {\n    background-color: rgb(139, 195, 74);\n    color: white;\n}\n\n.md-button.md-small.green:hover,\n.md-raised.md-primary.md-button.md-ink-ripple.green:hover,\n.md-primary.md-button.green:hover {\n    background-color: rgb(119, 175, 64);\n}\n\n.md-button.md-small.green[disabled],\n.md-raised.md-primary.md-button.md-ink-ripple.green[disabled],\n.md-primary.md-button.green[disabled],\n.md-button.blue[disabled],\n.md-button.md-small.blue[disabled],\n.md-raised.md-primary.md-button.md-ink-ripple.blue[disabled] {\n    background-color: #ccc;\n}\n\n.md-button.md-small {\n    width: 20px;\n    height: 20px;\n    line-height: 20px;\n    min-height: 20px;\n    vertical-align: top;\n    font-size: 10px;\n    padding: 0 0;\n    margin: 0;\n}\n\n.exportSchemas:hover {\n    color: rgb(230, 230, 230)\n}\n\n[ng\\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {\n    display: none !important;\n}\n\n.container-fluid-centered {\n    height: 100%;\n    display: table;\n    width: 100%;\n    padding: 0;\n}\n\na:link, header.a:visited, header.a:hover, header.a:active {\n    text-decoration: none;\n}\n\n.row-fluid {\n    height: 100%;\n    display: table-cell;\n    vertical-align: middle;\n}\n\n.textareacode {\n    border-radius: 3px;\n    outline: none;\n    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.075);\n    border: 1px solid #ccc;\n    width: 95%;\n    font: 12px Consolas, Menlo, Courier, monospace;\n}\n\n.example {\n    position: relative;\n    margin: 15px 0 0;\n    padding: 39px 19px 14px;\n    background-color: #fff;\n    border-radius: 4px 4px 0 0;\n    border: 1px solid #ddd;\n    z-index: 2;\n}\n\n.example1:after {\n    content: \"Register a Complex Schema\";\n}\n\n.example2:after {\n    content: \"Test Schema Compatibility\";\n}\n\n.example:after {\n    position: absolute;\n    top: 0;\n    left: 0;\n    padding: 2px 8px;\n    font-size: 12px;\n    font-weight: bold;\n    background-color: #f5f5f5;\n    color: #9da0a4;\n    border-radius: 4px 0 4px 0;\n}\n\n.snippet {\n    position: relative;\n    overflow: visible;\n}\n\npre {\n    margin-top: 0;\n    margin-bottom: 0;\n    font: 12px Consolas, \"Liberation Mono\", Menlo, Courier, monospace;\n}\n\n.centering {\n    float: none;\n    margin: 0 auto;\n}\n\n.bs-callout-warning {\n    border-left-color: #228415 !important;\n}\n\n.bs-callout {\n    padding: 10px;\n    margin: 10px 0;\n    border: 1px solid #eee;\n    border-left-width: 5px;\n    border-radius: 3px;\n}\n\n/* Style The Dropdown Button */\n.dropbtn {\n    background-color: #4f6375;\n    color: white;\n    font-size: 16px;\n    padding: 4px;\n    border: none;\n    cursor: pointer;\n    min-width: 250px;\n}\n\n/* The container <div> - needed to position the dropdown content */\n.dropdown {\n    position: relative;\n    display: inline-block;\n    z-index: 999;\n}\n\n/* Dropdown Content (Hidden by Default) */\n.dropdown-content {\n    display: none;\n    position: absolute;\n    background-color: green;\n    min-width: 250px;\n    box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);\n}\n\n/* Links inside the dropdown */\n.dropdown-content a {\n    color: black;\n    padding: 12px 16px;\n    text-decoration: none;\n    display: block;\n}\n\n/* Change color of dropdown links on hover */\n.dropdown-content a:hover {\n    background-color: #6e8294\n}\n\n/* Show the dropdown menu on hover */\n.dropdown:hover .dropdown-content {\n    display: block;\n    background-color: #4f6375;\n}\n\n/* Change the background color of the dropdown button when the dropdown content is shown */\n.dropdown:hover .dropbtn {\n    background-color: #4f6375;\n}\n\nmd-card {\n    margin: 0;\n}\n\nmd-toast.md-default-theme .md-toast-content, md-toast .md-toast-content {\n    margin-top: 70px;\n    margin-right: 25px;\n    background-color: white;\n    color: black;\n    text-align: center;\n}\n\nmd-chips.md-default-theme .md-chips, md-chips .md-chips {\n    box-shadow: none;\n}\n\n.md-button.light-blue {\n    background-color: rgba(74, 163, 223, 1);\n}\n\n/** Pagination **/\n.label-primary {\n    background-color: #286090;\n}\n\n/* Useful for the `New Subject` auto-complete field */\n.md-whiteframe-1dp, .md-whiteframe-z1 {\n    box-shadow: none;\n}\n\n/*.md-whiteframe-2dp {*/\n/*box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12);*/\n/*}*/\n\n/*.md-whiteframe-2dp:focus {*/\n/*box-shadow: 0 1px 5px 0 rgba(0, 0, 0, 0.4), 0 2px 2px 0 rgba(0, 0, 0, 0.28), 0 3px 1px -2px rgba(0, 0, 0, 0.24);*/\n/*}*/\n\n.md-button.light-blue {\n    background-color: rgba(74, 163, 223, 1);\n}\n\n.md-button.md-fab {\n    width: 42px;\n    height: 42px;\n    background-color: white;\n}\n\na.md-button.md-default-theme.md-warn.md-raised, a.md-button.md-warn.md-raised, a.md-button.md-default-theme.md-warn.md-fab, a.md-button.md-warn.md-fab, .md-button.md-default-theme.md-warn.md-raised, .md-button.md-warn.md-raised, .md-button.md-default-theme.md-warn.md-fab, .md-button.md-warn.md-fab {\n    color: rgb(255, 255, 255);\n    background-color: rgba(169, 169, 169, 0.1);\n}\n\n/* Custom topics-ui CSS */\nmd-list-item.md-2-line, md-list-item.md-2-line > .md-no-style {\n    min-height: 0;\n}\n\n.table > tbody > tr > td, .table > tbody > tr > th, .table > tfoot > tr > td, .table > tfoot > tr > th, .table > thead > tr > td, .table > thead > tr > th {\n    padding-top: 10px;\n    padding-bottom: 10px;\n    vertical-align: middle;\n}\n\nmd-card md-card-title {\n    padding-bottom: 10px;\n}\n\n/** Kafka-Connect only **/\n.ats-switch span.switch-right {\n    color: #000;\n    background: #f59800;\n}\n\n.md-tooltip ._md-content {\n    height: auto;\n}\n\n/*Animated cogs https://codepen.io/marclloyd77/pen/tAlmd*/\n#development_icon {\n    width: 100px;\n    margin: 0;\n    -webkit-animation: pop 0.4s ease-in;\n}\n\n/*Animate cogs*/\n#large-cog, #small-cog {\n    -webkit-animation: spin 4s linear infinite;\n    -webkit-transform-origin: 50% 50%;\n    -webkit-animation-delay: 0.6s;\n}\n\n#small-cog {\n    -webkit-animation: spinback 2s linear infinite;\n    -webkit-animation-delay: 0.6s;\n}\n\n@-webkit-keyframes pop {\n    0% {\n        -webkit-transform: scale(0);\n    }\n    90% {\n        -webkit-transform: scale(1.1);\n    }\n    100% {\n        -webkit-transform: scale(1);\n    }\n}\n\n@-webkit-keyframes spin {\n    100% {\n        -webkit-transform: rotate(360deg);\n    }\n}\n\n@-webkit-keyframes spinback {\n    100% {\n        -webkit-transform: rotate(-360deg);\n    }\n}\n\n.ace_diff_new_line {\n    background: rgba(0, 128, 0, 0.04);\n}\n\n.noselect {\n    -webkit-touch-callout: none;\n    -webkit-user-select: none;\n    -khtml-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n}\n\n/* diff css */\n.match {\n    display: none;\n    color: blue;\n}\n\n.ins {\n    background: rgba(55, 255, 55, 0.15);\n}\n\n.del {\n    background: rgba(243, 59, 59, 0.15);\n}\n\n/* Essential for dirPagination material design */\n.pagination .md-button {\n    min-width: 30px;\n    margin: 5px 8px;\n}\n\n/* Essential for dirPagination material design */\n.md-button {\n    min-width: 70px;\n    margin: 5px 8px;\n    color: #333;\n}\n\n.selectedListItem {\n    background-color: #DDDDDD;\n}\n\n/*Funny color*/\n.md-fab:hover, .md-fab.md-focused {\n    background-color: rgba(230, 100, 0, .9) !important;\n}\n\nmd-list-item.md-2-line, md-list-item.md-2-line > .md-no-style {\n    height: 48px;\n}\n\nmd-content {\n    background-color: white;\n}\n\n.md-button.md-default-theme.md-primary.md-raised.newschemabutton {\n    margin-right: 4px;\n    background-color: #448AFF;\n    color: white;\n}\n\nmd-list-item.md-2-line.shemaslistitem {\n    width: 100%;\n}\n\n.md-2-line.shemaslistitem a .md-button.md-warn.md-raised.divlistitem {\n    min-width: 100%;\n    text-align: left;\n    box-shadow: 0 0 0 0 rgba(0, 0, 0, .26) !important;\n}\n\n.md-raised.md-warn.md-button.versionbox {\n    box-shadow: 0 0 0 0 rgba(0, 0, 0, .46);\n    min-width: initial;\n    font-size: 75%;\n    line-height: 17px;\n    min-height: 18px;\n    text-transform: none;\n    background-color: rgba(44, 152, 240, 0.3);\n    color: black;\n    text-align: left;\n    float: right;\n    padding: 3px 12px;\n    margin-top: 10px;\n}\n\n.md-raised.md-warn.md-button.versionbox.moreversions {\n    background: rgb(139, 195, 74);\n}\n\n.md-raised.md-warn.md-button.md-ink-ripple.editbutton,\n.md-raised.md-warn.md-button.md-ink-ripple.testbutton {\n    padding-left: 20px;\n    padding-right: 20px;\n    background-color: #448AFF;\n    color: white;\n}\n\n.md-default-theme md-input-container .md-errors-spacer {\n    min-height: 0;\n}\n\nspan.title {\n    margin: 0;\n    padding: 0;\n    line-height: 44px;\n    font-size: 14px;\n}\n\nmd-tab-content md-content {\n    overflow: auto\n}\n\n.flex-2 {\n    width: 50%;\n    float: left;\n}\n\nmd-switch.md-default-theme.md-checked .md-thumb, md-switch.md-checked .md-thumb {\n    background-color: rgb(65, 191, 236);\n}\n\nmd-switch.md-default-theme.md-checked .md-bar, md-switch.md-checked .md-bar {\n    background-color: rgba(65, 191, 236, 0.6);\n}\n\n.seperator:last-child {\n    border-top: 2px dashed #aaa;\n    margin: 40px 0 30px;\n}\n\n\n\n/* The Modal (background) */\n.modal {\n  display: none; /* Hidden by default */\n  position: fixed; /* Stay in place */\n  z-index: 1; /* Sit on top */\n  left: 0;\n  top: 0;\n  width: 100%; /* Full width */\n  height: 100%; /* Full height */\n  overflow: auto; /* Enable scroll if needed */\n  background-color: rgb(0,0,0); /* Fallback color */\n  background-color: rgba(0,0,0,0.4); /* Black w/ opacity */\n  z-index: 999999;\n}\n\n/* Modal Content/Box */\n.modal-content {\n  background-color: #fefefe;\n  margin: 5% auto; /* 15% from the top and centered */\n  padding: 20px;\n  border: 1px solid #888;\n  width: 1200px; /* Could be more or less, depending on screen size */\n}\n\n/* The Close Button */\n.close {\n  color: #aaa;\n  float: right;\n  font-size: 28px;\n  font-weight: bold;\n}\n\n.close:hover,\n.close:focus {\n  color: black;\n  text-decoration: none;\n  cursor: pointer;\n}\n\n.md-button.btn-danger {\n  background:#d05653;\n  color:white;\n}\n\n.md-button.btn-danger:hover {\n  background:#a7110d;\n\n}"
  },
  {
    "path": "src/factories/avro4s-factory.js",
    "content": "var angular = require('angular');\nvar angularAPP = angular.module('angularAPP');\n\nvar Avro4ScalaFactory = function ($rootScope, $http, $location, $q, $log) {\n\n  /* Public API */\n  return {\n    getScalaFiles: function (apiData) {\n      $log.warn(apiData);\n      $http.defaults.useXDomain = true;\n\n      var singleLineApiData = apiData.split(\"\\n\").join(\" \");\n\n      var req = {\n        method: 'POST',\n        data: singleLineApiData,\n        crossDomain: true,\n        url: AVRO4S,\n        headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}\n      };\n\n      $http(req)\n        .success(function (data) {\n          $log.info(\"Received a response with: \" + data);\n          var results = data.split(\"###\");\n          $log.info(results);\n          if (results[0] === \"scala\") {\n            $log.info(\"It's Scala !! \");\n            $log.info(\"It's Scala :\" + results[1]);\n            //alg0\n            return results[1];\n          }\n        })\n        .error(function (data, status) {\n          $log.error(\"Bad data [\" + data + \"] status [\" + status + \"]\");\n        });\n    }\n  }\n};\n\nAvro4ScalaFactory.$inject = ['$rootScope', '$http', '$location', '$q', '$log'];\n\nangularAPP.factory('Avro4ScalaFactory', Avro4ScalaFactory);\n\n// curl 'https://platform.landoop.com/avro4s/avro4s' -H 'Pragma: no-cache' -H 'Origin: https://avro4s-ui.landoop.com' -H 'Accept-Encoding: gzip, deflate, br' -H 'Accept-Language: en-US,en;q=0.8,el;q=0.6' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36' -H 'Content-Type: application/json' -H 'Accept: application/json' -H 'Cache-Control: no-cache' -H 'Referer: https://avro4s-ui.landoop.com/' -H 'Connection: keep-alive' --data-binary '{   \"type\": \"record\",   \"name\": \"Evolution\",   \"namespace\": \"com.landoop\",   \"fields\": [     {         \"name\": \"name\",         \"type\": \"string\"     },     {         \"name\": \"number1\",         \"type\": \"int\"     },     {         \"name\": \"number2\",         \"type\": \"float\"     },     {         \"name\": \"text\",         \"type\": [             \"string\",             \"null\"         ],         \"default\": \"\"     }   ] }' --compressed"
  },
  {
    "path": "src/factories/env-factory.js",
    "content": "var angular = require('angular');\nvar angularAPP = angular.module('angularAPP');\n\nvar envFactory = function ($rootScope) {\n\n  var clusterArray = (typeof clusters !== \"undefined\") ? angular.copy(clusters) : [];\n  var selectedCluster = null;\n  setCluster();\n\n  return {\n    setSelectedCluster : function(clusterName) { setCluster(clusterName)},\n    getSelectedCluster : function() { return selectedCluster; },\n    getClusters : function() { return clusters} ,\n\n    SCHEMA_REGISTRY : function () { return selectedCluster.SCHEMA_REGISTRY; },\n    AVRO4S : 'https://platform.landoop.com/avro4s/avro4s', // Not currently used, will be used for converting Avro -> Scala Case classes\n    COLOR : function () { return selectedCluster.COLOR; },\n    allowGlobalConfigChanges : function () { return selectedCluster.allowGlobalConfigChanges; },\n    allowTransitiveCompatibilities: function () { return selectedCluster.allowTransitiveCompatibilities; },\n    allowSchemaDeletion: function () { return selectedCluster.allowSchemaDeletion; },\n    readonlyMode: function() { return selectedCluster.readonlyMode; }\n  };\n\n  function setCluster(clusterName) {\n    if(clusterArray.length === 0) {\n        $rootScope.missingEnvJS = true;\n              console.log(\"NOT EXISTS env.js\")\n     }\n     if(angular.isUndefined(clusterName)) {\n          selectedCluster = clusterArray[0];\n     } else {\n          var filteredArray = clusterArray.filter(function(el) {return el.NAME === clusterName});\n          selectedCluster = filteredArray.length === 1 ?  filteredArray[0]  : clusterArray[0]\n     }\n  }\n};\n\nenvFactory.$inject = ['$rootScope'];\n\nangularAPP.factory('env', envFactory);\n"
  },
  {
    "path": "src/factories/index.js",
    "content": "require(\"./utils-factory\");\nrequire(\"./schema-registry-factory\");\nrequire(\"./avro4s-factory\");\nrequire(\"./env-factory\");\nrequire(\"./toast-factory\");"
  },
  {
    "path": "src/factories/schema-registry-factory.js",
    "content": "var angular = require('angular');\nvar angularAPP = angular.module('angularAPP');\n\n/**\n * Schema-Registry angularJS Factory\n *\n * Landoop - version 0.9.x (May.2017)\n */\nvar SchemaRegistryFactory = function ($rootScope, $http, $location, $q, $log, UtilsFactory, env) {\n\n  /**\n   * Get subjects\n   * @see http://docs.confluent.io/3.0.0/schema-registry/docs/api.html#get--subjects\n   */\n  function getSubjects() {\n\n    var url = env.SCHEMA_REGISTRY() + '/subjects/';\n    $log.debug(\"  curl -X GET \" + url);\n    var start = new Date().getTime();\n\n    var deferred = $q.defer();\n    $http.get(url)\n      .then(\n        function successCallback(response) {\n          var allSubjectNames = response.data;\n          $log.debug(\"  curl -X GET \" + url + \" => \" + allSubjectNames.length + \" registered subjects in [ \" + ((new Date().getTime()) - start) + \" ] msec\");\n          deferred.resolve(allSubjectNames);\n        },\n        function errorCallback(response) {\n          deferred.reject(\"Failure with : \" + response)\n        });\n\n    return deferred.promise;\n  }\n\n  /**\n   * Get subjects versions\n   * @see http://docs.confluent.io/3.0.0/schema-registry/docs/api.html#get--subjects-(string- subject)-versions\n   */\n  function getSubjectsVersions(subjectName) {\n\n    var url = env.SCHEMA_REGISTRY() + '/subjects/' + subjectName + '/versions/';\n    $log.debug(\"  curl -X GET \" + url);\n    var start = new Date().getTime();\n\n    var deferred = $q.defer();\n    $http.get(url).then(\n      function successCallback(response) {\n        var allVersions = response.data;\n        $log.debug(\"  curl -X GET \" + url + \" => \" + JSON.stringify(allVersions) + \" versions in [ \" + (new Date().getTime() - start) + \" ] msec\");\n        deferred.resolve(allVersions);\n      },\n      function errorCallback(response) {\n        var msg = \"Failure with : \" + response + \" \" + JSON.stringify(response);\n        $log.error(\"Error in getting subject versions : \" + msg);\n        deferred.reject(msg);\n      });\n\n    return deferred.promise;\n\n  }\n\n  /**\n   * Get a specific version of the schema registered under this subject\n   * @see http://docs.confluent.io/3.0.0/schema-registry/docs/api.html#get--subjects-(string- subject)-versions-(versionId- version)\n   */\n  function getSubjectAtVersion(subjectName, version) {\n\n    var url = env.SCHEMA_REGISTRY() + '/subjects/' + subjectName + '/versions/' + version;\n    $log.debug(\"  curl -X GET \" + url);\n\n    var deferred = $q.defer();\n    var start = new Date().getTime();\n    $http.get(url).then(\n      function successCallback(response) {\n        var subjectInformation = response.data;\n        $log.debug(\"  curl -X GET \" + url + \" => [\" + subjectName + \"] subject \" + JSON.stringify(subjectInformation).length + \" bytes in [ \" + (new Date().getTime() - start) + \" ] msec\");\n        deferred.resolve(subjectInformation);\n      },\n      function errorCallback(response) {\n        var msg = \"Failure getting subject at version : \" + response + \" \" + JSON.stringify(response);\n        $log.error(msg);\n        deferred.reject(msg);\n      });\n\n    return deferred.promise;\n\n  }\n\n  function getAllSchemas(cache) {\n    var i;\n    var allSchemasCache = [];\n    angular.forEach(cache, function (schema) {\n      for (i = 1; i <= schema.version; i++) {\n        getSubjectAtVersion(schema.subjectName, i).then(function (selectedSubject) {\n          allSchemasCache.push(selectedSubject)\n          //$rootScope.downloadFile += '\\n echo >>>' + selectedSubject.subject +'.'+ selectedSubject.version + '.json <<< \\n' + schema.schema + ' \\n \\n EOF';\n        })\n      }\n    });\n    $rootScope.allSchemasCache = allSchemasCache;\n    return allSchemasCache\n  }\n\n  /**\n   * Register a new schema under the specified subject. If successfully registered, this returns the unique identifier of this schema in the registry.\n   * @see http://docs.confluent.io/3.0.0/schema-registry/docs/api.html#post--subjects-(string- subject)-versions\n   */\n  function postNewSubjectVersion(subjectName, newSchema) {\n\n    var deferred = $q.defer();\n    $log.debug(\"Posting new version of subject [\" + subjectName + \"]\");\n\n    var postSchemaRegistration = {\n      method: 'POST',\n      url: env.SCHEMA_REGISTRY() + '/subjects/' + subjectName + \"/versions\",\n      data: '{\"schema\":\"' + newSchema.replace(/\\n/g, \" \").replace(/\\s\\s+/g, ' ').replace(/\"/g, \"\\\\\\\"\") + '\"}' + \"'\",\n      dataType: 'json',\n      headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}\n    };\n\n    $http(postSchemaRegistration)\n      .success(function (data) {\n        //$log.info(\"Success in registering new schema \" + JSON.stringify(data));\n        var schemaId = data.id;\n        deferred.resolve(schemaId);\n      })\n      .error(function (data, status) {\n        $log.info(\"Error on schema registration : \" + JSON.stringify(data));\n        var errorMessage = data.message;\n        if (status >= 400) {\n          $log.debug(\"Schema registrations is not allowed \" + status + \" \" + data);\n        } else {\n          $log.debug(\"Schema registration failure: \" + JSON.stringify(data));\n        }\n        deferred.reject(data);\n      });\n\n    return deferred.promise;\n\n  }\n\n  /**\n   * Check if a schema has already been registered under the specified subject. If so, this returns the schema string\n   * along with its globally unique identifier, its version under this subject and the subject name.\n   *\n   * @see http://docs.confluent.io/3.0.0/schema-registry/docs/api.html#post--subjects-(string- subject)\n   */\n  function checkSchemaExists(subjectName, subjectInformation) {\n\n    var deferred = $q.defer();\n    $log.debug(\"Checking if schema exists under this subject [\" + subjectName + \"]\");\n\n    var postSchemaExists = {\n      method: 'POST',\n      url: env.SCHEMA_REGISTRY() + '/subjects/' + subjectName,\n      data: '{\"schema\":\"' + subjectInformation.replace(/\\n/g, \" \").replace(/\\s\\s+/g, ' ').replace(/\"/g, \"\\\\\\\"\") + '\"}' + \"'\",\n      dataType: 'json',\n      headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}\n    };\n\n    $http(postSchemaExists)\n      .success(function (data) {\n        var response = {\n          id: data.id,\n          version: data.version\n        };\n        $log.info(\"Response : \" + JSON.stringify(response));\n        deferred.resolve(response);\n      })\n      .error(function (data, status) {\n        $log.info(\"Error while checking if schema exists under a subject : \" + JSON.stringify(data));\n        var errorMessage = data.message;\n        if (status === 407) {\n          $log.debug(\"Subject not found or schema not found - 407 - \" + status + \" \" + data);\n        } else {\n          $log.debug(\"Some other failure: \" + JSON.stringify(data));\n        }\n        $defered.reject(\"Something\")\n      });\n\n    return deferred.promise;\n\n  }\n\n  /**\n   * Test input schema against a particular version of a subject’s schema for compatibility.\n   * @see http://docs.confluent.io/3.0.0/schema-registry/docs/api.html#post--compatibility-subjects-(string- subject)-versions-(versionId- version)\n   */\n  function testSchemaCompatibility(subjectName, subjectInformation) {\n\n    var deferred = $q.defer();\n    $log.debug(\"  Testing schema compatibility for [\" + subjectName + \"]\");\n\n    var postCompatibility = {\n      method: 'POST',\n      url: env.SCHEMA_REGISTRY() + '/compatibility/subjects/' + subjectName + \"/versions/latest\",\n      data: '{\"schema\":\"' + subjectInformation.replace(/\\n/g, \" \").replace(/\\s\\s+/g, ' ').replace(/\"/g, \"\\\\\\\"\") + '\"}' + \"'\",\n      dataType: 'json',\n      headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}\n    };\n\n    $http(postCompatibility)\n      .success(function (data) {\n        $log.info(\"Success in testing schema compatibility \" + JSON.stringify(data));\n        deferred.resolve(data.is_compatible)\n      })\n      .error(function (data, status) {\n        $log.warn(\"Error on check compatibility : \" + JSON.stringify(data));\n        if (status === 404) {\n          if (data.error_code === 40401) {\n            $log.warn(\"40401 = Subject not found\");\n          }\n          $log.warn(\"[\" + subjectName + \"] is a non existing subject\");\n          deferred.resolve(\"new\"); // This will be a new subject (!)\n        } else {\n          $log.error(\"HTTP > 200 && < 400 (!) \" + JSON.stringify(data));\n        }\n        deferred.reject(data);\n      });\n\n    return deferred.promise;\n\n  }\n\n  /**\n   * Put global config (Test input schema against a particular version of a subject’s schema for compatibility.\n   * @see http://docs.confluent.io/3.0.0/schema-registry/docs/api.html#put--config\n   */\n  function putConfig(compatibilityLevel) {\n\n    var deferred = $q.defer();\n\n    if ([\"NONE\", \"FULL\", \"FORWARD\", \"BACKWARD\", \"FULL_TRANSITIVE\", \"FORWARD_TRANSITIVE\", \"BACKWARD_TRANSITIVE\"].indexOf(compatibilityLevel) !== -1) {\n\n      var putConfig = {\n        method: 'PUT',\n        url: env.SCHEMA_REGISTRY() + '/config',\n        data: '{\"compatibility\":\"' + compatibilityLevel + '\"}' + \"'\",\n        dataType: 'json',\n        headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}\n      };\n\n      $http(putConfig)\n        .success(function (data) {\n          $log.info(\"Success in changing global schema-registry compatibility \" + JSON.stringify(data));\n          deferred.resolve(data.compatibility)\n        })\n        .error(function (data, status) {\n          $log.info(\"Error on changing global compatibility : \" + JSON.stringify(data));\n          if (status === 422) {\n            $log.warn(\"Invalid compatibility level \" + JSON.stringify(status) + \" \" + JSON.stringify(data));\n            if (JSON.stringify(data).indexOf('50001') > -1) {\n              $log.error(\" Error in the backend data store - \" + $scope.text);\n            } else if (JSON.stringify(data).indexOf('50003') > -1) {\n              $log.error(\"Error while forwarding the request to the master: \" + JSON.stringify(data));\n            }\n          } else {\n            $log.debug(\"HTTP > 200 && < 400 (!) \" + JSON.stringify(data));\n          }\n          deferred.reject(data);\n        });\n\n    } else {\n      $log.warn(\"Compatibility level:\" + compatibilityLevel + \" is not supported\");\n      deferred.reject();\n    }\n\n    return deferred.promise;\n\n  }\n\n  /**\n   * Get global compatibility-level config\n   * @see http://docs.confluent.io/3.0.0/schema-registry/docs/api.html#get--config\n   */\n  function getGlobalConfig() {\n\n    var deferred = $q.defer();\n    var url = env.SCHEMA_REGISTRY() + '/config';\n    $log.debug(\"  curl -X GET \" + url);\n    var start = new Date().getTime();\n    $http.get(url)\n      .success(function (data) {\n        $log.debug(\"  curl -X GET \" + url + \" => in [ \" + ((new Date().getTime()) - start) + \"] msec\");\n        deferred.resolve(data)\n      })\n      .error(function (data, status) {\n        deferred.reject(\"Get global config rejection : \" + data + \" \" + status)\n      });\n\n    return deferred.promise;\n\n  }\n\n  function getSubjectConfig(subjectName) {\n    var deferred = $q.defer();\n    var url = env.SCHEMA_REGISTRY() + '/config/' + subjectName;\n    $log.debug(\"  curl -X GET \" + url);\n    var start = new Date().getTime();\n    $http.get(url)\n      .success(function (data) {\n        $log.debug(\"  curl -X GET \" + url + \" => in [ \" + ((new Date().getTime()) - start) + \"] msec\");\n        deferred.resolve(data)\n      })\n      .error(function (data, status) {\n        if (status === 404) {\n          $log.warn('No compatibility level is set for ' + subjectName + '. Global compatibility level is applied');\n        } else\n          deferred.reject(\"Get global config rejection : \" + data + \" \" + status)\n      });\n    return deferred.promise;\n\n  }\n\n  /**\n   * Update compatibility level for the specified subject\n   * @see http://docs.confluent.io/3.0.0/schema-registry/docs/api.html#put--config-(string- subject)\n   */\n  function updateSubjectCompatibility(subjectName, newCompatibilityLevel) {\n\n    var deferred = $q.defer();\n\n    if ([\"NONE\", \"FULL\", \"FORWARD\", \"BACKWARD\", \"FULL_TRANSITIVE\", \"FORWARD_TRANSITIVE\", \"BACKWARD_TRANSITIVE\"].indexOf(newCompatibilityLevel) !== -1) {\n\n      var putConfig = {\n        method: 'PUT',\n        url: env.SCHEMA_REGISTRY() + '/config/' + subjectName,\n        data: '{\"compatibility\":\"' + newCompatibilityLevel + '\"}' + \"'\",\n        dataType: 'json',\n        headers: {'Content-Type': 'application/json', 'Accept': 'application/json'}\n      };\n\n      $http(putConfig)\n        .success(function (data) {\n          $log.info(\"Success in changing subject [ \" + subjectName + \" ] compatibility \" + JSON.stringify(data));\n          deferred.resolve(data.compatibility)\n        })\n        .error(function (data, status) {\n          $log.info(\"Error on changing compatibility : \" + JSON.stringify(data));\n          if (status === 422) {\n            $log.warn(\"Invalid compatibility level \" + JSON.stringify(status) + \" \" + JSON.stringify(data));\n            if (JSON.stringify(data).indexOf('50001') > -1) {\n              $log.error(\" Error in the backend data store - \" + $scope.text);\n            } else if (JSON.stringify(data).indexOf('50003') > -1) {\n              $log.error(\"Error while forwarding the request to the master: \" + JSON.stringify(data));\n            }\n          } else {\n            $log.debug(\"HTTP > 200 && < 400 (!) \" + JSON.stringify(data));\n          }\n          deferred.reject(data);\n        });\n\n    } else {\n      $log.warn(\"Compatibility level:\" + newCompatibilityLevel + \" is not supported\");\n      deferred.reject();\n    }\n\n    return deferred.promise;\n\n  }\n\n\n  /**\n   * Custom logic of Factory is implemented here.\n   *\n   * In a nut-shell `CACHE` is holding a cache of known subjects\n   * Methods here are utilizing the cache - picking from it or updating\n   *\n   * Subjects are immutable in the schema-registry, thus downloading them\n   * just once is enough !\n   */\n\n  var CACHE = []; // A cache of the latest subject\n\n  /**\n   * Gets from CACHE if exists - undefined otherwise\n   */\n  function getFromCache(subjectName, subjectVersion) {\n    var start = new Date().getTime();\n    var response = undefined;\n    angular.forEach(CACHE, function (subject) {\n      if (subject.subjectName === subjectName && subject.version === subjectVersion) {\n        $log.debug(\"  [ \" + subjectName + \"/\" + subjectVersion + \" ] found in cache \" + JSON.stringify(subject).length + \" bytes in [ \" + ((new Date().getTime()) - start) + \" ] msec\");\n        response = subject;\n      }\n    });\n    return response;\n  }\n\n  /**\n   * GETs latest from CACHE or 'undefined'\n   */\n  function getLatestFromCache(subjectName) {\n    var subjectFromCache = undefined;\n    for (var i = 1; i < 10000; i++) {\n      var x = getFromCache(subjectName, i);\n      if (x !== undefined)\n        subjectFromCache = x;\n    }\n    return subjectFromCache;\n  }\n\n\n  /**\n   *\n   * Composite & Public Methods of this factory\n   *\n   */\n  return {\n\n    // Proxy in function\n    getGlobalConfig: function () {\n      return getGlobalConfig();\n    },\n\n    getSubjectConfig: function (subjectName) {\n      return getSubjectConfig(subjectName);\n    },\n\n    putConfig: function (config) {\n      return putConfig(config);\n    },\n    updateSubjectCompatibility: function (subjectName, newCompatibilityLevel) {\n      return updateSubjectCompatibility(subjectName, newCompatibilityLevel);\n    },\n\n    // Proxy in function\n    testSchemaCompatibility: function (subjectName, subjectInformation) {\n      return testSchemaCompatibility(subjectName, subjectInformation);\n    },\n\n    // Proxy in function\n    registerNewSchema: function (subjectName, subjectInformation) {\n      return postNewSubjectVersion(subjectName, subjectInformation);\n    },\n\n    // Proxy in function\n    getSubjectsVersions: function (subjectName) {\n      return getSubjectsVersions(subjectName);\n    },\n\n    // Proxy in function\n    getLatestSubjectFromCache: function (subjectName) {\n      return getLatestFromCache(subjectName);\n    },\n    // Proxy in function\n    getAllSchemas: function (schemas) {\n      return getAllSchemas(schemas);\n    },\n\n    deleteVersionOfSubject: function (subjectName, version) {\n      var deferred = $q.defer();\n\n      var request = {\n        method: 'DELETE',\n        url: env.SCHEMA_REGISTRY() + '/subjects/' + subjectName + '/versions/' + version,\n        dataType: 'json',\n        headers: {'Content-Type': 'application/json', 'Accept': 'application/json, text/plain'}\n      };\n      $http(request)\n      .success(function (data) {\n        $log.info(\"Success in deleting subject version\" + subjectName + \", version\" + version);\n        var schemaId = data.id;\n        deferred.resolve(schemaId);\n      })\n      .error(function (data, status) {\n        $log.info(\"Error on subject version deletion : \", data);\n        deferred.reject(data);\n      });\n      return deferred.promise;\n    },\n\n    deleteSubject: function (subjectName) {\n      \n      var deferred = $q.defer();\n\n      var request = {\n        method: 'DELETE',\n        url: env.SCHEMA_REGISTRY() + '/subjects/' + subjectName,\n        dataType: 'json',\n        headers: {'Content-Type': 'application/json', 'Accept': 'application/json, text/plain'}\n      };\n      $http(request)\n      .success(function (data) {\n        $log.info(\"Success in deleting schema\" + subjectName);\n        deferred.resolve();\n      })\n      .error(function (data, status) {\n        $log.info(\"Error on schema deletion : \", data);\n        deferred.reject();\n      });\n      return deferred.promise;\n    },\n\n    /**\n     * GETs all subject-names and then GETs the /versions/latest of each one\n     *\n     * Refreshes the CACHE object with latest subjects\n     */\n    refreshLatestSubjectsCACHE: function () {\n\n      var deferred = $q.defer();\n      var start = new Date().getTime();\n\n      // 1. Get all subject names\n      getSubjects().then(\n        function success(allSubjectNames) {\n          // 2. Get full details of subject's final versions\n          var urlFetchLatestCalls = [];\n          angular.forEach(allSubjectNames, function (subject) {\n            urlFetchLatestCalls.push($http.get(env.SCHEMA_REGISTRY() + '/subjects/' + subject + '/versions/latest'));\n          });\n          $q.all(urlFetchLatestCalls).then(function (latestSchemas) {\n            CACHE = []; // Clean up existing cache - to replace with new one\n            angular.forEach(latestSchemas, function (result) {\n              var data = result.data;\n              var cacheData = {\n                version: data.version,  // version\n                id: data.id,            // id\n                schema: data.schema,    // schema - in String - schema i.e. {\\\"type\\\":\\\"record\\\",\\\"name\\\":\\\"User\\\",\\\"fields\\\":[{\\\"name\\\":\\\"name\\\",\\\"type\\\":\\\"string\\\"}]}\n                Schema: JSON.parse(data.schema), // js type | name | doc | fields ...\n                subjectName: data.subject\n              };\n              CACHE.push(cacheData);\n            });\n            $log.debug(\"  pipeline : get-latest-subjects-refresh-cache in [ \" + (new Date().getTime() - start) + \" ] msec\");\n            $rootScope.showSpinner = false;\n            $rootScope.Cache = CACHE;\n            deferred.resolve(CACHE);\n          });\n        });\n\n      return deferred.promise;\n\n    },\n    /**\n     * Get one subject at a particular version\n     */\n    getSubjectAtVersion: function (subjectName, subjectVersion) {\n\n      var deferred = $q.defer();\n\n      // If it's easier to fetch it from cache\n      var subjectFromCache = getFromCache(subjectName, subjectVersion);\n      if (subjectFromCache !== undefined) {\n        deferred.resolve(subjectFromCache);\n      } else {\n        var start = new Date().getTime();\n        getSubjectAtVersion(subjectName, subjectVersion).then(\n          function success(subjectInformation) {\n            //cache it\n            var subjectInformationWithMetadata = {\n              version: subjectInformation.version,\n              id: subjectInformation.id,\n              schema: subjectInformation.schema, // this is text\n              Schema: JSON.parse(subjectInformation.schema), // this is json\n              subjectName: subjectInformation.subject\n            };\n            $log.debug(\"  pipeline: \" + subjectName + \"/\" + subjectVersion + \" in [ \" + (new Date().getTime() - start) + \" ] msec\");\n            deferred.resolve(subjectInformationWithMetadata);\n          },\n          function errorCallback(response) {\n            $log.error(\"Failure with : \" + JSON.stringify(response));\n          });\n      }\n      return deferred.promise;\n\n    },\n\n    /**\n     * GETs the entire subject's history, by\n     *\n     * i. Getting all version\n     * ii. Fetching each version either from cache or from HTTP GET\n     */\n    getSubjectHistory: function (subjectName) {\n\n      var deferred = $q.defer();\n\n      $log.info(\"Getting subject [ \" + subjectName + \"] history\");\n      var completeSubjectHistory = [];\n      getSubjectsVersions(subjectName).then(\n        function success(allVersions) {\n          var urlCalls = [];\n          angular.forEach(allVersions, function (version) {\n            // If in cache\n            var subjectFromCache = getFromCache(subjectName, version);\n            if (subjectFromCache !== undefined) {\n              completeSubjectHistory.push(subjectFromCache);\n            } else {\n              urlCalls.push($http.get(env.SCHEMA_REGISTRY() + '/subjects/' + subjectName + '/versions/' + version));\n            }\n          });\n          // Get all missing versions and add them to cache\n          $q.all(urlCalls).then(function (results) {\n            angular.forEach(results, function (result) {\n              completeSubjectHistory.push(result.data);\n            });\n            deferred.resolve(completeSubjectHistory);\n          });\n        },\n        function failure(data) {\n          deferred.reject(\"pdata=>\" + data);\n        });\n\n      return deferred.promise;\n\n    },\n\n    /**\n     * Get the history in a diff format convenient for rendering a ui\n     */\n    getSubjectHistoryDiff: function (subjectHistory) {\n      var changelog = [];\n\n      $log.info(\"Sorting by version..\");\n      var sortedHistory = UtilsFactory.sortByVersion(subjectHistory);\n      for (var i = 0; i < sortedHistory.length; i++) {\n        var previous = '';\n        if (i > 0)\n          previous = JSON.parse(sortedHistory[i - 1].schema);\n        var changeDetected = {\n          version: sortedHistory[i].version,\n          id: sortedHistory[i].id,\n          current: JSON.parse(sortedHistory[i].schema),\n          previous: previous\n        };\n        changelog.push(changeDetected);\n      }\n\n      return changelog;\n    }\n  }\n\n};\n\nSchemaRegistryFactory.$inject = ['$rootScope', '$http', '$location', '$q', '$log', 'UtilsFactory', 'env'];\n\nangularAPP.factory('SchemaRegistryFactory', SchemaRegistryFactory);\n"
  },
  {
    "path": "src/factories/toast-factory.js",
    "content": "var angular = require('angular');\nvar angularAPP = angular.module('angularAPP');\n\nvar toastFactory = function ($rootScope, $mdToast, $window) {\n\n  var last = {\n    bottom: false,\n    top: true,\n    left: false,\n    right: true\n  };\n\n  var toastPosition = angular.extend({}, last);\n\n  /* Public API of this factory*/\n  this.getToastPosition = function () {\n    this.sanitizePosition();\n\n    return Object.keys(toastPosition)\n      .filter(function (pos) {\n        return toastPosition[pos];\n      })\n      .join(' ');\n  };\n\n  this.sanitizePosition = function () {\n    var current = toastPosition;\n    if (current.bottom && last.top) current.top = false;\n    if (current.top && last.bottom) current.bottom = false;\n    if (current.right && last.left) current.left = false;\n    if (current.left && last.right) current.right = false;\n    last = angular.extend({}, current);\n  };\n\n  this.showSimpleToast = function (message) {\n    $mdToast.show(\n      $mdToast.simple()\n        .textContent(message)\n        .position(this.getToastPosition())\n        .hideDelay(2000)\n    );\n  };\n\n  this.showSimpleToastToTop = function (message) {\n    this.showSimpleToast(message);\n    $window.scrollTo(0, 0);\n  };\n\n  this.showLongToast = function (message) {\n    var last = this.getToastPosition();\n\n    $mdToast.show(\n      $mdToast.simple()\n        .textContent(message)\n        .position(last)\n        .hideDelay(5000)\n    );\n    $window.scrollTo(0, 0);\n  };\n\n  this.showActionToast = function (message) {\n    var toast = $mdToast.simple()\n      .textContent(message)\n      .action('DELETE')\n      .highlightAction(true)\n      //.highlightClass('md-accent')// Accent is used by default, this just demonstrates the usage.\n      .position(this.getToastPosition())\n      .hideDelay(2000);\n\n    $mdToast.show(toast).then(function (response) {\n      if (response === 'ok') {\n        //alert('You clicked the \\'UNDO\\' action.');\n      }\n    });\n  };\n\n  this.hideToast = function () {\n    $mdToast.hide();\n  };\n\n};\n\ntoastFactory.$inject = ['$rootScope', '$mdToast', '$window'];\n\nangularAPP.service('toastFactory', toastFactory);"
  },
  {
    "path": "src/factories/utils-factory.js",
    "content": "var angular = require('angular');\nvar angularAPP = angular.module('angularAPP');\n\n/**\n * Utils angularJS Factory\n */\n\nvar UtilsFactory = function ($log) {\n\n  // Sort arrays by key\n  function sortByKey(array, key, reverse) {\n    return array.sort(function (a, b) {\n      var x = a[key];\n      var y = b[key];\n      return ((x < y) ? -1 * reverse : ((x > y) ? 1 * reverse : 0));\n    });\n  }\n\n  /* Public API */\n  return {\n\n    sortByKey: function (array, key, reverse) {\n      return sortByKey(array, key, reverse);\n    },\n    sortByVersion: function (array) {\n      var sorted = array.sort(function (a, b) {\n        return a.version - b.version;\n      });\n      return sorted;\n    },\n    IsJsonString: function (str) {\n      try {\n        JSON.parse(str);\n      } catch (e) {\n        return false;\n      }\n      return true;\n    }\n\n  }\n\n};\n\nUtilsFactory.$inject = ['$log'];\n\nangularAPP.factory('UtilsFactory', UtilsFactory);"
  },
  {
    "path": "src/index.html",
    "content": "<!DOCTYPE html>\n<html>\n\n<head>\n    <title>Schema Registry UI</title>\n    <link rel=\"shortcut icon\" href=\"./src/assets/icons/favicon.png\">\n    <meta charset=utf-8/>\n    <meta name=\"viewport\" content=\"width=device-width\">\n    <meta name=\"keywords\" content=\"kafka,schema registry,avro,landoop\">\n    <meta name=\"description\" content=\"Kafka Schema Registry UI\">\n    <meta name=\"author\" content=\"http://landoop.com\">\n    <script src=\"env.js\"></script>\n</head>\n\n<body ng-app=\"angularAPP\" ng-cloak>\n\n    <!--Header Starts here-->\n    <header class=\"header\" ng-controller=\"HeaderCtrl\" style=\"background-color:{{color}}\">\n        <div layout=\"row\" layout-xs=\"column\">\n            <div flex>\n                <span class=\"title\"><a style=\"color:#fff;\" class=\"md-padding\" href=\"{{cluster ? '#/cluster/'+cluster.NAME : '#/'}}\">SCHEMA REGISTRY</a></span>\n            </div>\n\n            <a style=\"\" class=\"exportSchemas\" ng-href=\"#/cluster/{{cluster.NAME}}/export\">\n      <i class=\"fa fa-download\" aria-hidden=\"true\"></i> <b>EXPORT SCHEMAS</b>\n    </a>\n\n            <label ng-show=\"!missingEnvJS && clusters.length > 1\" class=\"selectClusterLabel\"><b>SELECT CLUSTER :</b></label>\n            <md-input-container ng-show=\"!missingEnvJS && clusters.length > 1\" class=\"selectCluster\">\n                <md-select ng-model=\"connectEndPoint\">\n                    <md-option ng-repeat=\"connectEndPoint in clusters track by $index\" ng-click=\"updateEndPoint(connectEndPoint.NAME)\" value=\"{{connectEndPoint.NAME}}\"\n                        ng-selected=\"{{cluster.NAME == connectEndPoint.NAME}}\">{{connectEndPoint.NAME}}</md-option>\n                </md-select>\n            </md-input-container>\n        </div>\n    </header>\n\n    <div layout=\"row\" flex=\"100\" ng-show=\"missingEnvJS\" ng-cloak>\n        <md-card>\n            <md-card-content>\n                <h3 style=\"font-weight:300; color:red\"><i class=\"fa fa-exclamation-triangle\" aria-hidden=\"true\"></i> Missing Cluster Configuration</h3>\n                <br> In order to configure <code>schema-registry-ui</code> you need to add <code>env.js</code> file in the\n                root directory of the app.\n                <br> Example <b>env.js</b> structure:\n                <pre>\n        <code>\nvar clusters = [\n   {\n       NAME:\"prod\",\n       // Schema Registry service URL (i.e. http://localhost:8081)\n       SCHEMA_REGISTRY: \"http://localhost:8081\", // https://schema-registry.demo.landoop.com\n       COLOR: \"#141414\" // optional\n     },\n     {\n       NAME:\"dev\",\n       SCHEMA_REGISTRY: \"http://localhost:8383\",\n       COLOR: \"red\", // optional\n       allowGlobalConfigChanges: true, // optional\n       //allowTransitiveCompatibilities: true        // if using a Confluent Platform release >= 3.1.1 uncomment this line\n     }\n  ];\n        </code>\n      </pre>\n            </md-card-content>\n        </md-card>\n    </div>\n\n    <!--Main Content Starts here-->\n    <div layout=\"row\" layout-margin layout-sm=\"column\" layout-xs=\"column\" ng-controller=\"SchemaRegistryConfigCtrl\" ng-hide=\"missingEnvJS\"\n        style=\"margin-bottom:0;\">\n        <div flex-gt-sm=\"33\">\n            <div ng-include=\"'list.html'\"></div>\n            <br>\n            <div ng-include=\"'config.html'\" hide-sm hide-xs></div>\n        </div>\n        <div flex-gt-sm=\"66\" flex style=\"margin-bottom:0;\">\n            <ng-view></ng-view>\n            <div ng-include=\"'config.html'\" show-sm hide-gt-sm></div>\n        </div>\n    </div>\n\n    <!--CUSTOM-FOOTER-->    \n    \n    <!-- LENSES -->\n\n    <!-- analytics -->\n    <!--\n<script src=\"bower_components/ace-builds/src-min-noconflict/ace.js\"></script>\n<script src=\"bower_components/angular/angular.min.js\"></script>\n<script src=\"bower_components/angular-ui-ace/ui-ace.min.js\"></script>\n<script src=\"bower_components/spin.js/spin.min.js\"></script>\n<script src=\"bower_components/angular-spinner/angular-spinner.min.js\"></script>\n<script src=\"bower_components/angular-route/angular-route.min.js\"></script>\n<script src=\"bower_components/angular-sanitize/angular-sanitize.min.js\"></script>\n<script src=\"bower_components/angular-material/angular-material.min.js\"></script>\n<script src=\"bower_components/angular-animate/angular-animate.min.js\"></script>\n<script src=\"bower_components/angular-aria/angular-aria.min.js\"></script>\n<script src=\"bower_components/angular-material-data-table/dist/md-data-table.min.js\"></script>\n<script src=\"bower_components/angular-diff-match-patch/angular-diff-match-patch.js\"></script>\n<script src=\"bower_components/ace-diff/libs/diff_match_patch.js\"></script>\n<script src=\"bower_components/angular-json-tree/dist/angular-json-tree.min.js\"></script>\n<script src=\"bower_components/jszip/dist/jszip.min.js\"></script>\n<script src=\"bower_components/jszip/vendor/FileSaver.js\"></script>\n<script src=\"bower_components/jszip-utils/dist/jszip-utils.min.js\"></script>-->\n\n\n    <!-- build:js combined.js -->\n    <!--<script src=\"src/app.js\"></script>\n<script src=\"src/schema-registry/home/home.controller.js\"></script>\n<script src=\"src/schema-registry/config/config.controller.js\"></script>\n<script src=\"src/schema-registry/view/view.controller.js\"></script>\n<script src=\"src/schema-registry/export/export.controller.js\"></script>\n<script src=\"src/schema-registry/list/list.controller.js\"></script>\n<script src=\"src/schema-registry/new/new.controller.js\"></script>\n<script src=\"src/factories/dirPagination.js\"></script>\n<script src=\"src/factories/utils-factory.js\"></script>\n<script src=\"src/factories/schema-registry-factory.js\"></script>\n<script src=\"src/factories/avro4s-factory.js\"></script>\n<script src=\"src/factories/env.factory.js\"></script>\n<script src=\"src/factories/toast-factory.js\"></script>-->\n    <!-- endbuild -->\n\n</body>\n\n</html>"
  },
  {
    "path": "src/schema-registry/config/config.controller.js",
    "content": "var angular = require('angular');\nvar angularAPP = angular.module('angularAPP');\n\nvar SchemaRegistryConfigCtrl = function ($scope, $http, $log, $mdDialog, SchemaRegistryFactory, env) {\n\n  $log.info(\"Starting schema-registry controller\");\n  $scope.config = {};\n  $scope.connectionFailure = false;\n  $scope.showButton = false;\n  //Get the top level config\n  $scope.$watch(function () {\n    return env.getSelectedCluster().NAME;\n  }, function () {\n    $scope.schemaRegistryURL = env.SCHEMA_REGISTRY();\n\n    $scope.globalConfigOpts = [\"NONE\", \"FULL\", \"FORWARD\", \"BACKWARD\"];\n\n    if (env.allowTransitiveCompatibilities()) {\n      $scope.globalConfigOpts.push(\"FULL_TRANSITIVE\", \"FORWARD_TRANSITIVE\", \"BACKWARD_TRANSITIVE\");\n    }\n\n    SchemaRegistryFactory.getGlobalConfig().then(\n      function success(config) {\n        $scope.allowChanges = !env.readonlyMode() && env.allowGlobalConfigChanges();\n        $scope.config = config;\n        $scope.connectionFailure = false;\n        $scope.form = $scope.config.compatibilityLevel;\n      },\n      function failure(response) {\n        $log.error(\"Failure with : \" + JSON.stringify(response));\n        $scope.connectionFailure = true;\n      });\n  }, true);\n\n  $scope.updateGlobalConfig = function (config, event) {\n\n    $mdDialog.show(dialog(config, event)).then(function () {\n      SchemaRegistryFactory.putConfig(config).then(function () {\n        $scope.form = $scope.config.compatibilityLevel = config;\n        $scope.form = config;\n      });\n    });\n  };\n\n  var backwardText = '<b>Backward compatibility (default)</b>:<br /> A new schema is backward compatible if it can be used to read the data written in all previous schemas. <br />Backward compatibility is useful for loading data into systems like Hadoop since one can always query data of all versions using the latest schema.';\n  var forwardText = '<b>Forward compatibility</b>:<br /> A new schema is forward compatible if all previous schemas can read data written in this schema. <br />Forward compatibility is useful for consumer applications that can only deal with data in a particular version that may not always be the latest version.';\n  var fullText = \"<b>Full compatibility</b>: A new schema is fully compatible if it's both backward and forward compatible.\";\n  var noneText = \"<b>No compatibility</b>: A new schema can be any schema as long as it's a valid Avro.\";\n  var backward_transitive = \"<b>Backward transitive</b>: Only available for schema registry 3.1.0 and above.<br />New schema is backward and forward compatible with all previously registered schemas.\";\n  var forward_transitive = \"<b>Forward transitive</b>: Only available for schema registry 3.1.0 and above.<br />All previously registered schemas can read data produced by the new schema.\";\n  var full_transitive = \"<b>Full transitive</b>: Only available for schema registry 3.1.0 and above.<br />New schema can read data produced by all previously registered schemas.\";\n  var text = '';\n\n  function dialog(config, event) {\n\n    switch (config) {\n      case \"BACKWARD\":\n        text = backwardText;\n        break;\n      case \"FORWARD\":\n        text = forwardText;\n        break;\n      case \"FULL\":\n        text = fullText;\n        break;\n      case \"NONE\":\n        text = noneText;\n        break;\n      case \"BACKWARD_TRANSITIVE\":\n        text = backward_transitive;\n        break;\n      case \"FORWARD_TRANSITIVE\":\n        text = forward_transitive;\n        break;\n      case \"FULL_TRANSITIVE\":\n        text = full_transitive;\n        break;\n      default:\n        text = ''\n    }\n    return $mdDialog.confirm()\n      .title('Warning. You are about to change the \\'Global Compatibility Level\\'.')\n      .htmlContent('<b>This will affect the default behaviour and all subjects/schemas that do not have a compatibility level explicitly defined.</b> <br /><br />' + text)\n      .targetEvent(event)\n      .ok('UPDATE')\n      .cancel('CANCEL');\n  }\n\n};\n\nSchemaRegistryConfigCtrl.$inject = ['$scope', '$http', '$log', '$mdDialog', 'SchemaRegistryFactory', 'env'];\n\nangularAPP.controller('SchemaRegistryConfigCtrl', SchemaRegistryConfigCtrl);\n"
  },
  {
    "path": "src/schema-registry/config/config.html",
    "content": "<md-card>\n    <md-content flex layout-padding style=\"padding:6px;padding-bottom:0\">\n        <div>\n            <b>Url :</b> {{schemaRegistryURL}}\n            <span ng-show=\"connectionFailure\" style=\"color:red\">CONNECTIVITY ERROR</span><br>\n            <b>Global Compatibility level :</b>\n            <select ng-show=\"allowChanges && config.compatibilityLevel\" ng-model='form' required ng-options='option as option for option in globalConfigOpts'></select>\n            <span ng-hide=\"allowChanges \">{{config.compatibilityLevel}}</span>\n            <md-button class=\"green md-small\" style=\"padding: 0px 6px; line-height: 1.2;\" ng-hide=\"form == config.compatibilityLevel\" ng-click=\"updateGlobalConfig(form, $event);\">change</md-button>\n            <br>\n            <b>schema-registry-ui:</b> 0.9.5\n        </div>\n    </md-content>\n</md-card>\n<div layout-margin flex>\n    <div flex=\"nogrow\">\n        <img ng-src=\"src/assets/icons/landoop-dark.svg\" style=\"width:20px;float: left;padding-right:5px;\"></div>\n    <div flex>\n        <p class=\"md-caption\">Powered by <a href=\"https://www.landoop.com/\" target=\"_blank\">Landoop</a></p>\n    </div>\n</div>\n"
  },
  {
    "path": "src/schema-registry/export/export.controller.js",
    "content": "var angular = require('angular');\nvar angularAPP = angular.module('angularAPP');\nvar JSZip = require('jszip');\nvar FileSaver = require('file-saver');\n\nvar ExportSchemasCtrl = function ($rootScope, $scope, env, SchemaRegistryFactory) {\n\n  $scope.$on('$routeChangeSuccess', function () {\n    $scope.cluster = env.getSelectedCluster().NAME;//$routeParams.cluster;\n  });\n\n  var d = new Date();\n  $scope.date = '-' + d.getDate() + '' + (d.getMonth() + 1) + '' + d.getFullYear() + '' + d.getHours() + '' + d.getMinutes();\n  var script = '\\n\\n # To restore the schema - edit & run the following \\n # cat \"$schema\" | sed -e \\'s/\"/\\\\\"/g\\' -e \\'s/\\\\n//g\\' -e \\'1s/^/{ \"schema\": \"/\\' -e \\'$s/$/\"}/\\' | curl -XPOST -i -H \"Content-Type: application/vnd.schemaregistry.v1+json\" --data @- \"SCHEMA_REGISTRY_URL/subjects/$SUBJECT/versions\" \\n # done';\n\n  var latestZip = new JSZip();\n  var allZip = new JSZip();\n\n\n  if ($rootScope.Cache && $rootScope.Cache.length > 0) {\n    angular.forEach($scope.allSchemas, function (schema, key) {\n      latestZip.file(schema.subjectName + '.' + schema.version + '.json', schema.schema);\n    })\n  } else {\n    SchemaRegistryFactory.refreshLatestSubjectsCACHE().then(function (latestSchemas) {\n      angular.forEach(latestSchemas, function (schema) {\n        latestZip.file(schema.subjectName + '.' + schema.version + '.json', schema.schema);\n      })\n    })\n  }\n\n\n  $scope.$watch(function () {\n    return $rootScope.showSpinner;\n  }, function () {\n    $scope.allSchemas = SchemaRegistryFactory.getAllSchemas($rootScope.Cache)\n  }, true);\n\n  $scope.$watch(function () {\n    return $rootScope.allSchemasCache;\n  }, function () {\n    angular.forEach($rootScope.allSchemasCache, function (schema) {\n      allZip.file(schema.subject + '.' + schema.version + '.json', schema.schema);\n    })\n  }, true);\n\n  function bindEvent(el, eventName, eventHandler) {\n    if (el.addEventListener) {\n      // standard way\n      el.addEventListener(eventName, eventHandler, false);\n    } else if (el.attachEvent) {\n      // old IE\n      el.attachEvent('on' + eventName, eventHandler);\n    }\n  }\n\n  function downloadLatestSchemasWithBlob() {\n    latestZip.generateAsync({type: \"blob\"}).then(function (blob) {\n      FileSaver.saveAs(blob, \"latestSchemas\" + $scope.date + \".zip\");\n    }, function (err) {\n      latestLink.innerHTML += \" \" + err;\n    });\n    return false;\n  }\n\n  var latestLink = document.getElementById('latestSchemas');\n  if (JSZip.support.blob) {\n    bindEvent(latestLink, 'click', downloadLatestSchemasWithBlob);\n  } else {\n    latestLink.innerHTML += \" (not supported on this browser)\";\n  }\n\n  function downloadAllSchemasWithBlob() {\n    allZip.generateAsync({type: \"blob\"}).then(function (blob) {\n      FileSaver.saveAs(blob, \"allSchemas\" + $scope.date + \".zip\");\n    }, function (err) {\n      allLink.innerHTML += \" \" + err;\n    });\n    return false;\n  }\n\n  var allLink = document.getElementById('allSchemas');\n  if (JSZip.support.blob) {\n    bindEvent(allLink, 'click', downloadAllSchemasWithBlob);\n  } else {\n    allLink.innerHTML += \" (not supported on this browser)\";\n  }\n\n};\n\nExportSchemasCtrl.$inject = ['$rootScope', '$scope', 'env', 'SchemaRegistryFactory', '$location'];\n\nangularAPP.controller('ExportSchemasCtrl', ExportSchemasCtrl);\n\n"
  },
  {
    "path": "src/schema-registry/export/export.html",
    "content": "<md-card>\n\n  <md-toolbar class=\"md-hue-2\">\n\n    <!--<div class=\"md-toolbar-tools\">-->\n    <div layout=\"row\" layout-xs=\"column\" layout-align=\"center center\" layout-wrap>\n      <div flex>\n        <h3 class=\"md-toolbar-tools md-padding\" hide-xs><i class=\"fa fa-download\" aria-hidden=\"true\" style=\"margin-right:7px\"></i>Export Schemas\n        </h3>\n        </div>\n      </div>\n    </md-toolbar>\n  <md-content flex  class=\"md-padding\">\n    <div>\n      <div ng-show=\"isChecked\" >Number of schemas: {{Cache.length}}</div>\n      <div ng-hide=\"isChecked\" >Total number of schemas (including all versions): {{allSchemasCache.length}}</div>\n\n      <md-checkbox style=\"margin:10px\"  ng-model=\"isChecked\" aria-label=\"only latest\">\n        Export latest only version of each schema\n      </md-checkbox><br />\n\n      <md-button ng-show=\"isChecked\" id=\"latestSchemas\" class=\"btn btn-primary blue\">download latest</md-button>\n      <md-button ng-hide=\"isChecked\" ng-disabled=\"allSchemasCache.length < 1\" id=\"allSchemas\" class=\"btn btn-primary blue\">download all</md-button>\n\n    </div>\n    <!--<div flex=\"2\">-->\n      <!--<div class=\"md-padding\">Total number of schemas (including all versions): {{allSchemas.length}}</div>-->\n      <!--<md-button ng-click=\"downloadAllSchemas(allSchemas)\" download=\"allSchemas-{{date}}.txt\"  ng-href=\"{{curlsURL}}\">Export all schemas</md-button>-->\n    <!--</div>-->\n</md-content>\n</md-card>"
  },
  {
    "path": "src/schema-registry/home/home.controller.js",
    "content": "var angular = require('angular');\nvar angularAPP = angular.module('angularAPP');\n\nvar HomeCtrl = function ($log, SchemaRegistryFactory, toastFactory, $scope, env) {\n  $log.info(\"Starting schema-registry controller - home\");\n  $scope.readonlyMode = env.readonlyMode();\n  toastFactory.hideToast();\n\n  $scope.$watch(function () {\n    return env.getSelectedCluster().NAME;\n  }, function () {\n    $scope.cluster = env.getSelectedCluster().NAME;\n  }, true);\n};\n\nHomeCtrl.$inject = ['$log', 'SchemaRegistryFactory', 'toastFactory', '$scope', 'env'];\n\nangularAPP.controller('HomeCtrl', HomeCtrl);"
  },
  {
    "path": "src/schema-registry/home/home.html",
    "content": "<div class=\"container-fluid-centered\" style=\"height: 500px;text-align:center;\">\n  <div class=\"row-fluid\">\n    <div >\n      <p> Welcome to the <b>schema registry ui</b></p><br/>\n        <p> select a schema<span ng-hide=\"readonlyMode\"> or <a ng-href=\"#/cluster/{{cluster}}/schema/new\">create a new one</a></span></p><br/>\n    </div>\n  </div>\n</div>"
  },
  {
    "path": "src/schema-registry/index.js",
    "content": "require(\"./home/home.controller\");\nrequire(\"./config/config.controller\");\nrequire(\"./view/view.controller\");\nrequire(\"./export/export.controller\");\nrequire(\"./list/list.controller\");\nrequire(\"./new/new.controller\");"
  },
  {
    "path": "src/schema-registry/list/list.controller.js",
    "content": "var angular = require('angular');\nvar angularAPP = angular.module('angularAPP');\n\nvar SubjectListCtrl = function ($scope, $rootScope, $log, $mdMedia, SchemaRegistryFactory, env) {\n\n  $log.info(\"Starting schema-registry controller : list ( initializing subject cache )\");\n  $scope.readonlyMode = env.readonlyMode();\n\n  function addCompatibilityValue() {\n    angular.forEach($rootScope.allSchemas, function (schema) {\n      SchemaRegistryFactory.getSubjectConfig(schema.subjectName).then(\n        function success(config) {\n          schema.compatibilityLevel = config.compatibilityLevel;\n        },\n        function errorCallback(response) {\n          $log.error(response);\n        });\n    })\n  }\n\n  /*\n   * Watch the 'newCreated' and update the subject-cache accordingly\n   */\n\n  $scope.$watch(function () {\n    return $rootScope.listChanges;\n  }, function (a) {\n    if (a !== undefined && a === true) {\n      loadCache(); //When new is created refresh the list\n      $rootScope.listChanges = false;\n    }\n  }, true);\n  // listen for the event in the relevant $scope\n  $scope.$on('newEvolve', function (event, args) {\n    loadCache();\n  });\n\n  $scope.$watch(function () {\n    return env.getSelectedCluster().NAME;\n  }, function (a) {\n    $scope.cluster = env.getSelectedCluster().NAME;\n    $scope.readonlyMode = env.readonlyMode();\n    loadCache(); //When cluster change, reload the list\n  }, true);\n  /**\n   * Load cache by fetching all latest subjects\n   */\n  function loadCache() {\n    $rootScope.allSchemas = [];\n    var promise = SchemaRegistryFactory.refreshLatestSubjectsCACHE();\n    promise.then(function (cachedData) {\n      $rootScope.allSchemas = cachedData;\n      addCompatibilityValue();\n    }, function (reason) {\n      $log.error('Failed at loadCache : ' + reason);\n    }, function (update) {\n      $log.debug('Got notification: ' + update);\n    });\n  }\n\n  var itemsPerPage = (window.innerHeight - 355) / 48;\n  Math.floor(itemsPerPage) < 3 ? $scope.itemsPerPage = 3 : $scope.itemsPerPage = Math.floor(itemsPerPage);\n};\n\nSubjectListCtrl.$inject = ['$scope', '$rootScope', '$log', '$mdMedia', 'SchemaRegistryFactory', 'env'];\n\nangularAPP.controller('SubjectListCtrl', SubjectListCtrl);\n\n//In small devices the list is hidden\n// $scope.$mdMedia = $mdMedia;\n// $scope.$watch(function () {\n//   return $mdMedia('gt-sm');\n// }, function (display) {\n//   $rootScope.showList = display;\n// });\n"
  },
  {
    "path": "src/schema-registry/list/list.html",
    "content": "<md-card ng-controller=\"SubjectListCtrl\" md-theme=\"{{ showDarkTheme ? 'dark-grey' : 'default' }}\">\n  <md-toolbar class=\"md-hue-2\">\n    <div class=\"md-toolbar-tools\">\n      <h3>\n        <span>{{allSchemas.length}} Schemas</span>\n      </h3>\n      <span flex></span>\n      <a md-ink-ripple ng-hide=\"readonlyMode\" ng-href=\"#/cluster/{{cluster}}/schema/new\"\n         class=\"md-raised md-primary md-button md-ink-ripple blue\"\n         type=\"button\"\n         aria-label=\"new connector\">New</a>\n    </div>\n  </md-toolbar>\n  <md-content style=\"background-color:white;overflow:hidden;\">\n      <input ng-model=\"search\" class=\"searchSchemas\" placeholder=\"Search schemas\">\n      <i class=\"fa fa-search\" aria-hidden=\"true\" style=\"right: 26px;font-size: 16px;position: absolute;top: 20px;color:#ddd\"></i>\n    <md-list flex>\n      <md-list-item class=\"md-2-line shemaslistitem\"\n                    dir-paginate=\"schema in allSchemas | orderBy:'-schema.length' | filter : search | itemsPerPage: itemsPerPage\"\n                    href=\"#/cluster/{{cluster}}/schema/{{schema.subjectName}}/version/{{schema.version}}\"\n                    aria-label=\"{{schema.subjectName}}\"\n                    style=\"border-bottom: 1px solid rgba(0, 0, 0, .1)\"\n                    ng-class=\"{ 'selectedListItem': schema.subjectName == subjectObject.subjectName }\">\n\n        <!-- cute / sexy schema bar -->\n        <div class=\"md-list-item-text\" layout=\"column\">\n          <h4>{{schema.subjectName}}</h4>\n          <p style=\"font-size:12px;\" ng-if=\"schema.compatibilityLevel\">\n           Compatibility level is set to {{schema.compatibilityLevel}}\n          </p>\n        </div>\n        <div ng-class=\"{ 'moreversions': schema.version > 1}\"\n             class=\"md-raised md-warn md-button md-ink-ripple versionbox\"\n              type=\"button\" aria-label=\"Primary\">\n          <span>v.{{schema.version}}</span>\n        </div>\n      </md-list-item>\n    </md-list>\n    <dir-pagination-controls max-size=\"6\" style=\"margin:0;\"></dir-pagination-controls>\n  </md-content>\n</md-card>\n"
  },
  {
    "path": "src/schema-registry/new/new.controller.js",
    "content": "var angular = require('angular');\nvar angularAPP = angular.module('angularAPP');\n\nvar NewSubjectCtrl = function ($scope, $route, $rootScope, $http, $log, $q, $location, UtilsFactory, SchemaRegistryFactory, toastFactory, env) {\n  $log.debug(\"NewSubjectCtrl - initiating\");\n\n  $scope.$on('$routeChangeSuccess', function () {\n    $scope.cluster = env.getSelectedCluster().NAME;//$routeParams.cluster;\n  });\n\n  $scope.noSubjectName = true;\n  $rootScope.listChanges = false;\n  toastFactory.hideToast();\n\n  $scope.showSimpleToast = function (message) {\n    toastFactory.showSimpleToast(message)\n  };\n  $scope.showSimpleToastToTop = function (message) {\n    toastFactory.showSimpleToastToTop(message);\n  };\n\n  $scope.hideToast = function () {\n    toastFactory.hide();\n  };\n\n  $scope.$watch(function () {\n    return $scope.text;\n  }, function (a) {\n    $scope.allowCreateOrEvolution = false;\n    updateCurl();\n  }, true);\n\n  $scope.$watch(function () {\n    return $scope.newAvroString;\n  }, function (a) {\n    $scope.allowCreateOrEvolution = false;\n    updateCurl();\n  }, true);\n\n\n  /**\n   * Create filter function for a query string\n   */\n  function createFilterFor(query) {\n    var lowercaseQuery = angular.lowercase(query);\n    return function filterFn(state) {\n      return (state.value.indexOf(lowercaseQuery) === 0);\n    };\n  }\n\n  /**\n   * Possibilities\n   * 1. no-subject-name -> User has not filled-in the subjectName\n   * 2. not-json        -> Schema is invalid Json\n   * 3. new-schema      -> Schema is Json + subject does not exist\n   */\n  $scope.allowCreateOrEvolution = false;\n  var validTypes = [\"null\", \"double\", \"string\", \"record\", \"int\", \"float\", \"long\", \"array\", \"boolean\", \"enum\", \"map\", \"fixed\", \"bytes\", \"type\"];\n  var primitiveTypes = [\"null\", \"boolean\", \"int\", \"long\", \"float\", \"double\", \"bytes\", \"string\"];\n\n  function testCompatibility(subject, newAvroString) {\n    if (env.readonlyMode()) {\n      var deferred = $q.defer();\n      $scope.showSimpleToastToTop(\"Creation is not allowed in readonly mode\");\n      deferred.resolve(\"readonly\");\n      return deferred.promise;\n    }\n\n    $scope.notValidType = false;\n\n    if (newAvroString === \"null\") {\n      if (primitiveTypes.indexOf(newAvroString) === -1) {\n        $scope.wrongType = newAvroString;\n        $scope.notValidType = true;\n      }\n    } else {\n      var a;\n      try {\n        a = JSON.parse(newAvroString);\n        console.log(\"It's probably object, so checking types\", a)\n      } catch (e) {\n        if (typeof(newAvroString) === \"string\") {\n          if (primitiveTypes.indexOf(newAvroString) === -1) {\n            $scope.wrongType = newAvroString;\n            $scope.notValidType = true;\n          }\n        }\n\n      }\n    }\n\n    var flattenObject = function (ob) {\n      var toReturn = {};\n\n      for (var i in ob) {\n        if (!ob.hasOwnProperty(i)) continue;\n\n        if ((typeof ob[i]) === 'object') {\n          var flatObject = flattenObject(ob[i]);\n          for (var x in flatObject) {\n            if (!flatObject.hasOwnProperty(x)) continue;\n            toReturn[i + '.' + x] = flatObject[x];\n          }\n\n        } else {\n          toReturn[i] = ob[i];\n        }\n      }\n      return toReturn;\n    };\n\n    var obj = flattenObject(newAvroString);\n    var typeKeysToCheck = Object.keys(obj)\n      .reduce(function (typeKeys, key, idx) {\n        // Check that this string has a type substring, if not, we don't have to validate\n        if (key.indexOf('type') !== -1 && isPrimitiveTypeKey(key)) {\n          typeKeys.push(key);\n        } \n\n        return typeKeys;\n      }, []);\n\n    var typeKeysToCheckLength = typeKeysToCheck.length;\n\n    // Create for loop vars\n    var i;\n    var keyToCheck;\n\n    /* \n     * By iterating in a for loop, we can break out of an invalid key type found immediately.\n     * That way the UI shows each wrong type one by one(if there are many) instead of just the last\n     * one.\n     */\n    for (i = 0; i < typeKeysToCheckLength; i++) {\n      keyToCheck = typeKeysToCheck[i];\n\n      if (validTypes.indexOf(obj[keyToCheck]) < 0) {\n        $scope.wrongType = obj[keyToCheck];\n        $scope.notValidType = true;\n\n        break;\n      }\n    }\n\n    function isKeyType(key) {\n      return key === 'type';\n    }\n\n    function checkLastTwoKeyParts(lastKeyPart, nextToLastKeyPart) {\n      var isLastKeyPartNotANumber = isNaN(lastKeyPart);\n\n      // If it is not a number, then make sure it's a type key\n      if (isLastKeyPartNotANumber) {\n        return isKeyType(lastKeyPart);\n      }\n\n      // If the last part was a number, is the next to last a type part?\n      return isKeyType(nextToLastKeyPart);\n    };\n\n    // Check if they key is actually a key that defines the primitive type\n    function isPrimitiveTypeKey(key) {\n      var keyToArray = key.split('.');\n      var keyToArrayLength = keyToArray.length;\n      var lastKeyPart = keyToArray[keyToArrayLength - 1];\n      var nextToLastKeyPart = keyToArray[keyToArrayLength - 2];\n\n      return keyToArrayLength === 1 || checkLastTwoKeyParts(lastKeyPart, nextToLastKeyPart);\n    }\n\n    newAvroString = JSON.stringify(newAvroString);\n\n    var deferred = $q.defer();\n\n    if ((subject === undefined) || subject.length === 0) {\n      $scope.showSimpleToastToTop(\"Please fill in the subject name\"); // (1.)\n      $scope.aceBackgroundColor = \"rgba(0, 128, 0, 0.04)\";\n      deferred.resolve(\"no-subject-name\");\n    } else {\n      if ($scope.notValidType) {\n        $scope.showSimpleToastToTop($scope.wrongType + \" is not valid\"); // (2.)\n        $scope.aceBackgroundColor = \"rgba(255, 255, 0, 0.10)\";\n        deferred.resolve(\"not-valid-type\")\n      } else if (!UtilsFactory.IsJsonString(newAvroString)) {\n        $scope.showSimpleToastToTop(\"This schema is not valid\"); // (2.)\n        $scope.aceBackgroundColor = \"rgba(255, 255, 0, 0.10)\";\n        deferred.resolve(\"not-json\")\n      } else {\n        var latestKnownSubject = SchemaRegistryFactory.getLatestSubjectFromCache(subject);\n        if (latestKnownSubject === undefined) {\n          // (3.)\n          $scope.createOrEvolve = \"Create new schema\";\n          $scope.showSimpleToast(\"This will be a new Subject\");\n          $scope.allowCreateOrEvolution = true;\n          $scope.aceBackgroundColor = \"rgba(0, 128, 0, 0.04)\";\n          $log.info('Valid schema');\n          deferred.resolve(\"new-schema\")\n        } else {\n          SchemaRegistryFactory.testSchemaCompatibility($scope.text, $scope.newAvroString).then(\n            function success(data) {\n              $log.info(\"Success in testing schema compatibility \" + data);\n              // (4.)\n              $scope.allowCreateOrEvolution = false;\n              $scope.showSimpleToastToTop(\"Schema exists, please select a unique subject name\");\n              $scope.aceBackgroundColor = \"rgba(255, 255, 0, 0.10)\";\n              deferred.resolve(\"non-compatible\")\n            },\n            function failure(data) {\n              $scope.showSimpleToastToTop(\"Failure with - \" + data);\n              deferred.resolve(\"failure\");\n            }\n          );\n        }\n      }\n    }\n\n    return deferred.promise;\n  }\n\n  /**\n   * Update curl to reflect  selected subject + schema\n   */\n  function updateCurl() {\n    //$log.debug(\"Updating curl commands accordingly\");\n    var remoteSubject = \"FILL_IN_SUBJECT\";\n    if (($scope.text !== undefined) && $scope.text.length > 0) {\n      remoteSubject = $scope.text;\n    }\n    if (JSON.stringify($scope.newAvroString)) {\n      var curlPrefix = 'curl -vs --stderr - -XPOST -i -H \"Content-Type: application/vnd.schemaregistry.v1+json\" --data ';\n      $scope.curlCommand =\n        \"\\n\" +\n        \"// Register new schema\\n\" + curlPrefix +\n        \"'\" + '{\"schema\":\"' + JSON.stringify($scope.newAvroString).replace(/\\n/g, \" \").replace(/\\s\\s+/g, ' ').replace(/\"/g, \"\\\\\\\"\") +\n        '\"}' + \"' \" + env.SCHEMA_REGISTRY() + \"/subjects/\" + remoteSubject + \"/versions\";\n    }\n  }\n\n  /**\n   * Private method to register-new-schema\n   */\n  function registerNewSchemaPrivate(newSubject, newAvro) {\n\n    var deferred = $q.defer();\n    SchemaRegistryFactory.registerNewSchema(newSubject, newAvro).then(\n      function success(id) {\n        $log.info(\"Success in registering new schema \" + id);\n        var schemaId = id;\n        $scope.showSimpleToastToTop(\"Schema ID : \" + id);\n        $rootScope.listChanges = true; // trigger a cache re-load\n        $location.path('/cluster/' + $scope.cluster + '/schema/' + newSubject + '/version/latest');\n        deferred.resolve(schemaId);\n      },\n      function error(data, status) {\n        $log.info(\"Error on schema registration : \" + JSON.stringify(data));\n        var errorMessage = data.message;\n        $scope.showSimpleToastToTop(errorMessage);\n        if (status >= 400) {\n          $log.debug(\"Schema registrations is not allowed \" + status + \" \" + data);\n        } else {\n          $log.debug(\"Schema registration failure: \" + JSON.stringify(data));\n        }\n        deferred.reject(errorMessage);\n      });\n\n    return deferred.promise;\n\n  }\n\n  $scope.testCompatibility = function () {\n    return testCompatibility($scope.text, $scope.newAvroString);\n  };\n\n  /**\n   * How to responde to register new schema clicks\n   */\n  $scope.registerNewSchema = function () {\n    var subject = $scope.text;\n    testCompatibility(subject, $scope.newAvroString).then(\n      function success(response) {\n        // no-subject-name | not-json | new-schema | compatible | non-compatible | failure | readonly\n        switch (response) {\n          case \"no-subject-name\":\n          case \"not-json\":\n          case \"not-valid-type\":\n          case \"failure\":\n          case \"non-compatible\":\n          case \"readonly\":\n            $log.debug(\"registerNewSchema - cannot do anything more with [ \" + response + \" ]\");\n            break;\n          case 'new-schema':\n            var schemaString = '';\n            if (typeof $scope.newAvroString !== 'string')\n              schemaString = JSON.stringify($scope.newAvroString);\n            else\n              schemaString = $scope.newAvroString;\n            registerNewSchemaPrivate(subject, schemaString).then(\n              function success(newSchemaId) {\n                $log.info(\"New subject id after posting => \" + newSchemaId);\n              },\n              function failure(data) {\n                $log.error(\"peiler2=>\" + data);\n                $scope.allowCreateOrEvolution = false;\n                $scope.aceBackgroundColor = \"rgba(255, 255, 0, 0.10)\";\n              });\n            break;\n          case 'compatible':\n            $log.info(\"Compatibility [compatible]\");\n            // TODO\n            var latestKnownSubject = SchemaRegistryFactory.getLatestSubjectFromCache(subject);\n            if (latestKnownSubject === undefined) {\n              $log.error(\"This should never happen.\")\n            } else {\n              $log.info(\"Existing schema id = \" + latestKnownSubject.version);\n              registerNewSchemaPrivate(subject, $scope.newAvroString).then(\n                function success(newSchemaId) {\n                  $log.info(\"New subject id after posting => \" + newSchemaId);\n                  if (latestKnownSubject.version === newSchemaId) {\n                    toastFactory.showSimpleToastToTop(\"The schema you posted was same to the existing one\")\n                  }\n                },\n                function failure(data) {\n                  $log.error(\"peiler=>\" + data);\n                  $scope.allowCreateOrEvolution = false;\n                  $scope.aceBackgroundColor = \"rgba(255, 255, 0, 0.10)\";\n                });\n              break;\n            }\n          default:\n            $log.warn(\"Should never come here \" + response);\n        }\n      },\n      function failure(data) {\n        if (data.error_code === 500) {\n          $scope.aceBackgroundColor = \"rgba(255, 255, 0, 0.10)\";\n          toastFactory.showSimpleToastToTop(\"Not a valid avro\");\n        }\n        else {\n          $log.error(\"Could not test compatibilitydasdas\", data);\n        }\n      });\n\n  };\n\n  // $scope.createOrEvolve = \"Create new schema\";\n  // $scope.allowCreateOrEvolution = true;\n  // $scope.aceBackgroundColor = \"rgba(0, 128, 0, 0.04)\";\n\n\n  //   $http(postSchemaRegistration)\n  //   $http.get(env.SCHEMA_REGISTRY() + '/subjects/' + $scope.text + '/versions/latest')\n  //     .success(function (data) {\n  //       $log.info(\"Schema succesfully registered: \" + JSON.stringify(data));\n  //       $location.path('/subjects/' + data.subject + '/version/' + data.version);\n  //     });\n  // }\n\n  // When the 'Ace' of the schema/new is loaded\n  $scope.newSchemaAceLoaded = function (_editor) {\n    $scope.editor = _editor;\n    $scope.editor.$blockScrolling = Infinity;\n    $scope.aceSchemaSession = _editor.getSession(); // we can get data on changes now\n    var lines = $scope.newAvroString.split(\"\\n\").length;\n    // TODO : getScalaFiles($scope.aceString);\n    // Add one extra line for each command > 110 characters\n    angular.forEach($scope.newAvroString.split(\"\\n\"), function (line) {\n      lines = lines + Math.floor(line.length / 110);\n    });\n    if (lines <= 1) {\n      lines = 10;\n    }\n    _editor.setOptions({\n      minLines: lines + 1,\n      maxLines: lines + 1,\n      highlightActiveLine: false\n    });\n    updateCurl();\n  };\n\n  // When the 'Ace' of the schema/new is CHANGED (!)\n  $scope.newSchemaAceChanged = function (_editor) {\n    $scope.editor = _editor;\n    updateCurl();\n\n  };\n\n  // When the 'Ace' of the curl command is loaded\n  $scope.curlCommandAceLoaded = function (_editor) {\n    $scope.editor = _editor;\n    $scope.editor.$blockScrolling = Infinity;\n  };\n\n\n  $scope.newAvroString =\n    angular.toJson(\n      {\n        \"type\": \"record\",\n        \"name\": \"evolution\",\n        \"doc\": \"This is a sample Avro schema to get you started. Please edit\",\n        \"namespace\": \"com.landoop\",\n        \"fields\": [{\"name\": \"name\", \"type\": \"string\"}, {\"name\": \"number1\", \"type\": \"int\"}, {\n          \"name\": \"number2\",\n          \"type\": \"float\"\n        }]\n      }, true);\n\n};\n\nNewSubjectCtrl.$inject = ['$scope', '$route', '$rootScope', '$http', '$log', '$q', '$location', 'UtilsFactory', 'SchemaRegistryFactory', 'toastFactory', 'env']\n\nangularAPP.controller('NewSubjectCtrl', NewSubjectCtrl);\n\n"
  },
  {
    "path": "src/schema-registry/new/new.html",
    "content": "<form name=\"postSchema\" class=\"form-horizontal\" style=\"width: 100%\">\n\n  <!-- Main Card for new subject -->\n  <md-card md-theme-watch=\"\">\n    <md-toolbar class=\"md-hue-2\">\n      <div class=\"md-toolbar-tools\">\n        <h3>\n          <span>New Subject</span>\n        </h3>\n      </div>\n    </md-toolbar>\n    <!--Content: Form-->\n    <md-card-content style=\"padding-bottom: 0px;\">\n      <div layout=\"row\">\n        <md-input-container  flex style=\"margin:20px 0 0;\">\n          <label style=\"color:#43687a;font-weight:bold;font-size:19px;\">Subject Name</label>\n          <input ng-model=\"text\" autofocus placeholder=\"my-new-topic-value\" required>\n            <md-item-template>\n              <span md-highlight-text=\"ctrl.searchText\" md-highlight-flags=\"^i\">{{item.display}}</span>\n            </md-item-template>\n            <div ng-messages=\"postSchema.autocomplete.$error\">\n              <div ng-message=\"required\">This field is required</div>\n            </div>\n          </input>\n        </md-input-container>\n        <div class=\"md-errors-spacer\"></div>\n      </div>\n\n      <div layout=\"row\" layout-align=\"center center\" >\n        <div flex=\"80\" >\n            <b style=\"color:#43687a\" ng-hide=\"curlme\">Schema:</b>\n            <b style=\"color:#43687a\" ng-show=\"curlme\">CURL command:</b>\n        </div>\n        <div flex layout=\"row\" layout-align=\"end center\">\n          <md-switch  ng-model=\"curlme\" ng-show=\"curlme\" style=\"margin:0;color:#43687a\">schema / <b>curl</b></md-switch>\n          <md-switch ng-model=\"curlme\" ng-hide=\"curlme\" style=\"margin:0;color:#43687a\"><b>schema</b> / curl</md-switch>\n        </div>\n      </div>\n\n      <!-- data raw -->\n      <div\n           ng-style=\"{'background-color':aceBackgroundColor}\"\n           ng-hide=\"curlme\" id=\"newavro\"\n           style=\"height:313px;background-color:rgba(0, 128, 0, 0.04)\"\n           name=\"json\"\n           ng-model=\"newAvroString\"\n           ng-readonly=\"false\"\n           ui-ace=\"{\n            mode: 'json',\n            firstLineNumber: 1,\n            onLoad: newSchemaAceLoaded,\n            onChange: newSchemaAceChanged,\n            showPrintMargin:false,\n            }\"\n           valid-json\n      >\n      </div>\n\n      <div ng-show=\"curlme\" id=\"curlcommand\"\n           style=\"height:313px;\"\n           ng-model=\"curlCommand\" ng-readonly=\"true\"\n           ui-ace=\"{\n            mode: 'batchfile',\n            useWrapMode: true,\n            firstLineNumber: 1,\n            onLoad: curlCommandAceLoaded,\n            showPrintMargin:false,\n            onChange: curlCommandAceChanged\n            }\"\n      >\n      </div>\n    </md-card-content>\n\n    <!--Actions-->\n    <md-card-actions style=\"margin-left:16px;\">\n      <i>** This is a sample schema. Please edit! **</i>\n\n      <md-button style=\"float:right;\"\n              ng-disabled=\"postSchema.json.$error.validJson\"\n              ng-hide=\"allowCreateOrEvolution\"\n              ng-click=\"testCompatibility();\"\n              ng-validate=\"noSubjectName\"\n              class=\" md-raised\"\n              type=\"submit\"\n              aria-label=\"Test schema compatibility\">\n          VALIDATE\n      </md-button>\n      <md-button style=\"float:right;\"\n                 ng-disabled=\"postSchema.json.$error.validJson\"\n                 ng-show=\"allowCreateOrEvolution\"\n              ng-click=\"registerNewSchema();\"\n              ng-validate=\"noSubjectName\"\n              class=\" md-raised\"\n              type=\"submit\"\n              aria-label=\"Register new schema\">\n        <i class=\"fa fa-floppy-o ng-scope\" aria-hidden=\"true\"></i>\n        {{createOrEvolve}}\n      </md-button><br />\n    </md-card-actions>\n\n\n  </md-card>\n\n</form>"
  },
  {
    "path": "src/schema-registry/pagination/dirPaginationControlsTemplate.html",
    "content": "<section style=\"margin: 5px 10px 0;\" layout= \"row\" layout-align= \"center\" ng-if= \"1 < pages.length || !autoHide\"\n    class= \"pagination\">\n    <md-button aria-label= \"Previous page\" ng-if= \"boundaryLinks\" ng-disabled= \"pagination.current===1\" ng-click=\n        \"setCurrent(1)\">\n        <ng-md-icon icon= \"first_page\">\n        </ng-md-icon>\n    </md-button>\n    <md-button aria-label= \"First page\" ng-if= \"directionLinks\" ng-disabled= \"pagination.current===1\" ng-click=\n        \"setCurrent(pagination.current - 1)\">\n        <ng-md-icon class= \"fa fa-chevron-left\">\n        </ng-md-icon>\n    </md-button>\n    <md-button ng-repeat= \"pageNumber in pages track by tracker(pageNumber, $index)\" ng-class=\n        \"{'md-primary' : pagination.current==pageNumber}\" ng-disabled= \"pageNumber==='...'\" ng-click= \"setCurrent(pageNumber)\">{{pageNumber}}\n    </md-button>\n    <md-button aria-label= \"Last page\" ng-if= \"directionLinks\" ng-disabled= \"pagination.current===pagination.last\" ng-click=\n        \"setCurrent(pagination.current + 1)\">\n        <ng-md-icon class= \"fa fa-chevron-right\">\n        </ng-md-icon>\n    </md-button>\n    <md-button ng-if= \"boundaryLinks\" ng-disabled= \"pagination.current===pagination.last\" ng-click=\n        \"setCurrent(pagination.last)\">\n        <ng-md-icon icon= \"last_page\">\n        </ng-md-icon>\n    </md-button>\n</section>"
  },
  {
    "path": "src/schema-registry/view/view.controller.js",
    "content": "var angular = require('angular');\nvar angularAPP = angular.module('angularAPP');\nvar ace = require('brace');\nrequire('brace/mode/json');\nrequire('brace/mode/batchfile');\nrequire('brace/theme/chrome');\nrequire('brace/worker/json');\nrequire.context(\"brace/ext/\", false);\n//var Range = ace.acequire('ace/range').Range;\n\n\nvar SubjectsCtrl = function ($rootScope, $scope, $route, $routeParams, $log, $location, $mdDialog, SchemaRegistryFactory, UtilsFactory, toastFactory, Avro4ScalaFactory, env) {\n\n  $log.info(\"Starting schema-registry controller: view ( \" + $routeParams.subject + \"/\" + $routeParams.version + \" )\");\n  $rootScope.listChanges = false;\n  toastFactory.hideToast();\n\n  /**\n   * At start-up - get the entire subject `History`\n   */\n  SchemaRegistryFactory.getSubjectHistory($routeParams.subject).then(\n    function success(data) {\n      $scope.completeSubjectHistory = SchemaRegistryFactory.getSubjectHistoryDiff(data);\n      //$log.warn(\"Diff is:\");\n      //$log.warn(JSON.stringify($scope.completeSubjectHistory));\n    }\n  );\n  $scope.allowSchemaDeletion = env.allowSchemaDeletion();\n  $scope.readonlyMode = env.readonlyMode();\n  $scope.allowTransitiveCompatibilities = env.allowTransitiveCompatibilities();\n\n  $scope.$watch(function () {\n    return $scope.aceString;\n  }, function (a) {\n    $scope.isAvroUpdatedAndCompatible = false;\n  }, true);\n\n  SchemaRegistryFactory.getSubjectConfig($routeParams.subject).then(\n    function success(config) {\n      $scope.compatibilitySelect = config.compatibilityLevel;\n      $scope.existingValue = config.compatibilityLevel;\n    },\n    function errorCallback(response) {\n      $log.error(response);\n    });\n\n  SchemaRegistryFactory.getGlobalConfig().then(\n    function success(config) {\n      $scope.globalConfig = config.compatibilityLevel;\n    },\n    function failure(response) {\n      $log.error(\"Failure with : \" + JSON.stringify(response));\n      $scope.connectionFailure = true;\n    });\n\n\n  /**\n   * At start-up do something more ...\n   */\n  function getSchema(){\n    var promise = SchemaRegistryFactory.getSubjectAtVersion($routeParams.subject, $routeParams.version);\n    promise.then(function (selectedSubject) {\n      $log.info('Success fetching [' + $routeParams.subject + '/' + $routeParams.version + '] with MetaData');\n      $rootScope.subjectObject = selectedSubject;\n\n      $scope.arraySchema = typeof $rootScope.subjectObject.Schema[0] !== 'undefined' ? true : false;\n      $scope.tableWidth = 100 / $scope.subjectObject.Schema.length;\n\n\n      $rootScope.schema = selectedSubject.Schema.fields;\n\n      $scope.aceString = angular.toJson(selectedSubject.Schema, true);\n      $scope.aceStringOriginal = $scope.aceString;\n      $scope.aceReady = true;\n      SchemaRegistryFactory.getSubjectsVersions($routeParams.subject).then(\n        function success(allVersions) {\n          var otherVersions = [];\n          angular.forEach(allVersions, function (version) {\n            if (version !== $rootScope.subjectObject.version) {\n              otherVersions.push(version);\n            }\n          });\n          $scope.otherVersions = otherVersions;\n          $scope.multipleVersionsOn = $scope.otherVersions.length > 0; // TODO remove\n        },\n        function failure(response) {\n          // TODO\n        }\n      )\n    }, function (reason) {\n      $log.error('Failed: ' + reason);\n    }, function (update) {\n      $log.info('Got notification: ' + update);\n    });\n  }\n  if ($routeParams.subject && $routeParams.version) {\n    getSchema();\n  }\n  $scope.$on('$routeChangeSuccess', function () {\n    $scope.cluster = env.getSelectedCluster().NAME;//$routeParams.cluster;\n    $scope.maxHeight = window.innerHeight - 215;\n    if ($scope.maxHeight < 310) {\n      $scope.maxHeight = 310\n    }\n  });\n\n  $scope.updateCompatibility = function (compatibilitySelect) {\n    SchemaRegistryFactory.updateSubjectCompatibility($routeParams.subject, compatibilitySelect).then(\n      function success() {\n        $scope.existingValue = compatibilitySelect;\n        $rootScope.listChanges = true; // trigger a cache re-load\n        $scope.success = true;\n      });\n  };\n\n  $scope.aceString = \"\";\n  $scope.aceStringOriginal = \"\";\n  $scope.multipleVersionsOn = false;\n\n  $scope.isAvroUpdatedAndCompatible = false;\n  $scope.testAvroCompatibility = function () {\n    $log.debug(\"Testing Avro compatibility\");\n    if ($scope.aceString === $scope.aceStringOriginal) {\n      toastFactory.showSimpleToastToTop(\"You have not changed the schema\");\n    } else {\n      if (UtilsFactory.IsJsonString($scope.aceString)) {\n        $scope.aceBackgroundColor = \"rgba(0, 128, 0, 0.04)\";\n        $log.debug(\"Edited schema is a valid json and is a augmented\");\n        SchemaRegistryFactory.testSchemaCompatibility($routeParams.subject, $scope.aceString).then(\n          function success(result) {\n            if (result) {\n              $log.info(\"Schema is compatible\");\n              $scope.aceBackgroundColor = \"rgba(0, 128, 0, 0.04)\";\n              toastFactory.showSimpleToast(\"You can now evolve the schema\");\n              $scope.isAvroUpdatedAndCompatible = true;\n            } else {\n              $scope.aceBackgroundColor = \"rgba(255, 255, 0, 0.10)\";\n              toastFactory.showLongToast(\"This schema is incompatible with the latest version\");\n            }\n          },\n          function failure(data) {\n            if (data.error_code === 500) {\n              $scope.aceBackgroundColor = \"rgba(255, 255, 0, 0.10)\";\n              toastFactory.showSimpleToastToTop(\"Not a valid avro\");\n            }\n            else {\n              $log.error(\"Could not test compatibilitydasdas\", data);\n            }\n          });\n      } else {\n        $scope.aceBackgroundColor = \"rgba(255, 255, 0, 0.10)\";\n        toastFactory.showLongToast(\"Invalid Avro\");\n      }\n    }\n  };\n\n  $scope.evolveAvroSchema = function () {\n    if ($scope.aceString !== $scope.aceStringOriginal &&\n      UtilsFactory.IsJsonString($scope.aceString)) {\n      SchemaRegistryFactory.testSchemaCompatibility($routeParams.subject, $scope.aceString).then(\n        function success(result) {\n          var latestSchema = SchemaRegistryFactory.getLatestSubjectFromCache($routeParams.subject);\n          $log.warn(\"peiler\");\n          $log.warn(latestSchema);\n          var latestID = latestSchema.id;\n          SchemaRegistryFactory.registerNewSchema($routeParams.subject, $scope.aceString).then(\n            function success(schemaId) {\n              $log.info(\"Latest schema ID was : \" + latestID);\n              $log.info(\"New    schema ID is  : \" + schemaId);\n              if (latestID === schemaId) {\n                toastFactory.showSimpleToastToTop(\" Schema is the same as latest \")\n              } else {\n                toastFactory.showSimpleToastToTop(\" Schema evolved to ID: \" + schemaId);\n                $rootScope.$broadcast('newEvolve');\n                $location.path('/cluster/' + $scope.cluster + '/schema/' + $routeParams.subject + '/version/latest');\n                $route.reload();\n              }\n            },\n            function failure(data) {\n            }\n          );\n        },\n        function failure(data) {\n\n        }\n      );\n    } else {\n      $scope.aceBackgroundColor = \"rgba(255, 255, 0, 0.10)\";\n      toastFactory.showLongToast(\"Invalid Avro\");\n    }\n  };\n\n  $scope.isAvroAceEditable = false;\n  $scope.aceBackgroundColor = \"white\";\n  $scope.cancelEditor = function () {\n    $scope.selectedIndex = 0;\n    $log.info(\"Canceling editor\");\n    $scope.maxHeight = $scope.maxHeight + 64;\n    $scope.form.json.$error.validJson = false;\n    $scope.aceBackgroundColor = \"white\";\n    toastFactory.hideToast();\n    $log.info(\"Setting \" + $scope.aceStringOriginal);\n    $scope.isAvroAceEditable = false;\n    $scope.isAvroUpdatedAndCompatible = false;\n    $scope.aceString = $scope.aceStringOriginal;\n    $scope.aceSchemaSession.setValue($scope.aceString);\n\n  };\n\n  $scope.toggleEditor = function () {\n    $scope.isAvroAceEditable = !$scope.isAvroAceEditable;\n    if ($scope.isAvroAceEditable) {\n      $scope.maxHeight = $scope.maxHeight - 64;\n      toastFactory.showLongToast(\"You can now edit the schema\");\n      $scope.aceBackgroundColor = \"rgba(0, 128, 0, 0.04)\";\n    } else {\n      $scope.aceBackgroundColor = \"white\";\n      toastFactory.hideToast();\n    }\n  };\n\n  /************************* md-table ***********************/\n  $scope.tableOptions = {\n    rowSelection: false,\n    multiSelect: false,\n    autoSelect: false,\n    decapitate: false,\n    largeEditDialog: false,\n    boundaryLinks: false,\n    limitSelect: true,\n    pageSelect: true\n  };\n\n  $scope.query = {\n    order: 'name',\n    limit: 100,\n    page: 1\n  };\n\n  // This one is called each time - the user clicks on an md-table header (applies sorting)\n  $scope.logOrder = function (a) {\n    // $log.info(\"Ordering event \" + a);\n    sortSchema(a);\n  };\n\n  function sortSchema(type) {\n    var reverse = 1;\n    if (type.indexOf('-') === 0) {\n      // remove the - symbol\n      type = type.substring(1, type.length);\n      reverse = -1;\n    }\n    // $log.info(type + \" \" + reverse);\n    $scope.schema = UtilsFactory.sortByKey($scope.schema, type, reverse);\n  }\n\n  function getScalaFiles(xx) {\n    var scala = Avro4ScalaFactory.getScalaFiles(xx);\n    $log.error(\"SCALA-> \" + scala);\n  }\n\n  $scope.otherTabSelected = function () {\n    $scope.hideEdit = true;\n  };\n\n  /************************* md-table ***********************/\n  $scope.editor;\n\n  // When the 'Ace' schema/view is loaded\n  $scope.viewSchemaAceLoaded = function (_editor) {\n    // $log.info(\"me\");\n    $scope.editor = _editor;\n    $scope.editor.$blockScrolling = Infinity;\n    $scope.aceSchemaSession = _editor.getSession(); // we can get data on changes now\n    $scope.editor.getSession().setUseWrapMode(true);\n    $scope.editor.getSession().setBehavioursEnabled(false);\n\n\n    var lines = $scope.aceString.split(\"\\n\").length;\n    // TODO : getScalaFiles($scope.aceString);\n    // Add one extra line for each command > 110 characters\n    angular.forEach($scope.aceString.split(\"\\n\"), function (line) {\n      lines = lines + Math.floor(line.length / 110);\n    });\n    if (lines <= 1) {\n      lines = 10;\n    }\n    // $log.warn(\"Lines loaded for curl create connector -> \" + lines + \"\\n\" + $scope.curlCommand);\n    _editor.setOptions({\n      minLines: lines,\n      maxLines: lines,\n      highlightActiveLine: false\n    });\n    // var _renderer = _editor.renderer;\n    // _renderer.animatedScroll = false;\n  };\n\n  // When the 'Ace' schema/view is CHANGED\n  $scope.viewSchemaAceChanged = function (_editor) {\n    $scope.editor = _editor;\n    var aceString = $scope.aceSchemaSession.getDocument().getValue();\n    // $log.warn(\"LOADED ....\");\n    // Highlight differences\n    //TODO\n    //$scope.aceSchemaSession.addMarker(new Range(2, 5, 4, 16), \"ace_diff_new_line\", \"fullLine\");\n    $scope.aceString = aceString;\n  };\n\n  $scope.showTree = function (keyOrValue) {\n    return !(angular.isNumber(keyOrValue) || angular.isString(keyOrValue) || (keyOrValue === null));\n  }\n\n  $scope.askForConfirmToDelete = function (version){\n      $scope.versionToBeDeleted = version;\n      $scope.showDeleteConfirmation = true;\n  }\n\n  $scope.deleteSchema = function (versionToBeDeleted) {\n    $scope.showDeleteConfirmation =false;\n\n    var subjectName = $routeParams.subject\n    if(versionToBeDeleted) {\n     SchemaRegistryFactory.deleteVersionOfSubject(subjectName, versionToBeDeleted).then(function(){\n        $rootScope.listChanges = true; \n        toastFactory.showLongToast(subjectName + \" version \" + versionToBeDeleted + \" deleted successfully\");\n        getSchema()\n        $location.path('/cluster/'+ $scope.cluster + '/schema/' + subjectName + '/version/latest')\n      })      \n    }\n    else {\n      SchemaRegistryFactory.deleteSubject(subjectName).then(function(){\n        $rootScope.listChanges = true; \n        toastFactory.showLongToast(subjectName +  \"deleted successfully\");\n        $location.path('/cluster/'+ $scope.cluster)\n\n      })\n\n    }\n  }\n\n};\n\nSubjectsCtrl.$inject = ['$rootScope', '$scope', '$route', '$routeParams', '$log', '$location', '$mdDialog', 'SchemaRegistryFactory', 'UtilsFactory', 'toastFactory', 'Avro4ScalaFactory', 'env']\n\nangularAPP.controller('SubjectsCtrl', SubjectsCtrl); //end of controller\n\n// Useful for browsing through different versions of a schema\nangularAPP.directive('clickLink', ['$location', function ($location) {\n  return {\n    link: function (scope, element, attrs) {\n      element.on('click', function () {\n        scope.$apply(function () {\n          $location.path(attrs.clickLink);\n        });\n      });\n    }\n  }\n\n}]);\n"
  },
  {
    "path": "src/schema-registry/view/view.html",
    "content": "<md-card ng-show=\"subjectObject\">\n\n  <md-toolbar class=\"md-hue-2\">\n\n    <!--<div class=\"md-toolbar-tools\">-->\n    <div layout=\"row\" layout-xs=\"column\" layout-align=\"center center\" layout-wrap>\n      <div flex>\n        <h3 class=\"md-toolbar-tools\" style=\"padding:0px;\" hide-xs>\n          <div layout=\"row\" style=\"height: 64px;\">\n            <md-icon class=\"md-avatar-icon\" md-svg-icon=\"src/assets/icons/avro.svg\"\n                     style=\"height: 40px;width: 40px;padding: 5px;background-color: rgba(255,255,255,0.87);border-radius: 60px;margin-left: 10px;margin-right: 10px;\">\n            </md-icon>\n            <!--<md-tooltip md-direction=\"top\" style=\"margin-top:15px;margin-left:-20px\">-->\n            <!--Schema [{{subjectObject.subjectName}}]-->\n            <!--</md-tooltip>-->\n            <div layout=\"column\" style=\"padding-top: 12px;padding-bottom: 12px;\">\n\n              <div flex>{{subjectObject.subjectName}}</div>\n              <div flex>\n                  <span>\n                    <p class=\"md-caption\"\n                       style=\"margin-top:10px;margin-bottom:0px;\">\n                      SCHEMA ID: {{subjectObject.id}}\n                    </p>\n                  </span>\n              </div>\n            </div>\n          </div>\n        </h3>\n        <!--Mobile version only-->\n        <h3 class=\"md-toolbar-tools\" style=\"margin-top:10px;text-align:center;\" hide-gt-xs>\n          <div layout=\"column\">\n            <div flex><span style=\"color: black;\">{{subjectObject.subjectName}}</span></div>\n            <div flex>\n                  <span>\n                    <p class=\"md-caption\"\n                       style=\"margin-top:10px;margin-bottom:0px; text-align:center;\">\n                      SCHEMA ID: {{subjectObject.id}}\n                    </p>\n                  </span>\n            </div>\n          </div>\n        </h3>\n        <span flex></span>\n      </div>\n\n      <div flex-gt-sm=\"nogrow\" flex>\n        <md-button ng-hide=\"multipleVersionsOn\"\n                   md-no-ink\n                   style=\"color: white; background-color: rgb(55, 70, 79);box-shadow:0px;cursor:text;\"\n                   disabled>\n          version {{subjectObject.version}}\n        </md-button>\n\n        <md-menu d-position-mode=\"target-right target\" ng-show=\"multipleVersionsOn\">\n          <md-button style=\"color: white; background-color: rgba(139, 195, 74,0.9)\" class=\"md-raised\" ng-click=\"$mdOpenMenu($event)\">\n            version {{subjectObject.version}}\n            <i class=\"fa fa-caret-down\" aria-hidden=\"true\"></i>\n          </md-button>\n          <md-menu-content width=\"3\">\n            <md-menu-item ng-repeat=\"version in otherVersions | orderBy:'version'\">\n              <md-button click-link=\"cluster/{{cluster}}/schema/{{subjectObject.subjectName}}/version/{{version}}\">\n                <span md-menu-align-target=\"\">version</span> {{version}}\n              </md-button>\n            </md-menu-item>\n          </md-menu-content>\n        </md-menu>\n      </div>\n    </div>\n    <!--</div>-->\n    <div class=\"buttonGroup\" ng-hide=\"hideEdit\" ng-if=\"aceReady && !showDeleteConfirmation\"  >\n\n        <!-- When in non-editable state, display the EDIT button -->\n        <md-button ng-show=\"!isAvroAceEditable\" ng-click=\"toggleEditor();\" ng-if=\"!readonlyMode\"\n           aria-label=\"EDIT\"\n           aria-hidden=\"false\">\n          <i class=\"fa fa-pencil-square-o ng-scope\" aria-hidden=\"true\"></i>\n            EDIT\n        </md-button>\n        <!-- When in edit-state, display the CANCEL button -->\n        <md-button ng-show=\"isAvroAceEditable && !readonlyMode\" ng-click=\"cancelEditor();\"\n            type=\"button\" aria-label=\"CANCEL\"\n           aria-hidden=\"false\">\n          <i class=\"fa fa-ban ng-scope\" aria-hidden=\"true\"></i>\n            CANCEL\n        </md-button>\n        <md-menu d-position-mode=\"target-right target\" ng-if=\"!isAvroAceEditable && allowSchemaDeletion && !readonlyMode\">\n          <md-button ng-click=\"$mdOpenMenu($event)\">\n              <i class=\"fa fa-trash\" aria-hidden=\"true\"></i>\n            DELETE\n          </md-button>\n          <md-menu-content width=\"3\">\n            <md-menu-item ng-if=\"multipleVersionsOn\">\n              <md-button ng-click=\"askForConfirmToDelete('latest')\">\n                <span md-menu-align-target=\"\">Delete Latest Version</span>\n              </md-button>\n            </md-menu-item>\n            <md-menu-item ng-if=\"multipleVersionsOn\">\n              <md-button ng-click=\"askForConfirmToDelete(subjectObject.version)\">\n                <span md-menu-align-target=\"\"> Delete Selected Version ({{subjectObject.version}})</span>\n              </md-button>\n            </md-menu-item>\n            <md-menu-item>\n              <md-button ng-click=\"askForConfirmToDelete()\">\n                <span md-menu-align-target=\"\">Delete Subject</span>\n              </md-button>\n            </md-menu-item>\n          </md-menu-content>\n        </md-menu>\n    </div>\n  </md-toolbar>\n  <md-content flex layout-padding style=\"padding: 2px;\">\n      <div  flex-gt-sm=\"nogrow\"  style=\"background-color: rgba(0, 128, 0, 0.04);padding:20px;\" flex ng-show=\"showDeleteConfirmation\">\n          Schema <b>{{subjectObject.subjectName}}</b> <span ng-if=\"versionToBeDeleted\">version: <b>{{versionToBeDeleted}}</b></span> will be <span class=\"text-danger\">deleted</span>.\n            <div style=\"position:absolute;top:5px;right:0;\">\n                <md-button class=\"btn-danger\" type=\"button\" ng-click=\"deleteSchema(versionToBeDeleted)\">\n                    <i class=\"fa fa-trash\" aria-hidden=\"true\"></i>\n                DELETE\n                </md-button>\n                <md-button type=\"button\" ng-click=\"showDeleteConfirmation=false;\">\n                    <i class=\"fa fa fa-ban ng-scope\" aria-hidden=\"true\"></i>\n                CANCEL</md-button>\n\n            </div>\n\n        </div>\n    <md-tabs md-dynamic-height md-border-bottom style=\"padding:0\">\n      <md-tab md-on-select=\"hideEdit = false;\">\n        <md-tab-label>\n          Schema\n          <!--<i class=\"fa fa-file-text-o\" style=\"padding-right:10px;\" aria-hidden=\"true\"></i> Schema-->\n        </md-tab-label>\n        <md-tab-body>\n          <md-content class=\"md-padding\" style=\"max-height:{{maxHeight}}px\">\n            <!--put avro here-->\n              <form name=\"form\" class=\"form\">\n                <div ng-if=\"aceReady\">\n                  <div style=\"color:red;\" ng-show=\"form.json.$error.validJson\">- Syntax Error</div>\n\n                    <div id=\"left\"\n                         ng-class=\"{'has-error':form.json.$invalid, 'has-success':!form.json.$invalid}\"\n                         ng-model=\"aceString\"\n                         ng-readonly=\"!isAvroAceEditable\"\n                         ng-style=\"{'background-color':aceBackgroundColor}\"\n                         name=\"json\"\n                         ui-ace=\"{ mode: 'json', firstLineNumber: 1,  onLoad: viewSchemaAceLoaded, onChange: viewSchemaAceChanged,  blockScrolling: Infinity ,  showPrintMargin:false}\"\n                         valid-json\n                    ></div>\n                </div>\n              </form>\n          </md-content><!--<div ng-show=\"form.json.$invalid && isAvroAceEditable\" style=\"color:red;\">- Invalid syntax</div>-->\n          <!-- When in edit-state, display the TEST button -->\n          <md-button style=\"float: right; margin-right: 32px;\"\n                     class=\"md-raised\"\n                     ng-disabled=\"form.json.$error.validJson\"\n                     ng-show=\"isAvroAceEditable && !isAvroUpdatedAndCompatible && !hideEdit\" ng-click=\"testAvroCompatibility();\"\n                     aria-label=\"TEST\"\n                     aria-hidden=\"false\">\n            VALIDATE\n          </md-button>\n          <!-- When in edit-state, and Avro is Updated and Compatible display the UPDATE button -->\n          <md-button ng-show=\"isAvroAceEditable && isAvroUpdatedAndCompatible && !hideEdit\" ng-click=\"evolveAvroSchema();\"\n                     style=\"float: right; margin-right: 32px;\"\n                     class=\"md-raised\"\n                     type=\"button\" aria-label=\"EVOLVE SCHEMA\"\n                     aria-hidden=\"false\">\n            <i class=\"fa fa-floppy-o ng-scope\" aria-hidden=\"true\"></i>\n            EVOLVE SCHEMA\n          </md-button>\n        </md-tab-body>\n      </md-tab>\n\n      <md-tab  md-on-select=\"otherTabSelected()\" ng-if=\"aceReady && aceString.length > 10\">\n        <md-tab-label>\n          Info\n          <!--<i class=\"fa fa-table\" style=\"padding-right:10px;\" aria-hidden=\"true\"></i> Info-->\n        </md-tab-label>\n        <md-tab-body>\n          <md-content class=\"md-padding\">\n            <!-- Nice header -->\n            <md-card style=\"box-shadow:none;\" ng-hide=\"arraySchema\">\n              <md-card-header style=\"padding:10px\">\n                <md-card-avatar>\n                  <md-icon class=\"md-avatar-icon\" md-svg-icon=\"src/assets/icons/avro.svg\"\n                           style=\"height: 32px;width: 32px;margin-top: 10px;margin-left: 5px;padding:0;background-color:white\"></md-icon>\n                </md-card-avatar>\n                <md-card-header-text>\n                  <span class=\"md-title\"><b>type:</b> {{subjectObject.Schema.type}}</span>\n                  <span class=\"md-title\"><b>name:</b> {{subjectObject.Schema.name}}</span>\n                  <span class=\"md-title\"><b>namespace:</b> {{subjectObject.Schema.namespace}}</span>\n                </md-card-header-text>\n              </md-card-header>\n              <md-card-content ng-show=\"subjectObject.Schema.doc != undefined\" style=\"padding-bottom:5px\">\n                <p class=\"md-card-image md-caption ng-binding\">{{subjectObject.Schema.doc}}</p>\n              </md-card-content>\n            </md-card>\n\n            <!-- 3a. data table -->\n\n            <md-table-container ng-hide=\"arraySchema\">\n              <table md-table md-row-select=\"optionsTable.rowSelection\" multiple=\"{{optionsTable.multiSelect}}\"\n                     ng-model=\"selected\" md-progress=\"promise\">\n                <thead ng-if=\"!optionsTable.decapitate\" md-head md-order=\"query.order\" md-on-reorder=\"logOrder\">\n                <tr md-row>\n                  <th md-column md-order-by=\"name\"><span>Name</span></th>\n                  <th md-column md-order-by=\"type\"><span>Type</span></th>\n                  <th md-column md-order-by=\"default\"><span>Default</span></th>\n                  <th md-column md-order-by=\"doc\"><span>Documentation</span></th>\n                </tr>\n                </thead>\n                <tbody md-body>\n                <tr md-row md-select=\"selected\" md-select-id=\"name\" ng-repeat=\"s in schema\">\n                  <td md-cell>{{s.name}}</td>\n                  <td md-cell>\n                    <json-tree ng-show=\"showTree(s.type)\" object=\"s.type\" root-name=\"'Type'\"></json-tree>\n                    <div ng-hide=\"showTree(s.type)\">{{s.type}}</div>\n                  </td>\n                  <td md-cell>{{s.default}}</td>\n                  <td md-cell class=\"md-card-image md-caption\">{{s.doc}}</td>\n                </tr>\n                </tbody>\n              </table>\n            </md-table-container>\n            <div ng-repeat=\"schemas in subjectObject.Schema\" ng-show=\"arraySchema\">\n              <md-card style=\"box-shadow:none;\">\n                <md-card-header style=\"padding:10px\">\n                  <md-card-avatar>\n                    <md-icon class=\"md-avatar-icon\" md-svg-icon=\"src/assets/icons/avro.svg\"\n                             style=\"height: 32px;width: 32px;margin-top: 10px;margin-left: 5px;padding:0;background-color:white\"></md-icon>\n                  </md-card-avatar>\n                  <md-card-header-text>\n                    <span class=\"md-title\"><b>type:</b> {{schemas.type}}</span>\n                    <span class=\"md-title\"><b>name:</b> {{schemas.name}}</span>\n                    <span class=\"md-title\"><b>namespace:</b> {{schemas.namespace}}</span>\n                  </md-card-header-text>\n                </md-card-header>\n                <md-card-content ng-show=\"subjectObject.Schema.doc != undefined\" style=\"padding-bottom:5px\">\n                  <p class=\"md-card-image md-caption ng-binding\">{{subjectObject.Schema.doc}}</p>\n                </md-card-content>\n              </md-card>\n              <md-table-container>\n                <table md-table md-row-select=\"optionsTable.rowSelection\" multiple=\"{{optionsTable.multiSelect}}\"\n                       ng-model=\"selected\" md-progress=\"promise\"\n                >\n                  <thead ng-if=\"!optionsTable.decapitate\" md-head md-order=\"query.order\" md-on-reorder=\"logOrder\">\n                  <tr md-row>\n                    <th md-column md-order-by=\"name\"><span>Name</span></th>\n                    <th md-column md-order-by=\"type\"><span>Type</span></th>\n                    <th md-column md-order-by=\"default\"><span>Default</span></th>\n                    <th md-column md-order-by=\"doc\"><span>Documentation</span></th>\n                  </tr>\n                  </thead>\n                  <tbody md-body>\n                  <tr md-row md-select=\"selected\" md-select-id=\"name\" ng-repeat=\"s in schemas.fields\">\n                    <td md-cell>{{s.name}}</td>\n                    <td md-cell>\n                      <json-tree ng-show=\"showTree(s.type)\" object=\"s.type\" root-name=\"'Type'\"></json-tree>\n                      <div ng-hide=\"showTree(s.type)\">{{s.type}}</div>\n                    </td>\n                    <td md-cell>{{s.default}}</td>\n                    <td md-cell class=\"md-card-image md-caption\">{{s.doc}}</td>\n                  </tr>\n                  </tbody>\n                </table>\n              </md-table-container>\n              <div class=\"seperator\" ng-hide=\"$index ==  subjectObject.Schema.length -1\"></div>\n            </div>\n\n          </md-content>\n        </md-tab-body>\n      </md-tab>\n      <md-tab md-on-select=\"hideEdit = true;\" ng-if=\"!readonlyMode\">\n        <md-tab-label>\n          Config\n          <!--<i class=\"fa fa-file-text-o\" style=\"padding-right:10px;\" aria-hidden=\"true\"></i> Schema-->\n        </md-tab-label>\n        <md-tab-body>\n          <md-content class=\"md-padding\">\n            <!--put avro here-->\n            <form  ng-cloak>\n              <p><span  ng-if=\"existingValue\">Current compatibility for <b>{{subjectObject.subjectName}}</b>  : <span class=\"radioValue\">{{ existingValue }}</span><br /></span>\n              <span  ng-if=\"!existingValue\">Schema <b>{{subjectObject.subjectName}}</b> uses the global compatibility level [{{globalConfig}}]<br /></span>\n              Change compatibility level to:\n              </p>\n              <md-radio-group ng-model=\"compatibilitySelect\"  ng-change='success=false'>\n                <md-radio-button value=\"NONE\">NONE</md-radio-button>\n                <md-radio-button value=\"FULL\"> FULL </md-radio-button>\n                <md-radio-button value=\"FORWARD\">FORWARD</md-radio-button>\n                <md-radio-button value=\"BACKWARD\">BACKWARD</md-radio-button>\n                <md-radio-button ng-if=\"allowTransitiveCompatibilities\" value=\"FULL_TRANSITIVE\">FULL TRANSITIVE</md-radio-button>\n                <md-radio-button ng-if=\"allowTransitiveCompatibilities\" value=\"FORWARD_TRANSITIVE\">FORWARD TRANSITIVE</md-radio-button>\n                <md-radio-button ng-if=\"allowTransitiveCompatibilities\" value=\"BACKWARD_TRANSITIVE\">BACKWARD TRANSITIVE</md-radio-button>\n              </md-radio-group>\n              <md-button class=\"md-raised\" ng-disabled=\"!compatibilitySelect\" ng-click=\"updateCompatibility(compatibilitySelect)\" type=\"button\">Update</md-button>\n            </form>\n            <div ng-show = \"success\">\n              <span style=\"color:green\">Successfully changed compatibility level to {{compatibilitySelect}} </span>\n            </div>\n          </md-content>\n        </md-tab-body>\n      </md-tab>\n      <md-tab  md-on-select=\"otherTabSelected()\" ng-if=\"completeSubjectHistory.length > 1\">\n        <md-tab-label>\n          <i class=\"\" style=\"padding-right:10px;\" aria-hidden=\"true\"></i> History\n        </md-tab-label>\n        <md-tab-body>\n          <md-content class=\"md-padding\">\n            <div ng-show=\"x.version != 1\" ng-repeat=\"x in completeSubjectHistory | reverse\">\n              <!--<pre semantic-diff left-obj=\"x.left.text | json\" right-obj=\"x.right.text | json\"></pre>-->\n              <h5>Version {{x.version}} <span style=\"font-weight: 200;\">(Schema ID: {{x.id}})</span></h5>\n              <pre\n                      style=\"background-color:white;font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;\"\n                      line-diff left-obj=\"x.previous | json\" right-obj=\"x.current | json\"></pre>\n            </div>\n            <h5>Version 1 <span\n                    style=\"font-weight: 200;\">(Schema ID: {{completeSubjectHistory[0].id}})</span></h5>\n            <pre\n                    style=\"background-color:white;font: 12px/normal 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;\"\n                    line-diff\n                    left-obj=\"''\"\n                    right-obj=\"completeSubjectHistory[0].current | json\"></pre>\n          </md-content>\n        </md-tab-body>\n      </md-tab>\n    </md-tabs>\n  </md-content>\n  <!--old code ends here-->\n</md-card>\n"
  },
  {
    "path": "webpack.config.js",
    "content": "const path = require(\"path\");\nconst webpack = require(\"webpack\");\nconst HtmlWebpackPlugin = require(\"html-webpack-plugin\");\nconst ExtractTextPlugin = require(\"extract-text-webpack-plugin\");\nconst CopyWebpackPlugin = require(\"copy-webpack-plugin\");\nconst CleanWebpackPlugin = require('clean-webpack-plugin');\n\n\nconst ENV = process.env.NODE_ENV || 'development';\nconst isProd = ENV === 'production';\n\nconsole.log('Building for ' + ENV);\n\nconst config = {\n    watch: !isProd,\n    devtool: isProd ? \"cheap-source-map\" : \"cheap-module-source-map\",\n    entry: {\n        app: \"./src/app.js\"\n    },\n    output: {\n        filename: \"js/[name].[hash].bundle.js\",\n        path: path.resolve(__dirname, \"dist\"),\n        publicPath: \"\"\n    },\n    module: {\n        rules: [\n            {\n                test: /\\.(js|jsx)$/,\n                loader: \"babel-loader\",\n                exclude: /node_modules/,\n                query: {\n                    plugins: ['transform-decorators-legacy',\n                        'transform-runtime',\n                        'transform-object-rest-spread',\n                        'transform-class-properties'],\n                    presets: [['es2015', { modules: false }], 'stage-1']\n                }\n            },\n            {\n                test: /\\.css$/,\n                use: ExtractTextPlugin.extract({\n                    fallback: \"style-loader\",\n                    use: \"css-loader\"\n                })\n            },\n\n            {\n                test: /\\.woff(2)?(\\?v=[0-9]\\.[0-9]\\.[0-9])?$/,\n                loader: \"url-loader?limit=10000&mimetype=application/font-woff&outputPath=&publicPath=../../\"\n            },\n            {\n                test: /\\.(ttf|eot|svg)(\\?v=[0-9]\\.[0-9]\\.[0-9])?$/,\n                loader: \"file-loader\"\n            },\n            {\n                test: /\\.html$/,\n                loader: \"html-loader\"\n            }\n        ]\n    },\n    plugins: [\n        new ExtractTextPlugin({\n            filename: \"assets/css/[name].[contenthash].css\"\n        }),\n        new webpack.optimize.CommonsChunkPlugin({\n            name: \"vendor\",\n            minChunks: function (module) {\n                return module.context && module.context.indexOf(\"node_modules\") !== -1;\n            }\n        }),\n        new webpack.optimize.CommonsChunkPlugin({\n            name: \"manifest\"\n        }),\n        new HtmlWebpackPlugin({ template: \"./src/index.html\" }),\n        new CopyWebpackPlugin([{\n            from: __dirname + '/src/assets',\n            to: path.resolve(__dirname, \"dist/src/assets\")\n        }]),\n        new CopyWebpackPlugin([{\n            from: __dirname + '/env.js',\n            to: path.resolve(__dirname, \"dist/\")\n        }]),\n        new webpack.HotModuleReplacementPlugin()\n    ],\n    resolve: {\n        alias: {\n        }\n    },\n    devServer: {\n        host: \"localhost\",\n        port: \"8080\",\n        contentBase: path.resolve(__dirname, \"dist\"),\n        //compress: true,\n        historyApiFallback: true,\n        hot: true,\n        inline: true,\n        https: false,\n        noInfo: true\n    }\n};\n\nif (isProd) {\n    config.plugins.push(\n        new CleanWebpackPlugin(['dist']),\n        new webpack.optimize.UglifyJsPlugin({\n        compress: {\n            warnings: false,\n            screw_ie8: true,\n            conditionals: true,\n            unused: true,\n            comparisons: true,\n            sequences: true,\n            dead_code: true,\n            evaluate: true,\n            join_vars: true,\n            if_return: true\n        },\n        output: {\n            comments: false\n        }\n    }))\n}\n\nmodule.exports = config;"
  }
]