Repository: ambari
Updated Branches:
  refs/heads/trunk 08763a77f -> 5dbb43e7f


AMBARI-18247 Capacity scheduler's dependent config suggestion is 
incomprehensible (zhewang)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/5dbb43e7
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/5dbb43e7
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/5dbb43e7

Branch: refs/heads/trunk
Commit: 5dbb43e7ff9fedf9b35718a1980ec70fbf7b0cd2
Parents: 08763a7
Author: Zhe (Joe) Wang <[email protected]>
Authored: Thu Aug 25 15:00:21 2016 -0700
Committer: Zhe (Joe) Wang <[email protected]>
Committed: Thu Aug 25 15:00:21 2016 -0700

----------------------------------------------------------------------
 .../common/configs/config_recommendations.js    |  20 +-
 .../modal_popups/dependent_configs_list.hbs     |  29 +-
 ambari-web/app/utils/config.js                  |   4 +-
 ambari-web/config.coffee                        |   3 +
 ambari-web/karma.conf.js                        |   2 +
 .../configs/config_recommendations_test.js      |  13 +-
 ambari-web/vendor/scripts/difflib.js            | 413 +++++++++++++++++++
 ambari-web/vendor/scripts/diffview.js           | 172 ++++++++
 ambari-web/vendor/styles/diffview.css           |  84 ++++
 9 files changed, 718 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/5dbb43e7/ambari-web/app/mixins/common/configs/config_recommendations.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/mixins/common/configs/config_recommendations.js 
b/ambari-web/app/mixins/common/configs/config_recommendations.js
index 398cf55..c86aebb 100644
--- a/ambari-web/app/mixins/common/configs/config_recommendations.js
+++ b/ambari-web/app/mixins/common/configs/config_recommendations.js
@@ -96,6 +96,18 @@ App.ConfigRecommendations = Em.Mixin.create({
     Em.assert('name and fileName should be defined', name && fileName);
     var site = App.config.getConfigTagFromFileName(fileName);
     var service = App.config.get('serviceByConfigTypeMap')[site];
+    var trimAndSort = function (value) {
+      if (value == null) {
+        return [];
+      }
+      var values = value.split("\n").filter(function (item) {
+        return item != "";
+      }).sort().join("\n");
+      return difflib.stringAsLines(values);
+    };
+    var initialValues = trimAndSort(initialValue);
+    var recommendedValues = trimAndSort(recommendedValue);
+
     var recommendation = {
       saveRecommended: true,
       saveRecommendedDefault: true,
@@ -112,7 +124,13 @@ App.ConfigRecommendations = Em.Mixin.create({
       allowChangeGroup: false,//TODO groupName!= "Default" && 
(service.get('serviceName') != this.get('selectedService.serviceName'))
       //TODO&& (App.ServiceConfigGroup.find().filterProperty('serviceName', 
service.get('serviceName')).length > 1), //TODO
       serviceDisplayName: service.get('displayName'),
-      recommendedValue: recommendedValue
+      recommendedValue: recommendedValue,
+
+      diff: new Handlebars.SafeString(diffview.buildView({
+        baseTextLines: initialValues,
+        newTextLines: recommendedValues,
+        opcodes: new difflib.SequenceMatcher(initialValues, 
recommendedValues).get_opcodes()
+      }).outerHTML)
     };
     this.get('recommendations').pushObject(recommendation);
     return recommendation;

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dbb43e7/ambari-web/app/templates/common/modal_popups/dependent_configs_list.hbs
----------------------------------------------------------------------
diff --git 
a/ambari-web/app/templates/common/modal_popups/dependent_configs_list.hbs 
b/ambari-web/app/templates/common/modal_popups/dependent_configs_list.hbs
index 0fe073c..18dbe99 100644
--- a/ambari-web/app/templates/common/modal_popups/dependent_configs_list.hbs
+++ b/ambari-web/app/templates/common/modal_popups/dependent_configs_list.hbs
@@ -19,7 +19,7 @@
 <div class="alert alert-warning">
   {{t popup.dependent.configs.title}}
 </div>
-<div id="config-dependencies" class="limited-height-2">
+<span id="config-dependencies" class="limited-height-2">
   <table class="table table-striped">
     <thead>
     <tr>
@@ -28,8 +28,14 @@
       <th>{{t common.service}}</th>
       <th>{{t common.configGroup}}</th>
       <th>{{t common.fileName}}</th>
-      <th>{{t popup.dependent.configs.table.currentValue}}</th>
-      <th>{{t popup.dependent.configs.table.recommendedValue}}</th>
+      <th class="row-fliud">
+          <div class="span6">
+            {{t popup.dependent.configs.table.currentValue}}
+          </div>
+          <div class="span6">
+            {{t popup.dependent.configs.table.recommendedValue}}
+          </div>
+      </th>
     </tr>
     </thead>
     <tbody>
@@ -45,19 +51,10 @@
           </a></span>
         </td>
         <td 
class="config-dependency-filename">{{recommendation.propertyFileName}}</td>
-        <td class="config-dependency-value">
-          {{#if recommendation.notDefined}}
-            <i>{{t popup.dependent.configs.table.not.defined}}</i>
-          {{else}}
-            {{recommendation.initialValue}}
-          {{/if}}
-        </td>
-        <td class="config-dependency-recommended-value">
-          {{#if recommendation.isDeleted}}
-            <i>{{t common.removed}}</i>
-          {{else}}
-            {{recommendation.recommendedValue}}
-          {{/if}}
+        <td>
+          <div>
+            {{recommendation.diff}}
+          </div>
         </td>
       </tr>
     {{/each}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dbb43e7/ambari-web/app/utils/config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/config.js b/ambari-web/app/utils/config.js
index 7e1f5b8..ae09b82 100644
--- a/ambari-web/app/utils/config.js
+++ b/ambari-web/app/utils/config.js
@@ -773,8 +773,8 @@ App.config = Em.Object.create({
     return configs.sort(function(a, b) {
       if (Em.get(a, 'index') > Em.get(b, 'index')) return 1;
       if (Em.get(a, 'index') < Em.get(b, 'index')) return -1;
-      if (Em.get(a, 'name') > Em.get(b, 'index')) return 1;
-      if (Em.get(a, 'name') < Em.get(b, 'index')) return -1;
+      if (Em.get(a, 'name') > Em.get(b, 'name')) return 1;
+      if (Em.get(a, 'name') < Em.get(b, 'name')) return -1;
       return 0;
     });
   },

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dbb43e7/ambari-web/config.coffee
----------------------------------------------------------------------
diff --git a/ambari-web/config.coffee b/ambari-web/config.coffee
index 4a29e73..6a3f5ef 100644
--- a/ambari-web/config.coffee
+++ b/ambari-web/config.coffee
@@ -60,6 +60,8 @@ exports.config =
           'vendor/scripts/jquery.sticky-kit.js',
           'vendor/scripts/underscore.js',
           'vendor/scripts/backbone.js',
+          'vendor/scripts/difflib.js',
+          'vendor/scripts/diffview.js',
           'vendor/scripts/visualsearch.js',
           'vendor/scripts/moment.min.js',
           'vendor/scripts/moment-timezone-with-data-2010-2020.js',
@@ -88,6 +90,7 @@ exports.config =
           'vendor/styles/bootstrap-checkbox.css',
           'vendor/styles/bootstrap-slider.min.css',
           'vendor/styles/bootstrap-switch.min.css',
+          'vendor/styles/diffview.css',
           'vendor/styles/visualsearch-datauri.css'
         ],
         after: ['app/styles/custom-ui.css']

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dbb43e7/ambari-web/karma.conf.js
----------------------------------------------------------------------
diff --git a/ambari-web/karma.conf.js b/ambari-web/karma.conf.js
index 013cc2e..3dd6be1 100644
--- a/ambari-web/karma.conf.js
+++ b/ambari-web/karma.conf.js
@@ -69,6 +69,8 @@ module.exports = function(config) {
       'vendor/scripts/jquery.ui.custom-effects.js',
       'vendor/scripts/jquery.timeago.js',
       'vendor/scripts/jquery.ajax-retry.js',
+      'vendor/scripts/difflib.js',
+      'vendor/scripts/diffview.js',
       'vendor/scripts/underscore.js',
       'vendor/scripts/backbone.js',
       'vendor/scripts/visualsearch.js',

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dbb43e7/ambari-web/test/mixins/common/configs/config_recommendations_test.js
----------------------------------------------------------------------
diff --git 
a/ambari-web/test/mixins/common/configs/config_recommendations_test.js 
b/ambari-web/test/mixins/common/configs/config_recommendations_test.js
index 3f7d6b1..5de60e0 100644
--- a/ambari-web/test/mixins/common/configs/config_recommendations_test.js
+++ b/ambari-web/test/mixins/common/configs/config_recommendations_test.js
@@ -32,10 +32,12 @@ describe('App.ConfigRecommendations', function() {
       sinon.stub(App.config, 
'get').withArgs('serviceByConfigTypeMap').returns({
         'pFile': Em.Object.create({serviceName: 'sName', displayName: 
'sDisplayName'})
       });
+         sinon.stub(Handlebars, 'SafeString');
     });
     afterEach(function() {
       instanceObject.formatParentProperties.restore();
       App.config.get.restore();
+         Handlebars.SafeString.restore();
     });
 
     it('adds new recommendation', function() {
@@ -53,7 +55,8 @@ describe('App.ConfigRecommendations', function() {
         serviceName: 'sName',
         allowChangeGroup: false,
         serviceDisplayName: 'sDisplayName',
-        recommendedValue: 'pRecommended'
+        recommendedValue: 'pRecommended',
+               diff: {}
       });
       expect(instanceObject.getRecommendation('pName', 'pFile', 
'pGroup')).to.eql(res);
     });
@@ -128,7 +131,8 @@ describe('App.ConfigRecommendations', function() {
                                        serviceName: 'sName',
                                        allowChangeGroup: false,
                                        serviceDisplayName: 'sDisplayName',
-                                       recommendedValue: 'pRecommended'
+                                       recommendedValue: 'pRecommended',
+                                       diff: {}
                                }
                        },
                        {
@@ -148,7 +152,8 @@ describe('App.ConfigRecommendations', function() {
                                        serviceName: 'sName',
                                        allowChangeGroup: false,
                                        serviceDisplayName: 'sDisplayName',
-                                       recommendedValue: undefined
+                                       recommendedValue: undefined,
+                                       diff: {}
                                }
                        }
                ];
@@ -160,11 +165,13 @@ describe('App.ConfigRecommendations', function() {
                                        sinon.stub(App.config, 
'get').withArgs('serviceByConfigTypeMap').returns({
                                                'pFile': c.service
                                        });
+                                       sinon.stub(Handlebars, 'SafeString');
                                        recommendation = 
instanceObject.addRecommendation(c.name, c.file, c.group, c.recommended, 
c.initial, c.parent);
                                });
 
                                afterEach(function() {
                                        App.config.get.restore();
+                                       Handlebars.SafeString.restore();
                                });
 
                                it(c.title, function() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dbb43e7/ambari-web/vendor/scripts/difflib.js
----------------------------------------------------------------------
diff --git a/ambari-web/vendor/scripts/difflib.js 
b/ambari-web/vendor/scripts/difflib.js
new file mode 100755
index 0000000..191fe45
--- /dev/null
+++ b/ambari-web/vendor/scripts/difflib.js
@@ -0,0 +1,413 @@
+/***
+This is part of jsdifflib v1.0. <http://snowtide.com/jsdifflib>
+
+Copyright (c) 2007, Snowtide Informatics Systems, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without 
modification,
+are permitted provided that the following conditions are met:
+
+       * Redistributions of source code must retain the above copyright 
notice, this
+               list of conditions and the following disclaimer.
+       * Redistributions in binary form must reproduce the above copyright 
notice,
+               this list of conditions and the following disclaimer in the 
documentation
+               and/or other materials provided with the distribution.
+       * Neither the name of the Snowtide Informatics Systems nor the names of 
its
+               contributors may be used to endorse or promote products derived 
from this
+               software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 
EVENT
+SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
SUCH
+DAMAGE.
+***/
+/* Author: Chas Emerick <[email protected]> */
+var __whitespace = {" ":true, "\t":true, "\n":true, "\f":true, "\r":true};
+
+var difflib = {
+       defaultJunkFunction: function (c) {
+               return __whitespace.hasOwnProperty(c);
+       },
+       
+       stripLinebreaks: function (str) { return 
str.replace(/^[\n\r]*|[\n\r]*$/g, ""); },
+       
+       stringAsLines: function (str) {
+               var lfpos = str.indexOf("\n");
+               var crpos = str.indexOf("\r");
+               var linebreak = ((lfpos > -1 && crpos > -1) || crpos < 0) ? 
"\n" : "\r";
+               
+               var lines = str.split(linebreak);
+               for (var i = 0; i < lines.length; i++) {
+                       lines[i] = difflib.stripLinebreaks(lines[i]);
+               }
+               
+               return lines;
+       },
+       
+       // iteration-based reduce implementation
+       __reduce: function (func, list, initial) {
+               if (initial != null) {
+                       var value = initial;
+                       var idx = 0;
+               } else if (list) {
+                       var value = list[0];
+                       var idx = 1;
+               } else {
+                       return null;
+               }
+               
+               for (; idx < list.length; idx++) {
+                       value = func(value, list[idx]);
+               }
+               
+               return value;
+       },
+       
+       // comparison function for sorting lists of numeric tuples
+       __ntuplecomp: function (a, b) {
+               var mlen = Math.max(a.length, b.length);
+               for (var i = 0; i < mlen; i++) {
+                       if (a[i] < b[i]) return -1;
+                       if (a[i] > b[i]) return 1;
+               }
+               
+               return a.length == b.length ? 0 : (a.length < b.length ? -1 : 
1);
+       },
+       
+       __calculate_ratio: function (matches, length) {
+               return length ? 2.0 * matches / length : 1.0;
+       },
+       
+       // returns a function that returns true if a key passed to the returned 
function
+       // is in the dict (js object) provided to this function; replaces being 
able to
+       // carry around dict.has_key in python...
+       __isindict: function (dict) {
+               return function (key) { return dict.hasOwnProperty(key); };
+       },
+       
+       // replacement for python's dict.get function -- need easy default 
values
+       __dictget: function (dict, key, defaultValue) {
+               return dict.hasOwnProperty(key) ? dict[key] : defaultValue;
+       },      
+       
+       SequenceMatcher: function (a, b, isjunk) {
+               this.set_seqs = function (a, b) {
+                       this.set_seq1(a);
+                       this.set_seq2(b);
+               }
+               
+               this.set_seq1 = function (a) {
+                       if (a == this.a) return;
+                       this.a = a;
+                       this.matching_blocks = this.opcodes = null;
+               }
+               
+               this.set_seq2 = function (b) {
+                       if (b == this.b) return;
+                       this.b = b;
+                       this.matching_blocks = this.opcodes = this.fullbcount = 
null;
+                       this.__chain_b();
+               }
+               
+               this.__chain_b = function () {
+                       var b = this.b;
+                       var n = b.length;
+                       var b2j = this.b2j = {};
+                       var populardict = {};
+                       for (var i = 0; i < b.length; i++) {
+                               var elt = b[i];
+                               if (b2j.hasOwnProperty(elt)) {
+                                       var indices = b2j[elt];
+                                       if (n >= 200 && indices.length * 100 > 
n) {
+                                               populardict[elt] = 1;
+                                               delete b2j[elt];
+                                       } else {
+                                               indices.push(i);
+                                       }
+                               } else {
+                                       b2j[elt] = [i];
+                               }
+                       }
+       
+                       for (var elt in populardict) {
+                               if (populardict.hasOwnProperty(elt)) {
+                                       delete b2j[elt];
+                               }
+                       }
+                       
+                       var isjunk = this.isjunk;
+                       var junkdict = {};
+                       if (isjunk) {
+                               for (var elt in populardict) {
+                                       if (populardict.hasOwnProperty(elt) && 
isjunk(elt)) {
+                                               junkdict[elt] = 1;
+                                               delete populardict[elt];
+                                       }
+                               }
+                               for (var elt in b2j) {
+                                       if (b2j.hasOwnProperty(elt) && 
isjunk(elt)) {
+                                               junkdict[elt] = 1;
+                                               delete b2j[elt];
+                                       }
+                               }
+                       }
+       
+                       this.isbjunk = difflib.__isindict(junkdict);
+                       this.isbpopular = difflib.__isindict(populardict);
+               }
+               
+               this.find_longest_match = function (alo, ahi, blo, bhi) {
+                       var a = this.a;
+                       var b = this.b;
+                       var b2j = this.b2j;
+                       var isbjunk = this.isbjunk;
+                       var besti = alo;
+                       var bestj = blo;
+                       var bestsize = 0;
+                       var j = null;
+                       var k;
+       
+                       var j2len = {};
+                       var nothing = [];
+                       for (var i = alo; i < ahi; i++) {
+                               var newj2len = {};
+                               var jdict = difflib.__dictget(b2j, a[i], 
nothing);
+                               for (var jkey in jdict) {
+                                       if (jdict.hasOwnProperty(jkey)) {
+                                               j = jdict[jkey];
+                                               if (j < blo) continue;
+                                               if (j >= bhi) break;
+                                               newj2len[j] = k = 
difflib.__dictget(j2len, j - 1, 0) + 1;
+                                               if (k > bestsize) {
+                                                       besti = i - k + 1;
+                                                       bestj = j - k + 1;
+                                                       bestsize = k;
+                                               }
+                                       }
+                               }
+                               j2len = newj2len;
+                       }
+       
+                       while (besti > alo && bestj > blo && !isbjunk(b[bestj - 
1]) && a[besti - 1] == b[bestj - 1]) {
+                               besti--;
+                               bestj--;
+                               bestsize++;
+                       }
+                               
+                       while (besti + bestsize < ahi && bestj + bestsize < bhi 
&&
+                                       !isbjunk(b[bestj + bestsize]) &&
+                                       a[besti + bestsize] == b[bestj + 
bestsize]) {
+                               bestsize++;
+                       }
+       
+                       while (besti > alo && bestj > blo && isbjunk(b[bestj - 
1]) && a[besti - 1] == b[bestj - 1]) {
+                               besti--;
+                               bestj--;
+                               bestsize++;
+                       }
+                       
+                       while (besti + bestsize < ahi && bestj + bestsize < bhi 
&& isbjunk(b[bestj + bestsize]) &&
+                                       a[besti + bestsize] == b[bestj + 
bestsize]) {
+                               bestsize++;
+                       }
+       
+                       return [besti, bestj, bestsize];
+               }
+               
+               this.get_matching_blocks = function () {
+                       if (this.matching_blocks != null) return 
this.matching_blocks;
+                       var la = this.a.length;
+                       var lb = this.b.length;
+       
+                       var queue = [[0, la, 0, lb]];
+                       var matching_blocks = [];
+                       var alo, ahi, blo, bhi, qi, i, j, k, x;
+                       while (queue.length) {
+                               qi = queue.pop();
+                               alo = qi[0];
+                               ahi = qi[1];
+                               blo = qi[2];
+                               bhi = qi[3];
+                               x = this.find_longest_match(alo, ahi, blo, bhi);
+                               i = x[0];
+                               j = x[1];
+                               k = x[2];
+       
+                               if (k) {
+                                       matching_blocks.push(x);
+                                       if (alo < i && blo < j)
+                                               queue.push([alo, i, blo, j]);
+                                       if (i+k < ahi && j+k < bhi)
+                                               queue.push([i + k, ahi, j + k, 
bhi]);
+                               }
+                       }
+                       
+                       matching_blocks.sort(difflib.__ntuplecomp);
+       
+                       var i1 = 0, j1 = 0, k1 = 0, block = 0;
+                       var i2, j2, k2;
+                       var non_adjacent = [];
+                       for (var idx in matching_blocks) {
+                               if (matching_blocks.hasOwnProperty(idx)) {
+                                       block = matching_blocks[idx];
+                                       i2 = block[0];
+                                       j2 = block[1];
+                                       k2 = block[2];
+                                       if (i1 + k1 == i2 && j1 + k1 == j2) {
+                                               k1 += k2;
+                                       } else {
+                                               if (k1) non_adjacent.push([i1, 
j1, k1]);
+                                               i1 = i2;
+                                               j1 = j2;
+                                               k1 = k2;
+                                       }
+                               }
+                       }
+                       
+                       if (k1) non_adjacent.push([i1, j1, k1]);
+       
+                       non_adjacent.push([la, lb, 0]);
+                       this.matching_blocks = non_adjacent;
+                       return this.matching_blocks;
+               }
+               
+               this.get_opcodes = function () {
+                       if (this.opcodes != null) return this.opcodes;
+                       var i = 0;
+                       var j = 0;
+                       var answer = [];
+                       this.opcodes = answer;
+                       var block, ai, bj, size, tag;
+                       var blocks = this.get_matching_blocks();
+                       for (var idx in blocks) {
+                               if (blocks.hasOwnProperty(idx)) {
+                                       block = blocks[idx];
+                                       ai = block[0];
+                                       bj = block[1];
+                                       size = block[2];
+                                       tag = '';
+                                       if (i < ai && j < bj) {
+                                               tag = 'replace';
+                                       } else if (i < ai) {
+                                               tag = 'delete';
+                                       } else if (j < bj) {
+                                               tag = 'insert';
+                                       }
+                                       if (tag) answer.push([tag, i, ai, j, 
bj]);
+                                       i = ai + size;
+                                       j = bj + size;
+                                       
+                                       if (size) answer.push(['equal', ai, i, 
bj, j]);
+                               }
+                       }
+                       
+                       return answer;
+               }
+               
+               // this is a generator function in the python lib, which of 
course is not supported in javascript
+               // the reimplementation builds up the grouped opcodes into a 
list in their entirety and returns that.
+               this.get_grouped_opcodes = function (n) {
+                       if (!n) n = 3;
+                       var codes = this.get_opcodes();
+                       if (!codes) codes = [["equal", 0, 1, 0, 1]];
+                       var code, tag, i1, i2, j1, j2;
+                       if (codes[0][0] == 'equal') {
+                               code = codes[0];
+                               tag = code[0];
+                               i1 = code[1];
+                               i2 = code[2];
+                               j1 = code[3];
+                               j2 = code[4];
+                               codes[0] = [tag, Math.max(i1, i2 - n), i2, 
Math.max(j1, j2 - n), j2];
+                       }
+                       if (codes[codes.length - 1][0] == 'equal') {
+                               code = codes[codes.length - 1];
+                               tag = code[0];
+                               i1 = code[1];
+                               i2 = code[2];
+                               j1 = code[3];
+                               j2 = code[4];
+                               codes[codes.length - 1] = [tag, i1, 
Math.min(i2, i1 + n), j1, Math.min(j2, j1 + n)];
+                       }
+       
+                       var nn = n + n;
+                       var group = [];
+                       var groups = [];
+                       for (var idx in codes) {
+                               if (codes.hasOwnProperty(idx)) {
+                                       code = codes[idx];
+                                       tag = code[0];
+                                       i1 = code[1];
+                                       i2 = code[2];
+                                       j1 = code[3];
+                                       j2 = code[4];
+                                       if (tag == 'equal' && i2 - i1 > nn) {
+                                               group.push([tag, i1, 
Math.min(i2, i1 + n), j1, Math.min(j2, j1 + n)]);
+                                               groups.push(group);
+                                               group = [];
+                                               i1 = Math.max(i1, i2-n);
+                                               j1 = Math.max(j1, j2-n);
+                                       }
+                                       
+                                       group.push([tag, i1, i2, j1, j2]);
+                               }
+                       }
+                       
+                       if (group && !(group.length == 1 && group[0][0] == 
'equal')) groups.push(group)
+                       
+                       return groups;
+               }
+               
+               this.ratio = function () {
+                       matches = difflib.__reduce(
+                                                       function (sum, triple) 
{ return sum + triple[triple.length - 1]; },
+                                                       
this.get_matching_blocks(), 0);
+                       return difflib.__calculate_ratio(matches, this.a.length 
+ this.b.length);
+               }
+               
+               this.quick_ratio = function () {
+                       var fullbcount, elt;
+                       if (this.fullbcount == null) {
+                               this.fullbcount = fullbcount = {};
+                               for (var i = 0; i < this.b.length; i++) {
+                                       elt = this.b[i];
+                                       fullbcount[elt] = 
difflib.__dictget(fullbcount, elt, 0) + 1;
+                               }
+                       }
+                       fullbcount = this.fullbcount;
+       
+                       var avail = {};
+                       var availhas = difflib.__isindict(avail);
+                       var matches = numb = 0;
+                       for (var i = 0; i < this.a.length; i++) {
+                               elt = this.a[i];
+                               if (availhas(elt)) {
+                                       numb = avail[elt];
+                               } else {
+                                       numb = difflib.__dictget(fullbcount, 
elt, 0);
+                               }
+                               avail[elt] = numb - 1;
+                               if (numb > 0) matches++;
+                       }
+                       
+                       return difflib.__calculate_ratio(matches, this.a.length 
+ this.b.length);
+               }
+               
+               this.real_quick_ratio = function () {
+                       var la = this.a.length;
+                       var lb = this.b.length;
+                       return _calculate_ratio(Math.min(la, lb), la + lb);
+               }
+               
+               this.isjunk = isjunk ? isjunk : difflib.defaultJunkFunction;
+               this.a = this.b = null;
+               this.set_seqs(a, b);
+       }
+};
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dbb43e7/ambari-web/vendor/scripts/diffview.js
----------------------------------------------------------------------
diff --git a/ambari-web/vendor/scripts/diffview.js 
b/ambari-web/vendor/scripts/diffview.js
new file mode 100755
index 0000000..9345a32
--- /dev/null
+++ b/ambari-web/vendor/scripts/diffview.js
@@ -0,0 +1,172 @@
+/*
+This is part of jsdifflib v1.0. <http://github.com/cemerick/jsdifflib>
+
+Copyright 2007 - 2011 Chas Emerick <[email protected]>. All rights 
reserved.
+
+Redistribution and use in source and binary forms, with or without 
modification, are
+permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice, 
this list of
+      conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright 
notice, this list
+      of conditions and the following disclaimer in the documentation and/or 
other materials
+      provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY Chas Emerick ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Chas 
Emerick OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
(INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are 
those of the
+authors and should not be interpreted as representing official policies, 
either expressed
+or implied, of Chas Emerick.
+*/
+diffview = {
+       /**
+        * Builds and returns a visual diff view.  The single parameter, 
`params', should contain
+        * the following values:
+        *
+        * - baseTextLines: the array of strings that was used as the base text 
input to SequenceMatcher
+        * - newTextLines: the array of strings that was used as the new text 
input to SequenceMatcher
+        * - opcodes: the array of arrays returned by 
SequenceMatcher.get_opcodes()
+        * - baseTextName: the title to be displayed above the base text 
listing in the diff view; defaults
+        *         to "Base Text"
+        * - newTextName: the title to be displayed above the new text listing 
in the diff view; defaults
+        *         to "New Text"
+        * - contextSize: the number of lines of context to show around 
differences; by default, all lines
+        *         are shown
+        * - viewType: if 0, a side-by-side diff view is generated (default); 
if 1, an inline diff view is
+        *         generated
+        */
+       buildView: function (params) {
+               var baseTextLines = params.baseTextLines;
+               var newTextLines = params.newTextLines;
+               var opcodes = params.opcodes;
+               var contextSize = params.contextSize;
+               var inline = (params.viewType == 0 || params.viewType == 1) ? 
params.viewType : 0;
+
+               if (baseTextLines == null)
+                       throw "Cannot build diff view; baseTextLines is not 
defined.";
+               if (newTextLines == null)
+                       throw "Cannot build diff view; newTextLines is not 
defined.";
+               if (!opcodes)
+                       throw "Canno build diff view; opcodes is not defined.";
+               
+               function celt (name, clazz) {
+                       var e = document.createElement(name);
+                       e.className = clazz;
+                       return e;
+               }
+               
+               function telt (name, text) {
+                       var e = document.createElement(name);
+                       e.appendChild(document.createTextNode(text));
+                       return e;
+               }
+               
+               function ctelt (name, clazz, text) {
+                       var e = document.createElement(name);
+                       e.className = clazz;
+                       e.appendChild(document.createTextNode(text));
+                       return e;
+               }
+       
+               var tdata = [];
+               
+               var rows = [];
+               var node2;
+               
+               /**
+                * Adds two cells to the given row; if the given row 
corresponds to a real
+                * line number (based on the line index tidx and the endpoint 
of the 
+                * range in question tend), then the cells will contain the 
line number
+                * and the line of text from textLines at position tidx (with 
the class of
+                * the second cell set to the name of the change represented), 
and tidx + 1 will
+                * be returned.  Otherwise, tidx is returned, and two empty 
cells are added
+                * to the given row.
+                */
+               function addCells (row, tidx, tend, textLines, change) {
+                       if (tidx < tend) {
+                               row.appendChild(ctelt("td", change, 
textLines[tidx].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0")));
+                               return tidx + 1;
+                       } else {
+                               row.appendChild(celt("td", "empty"));
+                               return tidx;
+                       }
+               }
+               
+               function addCellsInline (row, tidx, tidx2, textLines, change) {
+                       row.appendChild(ctelt("td", change, textLines[tidx != 
null ? tidx : tidx2].replace(/\t/g, "\u00a0\u00a0\u00a0\u00a0")));
+               }
+               
+               for (var idx = 0; idx < opcodes.length; idx++) {
+                       code = opcodes[idx];
+                       change = code[0];
+                       var b = code[1];
+                       var be = code[2];
+                       var n = code[3];
+                       var ne = code[4];
+                       var rowcnt = Math.max(be - b, ne - n);
+                       var toprows = [];
+                       var botrows = [];
+                       for (var i = 0; i < rowcnt; i++) {
+                               // jump ahead if we've alredy provided leading 
context or if this is the first range
+                               if (contextSize && opcodes.length > 1 && ((idx 
> 0 && i == contextSize) || (idx == 0 && i == 0)) && change=="equal") {
+                                       var jump = rowcnt - ((idx == 0 ? 1 : 2) 
* contextSize);
+                                       if (jump > 1) {
+                                               toprows.push(node = celt("tr", 
"row"));
+                                               
+                                               b += jump;
+                                               n += jump;
+                                               i += jump - 1;
+                                               if (!inline) 
node.appendChild(ctelt("td", "skip span6", ""));
+                                               node.appendChild(ctelt("td", 
"skip span6", ""));
+                                               
+                                               // skip last lines if they're 
all equal
+                                               if (idx + 1 == opcodes.length) {
+                                                       break;
+                                               } else {
+                                                       continue;
+                                               }
+                                       }
+                               }
+                               
+                               toprows.push(node = celt("tr", "row"));
+                               if (inline) {
+                                       if (change == "insert") {
+                                               addCellsInline(node, null, n++, 
newTextLines, change + " span6");
+                                       } else if (change == "replace") {
+                                               botrows.push(node2 = celt("tr", 
"row"));
+                                               if (b < be) 
addCellsInline(node, b++, null, baseTextLines, "delete span6");
+                                               if (n < ne) 
addCellsInline(node2, null, n++, newTextLines, "insert span6");
+                                       } else if (change == "delete") {
+                                               addCellsInline(node, b++, null, 
baseTextLines, change + " span6");
+                                       } else {
+                                               // equal
+                                               addCellsInline(node, b++, n++, 
baseTextLines, change + " span6");
+                                       }
+                               } else {
+                                       b = addCells(node, b, be, 
baseTextLines, change + " span6");
+                                       n = addCells(node, n, ne, newTextLines, 
change + " span6");
+                               }
+                       }
+
+                       for (var i = 0; i < toprows.length; i++) 
rows.push(toprows[i]);
+                       for (var i = 0; i < botrows.length; i++) 
rows.push(botrows[i]);
+               }
+
+               tdata.push(node = document.createElement("tbody"));
+               for (var idx in rows) rows.hasOwnProperty(idx) && 
node.appendChild(rows[idx]);
+               
+               node = celt("table", "diff" + (inline ? " inlinediff" : ""));
+               for (var idx in tdata) tdata.hasOwnProperty(idx) && 
node.appendChild(tdata[idx]);
+               return node;
+       }
+};
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/5dbb43e7/ambari-web/vendor/styles/diffview.css
----------------------------------------------------------------------
diff --git a/ambari-web/vendor/styles/diffview.css 
b/ambari-web/vendor/styles/diffview.css
new file mode 100755
index 0000000..959f8b3
--- /dev/null
+++ b/ambari-web/vendor/styles/diffview.css
@@ -0,0 +1,84 @@
+/*
+This is part of jsdifflib v1.0. <http://github.com/cemerick/jsdifflib>
+
+Copyright 2007 - 2011 Chas Emerick <[email protected]>. All rights 
reserved.
+
+Redistribution and use in source and binary forms, with or without 
modification, are
+permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright notice, 
this list of
+      conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright 
notice, this list
+      of conditions and the following disclaimer in the documentation and/or 
other materials
+      provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY Chas Emerick ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Chas 
Emerick OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
(INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation are 
those of the
+authors and should not be interpreted as representing official policies, 
either expressed
+or implied, of Chas Emerick.
+*/
+table.diff {
+       border-collapse:collapse;
+       border:1px solid darkgray;
+       white-space:pre-wrap
+}
+table.diff tbody { 
+       font-family:Courier, monospace
+}
+table.diff tbody th {
+       font-family:verdana,arial,'Bitstream Vera Sans',helvetica,sans-serif;
+       background:#EED;
+       font-size:11px;
+       font-weight:normal;
+       border:1px solid #BBC;
+       color:#886;
+       padding:.3em .5em .1em 2em;
+       text-align:right;
+       vertical-align:top
+}
+table.diff thead {
+       border-bottom:1px solid #BBC;
+       background:#EFEFEF;
+       font-family:Verdana
+}
+table.diff thead th.texttitle {
+       text-align:left
+}
+table.diff tbody td {
+       padding:0px .4em;
+       padding-top:.4em;
+       vertical-align:top;
+       border:1px solid #BBC;
+}
+table.diff .empty {
+       background-color:#DDD !important;
+}
+table.diff .replace {
+       background-color:#FD8 !important;
+}
+table.diff .delete {
+       background-color:#E99 !important;
+}
+table.diff .skip {
+       background-color:#EFEFEF !important;
+       border:1px solid #AAA;
+       border-right:1px solid #BBC;
+}
+table.diff .insert {
+       background-color:#9E9 !important;
+}
+table.diff th.author {
+       text-align:right;
+       border-top:1px solid #BBC;
+       background:#EFEFEF
+}
\ No newline at end of file

Reply via email to