<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
sap.ui.jsview("sap.apf.ui.reuse.view.stepToolbar",{getControllerName:function(){return"sap.apf.ui.reuse.controller.stepToolbar";},createContent:function(c){this.chartToolbar=new sap.ca.ui.charts.ChartToolBar({showLegend:true,showFullScreen:true});return this.chartToolbar;}});
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

sap.ui.define(['jquery.sap.global', './Base'], function(jQuery, Base) {
	"use strict";

	/**
	 * Change handler for moving of a elements.
	 * 
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.MoveElements
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.34.0
	 */
	var MoveElements = function() {
	};
	MoveElements.prototype = jQuery.sap.newObject(Base.prototype);

	MoveElements.CHANGE_TYPE = "moveElements";

	/**
	 * Moves an element from one aggregation to another.
	 * 
	 * @param {sap.ui.fl.Change}
	 *          oChange change object with instructions to be applied on the control map
	 * @param {sap.ui.core.Control}
	 *          oSourceParent control that matches the change selector for applying the change, which is the source of the
	 *          move
	 * @public
	 */
	MoveElements.prototype.applyChange = function(oChange, oSourceParent) {
		var that = this;
		var mContent = oChange.getContent();

		if (oSourceParent.getId() !== oChange.getSelector().id) {
			throw new Error("Source parent id (selector) doesn't match the control on which to apply the change");
		}
		var sSourceAggregation = oChange.getSelector().aggregation;
		if (!sSourceAggregation) {
			throw new Error("No source aggregation supplied via selector for move");
		}

		if (!mContent.target || !mContent.target.selector) {
			throw new Error("No target supplied for move");
		}
		var oTargetParent = this._byId(mContent.target.selector.id);
		if (!oTargetParent) {
			throw new Error("Move target parent not found");
		}
		var sTargetAggregation = mContent.target.selector.aggregation;
		if (!sTargetAggregation) {
			throw new Error("No target aggregation supplied for move");
		}
		if (!mContent.movedElements) {
			throw new Error("No moveElements supplied");
		}

		mContent.movedElements.forEach(function(mMovedElement) {
			var oMovedElement = that._byId(mMovedElement.selector.id);
			if (!oMovedElement) {
				throw new Error("Unkown element with id '" + mMovedElement.selector.id + "' in moveElements supplied");
			}
			if ( typeof mMovedElement.targetIndex !== "number") {
				throw new Error("Missing targetIndex for element with id '" + mMovedElement.selector.id
						+ "' in moveElements supplied");
			}
			that.removeAggregation(oSourceParent, sSourceAggregation, oMovedElement);
			that.addAggregation(oTargetParent, sTargetAggregation, oMovedElement, mMovedElement.targetIndex);
		});

	};

	/**
	 * Completes the change by adding change handler specific content
	 * 
	 * @param {sap.ui.fl.Change}
	 *          oChange change object to be completed
	 * @param {object}
	 *          mSpecificChangeInfo as an empty object since no additional attributes are required for this operation
	 * @public
	 */
	MoveElements.prototype.completeChangeContent = function(oChange, mSpecificChangeInfo) {
		var that = this;

		var mSpecificInfo = this.getSpecificChangeInfo(mSpecificChangeInfo);

		var mChangeData = oChange.getDefinition();

		mChangeData.changeType = MoveElements.CHANGE_TYPE;

		mChangeData.selector = mSpecificInfo.source;

		mChangeData.content = {
			movedElements : [],
			target : {
				selector : mSpecificInfo.target
			}
		};
		mSpecificInfo.movedElements.forEach(function(mElement) {
			var oElement = mElement.element || that._byId(mElement.id);

			mChangeData.content.movedElements.push({
				selector : {
					id : oElement.getId(),
					type : that._getType(oElement)
				},
				sourceIndex : mElement.sourceIndex,
				targetIndex : mElement.targetIndex
			});
		});
	};

	/**
	 * Enrich the incoming change info with the change info from the setter, to get the complete data in one format
	 */
	MoveElements.prototype.getSpecificChangeInfo = function(mSpecificChangeInfo) {
		var oSourceParent = this._getParentElement(this._mSource || mSpecificChangeInfo.source);
		var oTargetParent = this._getParentElement(this._mTarget || mSpecificChangeInfo.target);

		var sSourceAggregation = this._mSource && this._mSource.aggregation || mSpecificChangeInfo.source.aggregation;
		var sTargetAggregation = this._mTarget && this._mTarget.aggregation || mSpecificChangeInfo.target.aggregation;

		var mSpecificInfo = {
			source : {
				id : oSourceParent.getId(),
				aggregation : sSourceAggregation,
				type : this._getType(oSourceParent)
			},
			target : {
				id : oTargetParent.getId(),
				aggregation : sTargetAggregation,
				type : this._getType(oTargetParent)
			},
			movedElements : this._aMovedElements || mSpecificChangeInfo.movedElements
		};

		return mSpecificInfo;
	};

	/**
	 * @param {array}
	 *          aElements
	 * @param {string}
	 *          aElements.elementId id of the moved element, can be omitted if element is passed
	 * @param {sap.ui.core.Element}
	 *          aElements.element moved element, optional fallback for elementId
	 * @param {number}
	 *          aElements.sourceIndex index of the moved elements in the source aggregation
	 * @param {number}
	 *          aElements.targetIndex index of the moved elements in the target aggregation
	 */
	MoveElements.prototype.setMovedElements = function(aElements) {
		this._aMovedElements = aElements;
	};

	/**
	 * @param {object}
	 *          mSource
	 * @param {string}
	 *          mSource.id id of the source parent, can be omitted if element is passed
	 * @param {sap.ui.core.Element}
	 *          mSource.parent optional fallback for id
	 * @param {string}
	 *          mSource.aggregation original aggregation of the moved elements
	 */
	MoveElements.prototype.setSource = function(mSource) {
		this._mSource = mSource;
	};

	/**
	 * @param {object}
	 *          mTarget
	 * @param {string}
	 *          mTarget.id id of the target parent
	 * @param {sap.ui.core.Element}
	 *          mTarget.parent optional fallback for id, can be omitted if parent is passed
	 * @param {string}
	 *          mTarget.aggregation target aggregation of the moved elements in the target element
	 */
	MoveElements.prototype.setTarget = function(mTarget) {
		this._mTarget = mTarget;
	};

	MoveElements.prototype._byId = function(sId) {
		return sap.ui.getCore().byId(sId);
	};

	MoveElements.prototype._getType = function(oElement) {
		return oElement.getMetadata().getName();
	};

	MoveElements.prototype._getParentElement = function(mData) {
		var oElement = mData.parent;
		if (!oElement) {
			oElement = this._byId(mData.id);
		}
		return oElement;
	};

	return MoveElements;
},
/* bExport= */true);
<file_sep>/**
 * Compiled inline version. (Library mode)
 */

/*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
/*globals $code */

(function(exports, undefined) {
	"use strict";

	var modules = {};

	function require(ids, callback) {
		var module, defs = [];

		for (var i = 0; i < ids.length; ++i) {
			module = modules[ids[i]] || resolve(ids[i]);
			if (!module) {
				throw 'module definition dependecy not found: ' + ids[i];
			}

			defs.push(module);
		}

		callback.apply(null, defs);
	}

	function define(id, dependencies, definition) {
		if (typeof id !== 'string') {
			throw 'invalid module definition, module id must be defined and be a string';
		}

		if (dependencies === undefined) {
			throw 'invalid module definition, dependencies must be specified';
		}

		if (definition === undefined) {
			throw 'invalid module definition, definition function must be specified';
		}

		require(dependencies, function() {
			modules[id] = definition.apply(null, arguments);
		});
	}

	function defined(id) {
		return !!modules[id];
	}

	function resolve(id) {
		var target = exports;
		var fragments = id.split(/[.\/]/);

		for (var fi = 0; fi < fragments.length; ++fi) {
			if (!target[fragments[fi]]) {
				return;
			}

			target = target[fragments[fi]];
		}

		return target;
	}

	function expose(ids) {
		var i, target, id, fragments, privateModules;

		for (i = 0; i < ids.length; i++) {
			target = exports;
			id = ids[i];
			fragments = id.split(/[.\/]/);

			for (var fi = 0; fi < fragments.length - 1; ++fi) {
				if (target[fragments[fi]] === undefined) {
					target[fragments[fi]] = {};
				}

				target = target[fragments[fi]];
			}

			target[fragments[fragments.length - 1]] = modules[id];
		}
		
		// Expose private modules for unit tests
		if (exports.AMDLC_TESTS) {
			privateModules = exports.privateModules || {};

			for (id in modules) {
				privateModules[id] = modules[id];
			}

			for (i = 0; i < ids.length; i++) {
				delete privateModules[ids[i]];
			}

			exports.privateModules = privateModules;
		}
	}

// Included from: js/DomTextMatcher.js

/**
 * DomTextMatcher.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/*eslint no-labels:0, no-constant-condition: 0 */

/**
 * This class logic for filtering text and matching words.
 *
 * @class tinymce.tinymcespellcheckerplugin.TextFilter
 * @private
 */
define("tinymce/tinymcespellcheckerplugin/DomTextMatcher", [], function() {
	// Based on work developed by: <NAME> http://james.padolsey.com
	// released under UNLICENSE that is compatible with LGPL
	// TODO: Handle contentEditable edgecase:
	// <p>text<span contentEditable="false">text<span contentEditable="true">text</span>text</span>text</p>
	return function(node, editor, wordCharPattern) {
		var m, dom = editor.dom;
		var blockElementsMap, hiddenTextElementsMap, shortEndedElementsMap, ignoreClass = "mce-spellchecker-ignore";

		blockElementsMap = editor.schema.getBlockElements(); // H1-H6, P, TD etc
		hiddenTextElementsMap = editor.schema.getWhiteSpaceElements(); // TEXTAREA, PRE, STYLE, SCRIPT
		shortEndedElementsMap = editor.schema.getShortEndedElements(); // BR, IMG, INPUT

		function createMatch(m, data) {
			if (!m[0]) {
				throw 'findAndReplaceDOMText cannot handle zero-length matches';
			}

			return {
				start: m.index,
				end: m.index + m[0].length,
				text: m[0],
				data: data
			};
		}

		function getText(node) {
			var txt;

			if (node.nodeType === 3) {
				return node.data;
			}

			if (hiddenTextElementsMap[node.nodeName] && !blockElementsMap[node.nodeName]) {
				return '';
			}

			txt = '';

			if (blockElementsMap[node.nodeName] || shortEndedElementsMap[node.nodeName]) {
				txt += '\n';
			}

			if ((node = node.firstChild)) {
				do {
					txt += getText(node);
				} while ((node = node.nextSibling));
			}

			return txt;
		}

		function getUniqueValuesFromArray(arrayToCheck) {
			function arrayContains(arrayToCheck, value) {
				for (var i = 0; i < arrayToCheck.length; i++) {
					if (arrayToCheck[i] === value) {
						return true;
					}
				}

				return false;
			}

			var arrayToKeep = [];

			for (var i = 0; i < arrayToCheck.length; i++) {
				if (!arrayContains(arrayToKeep, arrayToCheck[i])) {
					arrayToKeep.push(arrayToCheck[i]);
				}
			}

			return arrayToKeep;
		}

		function getWords(node) {
			var matches = getText(node).match(wordCharPattern);
			return matches ? getUniqueValuesFromArray(matches) : [];
		}

		function stepThroughMatches(node, matches, replaceFn) {

			var startNode, endNode, startNodeIndex,
				endNodeIndex, innerNodes = [], atIndex = 0, curNode = node,
				matchLocation, matchIndex = 0;

			matches = matches.slice(0);
			matches.sort(function(a, b) {
				return a.start - b.start;
			});

			matchLocation = matches.shift();

			out: while (true) {
				if (blockElementsMap[curNode.nodeName] || shortEndedElementsMap[curNode.nodeName]) {
					atIndex++;
				}

				if (curNode.nodeType === 3) {
					if (!endNode && curNode.length + atIndex >= matchLocation.end) {
						// We've found the ending
						endNode = curNode;
						endNodeIndex = matchLocation.end - atIndex;
					} else if (startNode) {
						// Intersecting node
						innerNodes.push(curNode);
					}

					if (!startNode && curNode.length + atIndex > matchLocation.start) {
						// We've found the match start
						startNode = curNode;
						startNodeIndex = matchLocation.start - atIndex;
					}

					atIndex += curNode.length;
				}

				if (startNode && endNode) {
					//We need to check if this is an ignored element
					var ignored = false;
					for (var currNode = startNode; currNode != node; currNode = currNode.parentNode) {
						if (currNode.className === ignoreClass) {
							ignored = true;
						}
					}

					if (!ignored) {
						curNode = replaceFn({
							startNode: startNode,
							startNodeIndex: startNodeIndex,
							endNode: endNode,
							endNodeIndex: endNodeIndex,
							innerNodes: innerNodes,
							match: matchLocation.text,
							matchIndex: matchIndex
						});

						// replaceFn has to return the node that replaced the endNode
						// and then we step back so we can continue from the end of the
						// match:
						atIndex -= (endNode.length - endNodeIndex);
					}

					startNode = null;
					endNode = null;
					innerNodes = [];
					matchLocation = matches.shift();
					matchIndex++;

					if (!matchLocation) {
						break; // no more matches
					}
				} else if ((!hiddenTextElementsMap[curNode.nodeName] || blockElementsMap[curNode.nodeName]) && curNode.firstChild) {
					// Move down
					curNode = curNode.firstChild;
					continue;
				} else if (curNode.nextSibling) {
					// Move forward:
					curNode = curNode.nextSibling;
					continue;
				}

				// Move forward or up:
				while (true) {
					if (curNode.nextSibling) {
						curNode = curNode.nextSibling;
						break;
					} else if (curNode.parentNode !== node) {
						curNode = curNode.parentNode;
					} else {
						break out;
					}
				}
			}
		}

		/**
		* Generates the actual replaceFn which splits up text nodes
		* and inserts the replacement element.
		*/
		function genReplacer(matches, callback) {
			function makeReplacementNode(fill, matchIndex) {
				var match = matches[matchIndex];

				if (!match.stencil) {
					match.stencil = callback(match);
				}

				var clone = match.stencil.cloneNode(false);
				clone.setAttribute('data-mce-index', matchIndex);

				if (fill) {
					clone.appendChild(dom.doc.createTextNode(fill));
				}

				return clone;
			}

			return function(range) {
				var before, after, parentNode, startNode = range.startNode,
					endNode = range.endNode, matchIndex = range.matchIndex,
					doc = dom.doc;

				if (startNode === endNode) {
					var node = startNode;

					parentNode = node.parentNode;
					if (range.startNodeIndex > 0) {
						// Add "before" text node (before the match)
						before = doc.createTextNode(node.data.substring(0, range.startNodeIndex));
						parentNode.insertBefore(before, node);
					}

					// Create the replacement node:
					var el = makeReplacementNode(range.match, matchIndex);
					parentNode.insertBefore(el, node);
					if (range.endNodeIndex < node.length) {
						// Add "after" text node (after the match)
						after = doc.createTextNode(node.data.substring(range.endNodeIndex));
						parentNode.insertBefore(after, node);
					}

					node.parentNode.removeChild(node);

					return el;
				}

				// Replace startNode -> [innerNodes...] -> endNode (in that order)
				before = doc.createTextNode(startNode.data.substring(0, range.startNodeIndex));
				after = doc.createTextNode(endNode.data.substring(range.endNodeIndex));
				var elA = makeReplacementNode(startNode.data.substring(range.startNodeIndex), matchIndex);
				var innerEls = [];

				for (var i = 0, l = range.innerNodes.length; i < l; ++i) {
					var innerNode = range.innerNodes[i];
					var innerEl = makeReplacementNode(innerNode.data, matchIndex);
					innerNode.parentNode.replaceChild(innerEl, innerNode);
					innerEls.push(innerEl);
				}

				var elB = makeReplacementNode(endNode.data.substring(0, range.endNodeIndex), matchIndex);

				parentNode = startNode.parentNode;
				parentNode.insertBefore(before, startNode);
				parentNode.insertBefore(elA, startNode);
				parentNode.removeChild(startNode);

				parentNode = endNode.parentNode;
				parentNode.insertBefore(elB, endNode);
				parentNode.insertBefore(after, endNode);
				parentNode.removeChild(endNode);

				return elB;
			};
		}

		/**
		 * Returns the index of a specific match object or -1 if it isn't found.
		 *
		 * @param  {Match} match Text match object.
		 * @return {Number} Index of match or -1 if it isn't found.
		 */
		function indexOf(matches, match) {
			var i = matches.length;
			while (i--) {
				if (matches[i] === match) {
					return i;
				}
			}

			return -1;
		}

		/**
		 * Filters the matches. If the callback returns true it stays if not it gets removed.
		 *
		 * @param {Function} callback Callback to execute for each match.
		 * @return {DomTextMatcher} Current DomTextMatcher instance.
		 */
		function filter(matches, callback) {
			var filteredMatches = [];

			each(matches, function(match, i) {
				if (callback(match, i)) {
					filteredMatches.push(match);
				}
			});

			matches = filteredMatches;

			/*jshint validthis:true*/
			return filteredMatches;
		}

		/**
		 * Executes the specified callback for each match.
		 *
		 * @param {Function} callback  Callback to execute for each match.
		 * @return {DomTextMatcher} Current DomTextMatcher instance.
		 */
		function each(matches, callback) {
			for (var i = 0, l = matches.length; i < l; i++) {
				if (callback(matches[i], i) === false) {
					break;
				}
			}

			/*jshint validthis:true*/
			return this;
		}

		/**
		 * Wraps the current matches with nodes created by the specified callback.
		 * Multiple clones of these matches might occur on matches that are on multiple nodex.
		 *
		 * @param {Function} callback Callback to execute in order to create elements for matches.
		 * @return {DomTextMatcher} Current DomTextMatcher instance.
		 */
		function wrap(matches, callback, node) {
			if (matches.length) {
				stepThroughMatches(node, matches, genReplacer(matches, callback));
			}

			/*jshint validthis:true*/
			return this;
		}

		/**
		 * Finds the specified regexp and adds them to the matches collection.
		 *
		 * @param {RegExp} regex Global regexp to search the current node by.
		 * @param {Object} [data] Optional custom data element for the match.
		 * @return {DomTextMatcher} Current DomTextMatcher instance.
		 */
		function find(regex, data, node) {
			var matches = [];
			var textToMatch = getText(node);
			if (textToMatch && regex.global) {
				while ((m = regex.exec(textToMatch))) {
					matches.push(createMatch(m, data));
				}
			}

			return matches;
		}

		return {
			getText: getText,
			getWords: getWords,
			each: each,
			filter: filter,
			find: find,
			wrap: wrap,
			indexOf: indexOf
		};
	};
});

// Included from: js/SpellingCache.js

/**
 * SpellingCache.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/**
 * This class is used to store spelling suggestions and more in one place.
 *
 * @class tinymce.tinymcespellcheckerplugin.TextFilter
 * @private
 */
define("tinymce/tinymcespellcheckerplugin/SpellingCache", [
	"tinymce/util/JSON"
], function(JSON) {
	return function() {
		var storageItemName = "tinyMCESpellingCache",
		fallbackCache = {},
		suggestionsLimit = 5;

		function cleanWord(word) {
			return word.replace(/\uFEFF/g, '');
		}

		function addWordToCache(language, word, misspelled, suggestions) {
			var spellingCache = getCache(language),
				fixedWord = cleanWord(word),
				cacheObject = {
					misspelled: misspelled,
					suggestions: suggestions
				};
			spellingCache[language][fixedWord] = cacheObject;

			if (storageSupported()) {
				sessionStorage.setItem(storageItemName, JSON.serialize(spellingCache));
			} else {
				fallbackCache = spellingCache;
			}
		}

		function storageSupported() {
			return typeof (Storage) !== "undefined";
		}

		function checkCacheLanguage(language, spellingCache) {
			if (!spellingCache[language]) {
				spellingCache[language] = {};
			}
			return spellingCache;
		}

		function getCache(language) {
			//if the cache isn't there yet
			var spellingCache = storageSupported() && sessionStorage.getItem(storageItemName) ?
				JSON.parse(sessionStorage.getItem(storageItemName)) : fallbackCache;
			return checkCacheLanguage(language, spellingCache);
		}

		function retrieveWordFromCache(language, word) {
			var spellingCache = getCache(language),
				fixedWord = cleanWord(word),
				cacheObject = spellingCache[language][fixedWord] ? spellingCache[language][fixedWord] : false;

			//If the suggestions array exists, and has a length greater than
			if (cacheObject && cacheObject.suggestions && cacheObject.suggestions.length > suggestionsLimit) {
				//limit the suggestions
				cacheObject.suggestions = cacheObject.suggestions.slice(0, suggestionsLimit);
			}

			return cacheObject;
		}

		return {
			addWordToCache: addWordToCache,
			retrieveWordFromCache: retrieveWordFromCache
		};
	};
});

// Included from: js/Plugin.js

/**
 * Plugin.js
 *
 * Released under LGPL License.
 * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

/*jshint camelcase:false */

/**
 * This class contains all core logic for the spellchecker plugin.
 *
 * @class tinymce.tinymcespellcheckerplugin.Plugin
 * @private
 */
define("tinymce/tinymcespellcheckerplugin/Plugin", [
	"tinymce/tinymcespellcheckerplugin/DomTextMatcher",
	"tinymce/tinymcespellcheckerplugin/SpellingCache",
	"tinymce/PluginManager",
	"tinymce/util/Tools",
	"tinymce/ui/Menu",
	"tinymce/dom/DOMUtils",
	"tinymce/util/XHR",
	"tinymce/util/URI",
	"tinymce/util/JSON"
], function(DomTextMatcher, SpellingCache, PluginManager, Tools, Menu, DOMUtils, XHR, URI, JSON) {
	PluginManager.add('tinymcespellchecker', function(editor, url) {
		var self = this, suggestionsMenu, settings = editor.settings, spellcheckerVersion = 1,
		word_regexp = '[' + '\\w' + '\'' + '\\-' + '\\u00C0-\\u00FF' + '\\uFEFF' + '\\u2018\\u2019' + ']+',
		languagesString = settings.spellchecker_languages ||
			'US English=en,UK English=en_gb,Danish=da,Dutch=nl,Finnish=fi,French=fr,' +
			'German=de,Italian=it,Norwegian=nb,Brazilian Portuguese=pt,Iberian Portuguese=pt_pt,' +
			'Spanish=es,Swedish=sv',
		languageMenuItems, wordClass = "mce-spellchecker-word", ignoreClass = "mce-spellchecker-ignore", currentParentNode,
		spellchecking = true, spellcheckButton, spellcheckMenuItem,
		successes, failed, successCount, requestCount, maxLetters = 15000;

		function getTextMatcher() {
			if (!self.textMatcher) {
				self.textMatcher = new DomTextMatcher(editor.getBody(), editor, getWordCharPattern());
			}

			return self.textMatcher;
		}

		function getSpellingCache() {
			if (!self.spellingCache) {
				self.spellingCache = new SpellingCache();
			}

			return self.spellingCache;
		}

		function showSuggestions(word, spans) {
			var items = [], suggestions = getSpellingCache().retrieveWordFromCache(settings.spellchecker_language, word).suggestions;

			Tools.each(suggestions, function(suggestion) {
				items.push({
					text: suggestion,
					onclick: function() {
						editor.insertContent(editor.dom.encode(suggestion));
						editor.dom.remove(spans);
					}
				});
			});

			items.push({text: '-'});

			items.push.apply(items, [
				{text: 'Ignore', onclick: function() {
					ignoreWord(word, spans);
				}},

				{text: 'Ignore all', onclick: function() {
					ignoreWord(word, spans, true);
				}}
			]);

			// Render menu
			suggestionsMenu = new Menu({
				items: items,
				context: 'contextmenu',
				onautohide: function(e) {
					if (e.target.className.indexOf('spellchecker') != -1) {
						e.preventDefault();
					}
				},
				onhide: function() {
					suggestionsMenu.remove();
					suggestionsMenu = null;
				}
			});

			suggestionsMenu.renderTo(document.body);

			// Position menu
			var pos = DOMUtils.DOM.getPos(editor.getContentAreaContainer());
			var targetPos = editor.dom.getPos(spans[0]);
			var root = editor.dom.getRoot();

			// Adjust targetPos for scrolling in the editor
			if (root.nodeName == 'BODY') {
				targetPos.x -= root.ownerDocument.documentElement.scrollLeft || root.scrollLeft;
				targetPos.y -= root.ownerDocument.documentElement.scrollTop || root.scrollTop;
			} else {
				targetPos.x -= root.scrollLeft;
				targetPos.y -= root.scrollTop;
			}

			pos.x += targetPos.x;
			pos.y += targetPos.y;

			suggestionsMenu.moveTo(pos.x, pos.y + spans[0].offsetHeight);
		}

		function getWordCharPattern() {
			// Regexp for finding word specific characters this will split words by
			// spaces, quotes, copy right characters etc. It's escaped with unicode characters
			// to make it easier to output scripts on servers using different encodings
			// so if you add any characters outside the 128 byte range make sure to escape it
			return editor.getParam('spellchecker_wordchar_pattern') || new RegExp(word_regexp, "g");
		}

		function cleanWord(word) {
			return word.replace(/\uFEFF/g, '');
		}

		function getCachedCleanedWords(words) {
			var cachedData = {},
				wordsToCheck = [],
				cleanedWordsForServer = [];

			//For each word we were going to send to the server
			for (var i = 0; i < words.length; i++) {
				//Attempt to get the cached word instead
				var cachedWord = getSpellingCache().retrieveWordFromCache(settings.spellchecker_language, words[i]);

				//If we have the word cached already and it's misspelled
				//we need to add it to the cachedData object under the unclean version of the word
				if (cachedWord && cachedWord.misspelled) {
					cachedData[words[i]] = cachedWord;
				}

				if (!cachedWord) { //Otherwise if we don't have it cached yet
					wordsToCheck.push({
						original: words[i],
						cleaned: cleanWord(words[i])
					});
					cleanedWordsForServer.push(cleanWord(words[i]));
				}
			}

			return {
				cachedData: cachedData,
				wordsToCheck: wordsToCheck,
				cleanedWordsForServer: cleanedWordsForServer
			};
		}

		function spellingSuccessCallback(result, cachedCleanedWords, node) {
			result = JSON.parse(result);

			if (!result) {
				spellingErrorCallback("Server response wasn't proper JSON.");
				failed = true;
			} else {
				successes.push(result);
				successCount++;
				if (!failed && successCount === requestCount) {
					editor.setProgressState(false);
					cacheAndMarkSuggestions(cachedCleanedWords.cachedData, successes, cachedCleanedWords.wordsToCheck, node);
				}
			}
		}

		function spellingErrorCallback(message) {
			if (!failed) {
				editor.setProgressState(false);
				editor.notificationManager.open({text: message, type: 'error'});
			}
		}

		function getApiKey() {
			return settings.api_key || settings.spellchecker_api_key;
		}

		function makeServerRequest(data, cachedCleanedWords, node) {
			var postSuffix = "/" + spellcheckerVersion + "/correction";

			var request = {
				url: new URI(url).toAbsolute(settings.spellchecker_rpc_url + postSuffix),
				type: "post",
				content_type: 'application/json',
				data: JSON.serialize(data),
				success: function(result) {
					spellingSuccessCallback.call(self, result, cachedCleanedWords, node);
				},
				error: function(type, xhr) {
					spellingErrorCallback("Spellchecker request error: " + xhr.status);
					failed = true;
				}
			};

			var apiKey = getApiKey();
			if (apiKey) {
				request.requestheaders = [
					{
						key: 'tiny-api-key',
						value: apiKey
					}
				];
			}

			return request;
		}

		function chunkServerRequestData(words) {
			var chunkLetters = 0, lastIndex = 0, requests = [];

			for (var i = 0; i < words.length; i++) {
				chunkLetters += words[i].length;
				if (chunkLetters > maxLetters) {
					requests.push({
						words: words.slice(lastIndex, i + 1),
						language: settings.spellchecker_language
					});
					lastIndex = i + 1;
					chunkLetters = 0;
				}
			}

			if (lastIndex != words.length) {
				requests.push({
					words: words.slice(lastIndex, words.length),
					language: settings.spellchecker_language
				});
			}
			requestCount = requests.length;
			successes = [];
			successCount = 0;
			failed = false;
			return requests;
		}

		function spellcheckServerCall(words, node) {
			var cachedCleanedWords = getCachedCleanedWords(words);

			//If we have some words to check
			if (cachedCleanedWords.wordsToCheck.length > 0) {
				var datas = chunkServerRequestData(cachedCleanedWords.cleanedWordsForServer);
				for (var i = 0; i < datas.length; i++) {
					var request = makeServerRequest(datas[i], cachedCleanedWords, node);
					XHR.send(request);
				}
			} else {
				cacheAndMarkSuggestions(cachedCleanedWords.cachedData, [], cachedCleanedWords.wordsToCheck, node);
			}
		}

		function spellcheck(node) {
			spellcheckServerCall(getTextMatcher().getWords(node), node);
			editor.focus();
		}

		function ignoreWord(word, spans, all) {
			editor.selection.collapse();

			if (all) {
				Tools.each(editor.dom.select('span.' + wordClass), function(span) {
					if (span.getAttribute('data-mce-word') == word) {
						//editor.dom.remove(span, true);
						span.className = ignoreClass;
					}
				});
			} else {
				//editor.dom.remove(spans, true);
				Tools.each(spans, function(span) {
					span.className = ignoreClass;
				});
			}

		}

		function getElmIndex(elm) {
			var value = elm.getAttribute('data-mce-index');

			if (typeof value == "number") {
				return "" + value;
			}

			return value;
		}

		function findSpansByIndex(index, node) {
			var nodes, spans = [];

			nodes = Tools.toArray(node.getElementsByTagName('span'));
			if (nodes.length) {
				for (var i = 0; i < nodes.length; i++) {
					var nodeIndex = getElmIndex(nodes[i]);

					if (nodeIndex === null || !nodeIndex.length) {
						continue;
					}

					if (nodeIndex === index.toString()) {
						spans.push(nodes[i]);
					}
				}
			}

			return spans;
		}

		function updateSelection(e) {
			var selectedLanguage = settings.spellchecker_language;

			Tools.each(e.control.items(), function(item) {
				item.active(item.data.data === selectedLanguage);
			});
		}

		function setUpActiveStateToggle(e) {
			e.control.on('show', function(ee) {
				updateSelection(ee);
			});
		}

		function setUpActiveSpellcheckingToggle(e) {
			spellcheckMenuItem = e.control;
			e.control.on('show', function() {
				this.active(spellchecking);
			});
			spellcheckMenuItem.active(spellchecking);
		}

		function cacheAndCombineResults(cachedData, wordResults, words) {
			var combinedResults = {};

			//Add cached results to combined data object
			for (var cachedField in cachedData) {
				if (cachedData[cachedField] && cachedData[cachedField].misspelled) {
					combinedResults[cachedField] = cachedData[cachedField].suggestions;
				}
			}

			//For each misspelled result we have from the server, we need to add it to the cache.
			for (var field in wordResults) {
				getSpellingCache().addWordToCache(settings.spellchecker_language, field, true, wordResults[field]);
				//For each word we were going to check, if the cleaned version of the word matches the currently being checked field
				for (var w = 0; w < words.length; w++) {
					//We've found our word
					if (words[w].cleaned === field) {
						combinedResults[words[w].original] = wordResults[field];
						break;
					}
				}
			}

			return combinedResults;
		}

		function cacheCorrectlySpelledWords(words) {
			//Finally, now that we have the combinedresults of a cache and service
			for (var i = 0; i < words.length; i++) {
				//If a word we were searching for isn't cached, and isn't part of the results
				//We need to assume that the word is in the dictionary
				var cachedWord = getSpellingCache().retrieveWordFromCache(settings.spellchecker_language, words[i].cleaned);

				if (!cachedWord) {
					getSpellingCache().addWordToCache(settings.spellchecker_language, words[i].cleaned, false, []);
				}
			}
		}

		function cacheAndMarkSuggestions(cachedData, responses, words, node) {

			var wordResults = {};

			for (var i = 0; i < responses.length; i++) {
				for (var field in responses[i].spell) {
					wordResults[field] = responses[i].spell[field];
				}
			}

			var combinedResults = cacheAndCombineResults(cachedData, wordResults, words);

			cacheCorrectlySpelledWords(words);

			markErrors(combinedResults, node);
		}

		function unwrapWordNode(wordNode) {
			var parentNode = wordNode.parentNode;
			var childNodes = wordNode.childNodes;
			while (childNodes.length > 0) {
				parentNode.insertBefore(childNodes[0], wordNode);
			}
			wordNode.parentNode.removeChild(wordNode);
		}

		function clearWordMarks(node) {
			var wrappedWords = editor.dom.select('span.' + wordClass, node);

			//Unwrap from node
			for (var i = 0; i < wrappedWords.length; i++) {
				unwrapWordNode(wrappedWords[i]);
			}
		}

		/**
		 * Find the specified words and marks them. It will also show suggestions for those words.
		 *
		 * @example
		 * editor.plugins.tinymcespellcheckerplugin.markErrors({
		 *     dictionary: true,
		 *     words: {
		 *         "word1": ["suggestion 1", "Suggestion 2"]
		 *     }
		 * });
		 * @param {Object} data Data object containing the words with suggestions.
		 */
		function markErrors(data, node) {

			var bm = editor.selection.getBookmark();

			clearWordMarks(node);

			var matches = getTextMatcher().find(getWordCharPattern(), undefined, node);
			matches = getTextMatcher().filter(matches, function(match) {
				return !!data[match.text];
			});

			getTextMatcher().wrap(matches, function(match) {
				return editor.dom.create('span', {
					"class": wordClass,
					"data-mce-bogus": 1,
					"data-mce-word": match.text
				});
			}, node);

			editor.selection.moveToBookmark(bm);
		}

		function getParentBlock(currNode) {
			var rootNode = editor.getBody(),
			parentNode = rootNode, blockElements = editor.schema.getBlockElements();

			for (currNode = currNode; currNode != rootNode; currNode = currNode.parentNode) {
				if (currNode === null || currNode === undefined) {
					break;
				}
				if (blockElements[currNode.nodeName]) {
					parentNode = currNode;
					break;
				}
			}

			return parentNode;
		}

		function buildMenuItems(listName, languageValues) {
			var items = [];

			Tools.each(languageValues, function(languageValue) {
				items.push({
					selectable: true,
					text: languageValue.name,
					data: languageValue.value,
					onclick: function() {
						settings.spellchecker_language = languageValue.value;
						if (spellchecking) {
							spellcheck(editor.getBody());
						}
					}
				});
			});

			return items;
		}

		languageMenuItems = buildMenuItems('Language',
			Tools.map(languagesString.split(','), function(langPair) {
				langPair = langPair.split('=');

				return {
					name: langPair[0],
					value: langPair[1]
				};
			})
		);

		function toggleSpellcheck() {
			if (spellchecking) {
				unBindEvents();
				clearWordMarks(editor.getBody());
			} else {
				bindEvents();
				spellcheck(editor.getBody());
			}
			spellchecking = !spellchecking;
			spellcheckButton.active(spellchecking);
			if (spellcheckMenuItem) {
				spellcheckMenuItem.active(spellchecking);
			}
		}

		var buttonArgs = {
			tooltip: 'Spellcheck',
			onclick: toggleSpellcheck,
			onPostRender: function(e) {
				e.control.active(spellchecking);
			}
		};

		if (languageMenuItems.length > 1) {
			buttonArgs.type = 'splitbutton';
			buttonArgs.menu = languageMenuItems;
			buttonArgs.onshow = updateSelection;
			buttonArgs.onpostrender = function(e) {
				spellcheckButton = e.control;
			};
		}

		editor.addButton('spellchecker', buttonArgs);
		editor.addCommand('mceSpellCheck', toggleSpellcheck);

		editor.addMenuItem('spellchecker', {
			text: 'Spellcheck',
			context: 'tools',
			onclick: toggleSpellcheck,
			onPostRender: setUpActiveSpellcheckingToggle,
			selectable: true
		});

		editor.addMenuItem('spellcheckerlanguage', {
			text: 'Spellcheck Language',
			context: 'tools',
			menu: languageMenuItems,
			onPostRender: setUpActiveStateToggle
		});

		function editorRemove() {
			if (suggestionsMenu) {
				suggestionsMenu.remove();
				suggestionsMenu = null;
			}
		}

		function editorKeydown(e) {
			//We probably don't want to unwrap the word we're in if we're just pressing arrow keys around
			if ((e.which || e.keycode) === 37 ||
				(e.which || e.keycode) === 38 ||
				(e.which || e.keycode) === 39 ||
				(e.which || e.keycode) === 40) {
				return;
			}

			var currNode = editor.selection.getNode();

			if (DOMUtils.DOM.hasClass(currNode, wordClass) || DOMUtils.DOM.hasClass(currNode, ignoreClass)) {

				var parentNode = getParentBlock(currNode),
					wordNodes = findSpansByIndex(getElmIndex(currNode), parentNode);

				//Unwrap the ignored/misspelled word
				if (wordNodes.length > 0) {
					var bm = editor.selection.getBookmark();
					for (var i = 0; i < wordNodes.length; i++) {
						unwrapWordNode(wordNodes[i]);
					}
					editor.selection.moveToBookmark(bm);
				}
			}
		}

		function editorKeyup(e) {

			var currNode = editor.selection.getNode(),
				parentNode = getParentBlock(currNode);

			if ((e.which || e.keycode) === 32) {

				spellcheck(parentNode);

			}
		}

		function editorNodeChange(e) {

			//We don't really need two events...
			if (e.selectionChange) {
				return;
			}

			var previousParentNode = currentParentNode;

			currentParentNode = getParentBlock(e.element);

			//If the node we just changed from is the exact same as the current node
			//we should prevent sending a request
			if (previousParentNode === currentParentNode) {
				return;
			}

			if (previousParentNode) {
				spellcheck(previousParentNode);
			}

		}

		function editorContextMenu(e) {
			var target = e.target;

			if (DOMUtils.DOM.hasClass(target, wordClass)) {

				var spans = findSpansByIndex(getElmIndex(target), getParentBlock(target));

				if (spans.length > 0) {
					var rng = editor.dom.createRng();
					rng.setStartBefore(spans[0]);
					rng.setEndAfter(spans[spans.length - 1]);
					editor.selection.setRng(rng);
					showSuggestions(target.getAttribute('data-mce-word'), spans, e);
				}

				e.preventDefault();
				e.stopImmediatePropagation();
			}
		}

		function bindEvents() {
			editor.on('remove', editorRemove);
			editor.on('keydown', editorKeydown);
			editor.on('keyup', editorKeyup);
			editor.on('nodechange', editorNodeChange);
		}

		function unBindEvents() {
			editor.off('remove', editorRemove);
			editor.off('keydown', editorKeydown);
			editor.off('keyup', editorKeyup);
			editor.off('nodechange', editorNodeChange);
		}

		editor.on('contextmenu', editorContextMenu, true);

		bindEvents();

		this.getTextMatcher = getTextMatcher;
		this.getWordCharPattern = getWordCharPattern;
		this.markErrors = markErrors;
		this.getLanguage = function() {
			return settings.spellchecker_language;
		};

		// Set default spellchecker language if it's not specified
		settings.spellchecker_language = settings.spellchecker_language || settings.language || 'en';
	});
});

expose(["tinymce/tinymcespellcheckerplugin/DomTextMatcher","tinymce/tinymcespellcheckerplugin/SpellingCache"]);
})(this);<file_sep>/*!
 * SAP APF Analysis Path Framework
 *
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
/* global  window*/
jQuery.sap.require('sap.apf.ui.utils.helper');
/**
 *@class stepToolbar
 *@name stepToolbar
 *@memberOf sap.apf.ui.reuse.controller
 *@description controller for view.stepToolbar
 */
sap.ui.controller("sap.apf.ui.reuse.controller.stepToolbar", {
    /**
     *@this {sap.apf.ui.reuse.controller.stepToolbar}
     */
    chartIconInserted: false,
    alternateRepresentationIcon: false,
    alternateRepresentationBool: false,
    selectedRepresentation: null,
    alternateRepresentationBtn: {},
    selectedNumber: null,
    selectedNumberLink: null,
    isSwitchRepresentation: false,
    viewSettingsIcon: null,
    onInit: function() {
        this.oCoreApi = this.getView().getViewData().oCoreApi;
        this.oUiApi = this.getView().getViewData().uiApi;
        if (sap.ui.Device.system.desktop) {
            this.getView().addStyleClass("sapUiSizeCompact");
        }
    },
    /**
     *@memberOf sap.apf.ui.reuse.controller.stepToolbar
     *@method addCompactStyleClassForDialog
     *@param Dialog Instance on which style class has to be applied
     *@description Sets compact mode for dialogs when application is running in desktop
     */
    addCompactStyleClassForDialog: function(oDialog) {
        if (sap.ui.Device.system.desktop) {
            oDialog.addStyleClass("sapUiSizeCompact");
        }
    },
    /**
     *@memberOf sap.apf.ui.reuse.controller.stepToolbar
     *@method drawAlternateRepresentation
     *@description Inserts the alternate representation icon to the chart toolbar
     */
    drawAlternateRepresentation: function() {
        var that = this;
        this.alternateRepresentationBtn = new sap.m.Button({
            icon: this.oCoreApi.getActiveStep().getSelectedRepresentation().getAlternateRepresentation().picture,
            tooltip: this.oCoreApi.getTextNotHtmlEncoded("TableRepresentation"),
            press: function() {
                var oStep = that.oCoreApi.getActiveStep();
                var currentRepresentation = oStep.getSelectedRepresentation();
                var activeStepIndex = that.oCoreApi.getSteps().indexOf(oStep);
                that.selectedRepresentation = "table";
                currentRepresentation.bIsAlternateView = true;
                if (currentRepresentation.toggleInstance === undefined) {
                    currentRepresentation.toggleInstance = that.oUiApi.getStepContainer().getController().createAlternateRepresentation(activeStepIndex);
                } else {
                    var data = currentRepresentation.getData(),
                        metadata = currentRepresentation.getMetaData();
                    if (data !== undefined && metadata !== undefined) {
                        currentRepresentation.toggleInstance.setData(data, metadata);
                    }
                    currentRepresentation.toggleInstance.adoptSelection(currentRepresentation);
                }
                that.oUiApi.getAnalysisPath().getController().refresh(-1);
                that.oUiApi.getStepContainer().getController().drawStepContent();
                that.oUiApi.getAnalysisPath().getCarousel().getStepView(activeStepIndex).getController().drawThumbnailContent(true);
            }
        }).addStyleClass("alternateButton");
        this.insertViewSettingsIcon();
        this.getView().chartToolbar.getToolBar().insertContentRight(this.alternateRepresentationBtn);
    },
    /** 
     *@memberOf sap.apf.ui.reuse.controller.stepToolbar
     *@method drawMultipleRepresentation
     *@description Method to insert icons for multiple representations
     */
    insertViewSettingsIcon: function() {
        var that = this;
        var viewSettingsDialog;
        this.sortButton = new sap.m.Button({
            icon: "sap-icon://drop-down-list",
            tooltip: this.oCoreApi.getTextNotHtmlEncoded("view-Settings"),
            press: function() {
                if (that.oCoreApi.getActiveStep().getSelectedRepresentation().type !== sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) {
                    viewSettingsDialog = that.oCoreApi.getActiveStep().getSelectedRepresentation().toggleInstance.viewSettingsDialog;
                    that.addCompactStyleClassForDialog(viewSettingsDialog);
                    viewSettingsDialog.open();
                } else {
                    viewSettingsDialog = that.oCoreApi.getActiveStep().getSelectedRepresentation().viewSettingsDialog;
                    that.addCompactStyleClassForDialog(viewSettingsDialog);
                    viewSettingsDialog.open();
                }
            }
        }).addStyleClass("sortButton");
        this.getView().chartToolbar.getToolBar().insertContentRight(this.sortButton);
    },
    /**
     *@memberOf sap.apf.ui.reuse.controller.stepToolbar
     *@method showSelectionCount
     *@description Shows the selected count(label) and delete icon of the representation
     */
    showSelectionCount: function() {
        var oActiveStep = this.oCoreApi.getActiveStep();
        var selectedRepresentation = oActiveStep.getSelectedRepresentation();
        var selectionCount = selectedRepresentation.getSelections().length || selectedRepresentation.getSelectionCount(); // read the selections from selection count or selections, which ever is available
        var bRequirefFilterPresent = selectedRepresentation.getParameter().requiredFilters !== undefined && selectedRepresentation.getParameter().requiredFilters.length !== 0;
        var bMetadataPresent = selectedRepresentation.getMetaData !== undefined && selectedRepresentation.getMetaData() !== undefined && selectedRepresentation.getMetaData().hasOwnProperty("getPropertyMetadata");
        var selectedDimension = bRequirefFilterPresent && bMetadataPresent ? selectedRepresentation.getMetaData().getPropertyMetadata(selectedRepresentation.getParameter().requiredFilters[0]).label : null;
        if (selectedDimension === null || selectionCount === 0) {
            jQuery(".showSelection").hide();
            jQuery(".resetSelection").hide();
        } else if (selectionCount > 0) {
            this.selectedNumber.setText("(" + this.oCoreApi.getTextNotHtmlEncoded("selected-objects", [selectedDimension]));
            this.selectedNumberLink.setText(selectionCount);
            this.selectedNumberEndText.setText(')');
            jQuery(".showSelection").show();
            jQuery(".resetSelection").show();
        }
    },
    /**
     *@memberOf sap.apf.ui.reuse.controller.stepToolbar
     *@method insertContentLeft
     *@description Inserts the Selection label,count and delete icon to the step toolbar
     */
    insertContentLeft: function() {
        var that = this;
        // insert left content to the toolbar
        this.currentStepText = new sap.m.Label({
            wrapping: true,
            text: this.oCoreApi.getTextNotHtmlEncoded("currentStep")
        }).addStyleClass("currentStep");
        this.selectedNumber = new sap.m.Label({
            wrapping: true
        }).addStyleClass("showSelection");
        this.selectedNumberEndText = new sap.m.Label({
            wrapping: true
        }).addStyleClass("showSelection");
        this.selectedNumberEndText.addStyleClass("selectedNumberEndText");
        this.selectedNumberLink = new sap.m.Link({
            press: function() {
                if (that.selectionDisplayDialog) {
                    that.selectionDisplayDialog.destroy();
                }
                that.selectionDisplayDialog = new sap.ui.jsfragment("sap.apf.ui.reuse.fragment.selectionDisplay", that);
                that.addCompactStyleClassForDialog(that.selectionDisplayDialog);
                that.selectionDisplayDialog.open();
            }
        }).addStyleClass("showSelection");
        this.selectedNumberLink.addStyleClass("selectedNumberLink");
        // delete icon for selected items
        this.resetSelection = new sap.m.Link({
            text: this.oCoreApi.getTextNotHtmlEncoded("resetSelection")
        }).attachPress(function() {
            jQuery(".showSelection").hide();
            jQuery(".resetSelection").hide();
            if (that.oCoreApi.getActiveStep().getSelectedRepresentation().bIsAlternateView) {
                that.oCoreApi.getActiveStep().getSelectedRepresentation().toggleInstance.removeAllSelection();
            }
            that.oCoreApi.getActiveStep().getSelectedRepresentation().removeAllSelection();
        }).addStyleClass("resetSelection");
        this.getView().chartToolbar.getToolBar().insertContentRight(this.resetSelection);
        this.getView().chartToolbar.getToolBar().insertContentLeft(this.selectedNumberEndText);
        this.getView().chartToolbar.getToolBar().insertContentLeft(this.selectedNumberLink);
        this.getView().chartToolbar.getToolBar().insertContentLeft(this.selectedNumber);
        this.getView().chartToolbar.getToolBar().insertContentLeft(this.currentStepText);
    },
    /**
     *@memberOf sap.apf.ui.reuse.controller.stepToolbar
     *@method drawSingleRepresentation
     *@description Method to insert icon for single representation
     */
    drawSingleRepresentation: function() {
        var that = this;
        var activeStep = this.oCoreApi.getActiveStep();
        activeStep.selectedRepresentaionType = activeStep.getSelectedRepresentationInfo();
        if (activeStep.selectedRepresentaionType.parameter && activeStep.selectedRepresentaionType.parameter.orderby) {
            var representationSortDetail = new sap.apf.ui.utils.Helper(that.oCoreApi).getRepresentationSortInfo(activeStep.selectedRepresentaionType);
            activeStep.selectedRepresentaionType.sortDescription = representationSortDetail;
        }
        var selectedMultipleRepresentationBtn = new sap.m.Button({
            icon: activeStep.selectedRepresentaionType.picture,
            tooltip: this.oCoreApi.getTextNotHtmlEncoded(activeStep.selectedRepresentaionType.label) + "\n" + ((activeStep.selectedRepresentaionType.sortDescription !== undefined) ? this.oCoreApi.getTextNotHtmlEncoded("sortBy") + ": " + activeStep.selectedRepresentaionType.sortDescription : ""),
            press: function() {
                var oStep = that.oCoreApi.getActiveStep();
                var currentRepresentation = oStep.getSelectedRepresentation();
                currentRepresentation.bIsAlternateView = false;
                that.oUiApi.getStepContainer().getController().drawStepContent();
                var activeStepIndex = that.oCoreApi.getSteps().indexOf(oStep);
                that.oUiApi.getAnalysisPath().getCarousel().getStepView(activeStepIndex).getController().drawThumbnailContent(true);
            }
        });
        this.getView().chartToolbar.getToolBar().insertContentRight(selectedMultipleRepresentationBtn, 0);
        this.insertContentLeft();
    },
    /** 
     *@memberOf sap.apf.ui.reuse.controller.stepToolbar
     *@method drawMultipleRepresentation
     *@description Method to insert icons for multiple representations
     */
    drawMultipleRepresentation: function() {
        var that = this;
        var activeStep = this.oCoreApi.getActiveStep();
        activeStep.representationtypes = activeStep.getRepresentationInfo();
        activeStep.representationtypes.forEach(function(oRepresentation) {
            if (oRepresentation.parameter && oRepresentation.parameter.orderby) { //if orderby has a value then only get the sort description
                var representationSortDetail = new sap.apf.ui.utils.Helper(that.oCoreApi).getRepresentationSortInfo(oRepresentation);
                oRepresentation.sortDescription = representationSortDetail;
            }
        });
        activeStep.selectedRepresentaionType = activeStep.getSelectedRepresentationInfo();
        if (activeStep.selectedRepresentaionType.parameter && activeStep.selectedRepresentaionType.parameter.orderby) {
            var representationSortDetail = new sap.apf.ui.utils.Helper(this.oCoreApi).getRepresentationSortInfo(activeStep.selectedRepresentaionType);
            activeStep.selectedRepresentaionType.sortDescription = representationSortDetail;
        }

        var reperesentationTypesLength = activeStep.representationtypes.length;
        var selectedMultipleRepresentationBtn;
        var drawSelectedRepresentation = function(data) {
            var activeStep = that.oCoreApi.getSteps()[data.nActiveStepIndex];
            activeStep.getSelectedRepresentation().bIsAlternateView = false;
            activeStep.setSelectedRepresentation(data.oRepresentationType.representationId);
            that.oUiApi.getAnalysisPath().getController().refresh(data.nActiveStepIndex);
            that.oCoreApi.updatePath(that.oUiApi.getAnalysisPath().getController().callBackForUpdatePath.bind(that.oUiApi.getAnalysisPath().getController()));
        };
        this.openList = function(oEvent) {
            var data = oEvent.getParameter("listItem").getCustomData()[0].getValue();
            drawSelectedRepresentation(data);
            selectedMultipleRepresentationBtn.setIcon(data.icon);
            selectedMultipleRepresentationBtn.setTooltip(that.oCoreApi.getTextNotHtmlEncoded(data.oRepresentationType.label) + "\n" + (data.oRepresentationType.sortDescription !== undefined ? that.oCoreApi.getTextNotHtmlEncoded("sortBy") + ": " + data.oRepresentationType.sortDescription : ""));
        };
        var oAllChartList = new sap.m.List({
            mode: sap.m.ListMode.SingleSelectMaster,
            showSeparators: sap.m.ListSeparators.None,
            includeItemInSelection: true,
            select: jQuery.proxy(function(oEvent) {
                this.openList(oEvent);
            }, this)
        });
        var bAdaptTitleSize = sap.ui.Device.system.desktop ? false : true;
        for (var j = 0; j < reperesentationTypesLength; j++) {
            var oItem = new sap.m.StandardListItem({
                description: activeStep.representationtypes[j].sortDescription && this.oCoreApi.getTextNotHtmlEncoded("sortBy") + ": " + activeStep.representationtypes[j].sortDescription,
                icon: activeStep.representationtypes[j].picture,
                title: that.oCoreApi.getTextNotHtmlEncoded(activeStep.representationtypes[j].label),
                adaptTitleSize: bAdaptTitleSize,
                customData: [new sap.ui.core.CustomData({
                    key: 'data',
                    value: {
                        oRepresentationType: activeStep.representationtypes[j],
                        nActiveStepIndex: that.oCoreApi.getSteps().indexOf(that.oCoreApi.getActiveStep()),
                        icon: activeStep.representationtypes[j].picture
                    }
                })]
            });
            if (sap.ui.Device.system.desktop) {
                oItem.addStyleClass("repItem");
            }
            oAllChartList.addItem(oItem);
        }
        var oShowAllChartPopover = new sap.m.Popover({
            placement: sap.m.PlacementType.Bottom,
            showHeader: false,
            content: [oAllChartList]
        }).addStyleClass("sapCaUiChartToolBarShowAllChartListPopover");
        //full-screen buttons
        function fnPress(oEvent) {
            var data = oEvent.getSource().getCustomData()[0].getValue();
            drawSelectedRepresentation(data);
        }
        for (var k = 0; k < reperesentationTypesLength; k++) {
            var button = new sap.m.Button({
                tooltip: that.oCoreApi.getTextNotHtmlEncoded(activeStep.representationtypes[k].label) + "\n" + ((activeStep.representationtypes[k].sortDescription !== undefined) ? this.oCoreApi.getTextNotHtmlEncoded("sortBy") + ": " + activeStep.representationtypes[k].sortDescription : ""),
                icon: activeStep.representationtypes[k].picture,
                customData: [new sap.ui.core.CustomData({
                    key: 'data',
                    value: {
                        oRepresentationType: activeStep.representationtypes[k],
                        nActiveStepIndex: that.oCoreApi.getSteps().indexOf(that.oCoreApi.getActiveStep()),
                        icon: activeStep.representationtypes[k].picture
                    }
                })],
                press: fnPress
            });
            button.addStyleClass("iconLeft");
            this.getView().chartToolbar.getToolBar().insertContentRight(button);
        }
        selectedMultipleRepresentationBtn = new sap.m.Button({
            icon: activeStep.selectedRepresentaionType.picture,
            tooltip: this.oCoreApi.getTextNotHtmlEncoded(activeStep.selectedRepresentaionType.label) + "\n" + ((activeStep.selectedRepresentaionType.sortDescription !== undefined) ? this.oCoreApi.getTextNotHtmlEncoded("sortBy") + ": " + activeStep.selectedRepresentaionType.sortDescription : ""),
            press: function() {
                oShowAllChartPopover.openBy(this);
            }
        }).addStyleClass("iconList");
        this.getView().chartToolbar.getToolBar().insertContentRight(selectedMultipleRepresentationBtn, 0);
        this.insertContentLeft();
    },
    /**
     *@memberOf sap.apf.ui.reuse.controller.stepToolbar
     *@method drawToolBar
     *@description renders the toolbar specific for single or multiple representations and shows/hide legend icon/alternate representation icon
     */
    drawToolBar: function() {
        var that = this;
        this.showAndHideIcons = function() {
            var that = this;
            that.isSwitchRepresentation = false;
            if (that.getView().chartToolbar.getFullScreen() === true) {
                //full-screen
                jQuery(".iconList").hide();
                jQuery(".iconLeft").show();
            } else {
                //initial
                jQuery(".iconList").show();
                jQuery(".iconLeft").hide();
            }
            //show table sort icon, show only if the representation is table and if the alternate representation is table
            if ((that.oCoreApi.getActiveStep().getSelectedRepresentation().bIsAlternateView && that.oCoreApi.getActiveStep().getSelectedRepresentation().getAlternateRepresentation().id === sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) || that.oCoreApi.getActiveStep().getSelectedRepresentation().type === sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) {
                jQuery(".sortButton").show();
            } else {
                jQuery(".sortButton").hide();
            }
            // selection count and label
            if (that.oCoreApi.getSteps().length >= 1) {
                that.showSelectionCount();
            }
            // for iPhone and when screen resizes, the chartToolbar width will be equal to window width
            var toolbarId = that.getView().chartToolbar.getId();
            if (that.oCoreApi.getActiveStep().getSelectedRepresentation().getAlternateRepresentation() !== undefined) {
                if ((!that.oCoreApi.getActiveStep().getSelectedRepresentation().bIsAlternateView && that.oCoreApi.getActiveStep().getSelectedRepresentation().getAlternateRepresentation().id !== sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) || that.oCoreApi.getActiveStep().getSelectedRepresentation().type !== sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) {
                    if ((window.innerWidth === jQuery("#" + toolbarId + " > div:first-child > div:nth-child(2)").width())) {
                        jQuery(that.getView().chartToolbar._oShowLegendButton.getDomRef()).show();
                    }
                }
            }
        };
        this.renderIcons = function() {
            var that = this;
            var oActiveStep = that.oCoreApi.getActiveStep();
            if (oActiveStep !== undefined) {
                //tooltip added for fullscreen
                that.getView().chartToolbar._oFullScreenButton.setTooltip(that.oCoreApi.getTextNotHtmlEncoded("toggle-fullscreen"));
                that.getView().chartToolbar._oFullScreenExitButton.setTooltip(that.oCoreApi.getTextNotHtmlEncoded("toggle-fullscreen"));
                //draw table
                if (that.alternateRepresentationIcon === false && that.oCoreApi.getActiveStep().getSelectedRepresentation().type !== sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) {
                    that.drawAlternateRepresentation();
                    that.alternateRepresentationIcon = true;
                }
                //table sort icon
                if (that.oCoreApi.getActiveStep().getSelectedRepresentation().type === sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) {
                    if (that.viewSettingsIcon === false) {
                        that.insertViewSettingsIcon();
                    }
                    that.viewSettingsIcon = true;
                }
                //draw representation
                if (that.oCoreApi.getActiveStep().getRepresentationInfo().length > 1) {
                    if (that.chartIconInserted === false) {
                        that.drawMultipleRepresentation();
                    }
                    that.chartIconInserted = true;
                } else if (that.oCoreApi.getActiveStep().getRepresentationInfo().length === 1) { // table representation can exists as single representation
                    if (that.chartIconInserted === false) {
                        that.drawSingleRepresentation();
                    }
                    that.chartIconInserted = true;
                }
                //Disable if the representation is table or geomap
                if ((that.oCoreApi.getActiveStep().getSelectedRepresentation().bIsAlternateView && that.oCoreApi.getActiveStep().getSelectedRepresentation().getAlternateRepresentation().id === sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) || that.oCoreApi.getActiveStep().getSelectedRepresentation().type === (sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION || sap.apf.ui.utils.CONSTANTS.representationTypes.GEO_MAP)) {
                    that.getView().chartToolbar._oShowLegendButton.setVisible(false);
                } else {
                    that.getView().chartToolbar._oShowLegendButton.setVisible(true);
                    that.getView().chartToolbar._oShowLegendButton.setTooltip(that.oCoreApi.getTextNotHtmlEncoded("legend"));
                }
                //If representation is switched then show the legend
                if (that.isSwitchRepresentation === true) {
                    that.getView().chartToolbar.setShowLegend(true);
                }
            }
        };
        this.getView().chartToolbar.addEventDelegate({
            onAfterRendering: function() {
                if (that.oCoreApi.getSteps().length > 0) {
                    that.showAndHideIcons();
                }

                var oStep = that.oCoreApi.getActiveStep();
                if (oStep) { //If step exists then toggle the legend 
                    var currentRepresentation = oStep.getSelectedRepresentation();
                    var formatString;
                    var stepRepresentation = oStep.getSelectedRepresentation().chart || {};
                    //Show/Hide Legend
                    if (currentRepresentation.bIsLegendVisible === true || currentRepresentation.bIsLegendVisible === undefined) {
                        if (stepRepresentation.setVizProperties) { //Check if Viz Frame Charts
                            stepRepresentation.setVizProperties({
                                legend: {
                                    visible: true
                                },
                                sizeLegend: {
                                    visible: true
                                }
                            });
                        } else { //Fallback for Viz Charts
                            if (stepRepresentation.setLegend !== undefined) {
                                stepRepresentation.setLegend(new sap.viz.ui5.types.legend.Common({
                                    visible: true,
                                    title: new sap.viz.ui5.types.legend.Common_title({
                                        visible: true
                                    })
                                }));
                            }
                            if (stepRepresentation.setSizeLegend !== undefined) {
                                formatString = stepRepresentation.getSizeLegend().getFormatString();
                                stepRepresentation.setSizeLegend(new sap.viz.ui5.types.legend.Common({
                                    visible: true,
                                    title: new sap.viz.ui5.types.legend.Common_title({
                                        visible: true
                                    })
                                }));
                                if (formatString !== null) {
                                    stepRepresentation.getSizeLegend().setFormatString(formatString);
                                }
                            }
                        }
                    } else {
                        if (stepRepresentation.setVizProperties) { //Check if Viz Frame Charts
                            stepRepresentation.setVizProperties({
                                legend: {
                                    visible: false
                                },
                                sizeLegend: {
                                    visible: false
                                }
                            });
                        } else { //Fallback for Viz Charts
                            if (stepRepresentation.setLegend !== undefined) {
                                stepRepresentation.setLegend(new sap.viz.ui5.types.legend.Common({
                                    visible: false,
                                    title: new sap.viz.ui5.types.legend.Common_title({
                                        visible: false
                                    })
                                }));
                            }
                            if (stepRepresentation.setSizeLegend !== undefined) {
                                formatString = stepRepresentation.getSizeLegend().getFormatString();
                                stepRepresentation.setSizeLegend(new sap.viz.ui5.types.legend.Common({
                                    visible: false,
                                    title: new sap.viz.ui5.types.legend.Common_title({
                                        visible: false
                                    })
                                }));
                                if (formatString !== null) {
                                    stepRepresentation.getSizeLegend().setFormatString(formatString);
                                }
                            }
                        }
                    }
                }
            },
            onBeforeRendering: function() {
                if (that.oCoreApi.getSteps().length > 0) {
                    that.renderIcons();
                }
            }
        });
    },
    /**
     *@memberOf sap.apf.ui.reuse.controller.stepToolbar
     *@method drawRepresentation
     *@description This method clears the toolbar content, insert chart and renders toolbar
     */
    drawRepresentation: function(oChart) {
        var that = this;
        this.isSwitchRepresentation = true;
        this.getView().chartToolbar.getToolBar().removeAllContentLeft();
        this.getView().chartToolbar.getToolBar().removeAllContentRight();
        this.chartIconInserted = false;
        this.alternateRepresentationIcon = false;
        this.viewSettingsIcon = false;
        this.getView().chartToolbar.removeAllCharts();
        this.getView().chartToolbar.insertChart(oChart);
        if (this.getView().chartToolbar.getFullScreen() === true) {
            this.getView().chartToolbar.rerender(); //re-render's main chart on fullscreen   
            //re-render the table after the selection mode is changed
            if (this.oCoreApi.getActiveStep().getSelectedRepresentation().bIsAlternateView || this.oCoreApi.getActiveStep().getSelectedRepresentation().type === sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) {
                var selectionMode = this.oCoreApi.getActiveStep().getSelectedRepresentation().getParameter().requiredFilters.length > 0 ? "MultiSelect" : "None";
                this.getView().chartToolbar.getCharts()[0].getContent()[0].getContent()[1].getContent()[0].setMode(selectionMode);
                this.getView().chartToolbar.getCharts()[0].getContent()[0].getContent()[1].getContent()[0].rerender();
            }
        }
        this.drawToolBar();
        //Handle Legend Show/Hide Mapped to Representations
        this.getView().chartToolbar.onAfterRendering = function() {
            var legendIcon = this._oShowLegendButton.getDomRef();
            //Bind Click Event on legend icon to switch the state of hide/show boolean
            var evtType = sap.ui.Device.browser.mobile ? "tap" : "click";
            jQuery(legendIcon).on(evtType, function() {
                var oStep = that.oCoreApi.getActiveStep();
                var currentRepresentation = oStep.getSelectedRepresentation();
                if (currentRepresentation.bIsLegendVisible === true || currentRepresentation.bIsLegendVisible === undefined) {
                    currentRepresentation.bIsLegendVisible = false;
                } else {
                    currentRepresentation.bIsLegendVisible = true;
                }
            });
        };
    }
});<file_sep>/* @copyright */

/**
* Constructor for the Feed Component.
*
* Accepts an object literal <code>mSettings</code> that defines initial 
* property values, aggregated and associated objects as well as event handlers.
* 
*
* @param {string} [sId] id for the new component, generated automatically if no id is given 
* @param {map} [mSettings] initial settings for the new component. See the documentation of the component's properties for the structure of the expected data.
* 
* @class 
* The Feed Component is an SAPUI5 component that allows you to display SAP Jam feeds. 
* It includes the option to add new posts and reply to entries and view other users' social profiles from SAP Jam,
*
* @extends sap.ui.core.UIComponent
* @version ${version}
* @since 1.30
* 
* @constructor
* @public
* @name sap.collaboration.components.feed.Component
* 
*/
(function() {
	var sComponentName = "sap.collaboration.components.feed.Component";
	jQuery.sap.require("sap.ui.core.UIComponent");
	jQuery.sap.require("sap.suite.ui.commons.library");
	jQuery.sap.declare(sComponentName);
	sap.ui.core.UIComponent.extend(sComponentName, {

	    metadata : {
	        stereotype: "component",
	    	version: "1.0",
	    	includes: ["../resources/css/MorePopover.css"],
	    	dependencies: {
	    		libs: [],
	    		components: [],
	    		ui5version: ""
	    	},
	    	library: "sap.collaboration",
	    	properties: {
				"axisOrientation": {type:"sap.suite.ui.commons.TimelineAxisOrientation",group:"Misc",defaultValue:sap.suite.ui.commons.TimelineAxisOrientation.Vertical},
				"feedSources": {type:"object|string[]"}
	    	},
	    	
	        rootView : null, // the rootView to open (view name as string or view configuration object)
	        publicMethods: [ "setSettings", "getSelectedGroup" ],
	        aggregations: {
	        },
		    routing: {  
	        },
	        config: {
	        },
	        customizing: {
	        }
	    },
		/**
		* Initializes the Component instance after creation. 
		* @protected
		* @memberOf sap.collaboration.components.feed.Component
		*/
		init: function() {
			this._logger = new jQuery.sap.log.getLogger(sComponentName);
			sap.ui.core.UIComponent.prototype.init.apply(this); // call superclass; needed to call createContent
		},
		/**
		* Cleans up the component instance before destruction.
		* @protected
		* @memberOf sap.collaboration.components.feed.Component
		*/
		exit: function() {
			
		},
		/**
		* Function is called when the rendering of the Component Container is started.
		* @protected
		* @memberOf sap.collaboration.components.feed.Component
		*/
		onBeforeRendering: function() {			
			
		},
		
		/**
		* Function is called when the rendering of the Component Container is completed. 
		* @protected
		* @memberOf sap.collaboration.components.feed.Component
		*/
		onAfterRendering: function() {
		},
		/**
		 * The method to create the Content (UI Control Tree) of the Component. 
		 * @protected
		 * @memberOf sap.collaboration.components.feed.Component
		 */
		createContent: function() {
			this._view = sap.ui.view({
				id: this.createId("group_feed_view"),
				height: "100%",
				type:sap.ui.core.mvc.ViewType.XML, 
				viewName:"sap.collaboration.components.feed.views.GroupFeed"
			});
			
			this.setAxisOrientation(this.getAxisOrientation());
			
			return this._view;
		},
		/**
		 * Sets all the properties passed in oSettings.
		 * @param {map} settings - key/value map for settings
		 * @memberOf sap.collaboration.components.feed.Component 
		 * @public
		 */
		setSettings: function(settings) {
			for(var key in settings) {
				if(settings.hasOwnProperty(key)) {
					this._setProperty(key, settings[key]);
				}
			}
		},
		/**
		 * Returns the selected Group.
		 * @memberOf sap.collaboration.components.feed.Component
		 * @return {map} a map containing information about the selected Group (e.g. Id, Name, etc...)
		 * @public
		 */
		getSelectedGroup: function() {
			return this._view.getModel().getProperty("/groupSelected");
		},
		/**
		 * Set the property's new value in the component and in the view's model
		 * @param {string} propertyName
		 * @param {string} propertyValue
		 * @memberOf sap.collaboration.components.feed.Component
		 */
		_setProperty: function(propertyName, propertyValue) {
			this._logger.info(propertyName + ": " + propertyValue);
			this._view.getModel().setProperty("/" + propertyName, propertyValue);
			this.setProperty(propertyName, propertyValue);
		},
		/**
		 * Set the axis orientation for the timeline
		 * 
		 * @override 
		 * @param {sap.suite.ui.commons.TimelineAxisOrientation} axisOrientation
		 * @memberOf sap.collaboration.components.feed.Component
		 */
		setAxisOrientation: function(axisOrientation) {
			this._setProperty("axisOrientation", axisOrientation);
		},
		/**
		 * Sets the sources for the feed
		 * - Array of strings representing the Jam group IDs (e.g. ["groupid1", "groupid2"])
		 * 
		 * @override 
		 * @param {object} feedSources
		 * @memberOf sap.collaboration.components.feed.Component
		 */
		setFeedSources: function(feedSources) {
			this._setProperty("feedSources", feedSources);
		}
	});
})();
<file_sep>/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

// -------------------------------------------------------------------------------
// Generates the view metadata required for a field using SAP-Annotations metadata
// -------------------------------------------------------------------------------
sap.ui.define([
	'jquery.sap.global', 'sap/m/CheckBox', 'sap/m/ComboBox', 'sap/m/DatePicker', 'sap/m/TimePicker', 'sap/m/HBox', 'sap/m/Input', 'sap/m/Text', 'sap/ui/comp/navpopover/SmartLink', 'sap/ui/comp/odata/MetadataAnalyser', 'sap/ui/comp/smartfield/ODataHelper', 'sap/ui/comp/smartfield/SmartField', 'sap/ui/comp/odata/ODataType', 'sap/ui/comp/util/FormatUtil'
], function(jQuery, CheckBox, ComboBox, DatePicker, TimePicker, HBox, Input, Text, SmartLink, MetadataAnalyser, ODataHelper, SmartField, ODataType, FormatUtil) {
	"use strict";

	// TODO: CleanUp!

	/**
	 * Constructs a class to generate the view/data model metadata for the controls - that can be used in table/forms etc.
	 * 
	 * @constructor
	 * @experimental This module is only for internal/experimental use!
	 * @public
	 * @param {object} mPropertyBag - PropertyBag having members model, entitySet
	 * @author <NAME>
	 */
	var ControlProvider = function(mPropertyBag) {
		if (mPropertyBag) {
			this._oParentODataModel = mPropertyBag.model;
			this._oMetadataAnalyser = mPropertyBag.metadataAnalyser;
			this._aODataFieldMetadata = mPropertyBag.fieldsMetadata;
			this._oDateFormatSettings = mPropertyBag.dateFormatSettings;
			this._bEnableDescriptions = mPropertyBag.enableDescriptions;
			this._oCurrencyFormatSettings = mPropertyBag.currencyFormatSettings;
			this._oDefaultDropDownDisplayBehaviour = mPropertyBag.defaultDropDownDisplayBehaviour || "descriptionAndId";
			this.useSmartField = mPropertyBag.useSmartField === "true";
			this._sEntitySet = mPropertyBag.entitySet;
		}

		if (!this._oMetadataAnalyser && this._oParentODataModel) {
			this._oMetadataAnalyser = new MetadataAnalyser(this._oParentODataModel);
			this._intialiseMetadata();
		}

		this._mSmartField = {};
		this._oHelper = new ODataHelper(this._oMetadataAnalyser.oModel);

		this._aValueListProvider = [];
		this._aValueHelpProvider = [];
	};

	/**
	 * Initialises the necessary metadata
	 * 
	 * @private
	 */
	ControlProvider.prototype._intialiseMetadata = function() {
		if (!this._aODataFieldMetadata) {
			this._aODataFieldMetadata = this._oMetadataAnalyser.getFieldsByEntitySetName(this.sEntity);
		}
	};

	/**
	 * Get the field metadata
	 * 
	 * @param {object} oFieldODataMetadata - OData metadata for the field
	 * @param {boolean} isEditable - specifies if the control shall be editable
	 * @returns {Object} the field view metadata object
	 * @public
	 */
	ControlProvider.prototype.getFieldViewMetadata = function(oFieldODataMetadata, isEditable) {
		var oFieldViewMetadata = this._createFieldMetadata(oFieldODataMetadata);
		// Create and set the template
		this._createFieldTemplate(oFieldViewMetadata, isEditable);
		return oFieldViewMetadata;
	};

	/**
	 * Creates and extends the field view with a template for the UI content
	 * 
	 * @param {object} oViewField - the view field metadata
	 * @param {boolean} isEditable - specifies if the control shall be editable
	 * @private
	 */
	ControlProvider.prototype._createFieldTemplate = function(oViewField, isEditable) {
		if (this.useSmartField) {
			oViewField.template = new SmartField({
				value: {
					path: oViewField.name
				},
				entitySet: this._sEntitySet,
				contextEditable: {
					path: "sm4rtM0d3l>/editable",
					mode: "OneWay"
				},
				controlContext: "table",
				wrapping: false
			});

			if (ODataType.isNumeric(oViewField.type) || ODataType.isDateOrTime(oViewField.type)) {
				oViewField.template.setTextAlign("End");
				oViewField.template.setWidth("100%");
			}
			this._completeSmartField(oViewField);

			oViewField.template._setPendingEditState(isEditable);

		} else {
			oViewField.template = isEditable ? this._createEditableTemplate(oViewField) : this._createDisplayOnlyTemplate(oViewField);
		}
	};

	/**
	 * Completes the Smart Field template, adds especially meta data.
	 * 
	 * @param {object} oViewField The current meta data
	 * @private
	 */
	ControlProvider.prototype._completeSmartField = function(oViewField) {
		var oData = {
			annotations: {},
			path: oViewField.name
		};

		if (!this._mSmartField.entitySetObject) {
			this._mSmartField.entitySetObject = this._oHelper.oMeta.getODataEntitySet(this._sEntitySet);
			this._mSmartField.entityType = this._oHelper.oMeta.getODataEntityType(this._mSmartField.entitySetObject.entityType);
		}

		oData.modelObject = this._oParentODataModel;
		oData.entitySetObject = this._mSmartField.entitySetObject;
		// ODataHelper expects entitySet and not entitySetObject!
		oData.entitySet = this._mSmartField.entitySetObject;
		oData.entityType = this._mSmartField.entityType;
		this._oHelper.getProperty(oData);

		oData.annotations.uom = this._oHelper.getUnitOfMeasure2(oData);
		oData.annotations.text = this._oHelper.getTextProperty2(oData);
		oData.annotations.lineitem = this._oMetadataAnalyser.getLineItemAnnotation(oData.entitySetObject.entityType);
		oData.annotations.semantic = this._oMetadataAnalyser.getSemanticObjectAnnotationFromProperty(oData.property.property);
		this._oHelper.getUOMTextAnnotation(oData);
		if (oData.property.property["sap:value-list"] || oData.property.property["com.sap.vocabularies.Common.v1.ValueList"]) {
			oData.annotations.valuelist = this._oHelper.getValueListAnnotationPath(oData);
			if (oData.property.property["sap:value-list"]) {
				oData.annotations.valuelistType = oData.property.property["sap:value-list"];
			} else {
				oData.annotations.valuelistType = this._oMetadataAnalyser.getValueListSemantics(oData.property.property["com.sap.vocabularies.Common.v1.ValueList"]);
			}
		}
		this._oHelper.getUOMValueListAnnotationPath(oData);
		delete oData.entitySet;
		oViewField.template.data("configdata", {
			"configdata": oData
		});

		oViewField.template.data("dateFormatSettings", this._oDateFormatSettings);
		oViewField.template.data("currencyFormatSettings", this._oCurrencyFormatSettings);
		oViewField.template.data("defaultDropDownDisplayBehaviour", this._oDefaultDropDownDisplayBehaviour);

		if (oData.annotations.uom || ODataType.isNumeric(oViewField.type) || ODataType.isDateOrTime(oViewField.type)) {
			var sAlign = oViewField.template.getTextAlign();

			if (sAlign === "Initial") {
				sAlign = "End";
			}

			oViewField.align = sAlign;
			oViewField.textDirection = "LTR";
		}
	};

	/**
	 * Creates and extends the field view with a template for editable UI content
	 * 
	 * @param {object} oViewField - the view field
	 * @param {boolean} bBlockSmartLinkCreation - if true, no SmartLink is created independent of the semanitcObject notation
	 * @returns {sap.ui.core.Control} the template control
	 * @private
	 */
	ControlProvider.prototype._createEditableTemplate = function(oViewField, bBlockSmartLinkCreation) {
		var oTemplate = null, oFormatOptions, oConstraints, oType;
		if (oViewField.type === "Edm.DateTime" || oViewField.type === "Edm.DateTimeOffset") {
			// Create DatePicker for Date display fields
			if (oViewField.displayFormat === "Date") {
				oFormatOptions = this._oDateFormatSettings;
				oConstraints = {
					displayFormat: "Date"
				};
				oTemplate = new DatePicker({
					dateValue: {
						path: oViewField.name
					}
				});
			}
		} else if (oViewField.type === "Edm.Boolean") {
			oTemplate = new CheckBox({
				selected: {
					path: oViewField.name
				}
			});
		} else if (oViewField.type === "Edm.Decimal") {
			oConstraints = {
				precision: oViewField.precision,
				scale: oViewField.scale
			};
		}

		oType = ODataType.getType(oViewField.type, oFormatOptions, oConstraints);

		// semantic link
		if (oViewField.semanticObject && (!bBlockSmartLinkCreation)) {
			oTemplate = this._createSmartLinkFieldTemplate(oViewField, oType, function() {
				var oInnerControl = this._createEditableTemplate(oViewField, true);
				// This callback implementation done by SmartLink in the SmartTable - does not take into account that wrapping should be enabled.
				// There could also be other issues e.g. w.r.t alignment of the controls.
				// Set the wrapping style of SmartLink, also on the inner control.
				if (oInnerControl.setWrapping && oViewField.template && oViewField.template.getWrapping) {
					oInnerControl.setWrapping(oViewField.template.getWrapping());
				}
				return oInnerControl;
			}.bind(this));
		}

		// TODO: ComboBox handling!

		// Default ==> sap.m.Input
		if (!oTemplate) {
			if (oViewField.type === "Edm.Time") {
				oTemplate = new TimePicker({
					value: {
						path: oViewField.name,
						type: oType
					}
				});
			} else {
				oTemplate = new Input({
					value: {
						path: oViewField.name,
						type: oType
					}
				});

				if (oViewField.isMeasureField) {
					oTemplate.bindProperty("description", {
						path: oViewField.unit
					});
					oTemplate.setTextAlign("End");
					oTemplate.setTextDirection("LTR");
					oTemplate.setFieldWidth("80%");
				} else if (this._bEnableDescriptions && oViewField.description) {
					oTemplate.bindProperty("description", {
						path: oViewField.description
					});

				} else if (ODataType.isNumeric(oViewField.type) || ODataType.isDateOrTime(oViewField.type)) {
					oTemplate.setTextAlign("End");
					oTemplate.setTextDirection("LTR");
				}

				if (oViewField.hasValueListAnnotation) {
					this._associateValueHelpAndSuggest(oTemplate, oViewField);
				}
			}
		}
		return oTemplate;
	};

	/**
	 * Associates the control with a ValueHelp Dialog and suggest using the details retrieved from the metadata (annotation)
	 * 
	 * @param {object} oControl - The control
	 * @param {object} oFieldViewMetadata - The metadata merged from OData metadata and additional control configuration
	 * @private
	 */
	ControlProvider.prototype._associateValueHelpAndSuggest = function(oControl, oFieldViewMetadata) {
		// F4 Help with selection list
		oControl.setShowValueHelp(true);
		this._aValueHelpProvider.push(new sap.ui.comp.providers.ValueHelpProvider({
			loadAnnotation: true,
			fullyQualifiedFieldName: oFieldViewMetadata.fullName,
			metadataAnalyser: this._oMetadataAnalyser,
			control: oControl,
			model: this._oParentODataModel,
			preventInitialDataFetchInValueHelpDialog: true,
			dateFormatSettings: this._oDateFormatSettings,
			takeOverInputValue: false,
			fieldName: oFieldViewMetadata.fieldName,
			type: oFieldViewMetadata.type,
			maxLength: oFieldViewMetadata.maxLength,
			displayFormat: oFieldViewMetadata.displayFormat,
			displayBehaviour: oFieldViewMetadata.displayBehaviour,
			title: oFieldViewMetadata.label
		}));

		oControl.setShowSuggestion(true);
		oControl.setFilterSuggests(false);
		this._aValueListProvider.push(new sap.ui.comp.providers.ValueListProvider({
			loadAnnotation: true,
			fullyQualifiedFieldName: oFieldViewMetadata.fullName,
			metadataAnalyser: this._oMetadataAnalyser,
			control: oControl,
			model: this._oParentODataModel,
			dateFormatSettings: this._oDateFormatSettings,
			typeAheadEnabled: true,
			aggregation: "suggestionRows",
			displayFormat: oFieldViewMetadata.displayFormat,
			displayBehaviour: oFieldViewMetadata.displayBehaviour
		}));
	};

	/**
	 * Creates and extends the field view with a template for display only UI content
	 * 
	 * @param {object} oViewField - the view field
	 * @param {boolean} bBlockSmartLinkCreation - if true, no SmartLink is created independent of the semanitcObject notation
	 * @returns {sap.ui.core.Control} the template control
	 * @private
	 */
	ControlProvider.prototype._createDisplayOnlyTemplate = function(oViewField, bBlockSmartLinkCreation) {
		var oTemplate = null, oType = null, oFormatOptions, oConstraints, sAlign, sDisplayBehaviour, oBindingInfo;

		// Create Date type for Date display fields
		if (oViewField.displayFormat === "Date") {
			oFormatOptions = this._oDateFormatSettings;
			oConstraints = {
				displayFormat: "Date"
			};
		} else if (oViewField.type === "Edm.Decimal") {
			oConstraints = {
				precision: oViewField.precision,
				scale: oViewField.scale
			};
		}

		oType = ODataType.getType(oViewField.type, oFormatOptions, oConstraints);
		if (ODataType.isNumeric(oViewField.type) || ODataType.isDateOrTime(oViewField.type)) {
			sAlign = "End";
		}
		if (oViewField.isMeasureField) {
			oViewField.textDirection = "LTR";
			oTemplate = this._createMeasureFieldTemplate(oViewField, oType);
		} else if (oViewField.semanticObject && (!bBlockSmartLinkCreation)) {
			oTemplate = this._createSmartLinkFieldTemplate(oViewField, oType, function() {
				var oInnerControl = this._createDisplayOnlyTemplate(oViewField, true);
				// This callback implementation done by SmartLink in the SmartTable - does not take into account that wrapping should be enabled.
				// There could also be other issues e.g. w.r.t alignment of the controls.
				// Set the wrapping style of SmartLink, also on the inner control.
				if (oInnerControl.setWrapping && oViewField.template && oViewField.template.getWrapping) {
					oInnerControl.setWrapping(oViewField.template.getWrapping());
				}
				return oInnerControl;
			}.bind(this));
		} else {
			oBindingInfo = {
				path: oViewField.name,
				type: oType
			};
			if (this._bEnableDescriptions && oViewField.description) {
				sDisplayBehaviour = oViewField.displayBehaviour;
				oBindingInfo = {
					parts: [
						{
							path: oViewField.name,
							type: oType
						}, {
							path: oViewField.description
						}
					],
					formatter: function(sId, sDescription) {
						return FormatUtil.getFormattedExpressionFromDisplayBehaviour(sDisplayBehaviour, sId, sDescription);
					}
				};
			}

			oTemplate = new Text({
				wrapping: false,
				textAlign: sAlign,
				textDirection: sAlign === "End" ? "LTR" : undefined,
				text: oBindingInfo
			});
		}

		oViewField.align = sAlign;

		return oTemplate;
	};

	/**
	 * Creates and extends the field view with a template for currency (display only) content
	 * 
	 * @param {object} oViewField - the view field
	 * @param {object} oType - the binding data type
	 * @param {function} fCreateControl - callback function which creates the control which would have been created instead of the SmartLink
	 * @returns {Object} the template
	 * @private
	 */
	ControlProvider.prototype._createSmartLinkFieldTemplate = function(oViewField, oType, fCreateControl) {
		var oBindingInfo = {
			path: oViewField.name,
			type: oType
		};
		if (this._bEnableDescriptions && oViewField.description) {
			oBindingInfo = {
				parts: [
					{
						path: oViewField.name,
						type: oType
					}, {
						path: oViewField.description
					}
				],
				formatter: function(sId, sDescription) {
					return FormatUtil.getFormattedExpressionFromDisplayBehaviour(oViewField.displayBehaviour, sId, sDescription);
				}
			};
		}
		// semantic link
		var oTemplate = new SmartLink({
			semanticObject: oViewField.semanticObject,
			semanticObjectLabel: oViewField.label,
			fieldName: oViewField.name,
			text: oBindingInfo
		});

		oTemplate.setCreateControlCallback(fCreateControl);

		return oTemplate;
	};

	/**
	 * Creates and extends the field view with a template for currency (display only) content
	 * 
	 * @param {object} oViewField - the view field
	 * @param {object} oType - the odata binding data type
	 * @private
	 * @returns {Object} the template
	 */
	ControlProvider.prototype._createMeasureFieldTemplate = function(oViewField, oType) {
		var oTemplate, oValueText, oUnitText, bEnableCurrencySymbol = false;

		bEnableCurrencySymbol = !!(oViewField.isCurrencyField && this._oCurrencyFormatSettings && this._oCurrencyFormatSettings.showCurrencySymbol);

		oValueText = new Text({
			wrapping: false,
			textAlign: "End",
			text: {
				parts: [
					{
						path: oViewField.name,
						type: oType
					}, {
						path: oViewField.unit
					}
				],
				formatter: oViewField.isCurrencyField ? FormatUtil.getAmountCurrencyFormatter() : FormatUtil.getMeasureUnitFormatter(),
				useRawValues: oViewField.isCurrencyField
			}
		});
		oUnitText = new Text({
			wrapping: false,
			textAlign: "Begin",
			width: "2.5em",
			text: {
				path: oViewField.unit,
				formatter: bEnableCurrencySymbol ? FormatUtil.getCurrencySymbolFormatter() : undefined
			}
		});

		// Create measure format using HBox --> we need to 2 controls to properly align the value and unit part
		oTemplate = new HBox({
			justifyContent: "End",
			items: [
				oValueText, oUnitText
			]
		});

		oTemplate.addStyleClass("sapUiCompUOMInTableLTR");

		return oTemplate;
	};

	/**
	 * Calculates and sets additional flags and attributes for a field
	 * 
	 * @param {object} oFieldODataMetadata - OData metadata for the field
	 * @returns {object} the field view metadata
	 * @private
	 */
	ControlProvider.prototype._createFieldMetadata = function(oFieldODataMetadata) {
		var oFieldViewMetadata = jQuery.extend({}, oFieldODataMetadata);

		oFieldViewMetadata.label = oFieldODataMetadata.fieldLabel || oFieldODataMetadata.name;
		oFieldViewMetadata.quickInfo = oFieldODataMetadata.quickInfo || oFieldViewMetadata.label;
		oFieldViewMetadata.displayBehaviour = oFieldViewMetadata.displayBehaviour || this._oDefaultDropDownDisplayBehaviour;
		oFieldViewMetadata.filterType = this._getFilterType(oFieldODataMetadata);
		this._updateValueListMetadata(oFieldViewMetadata, oFieldODataMetadata);
		this._setAnnotationMetadata(oFieldViewMetadata);
		return oFieldViewMetadata;
	};

	/**
	 * Update the metadata for ValueList annotation
	 * 
	 * @param {Object} oFieldViewMetadata - view metadata for the filter field
	 * @param {object} oFieldODataMetadata - OData metadata for the filter field
	 * @private
	 */
	ControlProvider.prototype._updateValueListMetadata = function(oFieldViewMetadata, oFieldODataMetadata) {
		// First check for "sap:value-list" annotation
		oFieldViewMetadata.hasValueListAnnotation = oFieldODataMetadata["sap:value-list"] !== undefined;
		if (oFieldViewMetadata.hasValueListAnnotation) {
			oFieldViewMetadata.hasFixedValues = oFieldODataMetadata["sap:value-list"] === "fixed-values";
		} else if (oFieldODataMetadata["com.sap.vocabularies.Common.v1.ValueList"]) {
			// Then check for "com.sap.vocabularies.Common.v1.ValueList", and retrieve the semantics
			oFieldViewMetadata.hasValueListAnnotation = true;
			oFieldViewMetadata.hasFixedValues = this._oMetadataAnalyser.getValueListSemantics(oFieldODataMetadata["com.sap.vocabularies.Common.v1.ValueList"]) === "fixed-values";
		}
	};

	/**
	 * Set any annotation(s) metadata on the control
	 * 
	 * @param {Object} oFieldViewMetadata - the field view metadata
	 * @private
	 */
	ControlProvider.prototype._setAnnotationMetadata = function(oFieldViewMetadata) {
		var mAnnotation = null;
		if (!this.useSmartField && oFieldViewMetadata && oFieldViewMetadata.fullName) {
			// Update with SemanticObject annotation data
			mAnnotation = this._oMetadataAnalyser.getSemanticObjectAnnotation(oFieldViewMetadata.fullName);
			if (mAnnotation) {
				oFieldViewMetadata.semanticObject = mAnnotation.semanticObject;
			}
		}
	};
	/**
	 * Returns the filterType of the field based on metadata, else undefined
	 * 
	 * @param {object} oField - OData metadata for the field
	 * @returns {string} the filter type for the field
	 * @private
	 */
	ControlProvider.prototype._getFilterType = function(oField) {
		if (ODataType.isNumeric(oField.type)) {
			return "numeric";
		} else if (oField.type === "Edm.DateTime" && oField.displayFormat === "Date") {
			return "date";
		} else if (oField.type === "Edm.String") {
			return "string";
		} else if (oField.type === "Edm.Boolean") {
			return "boolean";
		} else if (oField.type === "Edm.Time") {
			return "time";
		}
		return undefined;
	};

	/**
	 * Destroys the object
	 * 
	 * @public
	 */
	ControlProvider.prototype.destroy = function() {
		var i;
		if (this._oMetadataAnalyser && this._oMetadataAnalyser.destroy) {
			this._oMetadataAnalyser.destroy();
		}
		this._oMetadataAnalyser = null;
		if (this._aValueHelpProvider) {
			i = this._aValueHelpProvider.length;
			while (i--) {
				this._aValueHelpProvider[i].destroy();
			}
		}
		this._aValueHelpProvider = null;

		if (this._aValueListProvider) {
			i = this._aValueListProvider.length;
			while (i--) {
				this._aValueListProvider[i].destroy();
			}
		}

		if (this._oHelper) {
			this._oHelper.destroy();
		}

		this._oHelper = null;
		this._mSmartField = null;
		this._aValueListProvider = null;
		this._aODataFieldMetadata = null;
		this._oCurrencyFormatter = null;
		this.bIsDestroyed = true;
	};

	return ControlProvider;

}, /* bExport= */true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

sap.ui.define([
	'jquery.sap.global', 'sap/ui/fl/changeHandler/Base', 'sap/ui/fl/Utils'
], function(jQuery, Base, FlexUtils) {
	"use strict";

	/**
	 * Change handler for moving of fields within/between groups.
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.MoveFields
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 */
	var MoveFields = function() {
	};
	MoveFields.prototype = jQuery.sap.newObject(Base.prototype);

	/**
	 * Moves field(s) within a group or between groups.
	 *
	 * @param {object} oChange change object with instructions to be applied on the control
	 * @param {object} oGroup Smart form group instance which is referred to in change selector section 
	 * @public
	 */
	MoveFields.prototype.applyChange = function(oChange, oGroup) {

		if (!oChange) {
			throw new Error("No change instance");
		}

		var oChangeJson = oChange.getDefinition();

		if (!oChangeJson.selector || !oChangeJson.content || !oChangeJson.content.moveFields || oChangeJson.content.moveFields.length === 0 || Object.keys(oChangeJson.selector).length !== 1) {
			throw new Error("Change format invalid");
		}

		if (!oGroup || !oGroup.getGroupElements || !oGroup.getId) {
			throw new Error("No smart form group instance supplied");
		}

		// determine target group of move
		var oTargetGroup = oGroup;
		var bTargetDiffers = false;

		if (oChangeJson.content.targetId) {
			var sSourceKey = oGroup.getId();
			if (sSourceKey !== oChangeJson.content.targetId) {
				oTargetGroup = sap.ui.getCore().byId(oChangeJson.content.targetId);
				bTargetDiffers = true;
			}
		}
		
		// Array of fields of smart form group in old order
		var aFields = oGroup.getGroupElements();
		if (!aFields) {
			return;
		}
		var iFieldNumber = aFields.length;

		// move is within a group - adapt order of fields in aFields according to the change
		// move is between groups - remove field from source group and insert it at target group
		var oField = {}, oMoveField = {};
		var iMoveFields = oChangeJson.content.moveFields.length;
		var iIndex, i, j;

		for (i = 0; i < iMoveFields; i++) {

			oMoveField = oChangeJson.content.moveFields[i];

			if (!oMoveField.id) {
				throw new Error("Change format invalid - moveFields element has no id attribute");
			}
			if (typeof (oMoveField.index) !== "number") {
				throw new Error("Change format invalid - moveFields element index attribute is no number");
			}
			
			// determine the index of the field to move in aFields 
			iIndex = -1;
			for (j = 0; j < iFieldNumber; j++) {
				var sControlId = aFields[j].getId();
				if (sControlId === oMoveField.id) {
					iIndex = j;
					break;
				}
			}

			// move within group and position of field is unchanged
			if (bTargetDiffers === false && iIndex === oMoveField.index) {
				continue;
			}
			// field not found in source group
			if (iIndex === -1) {
				continue;
			}

			// get the field to move
			oField = aFields[iIndex];
			
			// move is between groups - remove field from source group
			// and insert it at target group
			if (bTargetDiffers === true) {
				oGroup.removeGroupElement(oField);
				oTargetGroup.insertGroupElement(oField, oMoveField.index);
				continue;
			}

			// move is within a group
			// remove the field to move from aFields
			aFields.splice(iIndex, 1);

			// reinsert the field to aFields at the new index
			if (bTargetDiffers === false) {
				aFields.splice(oMoveField.index, 0, oField);
			}

		}
		
		// in case of move between groups we are done
		if (bTargetDiffers === true) {
			return;
		}

		// remove all fields from smart form group (source)
		oGroup.removeAllGroupElements();

		// reinsert fields into smart form group in new order (source)
		for (i = 0; i < iFieldNumber; i++) {
			oGroup.insertGroupElement(aFields[i], i);
		}

	};

	/**
	 * Completes the change by adding change handler specific content
	 *
	 * @param {object} oChange change object to be completed
	 * @param {object} oSpecificChangeInfo with attribute moveFields which contains an array which holds objects which have attributes
	 * 				   id and index - id is the id of the field to move and index the new position of the field in the smart form group 
	 * @public
	 * @function
	 * @name sap.ui.fl.changeHandler.MoveGroups#completeChangeContent
	 */
	MoveFields.prototype.completeChangeContent = function(oChange, oSpecificChangeInfo) {

		var oChangeJson = oChange.getDefinition();

		if (oSpecificChangeInfo.moveFields) {

			var oMoveField = {};
			var i, iLength = oSpecificChangeInfo.moveFields.length;

			if (iLength === 0) {
				throw new Error("MoveFields array is empty");
			}

			for (i = 0; i < iLength; i++) {
				oMoveField = oSpecificChangeInfo.moveFields[i];
				if (!oMoveField.id) {
					throw new Error("MoveFields element has no id attribute");
				}
				if (typeof (oMoveField.index) !== "number") {
					throw new Error("Index attribute at MoveFields element is no number");
				}
			}

			if (!oChangeJson.content) {
				oChangeJson.content = {};
			}

			if (!oChangeJson.content.moveFields) {
				oChangeJson.content.moveFields = [];
			}

			oChangeJson.content.moveFields = oSpecificChangeInfo.moveFields;

			if (oSpecificChangeInfo.targetId) {
				oChangeJson.content.targetId = oSpecificChangeInfo.targetId;
			}

		} else {

			throw new Error("oSpecificChangeInfo.moveFields attribute required");

		}

	};

	return MoveFields;
},
/* bExport= */true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
sap.ui.define(["jquery.sap.global","sap/ui/fl/changeHandler/HideControl","sap/ui/fl/changeHandler/UnhideControl","sap/ui/fl/changeHandler/MoveElements","sap/ui/fl/changeHandler/PropertyChange"],function(q,H,U,M,P){"use strict";var S={hideControl:{changeType:"hideControl",changeHandler:H},unhideControl:{changeType:"unhideControl",changeHandler:U},moveElements:{changeType:"moveElements",changeHandler:M},propertyChange:{changeType:"propertyChange",changeHandler:P}};return S;},true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

sap.ui.define([
	"sap/ui/fl/Utils", "jquery.sap.global", "sap/ui/fl/registry/ChangeRegistryItem", "sap/ui/fl/registry/SimpleChanges", "sap/ui/fl/registry/ChangeTypeMetadata", "sap/ui/fl/registry/Settings"
], function(Utils, jQuery, ChangeRegistryItem, SimpleChanges, ChangeTypeMetadata, Settings) {
	"use strict";

	/**
	 * Central registration for available change types on controls
	 * @constructor	 	  
	 * @alias sap.ui.fl.registry.ChangeRegistry
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 *
	 */
	var ChangeRegistry = function() {
		this._registeredItems = {};
		this.simpleChanges = SimpleChanges;
		this.initSettings();
	};

	ChangeRegistry._instance = undefined;

	ChangeRegistry.getInstance = function() {
		if (!ChangeRegistry._instance) {
			ChangeRegistry._instance = new ChangeRegistry();
		}
		return ChangeRegistry._instance;
	};

	ChangeRegistry.prototype.registerControlsForChanges = function(mControlChanges) {
		var that = this;
		Object.keys(mControlChanges).forEach(function(sControlType){
			mControlChanges[sControlType].forEach(function(oChangeType){
				that.registerControlForSimpleChange(sControlType, oChangeType);
			});
		});
	};

	/**
	 * Adds registration for a control and a simple change
	 * @param {String} sControlType - Name of the control, for example "sap.ui.comp.smartfilterbar.SmartFilterBar"
	 * @param {sap.ui.fl.registry.SimpleChange.member} oSimpleChange - One of the simple changes
	 *
	 * @public
	 */
	ChangeRegistry.prototype.registerControlForSimpleChange = function(sControlType, oSimpleChange) {
		var oChangeRegistryItem;
		if (!sControlType) {
			return;
		}
		if (!oSimpleChange || !oSimpleChange.changeType || !oSimpleChange.changeHandler) {
			return;
		}

		oChangeRegistryItem = this._createChangeRegistryItemForSimpleChange(sControlType, oSimpleChange);

		if (oChangeRegistryItem) {
			this.addRegistryItem(oChangeRegistryItem);
		}
	};

	/**
	 * Adds registration for a control and a simple change
	 * @param {String} sControlType - Name of the control, for example "sap.ui.comp.smartfilterbar.SmartFilterBar"
	 * @param {sap.ui.fl.registry.SimpleChange.member} oSimpleChange - One of the simple changes
	 * @returns {sap.ui.fl.registry.ChangeRegistryItem} the registry item
	 *
	 * @public
	 */
	ChangeRegistry.prototype._createChangeRegistryItemForSimpleChange = function(sControlType, oSimpleChange) {
		var mParam, oChangeTypeMetadata, oChangeRegistryItem;

		//Create change type metadata
		mParam = {
			name: oSimpleChange.changeType,
			changeHandler: oSimpleChange.changeHandler
		};
		oChangeTypeMetadata = new ChangeTypeMetadata(mParam);

		//Create change registry item
		mParam = {
			changeTypeMetadata: oChangeTypeMetadata,
			controlType: sControlType
		};
		oChangeRegistryItem = new ChangeRegistryItem(mParam);

		return oChangeRegistryItem;
	};

	/**
	 * Add a registry item for the controlType and changeType. If the item already exists, it will be overwritten
	 * @param {sap.ui.fl.registry.ChangeRegistryItem} oRegistryItem the registry item
	 * @public
	 */
	ChangeRegistry.prototype.addRegistryItem = function(oRegistryItem) {
		var sChangeType, sControlType;
		if (!oRegistryItem) {
			return;
		}

		sChangeType = oRegistryItem.getChangeTypeName();
		sControlType = oRegistryItem.getControlType();

		this._registeredItems[sControlType] = this._registeredItems[sControlType] || {};
		this._registeredItems[sControlType][sChangeType] = oRegistryItem;
	};

	/**
	 * Remove a registration for:
	 *  - A single change type (only changeTypeName parameter set)
	 *  - The complete registration on a certain control (only controlType parameter set)
	 *  - Or all registrations of a change type on any control (both changeTypeName AND controlType set)
	 * @param {Object} mParam Description see below
	 * @param {String} [mParam.changeTypeName] Change type name which should be removed
	 * @param {String} [mParam.controlType] Control type which should be removed.
	 *
	 * @public	 
	 */
	ChangeRegistry.prototype.removeRegistryItem = function(mParam) {
		if (!mParam.changeTypeName && !mParam.controlType) {
			Utils.log.error("sap.ui.fl.registry.ChangeRegistry: ChangeType and/or ControlType required");
			return;
		}
		//Either remove a specific changeType from a specific control type
		if (mParam.controlType && mParam.changeTypeName) {
			if (this._registeredItems[mParam.controlType]) {
				if (Object.keys(this._registeredItems[mParam.controlType]).length === 1) { //only one changeType...
					delete this._registeredItems[mParam.controlType];
				} else {
					delete this._registeredItems[mParam.controlType][mParam.changeTypeName];
				}
			}
		//or remove by control type
		} else if (mParam.controlType) {
			if (this._registeredItems[mParam.controlType]) {
				delete this._registeredItems[mParam.controlType];
			}
		//or via changeType on all control types
		} else if (mParam.changeTypeName) {
			for ( var controlTypeKey in this._registeredItems) {
				var controlItem = this._registeredItems[controlTypeKey];
				delete controlItem[mParam.changeTypeName];
			}
		}
	};

	/**
	 * Get a registration for:
	 *  - All registration items with specific change type name on all controls (only changeTypeName parameter set)
	 *  - The complete registration(s) on a certain control (only controlType parameter set)
	 *  - Or all registrations of a change type name on any control (both changeTypeName AND controlType set)
	 * @param {Object} mParam Description see below
	 * @param {String} [mParam.changeTypeName] Change type to find registration(s) for this changeType
	 * @param {String} [mParam.controlType] Control type to find registration(s) for this controlType
	 * @param {String} [mParam.layer] Layer where changes are currently applied. If not provided no filtering for valid layers is done.
	 * @returns {Object} Returns an object in the format 
	 * @example {
	 * 				"sap.ui.core.SampleControl":{
	 * 					"labelChange":{<type of @see sap.ui.fl.registry.ChangeRegistryItem>},
	 * 					"visibility":{<type of @see sap.ui.fl.registry.ChangeRegistryItem>}
	 * 				},
	 * 				"sap.ui.core.TestControl":{
	 * 					"visibility":{<type of @see sap.ui.fl.registry.ChangeRegistryItem>}
	 * 				}
	 * 			}
	 * @public	 
	 */
	ChangeRegistry.prototype.getRegistryItems = function(mParam) {
		if (!mParam.changeTypeName && !mParam.controlType) {
			Utils.log.error("sap.ui.fl.registry.ChangeRegistry: Change Type Name and/or Control Type required");
		}

		var result = null;
		if (mParam.controlType && mParam.changeTypeName) {
			var controlRegistrations = this._registeredItems[mParam.controlType];
			if (controlRegistrations) {
				if (controlRegistrations[mParam.changeTypeName]) {
					result = {};
					result[mParam.controlType] = {};
					result[mParam.controlType][mParam.changeTypeName] = controlRegistrations[mParam.changeTypeName];
				}
			}
		} else if (mParam.controlType) {
			if (this._registeredItems[mParam.controlType]) {
				result = {};
				//keep the actual registry items but clone the control-changetype object structure to not modify the registry during filtering
				result[mParam.controlType] = {};
				jQuery.each(this._registeredItems[mParam.controlType], function(sChangeTypeName, oRegistryItem) {
					result[mParam.controlType][sChangeTypeName] = oRegistryItem;
				});
			}
		} else if (mParam.changeTypeName) {
			result = {};
			for ( var controlTypeKey in this._registeredItems) {
				if (this._registeredItems[controlTypeKey][mParam.changeTypeName]) {
					result[controlTypeKey] = {};
					result[controlTypeKey][mParam.changeTypeName] = this._registeredItems[controlTypeKey][mParam.changeTypeName];
				}
			}
		}
		//filter out disabled change types
		this._filterChangeTypes(result, mParam.layer);
		return result;
	};

	/**
	 * Retrieves the Flex Settings for a UI5 component.
	 * 
	 * @param {string} sComponentName the UI5 component name for which settings are requested;
	 * 				   if not provided, hardcoded settings will be used.
	 * 
	 * @private
	 */
	ChangeRegistry.prototype.initSettings = function(sComponentName) {
		this._oSettings = Settings.getInstanceOrUndef(sComponentName);
		if (!this._oSettings) {
			this._oSettings = new Settings({});
		}
	};

	/**
	 * Removes registry items that are not enabled for the current writable layer.
	 * @param {object} oRegistryItems see example
	 * @param {string} sLayer persistency layer, if not provided no filtering is done.
	 * @example {
	 * 				"sap.ui.core.SampleControl":{
	 * 					"labelChange":{<type of @see sap.ui.fl.registry.ChangeRegistryItem>},
	 * 					"visibility":{<type of @see sap.ui.fl.registry.ChangeRegistryItem>}
	 * 				},
	 * 				"sap.ui.core.TestControl":{
	 * 					"visibility":{<type of @see sap.ui.fl.registry.ChangeRegistryItem>}
	 * 				}
	 * 			}
	 * @private
	 */
	ChangeRegistry.prototype._filterChangeTypes = function(oRegistryItems, sLayer) {
		if (this._oSettings && sLayer && oRegistryItems) {
			var that = this;
			jQuery.each(oRegistryItems, function(sControlType, oControlReg) {
				jQuery.each(oControlReg, function(sChangeType, oRegistryItem) {
					var bIsChangeTypeEnabled = that._oSettings.isChangeTypeEnabled(sChangeType, sLayer);
					if (!bIsChangeTypeEnabled) {
						delete oControlReg[sChangeType];
					}
				});
			});
		}
	};

	ChangeRegistry.prototype.getDragInfo = function(sControlType) {
		var controlTypeItems = this._registeredItems[sControlType];
		if (controlTypeItems) {
			return controlTypeItems.getDragInfo();
		}
		return null;
	};

	return ChangeRegistry;
}, true);
<file_sep>/*!
* SAP APF Analysis Path Framework
*
* (c) Copyright 2012-2014 SAP SE. All rights reserved
*/
jQuery.sap.require("sap.apf.ui.utils.constants");
jQuery.sap.require("sap.apf.core.constants");
jQuery.sap.require("sap.apf.modeler.ui.utils.textPoolHelper");
/**
* @class representation
* @memberOf sap.apf.modeler.ui.controller
* @name representation
* @description controller for view.representation
*/
sap.ui.controller("sap.apf.modeler.ui.controller.representation", {
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#onInit
	* @description Called on initialization of the view.
	* Sets the static texts for all controls in UI.
	* Sets the scroll height for the container.
	* Adds style classes to all UI controls.
	* Prepares dependencies.
	* Sets dynamic text for input controls
	* Set a preview button in footer 
	* */
	onInit : function() {
		// Data
		this.getView().addStyleClass("sapUiSizeCompact");//For non touch devices- compact style class increases the information density on the screen by reducing control dimensions
		this.oViewData = this.getView().getViewData();
		this.oConfigurationHandler = this.oViewData.oConfigurationHandler;
		this.oConfigurationEditor = this.oViewData.oConfigurationEditor;
		this.oTextPool = this.oConfigurationHandler.getTextPool();
		this.getText = this.oViewData.getText;
		this.getEntityTypeMetadata = this.oViewData.getEntityTypeMetadata;
		this.getRepresentationTypes = this.oViewData.getRepresentationTypes;
		this.mParam = this.oViewData.oParams;
		var self = this;
		if (!this.oConfigurationEditor) {
			this.oConfigurationHandler.loadConfiguration(this.mParam.arguments.configId, function(configurationEditor) {
				self.oConfigurationEditor = configurationEditor;
			});
		}
		this._setDisplayText();
		this.setDetailData();
		// Insert Preview Button into the Footer.
		this._oPreviewButton = new sap.m.Button({
			text : this.getText("preview"),
			press : self._handlePreviewButtonPress.bind(this)
		// the current context should be bound to the event handler
		});
		this._insertPreviewButtonInFooter();
	},
	onAfterRendering : function() {
		this._enableDisableItemsInDisplayOptionOrDisplayOptionBox();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_setDisplayText
	* @description Sets static texts in UI and place holders.
	* */
	_setDisplayText : function() {
		this.byId("idVisualization").setTitle(this.getText("visualization"));
		this.byId("idChartTypeLabel").setText(this.getText("chartType"));
		this.byId("idChartTypeLabel").setTooltip(this.getText("chartType"));
		this.byId("idBasicData").setTitle(this.getText("basicData"));
		this.byId("idSorting").setTitle(this.getText("sorting"));
		this.byId("idThumbnailTexts").setTitle(this.getText("cornerTextLabel"));
		this.byId("idLeftUpper").setPlaceholder(this.getText("leftTop"));
		this.byId("idRightUpper").setPlaceholder(this.getText("rightTop"));
		this.byId("idLeftLower").setPlaceholder(this.getText("leftBottom"));
		this.byId("idRightLower").setPlaceholder(this.getText("rightBottom"));
	},
	/**
	 * @private
	 * @description Handler for change event on chartTypes drop down.
	 * 				Updates the property drop downs according to the new chart type.
	 * 				Updates the representation object with corresponding data.
	 * 				Updates the tree node with selected representation type.
	 * 				Updates the title and bread crumb. 
	 * @name sap.apf.modeler.ui.controller.representation#handleChangeForChartType
	 * @param {oEvent} oEvt - Selection Event
	 **/
	handleChangeForChartType : function(oEvt) {
		var sNewChartType = oEvt.getParameter("selectedItem").getKey();
		var sPrevChart = this.sCurrentChartType;//getting prevChart type
		this.sCurrentChartType = sNewChartType;
		this._updateAndSetDatasetsByChartType(sNewChartType);
		var aRepresentationTypes = sap.apf.ui.utils.CONSTANTS.representationTypes;
		var aBarClassChart = aRepresentationTypes.BAR_CHART;
		var aColumnClassCharts = [ aRepresentationTypes.COLUMN_CHART, aRepresentationTypes.STACKED_COLUMN_CHART, aRepresentationTypes.PERCENTAGE_STACKED_COLUMN_CHART, aRepresentationTypes.LINE_CHART ];
		var bIsBarClassType = (aBarClassChart === sNewChartType);
		this.bIsBarClassType = bIsBarClassType;
		// Checking selected chart belongs to ColumnClass,Line Chart
		var bIsColumnClassType = aColumnClassCharts.indexOf(sNewChartType) !== -1;
		//Checking selected chart belongs to same ChartClass
		var bIsColumnClassSameType = (aColumnClassCharts.indexOf(sNewChartType) !== -1 && aColumnClassCharts.indexOf(sPrevChart) !== -1);
		if (bIsBarClassType || (bIsColumnClassType && !bIsColumnClassSameType)) {
			this._switchLabelForCharts();//Switches the text for "BarClassCharts","ColumnClassCharts" & LineChart
		}
		this.oRepresentation.setRepresentationType(sNewChartType);
		var sAlternateRepresentation;
		if (sNewChartType !== sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) {
			sAlternateRepresentation = sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION;
		}
		var sSelectedChartIcon = this._getChartPictureDataset().sSelectedChartPicture;
		this.oRepresentation.setAlternateRepresentationType(sAlternateRepresentation);
		// Update Tree Node
		var sRepresentationTypeText = this.getText(this.oRepresentation.getRepresentationType());
		var aStepCategories = this.oConfigurationEditor.getCategoriesForStep(this.oParentStep.getId());
		if (aStepCategories.length === 1) {//In case the step of representation is only assigned to one category
			this.oViewData.updateSelectedNode({
				name : sRepresentationTypeText,
				icon : sSelectedChartIcon
			});
		} else {
			this.oViewData.updateTree();
		}
		var sTitle = this.getText("representation") + ": " + sRepresentationTypeText;
		this.oViewData.updateTitleAndBreadCrumb(sTitle);
		this.oConfigurationEditor.setIsUnsaved();
	},
	/**
	    * @private
	    * @function
	    * @name sap.apf.modeler.ui.controller.representation#_switchLabelForCharts
	    * @description Get all property rows in basic data layout & reads aggregation role & kind                        
	    * */
	_switchLabelForCharts : function() {
		var oSelf = this;
		var oBasicDataLayout = this.byId("idBasicDataLayout").getItems();
		var sAggRole, sKind;
		oBasicDataLayout.forEach(function(dataLayout) {
			//Getting Aggregation role for each property row
			sAggRole = dataLayout.getContent()[0].getBindingContext().getProperty("sAggregationRole");
			//Getting kind for each property row
			sKind = dataLayout.getContent()[0].getBindingContext().getProperty("sKind");
			if (sAggRole && sKind) {
				var sText = oSelf._createDimMeasForCharts(sAggRole, sKind);
				if (sAggRole === "dimension") {
					sText = oSelf.getText("display", [ sText ]);
				}
				dataLayout.getContent()[0].setText(sText);//setting newly created text for property row label
			}
		});
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_createDimMeasForCharts
	* @return sText :Text for label
	* @description Creates text for property row labels(Dimension&Measure)in respect of chart type
	* 
	* */
	_createDimMeasForCharts : function(sAggRole, sKind) {
		var sHorizontal = sap.apf.core.constants.representationMetadata.kind.XAXIS;
		var sVertical = sap.apf.core.constants.representationMetadata.kind.YAXIS;
		//if chart is bar and Aggregation role is 'dimension' & sKind is 'Horizontal' set sKind = 'Vertical'
		if (sAggRole === "dimension" && sKind === sHorizontal) {
			sKind = sHorizontal;
			if (this.bIsBarClassType) {
				sKind = sVertical;
			}
		} else if (sAggRole === "measure" && sKind === sVertical) {//if chart is bar and Aggregation role is 'measure' set sKind = 'Horizontal' 
			sKind = sVertical;
			if (this.bIsBarClassType) {
				sKind = sHorizontal;
			}
		}
		var sUiAggRole = this.getText(sAggRole);
		var sUiKind = this.getText(sKind);
		var sText = this.getText("dim-measure-label", [ sUiAggRole, sUiKind ]);
		//if chart is dual line with kind of "yAxis" in measure then need to change the label		
		if (this.bIsDualLineChart && sKind === sVertical && sAggRole === "measure") {
			var sUiLeft = this.getText("leftVerticalAxis");
			sText = this.getText("dim-measure-label", [ sUiAggRole, sUiLeft ]);
		}
		return sText; //Newly created text for Label in respect of Chart type
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#handleChangeForCornerText
	* @param {oEvent} oEvt - Selection Event
	* @description Handler for change event on corner text input boxes.
	* Sets the corresponding corner text on the representation object.
	* */
	handleChangeForCornerText : function(oEvt) {
		var oCornerTextInput = oEvt.getSource();
		var sCornerTextValue = oCornerTextInput.getValue();
		var oTranslationFormat = sap.apf.modeler.ui.utils.TranslationFormatMap.REPRESENTATION_CORNER_TEXT;
		var sCornerTextId = this.oTextPool.setText(sCornerTextValue, oTranslationFormat);
		var sCornerTextName = oCornerTextInput.getBindingPath('value').replace("/", "");
		var sSetCornerTextMethodName = [ "set", sCornerTextName, "CornerTextKey" ].join("");
		this.oRepresentation[sSetCornerTextMethodName](sCornerTextId);
		this.oConfigurationEditor.setIsUnsaved();
		// Run the fall back logic to update the corner text.
		this.mDataset.oCornerTextsDataset[sCornerTextName] = this._getCornerTextsDataset()[sCornerTextName];
		this.mModel.oCornerTextsModel.updateBindings();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_addAutoCompleteFeatureOnInputs
	* @description Adds auto complete feature on all the four corner texts.
	* */
	_addAutoCompleteFeatureOnInputs : function() {
		var oSelf = this;
		var oTextPoolHelper = new sap.apf.modeler.ui.utils.TextPoolHelper(this.oTextPool);
		// Add Feature on Corner Texts
		var oDependenciesForText = {
			oTranslationFormat : sap.apf.modeler.ui.utils.TranslationFormatMap.REPRESENTATION_CORNER_TEXT,
			type : "text"
		};
		var aCornerTextInputIds = [ "idLeftUpper", "idRightUpper", "idLeftLower", "idRightLower" ];
		aCornerTextInputIds.forEach(function(sId) {
			var oInputControl = oSelf.getView().byId(sId);
			oTextPoolHelper.setAutoCompleteOn(oInputControl, oDependenciesForText);
		});
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_bindBasicRepresentationData
	* @description Binds sap.apf.modeler.ui.controller.representation#mModel.oPropertyModel to Basic Data layout.
	* Iteratively binds the data to each and every control in Basic Data Layout.
	* */
	_bindBasicRepresentationData : function() {
		var oSelf = this;
		var nPropertyRowIndex, sPathOfPropertyRow, oCopyPropertyRowTemplate, oLabelDisplayOptionBox;
		var oBasicDataLayout = this.byId("idBasicDataLayout");
		var oPropertyRowTemplate = new sap.ui.layout.Grid({ // add the labels and input control to the grid
			width : "100%"
		});
		// Label
		var oAggregationKindLabel = new sap.m.Label({
			width : "100%",
			textAlign : "End",
			layoutData : new sap.ui.layout.GridData({
				span : "L2 M2 S2"
			}),
			text : {
				path : "/",
				formatter : function() {
					var oLabelControl = this, sLabel, sAggRoleText;
					var sAggRole = this.getBindingContext().getProperty("sAggregationRole");
					var sKind = this.getBindingContext().getProperty("sKind");
					var sChartName = oSelf.sCurrentChartType;
					var aRepresentationTypes = sap.apf.ui.utils.CONSTANTS.representationTypes;
					var aBarClassCharts = [ aRepresentationTypes.BAR_CHART, aRepresentationTypes.STACKED_BAR_CHART, aRepresentationTypes.PERCENTAGE_STACKED_BAR_CHART ];
					oSelf.bIsBarClassType = (aBarClassCharts.indexOf(sChartName) !== -1);
					oSelf.bIsDualLineChart = (aRepresentationTypes.LINE_CHART_WITH_TWO_VERTICAL_AXES.indexOf(sChartName) !== -1);//Is current chart dual line chart?
					if (sAggRole && sKind) {
						if (oSelf.bIsBarClassType || oSelf.bIsDualLineChart) { //BarCharts or Dual line Chart
							sLabel = oSelf._createDimMeasForCharts(sAggRole, sKind);
						} else {
							sAggRoleText = oSelf.getText(sAggRole);
							sKind = oSelf.getText(sKind);
							sLabel = oSelf.getText("dim-measure-label", [ sAggRoleText, sKind ]);
						}
						if (sAggRole === "dimension") {
							sLabel = oSelf.getText("display", [ sLabel ]);
						}
						oLabelControl.setTooltip(sLabel);
						return sLabel;
					}
				}
			}
		});
		oPropertyRowTemplate.addContent(oAggregationKindLabel);
		// Select Box
		var oPropertySelectBox = new sap.m.Select({
			width : "100%",
			layoutData : new sap.ui.layout.GridData(),
			items : {
				path : "aAllProperties",
				template : new sap.ui.core.ListItem({
					key : "{sName}",
					text : "{sName}"
				}),
				templateShareable : true
			},
			selectedKey : "{sSelectedProperty}",
			change : oSelf._handleChangeForBasicDataSelectProperty.bind(this)
		// the current context should be bound to the event handler
		});
		oPropertyRowTemplate.addContent(oPropertySelectBox);
		// Label for 'Label'
		var oLabel = new sap.m.Label({
			textAlign : "End",
			width : "100%",
			layoutData : new sap.ui.layout.GridData({
				span : "L2 M2 S2"
			}),
			text : {
				path : "/",
				formatter : function() {
					var sText;
					var sDefaultLabel, sSelectedProperty;
					var sLabel = this.getBindingContext().getProperty("sLabel");
					var oLabelControl = this;
					if (this.getParent().getContent()[1].getSelectedItem()) {
						sSelectedProperty = this.getParent().getContent()[1].getSelectedItem().getText();
					} else {
						sSelectedProperty = this.getBindingContext().getProperty("sSelectedProperty");
					}
					sText = oSelf.getText("label"); //"label" title has to be displayed
					//if label is default , only then it should be overridden
					if (sSelectedProperty && sSelectedProperty !== oSelf.getText("none")) {// if a property is selected other than none
						var oPropertyMetadata = oSelf.oEntityMetadata.getPropertyMetadata(sSelectedProperty);
						sDefaultLabel = oPropertyMetadata.label ? oPropertyMetadata.label : oPropertyMetadata.name;// read the default label from metadata
						if (!sLabel || (sLabel && sDefaultLabel && (sLabel === sDefaultLabel))) { // if the label is not defined or label is same as default label
							sText = oSelf.getText("label") + "(" + oSelf.getText("default") + ")"; // "Default" has to be prefixed to label title
						}
					}
					oLabelControl.setTooltip(sText);
					return sText;
				}
			}
		}).addStyleClass("repFormRightLabel");
		oPropertyRowTemplate.addContent(oLabel);
		// Input for 'Label'
		var oInputLabel = new sap.m.Input({
			width : "100%",
			layoutData : new sap.ui.layout.GridData({
				span : "L3 M2 S2"
			}),
			value : {
				path : "sLabel",
				formatter : function() {
					var sDefaultLabel, sSelectedProperty;
					if (!this.mEventRegistry.suggest && this.getShowSuggestion() === false) {
						var oTextPoolHelper = new sap.apf.modeler.ui.utils.TextPoolHelper(oSelf.oTextPool);
						// Add Auto Complete Feature on Label inputs.
						var oDependenciesForText = {
							oTranslationFormat : sap.apf.modeler.ui.utils.TranslationFormatMap.REPRESENTATION_LABEL,
							type : "text"
						};
						oTextPoolHelper.setAutoCompleteOn(this, oDependenciesForText);
					}
					if (this.getParent().getContent()[1].getSelectedItem()) {
						sSelectedProperty = this.getParent().getContent()[1].getSelectedItem().getText();
					} else {
						sSelectedProperty = this.getBindingContext().getProperty("sSelectedProperty");
					}
					if (sSelectedProperty && sSelectedProperty !== oSelf.getText("none")) {
						var oPropertyMetadata = oSelf.oEntityMetadata.getPropertyMetadata(sSelectedProperty);
						sDefaultLabel = oPropertyMetadata.label ? oPropertyMetadata.label : oPropertyMetadata.name;
					}
					var sLabel = this.getBindingContext().getProperty("sLabel");
					// if there is a selected property other than none and the label is not defined for it or label is defined and it is same as default label 
					if ((sSelectedProperty && sSelectedProperty !== oSelf.getText("none") && !sLabel) || (sLabel && sDefaultLabel && (sLabel === sDefaultLabel))) {
						return sDefaultLabel; //default label should be displayed
					}
					return sLabel; //else manual entered label has to be displayed
				}
			},
			change : oSelf._handleChangeForBasicDataPropertyRowLabelInput.bind(this)
		// the current context should be bound to the event handler
		});
		oPropertyRowTemplate.addContent(oInputLabel);
		// Add Icon
		var oAddIcon = new sap.ui.core.Icon({
			width : "100%",
			src : "sap-icon://add",
			tooltip : oSelf.getText("addButton"),
			visible : {
				path : "nMax",
				formatter : function(nMax) {
					return (nMax === "*");
				}
			},
			press : oSelf._handlerForBasicDataAddPropertyRow.bind(this)
		// the current context should be bound to the event handler
		}).addStyleClass("addIconRepresentation");
		// Remove Icon
		var oRemoveIcon = new sap.ui.core.Icon({
			width : "100%",
			src : "sap-icon://less",
			tooltip : oSelf.getText("deleteButton"),
			visible : {
				path : "/",
				formatter : function() {
					var bIsFirstOfItsKind = true;
					var oBindingContext = this.getBindingContext();
					var nCurrentIndex = parseInt(oBindingContext.getPath().split("/").pop(), 10);
					if (nCurrentIndex) {
						var aPropertyRows = oSelf.mDataset.oPropertyDataset.aPropertyRows;
						var sCurrentKind = aPropertyRows[nCurrentIndex].sKind;
						var sCurrentAggRole = aPropertyRows[nCurrentIndex].sAggregationRole;
						var nPreviousIndex = nCurrentIndex - 1;
						var sPreviousKind = aPropertyRows[nPreviousIndex].sKind;
						var sPreviousAggRole = aPropertyRows[nPreviousIndex].sAggregationRole;
						bIsFirstOfItsKind = !(sCurrentKind === sPreviousKind && sCurrentAggRole === sPreviousAggRole);
					}
					return !bIsFirstOfItsKind;
				}
			},
			press : oSelf._handlerForBasicDataDeletePropertyRow.bind(this)
		// the current context should be bound to the event handler
		}).addStyleClass("lessIconRepresentation");
		var oIconLayout = new sap.m.HBox({ //layout to hold the add/less icons
			layoutData : new sap.ui.layout.GridData({
				span : "L1 M2 S2"
			}),
			items : [ oAddIcon, oRemoveIcon ]
		});
		oPropertyRowTemplate.addContent(oIconLayout);
		oBasicDataLayout.bindAggregation("items", "/aPropertyRows", function(sId, oModelData) {
			oCopyPropertyRowTemplate = jQuery.extend(true, {}, oPropertyRowTemplate);
			sPathOfPropertyRow = oModelData.sPath.split("/");
			nPropertyRowIndex = sPathOfPropertyRow[sPathOfPropertyRow.indexOf("aPropertyRows") + 1];
			oCopyPropertyRowTemplate.getContent()[1].getLayoutData().setSpan("L4 M4 S4");
			if (oSelf.mModel.oPropertyModel.getData().aPropertyRows[nPropertyRowIndex].sAggregationRole === "dimension") {
				oLabelDisplayOptionBox = new sap.m.Select({
					width : "100%",
					layoutData : new sap.ui.layout.GridData({
						span : "L2 M2 S2"
					}),
					items : {
						path : "aLabelDisplayOptionTypes",
						template : new sap.ui.core.ListItem({
							key : "{key}",
							text : "{value}"
						}),
						templateShareable : true
					},
					selectedKey : "{sLabelDisplayOptionProperty}",
					change : oSelf._handleChangeForLabelDisplayOption.bind(oSelf)
				});
				oCopyPropertyRowTemplate.insertContent(oLabelDisplayOptionBox, 2);
				oCopyPropertyRowTemplate.getContent()[1].getLayoutData().setSpan("L2 M2 S2");
			}
			return oCopyPropertyRowTemplate.clone(sId);
		});
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_handleChangeForBasicDataSelectProperty
	* @param {oControl}
	* @description Handler for change in select property
	* Sets the corresponding properties on the representation object.
	* */
	_handleChangeForBasicDataSelectProperty : function(oSelectEvent) {
		var oLabelDisplayOptionControl;
		var sSelectedKey = oSelectEvent.getSource().getSelectedKey();
		var oPropertyRow = oSelectEvent.getSource().getParent().getContent();
		var oLabelControl = oSelectEvent.getSource().getBindingContext().getProperty("sAggregationRole") === "dimension" ? oPropertyRow[3] : oPropertyRow[2];
		var oLabelInputControl = oSelectEvent.getSource().getBindingContext().getProperty("sAggregationRole") === "dimension" ? oPropertyRow[4] : oPropertyRow[3];
		if (sSelectedKey && (sSelectedKey !== this.getText("none"))) { // if a property is selected
			this._setDefaultLabelForSelectedProperty(sSelectedKey, oLabelControl); //pass the selected property and the label control as an argument
		} else {
			oLabelControl.setText(this.getText("label")); // if no property is selected, set the label value as empty string
			oLabelInputControl.setValue("");
		}
		this._setPropertiesFromCurrentDataset(); // set the current properties on the representation
		if (oSelectEvent.getSource().getBindingContext().getProperty("sAggregationRole") === "dimension") {
			this._setDefaultLabelDisplayOption(sSelectedKey);
			oLabelDisplayOptionControl = oSelectEvent.getSource().getParent().getContent()[2];
			oLabelDisplayOptionControl.setSelectedKey(this.oRepresentation.getLabelDisplayOption(sSelectedKey));
			this._enableDisableItemsInDisplayOptionOrDisplayOptionBox();
		}
		this.oConfigurationEditor.setIsUnsaved();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_handleChangeForBasicDataPropertyRowLabelInput
	* @param {oControl}
	* @description Handler for change in label for the property row
	* Sets the corresponding properties on the representation object.
	* */
	_handleChangeForBasicDataPropertyRowLabelInput : function(oInputEvent) {
		var sProperty = oInputEvent.getSource().getBindingContext().getProperty("sSelectedProperty");
		var oPropertyRow = oInputEvent.getSource().getParent().getContent();
		var oLabelControl = oInputEvent.getSource().getBindingContext().getProperty("sAggregationRole") === "dimension" ? oPropertyRow[3] : oPropertyRow[2];
		if (sProperty && sProperty !== this.getText("none")) {
			this._updatLabelInPropertyRow(sProperty, oInputEvent.getSource().getValue(), oLabelControl);
		}
		this._setPropertiesFromCurrentDataset();
		this.oConfigurationEditor.setIsUnsaved();
	},
	_handleChangeForLabelDisplayOption : function(oEvent) {
		var sSelectedDisplayOption = oEvent.getSource().getSelectedKey();
		var sProperty = oEvent.getSource().getBindingContext().getProperty("sSelectedProperty");
		this.oRepresentation.setLabelDisplayOption(sProperty, sSelectedDisplayOption);
		this.oConfigurationEditor.setIsUnsaved();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_handlerForBasicDataAddPropertyRow
	* @param {oPropertyRow}
	* @description Handler for the "+" icon in the property row
	* adds a new property row in the representation basic data and also sets the corresponding properties on the representation object.          
	* */
	_handlerForBasicDataAddPropertyRow : function(oAddRowEvent) {
		var oBindingContext = oAddRowEvent.getSource().getBindingContext();
		var oCurrentObjectClone = jQuery.extend(true, {}, oBindingContext.getObject());
		delete oCurrentObjectClone.sSelectedProperty;
		delete oCurrentObjectClone.sLabel;
		delete oCurrentObjectClone.sLabelDisplayOptionProperty;
		var nCurrentIndex = parseInt(oBindingContext.getPath().split("/").pop(), 10);
		var aPropertyRows = this.mDataset.oPropertyDataset.aPropertyRows;
		aPropertyRows.splice(nCurrentIndex + 1, 0, oCurrentObjectClone);
		this._setPropertiesFromCurrentDataset();
		this.mModel.oPropertyModel.updateBindings();
		this._enableDisableItemsInDisplayOptionOrDisplayOptionBox();
		this.oConfigurationEditor.setIsUnsaved();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_handlerForBasicDataDeletePropertyRow
	* @param {oAddRowEvent}
	* @description Handler for the "-" icon in the property row
	* remove a property row from the representation basic data and also sets the corresponding properties on the representation object.          
	* */
	_handlerForBasicDataDeletePropertyRow : function(oDeleteRowEvent) {
		var oBindingContext = oDeleteRowEvent.getSource().getBindingContext();
		var nCurrentIndex = parseInt(oBindingContext.getPath().split("/").pop(), 10);
		var aPropertyRows = this.mDataset.oPropertyDataset.aPropertyRows;
		aPropertyRows.splice(nCurrentIndex, 1);
		this.mModel.oPropertyModel.updateBindings();
		this._setPropertiesFromCurrentDataset();
		this.oConfigurationEditor.setIsUnsaved();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_updatLabelInPropertyRow
	* @param {sSelectedProperty,sLabelValue,oLabel} - Selected property in the drop down, the new value of the lable and the lable control
	* @description gets the default label from the metadata, compares if the same value is given by user 
	* and accordingly adds the "default" prefix to the label. Also sets the text on the label control for every select property.       
	* */
	_updatLabelInPropertyRow : function(sSelectedProperty, sLabelValue, oLabelControl) {
		var oPropertyMetadata = this.oEntityMetadata.getPropertyMetadata(sSelectedProperty);
		var sDefaultLabel = oPropertyMetadata.label ? oPropertyMetadata.label : oPropertyMetadata.name;
		var sLableControlText, sLabelControlValue;
		if (sDefaultLabel !== sLabelValue && sLabelValue.length !== 0) {
			sLableControlText = this.getText("label");
			sLabelControlValue = sLabelValue;
		} else {
			sLableControlText = this.getText("label") + "(" + this.getText("default") + ")";
			sLabelControlValue = sDefaultLabel;
		}
		this.mDataset.oPropertyDataset.aPropertyRows.forEach(function(oPropertyRow) {
			if (oPropertyRow.sSelectedProperty === sSelectedProperty) { //Update the dataset with default value of input label
				oPropertyRow.sLabel = sLabelControlValue;
			}
		});
		this.mModel.oPropertyModel.updateBindings();
		oLabelControl.setText(sLableControlText);
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_setDefaultLabelForSelectedProperty
	* @param {sSelectedProperty,oLabelControl} - Selected property in the drop down and the label control
	* @description gets the default label from the metadata, adds the "default" prefix to the label. 
	* Also sets the default text on the label control for every select property.       
	* */
	_setDefaultLabelForSelectedProperty : function(sSelectedProperty, oLabelControl) {
		var oPropertyMetadata = this.oEntityMetadata.getPropertyMetadata(sSelectedProperty);
		var sDefaultLabel = oPropertyMetadata.label ? oPropertyMetadata.label : oPropertyMetadata.name;
		var sLabelText = this.getText("label") + "(" + this.getText("default") + ")";
		this.mDataset.oPropertyDataset.aPropertyRows.forEach(function(oPropertyRow) {
			if (oPropertyRow.sSelectedProperty === sSelectedProperty) {
				oPropertyRow.sLabel = sDefaultLabel; //Update the dataset with default value of input label
			}
		});
		this.mModel.oPropertyModel.updateBindings();
		oLabelControl.setText(sLabelText);
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_bindSortLayoutData
	* @description Binds sap.apf.modeler.ui.controller.representation#mModel.oSortModel to Sort layout.
	*               Iteratively binds the data to both the controls in Sort Data Layout.
	* */
	_bindSortLayoutData : function() {
		var oSelf = this;
		var oSortLayout = this.byId("idSortLayout");
		var oSortRowTemplate = new sap.ui.layout.Grid({ // add the select box controls to the grid.
			width : "100%"
		});
		// "Sort Label" Label
		var oSortFieldLabel = new sap.m.Label({
			width : "100%",
			textAlign : "End",
			layoutData : new sap.ui.layout.GridData({
				span : "L2 M2 S2"
			}),
			text : this.getText("sortingField"),
			tooltip : this.getText("sortingField")
		});
		oSortRowTemplate.addContent(oSortFieldLabel);
		// "Sort Fields" Select Box
		var oSortPropertySelectBox = new sap.m.Select({
			width : "100%",
			layoutData : new sap.ui.layout.GridData({
				span : "L4 M4 S4"
			}),
			items : {
				path : "aAllProperties",
				template : new sap.ui.core.ListItem({
					key : "{sName}",
					text : "{sName}"
				}),
				templateShareable : true
			},
			selectedKey : "{sSortProperty}",
			change : oSelf._handleChangeForSortDataProperty.bind(this)
		// the current context should be bound to the event handler
		});
		oSortRowTemplate.addContent(oSortPropertySelectBox);
		// "Direction" Label
		var oDirectionLabel = new sap.m.Label({
			layoutData : new sap.ui.layout.GridData({
				span : "L2 M2 S2"
			}),
			width : "100%",
			textAlign : "End",
			text : this.getText("direction"),
			tooltip : this.getText("direction")
		});
		oSortRowTemplate.addContent(oDirectionLabel);
		// "Direction" Select Box
		var oDirectionSelectBox = new sap.m.Select({
			width : "100%",
			layoutData : new sap.ui.layout.GridData({
				span : "L3 M2 S2"
			}),
			items : [ {
				key : this.getText("ascending"),
				text : this.getText("ascending")
			}, {
				key : this.getText("descending"),
				text : this.getText("descending")
			} ],
			selectedKey : "{sDirection}",
			change : oSelf._handleChangeForSortDirection.bind(this)
		// the current context should be bound to the event handler
		});
		oSortRowTemplate.addContent(oDirectionSelectBox);
		// Add Icon
		var oAddIcon = new sap.ui.core.Icon({
			width : "100%",
			src : "sap-icon://add",
			tooltip : this.getText("addButton"),
			visible : true,
			press : oSelf._handleChangeForAddSortRow.bind(this)
		// the current context should be bound to the event handler
		}).addStyleClass("addIconRepresentation");
		// Remove Icon
		var oRemoveIcon = new sap.ui.core.Icon({
			width : "100%",
			src : "sap-icon://less",
			tooltip : this.getText("deleteButton"),
			visible : {
				path : "/",
				formatter : function() {
					var oBindingContext = this.getBindingContext();
					var nCurrentIndex = parseInt(oBindingContext.getPath().split("/").pop(), 10);
					return !!nCurrentIndex;
				}
			},
			press : oSelf._handleChangeForDeleteSortRow.bind(this)
		// the current context should be bound to the event handler
		}).addStyleClass("lessIconRepresentation");
		// Layout to hold the add/less icons
		var oIconLayout = new sap.m.HBox({
			layoutData : new sap.ui.layout.GridData({
				span : "L1 M2 S2"
			}),
			items : [ oAddIcon, oRemoveIcon ]
		});
		oSortRowTemplate.addContent(oIconLayout);
		oSortLayout.bindAggregation("items", "/aSortRows", oSortRowTemplate);
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_handleChangeForSortDataProperty
	* @description handler for the change in sort property in representation.       
	* */
	_handleChangeForSortDataProperty : function() {
		this._setSortFieldsFromCurrentDataset();
		this.oConfigurationEditor.setIsUnsaved();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_handleChangeForSortDirection
	* @description handler for the change in sort direction for a property in representation.       
	* */
	_handleChangeForSortDirection : function(oSelectEvent) {
		var sSortProperty = oSelectEvent.getSource().getBindingContext().getProperty("sSortProperty");
		if (sSortProperty !== this.getText("none")) {
			this._setSortFieldsFromCurrentDataset();
			this.oConfigurationEditor.setIsUnsaved();
		}
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_handleChangeForAddSortRow
	* @param {oAddRowEvent}
	* @description Handler for the "+" icon in the sort property row
	* adds a new sort property row in the representation sort data and also sets the corresponding properties on the representation object.          
	* */
	_handleChangeForAddSortRow : function(oAddRowEvent) {
		var oBindingContext = oAddRowEvent.getSource().getBindingContext();
		var oCurrentObjectClone = jQuery.extend(true, {}, oBindingContext.getObject());
		delete oCurrentObjectClone.sSortProperty;
		delete oCurrentObjectClone.sDirection;
		var nCurrentIndex = parseInt(oBindingContext.getPath().split("/").pop(), 10);
		var aSortRows = this.mDataset.oSortDataset.aSortRows;
		aSortRows.splice(nCurrentIndex + 1, 0, oCurrentObjectClone);
		this.mModel.oSortModel.updateBindings();
		this._setSortFieldsFromCurrentDataset();
		this.oConfigurationEditor.setIsUnsaved();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_handleChangeForDeleteSortRow
	* @param {oDeleteRowEvent}
	* @description Handler for the "-" icon in the sort property row
	* removes a sort property row from the representation sort data and also sets the corresponding properties on the representation object.          
	* */
	_handleChangeForDeleteSortRow : function(oDeleteRowEvent) {
		var oBindingContext = oDeleteRowEvent.getSource().getBindingContext();
		var nCurrentIndex = parseInt(oBindingContext.getPath().split("/").pop(), 10);
		var aSortRows = this.mDataset.oSortDataset.aSortRows;
		aSortRows.splice(nCurrentIndex, 1);
		this.mModel.oSortModel.updateBindings();
		this._setSortFieldsFromCurrentDataset();
		this.oConfigurationEditor.setIsUnsaved();
	},
	_setPropertiesForTable : function() {
		var oSelf = this;
		var aDimensions = this.oRepresentation.getDimensions();
		var aMeasures = this.oRepresentation.getMeasures();
		//Add dimensions and measures as properties for table representation for old configurations
		aDimensions.forEach(function(sProperty) {
			oSelf.oRepresentation.addProperty(sProperty);
			oSelf.oRepresentation.setPropertyTextLabelKey(sProperty, oSelf.oRepresentation.getDimensionTextLabelKey(sProperty));
			oSelf.oRepresentation.setPropertyKind(sProperty, sap.apf.core.constants.representationMetadata.kind.COLUMN);
		});
		aMeasures.forEach(function(sProperty) {
			oSelf.oRepresentation.addProperty(sProperty);
			oSelf.oRepresentation.setPropertyTextLabelKey(sProperty, oSelf.oRepresentation.getMeasureTextLabelKey(sProperty));
			oSelf.oRepresentation.setPropertyKind(sProperty, sap.apf.core.constants.representationMetadata.kind.COLUMN);
		});
		aDimensions.forEach(function(sDimension) {
			oSelf.oRepresentation.removeDimension(sDimension);
		});
		aMeasures.forEach(function(sMeasure) {
			oSelf.oRepresentation.removeMeasure(sMeasure);
		});
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_validateRepresentationData
	* @description Validates the dimensions and measures of a representation by comparing them with the select properties of the step
	* Removes dimensions or measures that are not part of the step's select properties
	* */
	_validateRepresentationData : function() {
		var oSelf = this;
		//Dimensions set to the representation
		var aDimensions = this.oRepresentation.getDimensions().map(function(dimension) {
			return {
				sType : "Dimension",
				sName : dimension
			};
		});
		//Measures set to the representation
		var aMeasures = this.oRepresentation.getMeasures().map(function(measure) {
			return {
				sType : "Measure",
				sName : measure
			};
		});
		//Properties set to the representation in case of Table representation
		var aProperties = this.oRepresentation.getProperties().map(function(property) {
			return {
				sType : "Property",
				sName : property
			};
		});
		var aRepProperties = aDimensions.concat(aMeasures).length ? aDimensions.concat(aMeasures) : aProperties;
		//Compare representation properties and step properties
		aRepProperties.forEach(function(repProperty) {
			var bPropertyPresent = false;
			oSelf.aSelectProperties.forEach(function(selectProperty) {
				if (repProperty.sName === selectProperty.sName) {
					bPropertyPresent = true;
				}
			});
			//If property is not present in the step's select properties remove the property(dimension or measure) from the representation
			if (bPropertyPresent === false) {
				var sRemoveMethodName = [ "remove", repProperty.sType ].join("");
				oSelf.oRepresentation[sRemoveMethodName](repProperty.sName);
				oSelf.oConfigurationEditor.setIsUnsaved();
			}
		});
	},
	_enableDisableItemsInDisplayOptionOrDisplayOptionBox : function() {
		var index, itemIndex, displayLabelOptionBox, bIsTextPropertyPresent, aPropertyRows;
		if (this.byId('idBasicDataLayout').getModel()) {
			aPropertyRows = this.byId("idBasicDataLayout").getModel().getData().aPropertyRows;
			var basicDataLayout = this.byId("idBasicDataLayout");
			for(index = 0; index < aPropertyRows.length; index++) {
				if (aPropertyRows[index].sAggregationRole === "dimension") {
					displayLabelOptionBox = basicDataLayout.getItems()[index].getContent()[2];
					if (aPropertyRows[index].sSelectedProperty === this.getText("none")) {
						basicDataLayout.getItems()[index].getContent()[2].setEnabled(false);
						continue;
					} else {
						basicDataLayout.getItems()[index].getContent()[2].setEnabled(true);
					}
					bIsTextPropertyPresent = this._checkIfTextPropertyOfDimensionIsPresent(aPropertyRows[index].sSelectedProperty);
					for(itemIndex = 0; itemIndex < displayLabelOptionBox.getItems().length; itemIndex++) {
						if (itemIndex > 0) {
							displayLabelOptionBox.getItems()[itemIndex].setEnabled(bIsTextPropertyPresent);
						}
					}
				}
			}
		}
	},
	_checkIfTextPropertyOfDimensionIsPresent : function(dimension) {
		var isPresent = false;
		var oDimensionMetadata = this.oEntityMetadata.getPropertyMetadata(dimension);
		if (oDimensionMetadata.text) {
			var aSelectProperties = this.oParentStep.getSelectProperties();
			isPresent = aSelectProperties.indexOf(oDimensionMetadata.text) === -1 ? false : true;
		}
		return isPresent;
	},
	_setDefaultLabelDisplayOption : function(dimension) {
		var isTextPropertyPresent = this._checkIfTextPropertyOfDimensionIsPresent(dimension);
		if (isTextPropertyPresent) {
			this.oRepresentation.setLabelDisplayOption(dimension, sap.apf.core.constants.representationMetadata.labelDisplayOptions.KEY_AND_TEXT);
		} else {
			this.oRepresentation.setLabelDisplayOption(dimension, sap.apf.core.constants.representationMetadata.labelDisplayOptions.KEY);
		}
		this.oConfigurationEditor.setIsUnsaved();
	},
	_setDefaultLabelDisplayOptionToDimensions : function() {
		var oSelf = this;
		this.oRepresentation.getDimensions().forEach(function(dimension) {
			if (oSelf.oRepresentation.getLabelDisplayOption(dimension) === undefined) {
				oSelf._setDefaultLabelDisplayOption(dimension);
			}
		});
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#setDetailData
	* @description Prepares data set and model map to be used within the view.
	* */
	setDetailData : function() {
		var mContextParam = this.mParam.arguments;
		this.oParentStep = this.oConfigurationEditor.getStep(mContextParam.stepId);
		this.oEntityMetadata = this.getEntityTypeMetadata(this.oParentStep.getService(), this.oParentStep.getEntitySet());
		this.aSelectProperties = this._getSelectPropertiesFromParentStep();
		this.oRepresentation = this.oParentStep.getRepresentation(mContextParam.representationId);
		if (!this.oRepresentation) {
			this.oRepresentation = this.oParentStep.createRepresentation();
			// Set Default Chart Type
			this._setDefaultRepresentationType();
			// Set Default Dimensions/Measures
			this._setDefaultProperties();
			this.oConfigurationEditor.setIsUnsaved();
		}
		if (this.oRepresentation.getRepresentationType() === sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) {
			this._setPropertiesForTable();
		}
		this._validateRepresentationData();
		this._setDefaultLabelDisplayOptionToDimensions();
		// Datasets
		var oChartTypeDataset = this._getChartTypeDataset();
		var oPropertyDataset = this._getPropertyDataset();
		var oSortDataset = this._getSortDataset();
		var oCornerTextsDataset = this._getCornerTextsDataset();
		var oChartPictureDataset = this._getChartPictureDataset();
		this.mDataset = {
			oChartTypeDataset : oChartTypeDataset,
			oPropertyDataset : oPropertyDataset,
			oSortDataset : oSortDataset,
			oCornerTextsDataset : oCornerTextsDataset,
			oChartPictureDataset : oChartPictureDataset
		};
		// Models
		var oChartTypeModel = new sap.ui.model.json.JSONModel(this.mDataset.oChartTypeDataset);
		var oPropertyModel = new sap.ui.model.json.JSONModel(this.mDataset.oPropertyDataset);
		var oSortModel = new sap.ui.model.json.JSONModel(this.mDataset.oSortDataset);
		var oCornerTextsModel = new sap.ui.model.json.JSONModel(this.mDataset.oCornerTextsDataset);
		var oChartPictureModel = new sap.ui.model.json.JSONModel(this.mDataset.oChartPictureDataset);
		this.mModel = {
			oChartTypeModel : oChartTypeModel,
			oPropertyModel : oPropertyModel,
			oSortModel : oSortModel,
			oCornerTextsModel : oCornerTextsModel,
			oChartPictureModel : oChartPictureModel
		};
		// Bindings
		this.byId("idChartType").setModel(this.mModel.oChartTypeModel);
		var sChartType = this.sCurrentChartType;
		this._updateAndSetDatasetsByChartType(sChartType);
		this.byId("idBasicDataLayout").setModel(this.mModel.oPropertyModel);
		this._bindBasicRepresentationData();
		this.byId("idSortLayout").setModel(this.mModel.oSortModel);
		this._bindSortLayoutData();
		this.byId("idLeftLower").setModel(this.mModel.oCornerTextsModel);
		this.byId("idRightLower").setModel(this.mModel.oCornerTextsModel);
		this.byId("idLeftUpper").setModel(this.mModel.oCornerTextsModel);
		this.byId("idRightUpper").setModel(this.mModel.oCornerTextsModel);
		this.byId("idChartIcon").setModel(this.mModel.oChartPictureModel);
		// Actions
		this._addAutoCompleteFeatureOnInputs();
		//disable/enable the sort field based on the top N setting on the step
		var bIsSortFieldEnabled;
		if (this.oParentStep.getTopN()) {
			bIsSortFieldEnabled = false;
		} else {
			bIsSortFieldEnabled = true;
		}
		this._changeEditableOfSortProperty(bIsSortFieldEnabled);
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_changeEditableOfSortProperty
	* @description enables/disables the sort property in the representation based on the top N availibility in the parent step
	* */
	_changeEditableOfSortProperty : function(bIsSortFieldEnabled) {
		var sSortContent = this.byId("idSortLayout").getItems();
		sSortContent.forEach(function(oSortRow, nIndexFirstSortRow) {
			oSortRow.getContent().forEach(function(oControl) {
				if (oControl instanceof sap.m.Select) { //disable the select controls in the sort field
					oControl.setEnabled(bIsSortFieldEnabled);
				}
				if (oControl instanceof sap.m.HBox) { //add and delete icons are inside a HBox
					oControl.getItems().forEach(function(item, nIndexDeleteIcon) {
						if (item instanceof sap.ui.core.Icon) {
							item.setVisible(bIsSortFieldEnabled);
							if (nIndexFirstSortRow === 0 && nIndexDeleteIcon === 1) { // delete icon should not be shown for the first sort row
								item.setVisible(false);
							}
						}
					});
				}
			});
		});
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_insertPreviewButtonInFooter
	* @description Inserts the preview Button into the footer.
	* */
	_insertPreviewButtonInFooter : function() {
		var oFooter = this.oViewData.oFooter;
		oFooter.addContentRight(this._oPreviewButton);
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_removePreviewButtonFromFooter
	* @description Removes the preview Button from the footer.
	* */
	_removePreviewButtonFromFooter : function() {
		var oFooter = this.oViewData.oFooter;
		oFooter.removeContentRight(this._oPreviewButton);
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_handlePreviewButtonPress
	* @description Handler for press event on preview Button.
	*          Opens a dialog and inserts the preview content in it.
	* */
	_handlePreviewButtonPress : function() {
		var oPreviewDetails = this._getPreviewDetails();
		var oPreviewContent = new sap.ui.view({
			type : sap.ui.core.mvc.ViewType.XML,
			viewName : "sap.apf.modeler.ui.view.previewContent",
			viewData : oPreviewDetails
		});
		var oPreviewDialog = new sap.m.Dialog({
			title : this.getText("preview"),
			content : oPreviewContent,
			endButton : new sap.m.Button({
				text : this.getText("close"),
				press : function() {
					oPreviewDialog.close();
				}
			})
		});
		oPreviewDialog.open();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#onExit
	* @description Called when sub-view is destroyed by configuration list controller.
	*               Removes the preview button from footer.
	* */
	onExit : function() {
		this._removePreviewButtonFromFooter();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_getPreviewDetails
	* @description Prepares the argument for sap.apf.modeler.ui.controller.PreviewContent.
	*          Iterates through all the models and populates the result object.
	* @returns {Object} Argument for sap.apf.modeler.ui.controller.PreviewContent
	* */
	_getPreviewDetails : function() {
		var oSelf = this;
		var sChartType = this.mDataset.oChartTypeDataset.sSelectedChartType;
		var sStepTitle = this._getParentStepTitle();
		var sStepLongTitle = this._getParentStepLongTitle() || sStepTitle;
		var aDimensions = [], aMeasures = [], aProperties = [];
		this.aSelectProperties.forEach(function(oSelectProperty) {
			if (sChartType === sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) {
				aProperties.push(oSelectProperty.sName);
			} else {
				if (oSelectProperty.sAggregationRole === "dimension") {
					aDimensions.push(oSelectProperty.sName);
				} else if (oSelectProperty.sAggregationRole === "measure") {
					aMeasures.push(oSelectProperty.sName);
				}
			}
		});
		var oChartParameter = {
			dimensions : [],
			measures : [],
			properties : [],
			requiredFilters : []
		};
		this.mDataset.oPropertyDataset.aPropertyRows.forEach(function(oPropertyRow) {
			if (oPropertyRow.sSelectedProperty !== oSelf.getText("none")) {
				var sAggregationRole = (oPropertyRow.sAggregationRole !== "property") ? oPropertyRow.sAggregationRole + "s" : [ oPropertyRow.sAggregationRole.slice(0, -1), "ies" ].join("");
				oChartParameter[sAggregationRole].push({
					fieldDesc : oPropertyRow.sLabel,
					fieldName : oPropertyRow.sSelectedProperty,
					kind : oPropertyRow.sKind
				});
			}
		});
		// Sort Fields
		var aSort = [];
		this.mDataset.oSortDataset.aSortRows.forEach(function(oSortRow) {
			var sSortProperty = oSortRow.sSortProperty || (oSortRow.aAllProperties.length && oSortRow.aAllProperties[0].sName);
			if (sSortProperty && sSortProperty !== oSelf.getText("none")) {
				var bAscending = !oSortRow.sDirection || (oSortRow.sDirection === oSelf.getText("ascending"));
				aSort.push({
					sSortField : sSortProperty,
					bDescending : !bAscending
				});
			}
		});
		var aCornerTexts = {
			sLeftUpper : this.mDataset.oCornerTextsDataset.LeftUpper,
			sRightUpper : this.mDataset.oCornerTextsDataset.RightUpper,
			sLeftLower : this.mDataset.oCornerTextsDataset.LeftLower,
			sRightLower : this.mDataset.oCornerTextsDataset.RightLower
		};
		return {
			sChartType : sChartType,
			sStepTitle : sStepTitle,
			sStepLongTitle : sStepLongTitle,
			aDimensions : aDimensions,
			aMeasures : aMeasures,
			aProperties : aProperties,
			oChartParameter : oChartParameter,
			aSort : aSort,
			aCornerTexts : aCornerTexts
		};
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_getParentStepLongTitle
	* @description Getter for parent step's long title
	* @returns {String|undefined} Parent Step's Long Title or undefined if not available.
	* */
	_getParentStepLongTitle : function() {
		var sStepLongTitleId = this.oParentStep.getLongTitleId();
		sStepLongTitleId = !this.oTextPool.isInitialTextKey(sStepLongTitleId) ? sStepLongTitleId : undefined;
		var oStepLongTitleText = sStepLongTitleId && this.oTextPool.get(sStepLongTitleId);
		var sStepLongTitle = oStepLongTitleText && oStepLongTitleText.TextElementDescription;
		return sStepLongTitle;
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_getParentStepTitle
	* @description Getter for parent step's title
	* @returns {String|undefined} Parent Step's Title or undefined if not available.
	* */
	_getParentStepTitle : function() {
		var sStepTitleId = this.oParentStep.getTitleId();
		var oStepTitleText = sStepTitleId && this.oTextPool.get(sStepTitleId);
		var sStepTitle = oStepTitleText && oStepTitleText.TextElementDescription;
		return sStepTitle;
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_getSelectPropertiesFromParentStep
	* @description Getter for Select Property List from parent step.
	* @returns {Object[]} Array of select properties of the form : 
	*          {
	*               sName - Name of the property.
	*               sAggregationRole - dimension/measure.
	*               sLabel - Label of the property
	*          }
	* */
	_getSelectPropertiesFromParentStep : function() {
		var sAbsolutePathToServiceDocument = this.oParentStep.getService();
		var sEntitySet = this.oParentStep.getEntitySet();
		var oEntityMetadata = this.getEntityTypeMetadata(sAbsolutePathToServiceDocument, sEntitySet);
		var aSelectProperties = this.oParentStep.getSelectProperties();
		var aResultSet = aSelectProperties.map(function(sProperty) {
			var oMetadataForProperty = oEntityMetadata.getPropertyMetadata(sProperty);
			return {
				sName : sProperty,
				sAggregationRole : oMetadataForProperty["aggregation-role"],
				sLabel : oMetadataForProperty["label"]
			};
		});
		return aResultSet;
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_getCornerTextsFromConfigObject
	* @param {sap.apf.modeler.core.Step|sap.apf.modeler.core.Representation} oConfigObject - Instance of a configuration object.
	* @description Getter for corner text map of a configuration object.
	* @returns {Object} Map of corner Text of the form : 
	*          {
	*               LeftUpper - Left Upper corner text.
	*               RightUpper - Right Upper corner text.
	*               LeftLower - Left Lower corner text.
	*               RightLower - Right Lower corner text. 
	*          }
	* */
	_getCornerTextsFromConfigObject : function(oConfigObject) {
		var oSelf = this;
		var aCornerTextNames = [ "LeftUpper", "RightUpper", "LeftLower", "RightLower" ];
		var mDataset = {};
		aCornerTextNames.forEach(function(sCornerTextName) {
			var sMethodName = [ "get", sCornerTextName, "CornerTextKey" ].join("");
			var sCornerTextKey = oConfigObject[sMethodName]();
			var oCornerText = sCornerTextKey && oSelf.oTextPool.get(sCornerTextKey);
			var sCornterText = oCornerText && oCornerText.TextElementDescription;
			mDataset[sCornerTextName] = sCornterText;
		});
		return mDataset;
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_getChartTypeDataset
	* @description Returns the data set to be bound to chart type drop down.
	* @returns {Object} Data set for chart type drop down of the form:
	*          {
	*               aChartTypes : [
	*                    {
	*                          sId - {sap.apf.ui.utils.CONSTANTS.representationTypes} Chart Type.
	*                          sText - {String} Display text for the chart type     
	*                    }
	*               ]
	*               sSelectedChartType - {sap.apf.ui.utils.CONSTANTS.representationTypes} Currently selected Chart Type.
	*          }
	* */
	_getChartTypeDataset : function() {
		var self = this;
		var aKeys = Object.keys(this._getRepresentationMetadata());
		var aChartTypes = aKeys.map(function(sKey) {
			return {
				sId : sKey,
				sText : self.getText(sKey)
			};
		});
		var oDataset = {
			aChartTypes : aChartTypes,
			sSelectedChartType : this.oRepresentation.getRepresentationType()
		};
		this.sCurrentChartType = oDataset.sSelectedChartType;
		return oDataset;
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_getChartPictureDataset
	* @description Returns the data set to be bound to representation icon
	* @returns {Object} 
	*          {
	*               id : picture
	*          }
	* */
	_getChartPictureDataset : function() {
		var oRepnMetaData = this.getRepresentationTypes();
		var oDataSet = {};
		oRepnMetaData.forEach(function(o) {
			var sId = o.id;
			oDataSet[sId] = o.picture;
		});
		oDataSet.sSelectedChartPicture = oDataSet[this.oRepresentation.getRepresentationType()];
		return oDataSet;
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_updatePictureDataset
	* @description Update the picture model data set
	*/
	_updatePictureDataset : function(sChartType) {
		var oDataSet = this.mModel.oChartPictureModel.getData();
		oDataSet.sSelectedChartPicture = oDataSet[sChartType];
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_getPropertyDataset
	* @description Returns the data set to be bound to basic data layout.
	* @returns {Object} Data set for basic data layout of the form:
	*          {
	*               aPropertyRows : [
	*                    {
	                           sSelectedProperty - Selected Property of dropdown.
	                           sAggregationRole - dimension/measure.
	                           sLabel - Label of the selected property.
	                           sKind - {sap.apf.core.constants.representationMetadata.kind} kind value of corresponding row.
	                           nMin - Minimum value from representation metadata.
	                           nMax - Maximum value from representation metadata.
	                      }
	*               ]
	*          }
	* */
	_getPropertyDataset : function() {
		var oSelf = this;
		var aPropertyRows = [];
		var fnAddPropertyRowsOfType = function(sType) {
			var sChartName = oSelf.oRepresentation.getRepresentationType();
			var sGetterMethodName = sType !== "Property" ? [ "get", sType, "s" ].join("") : [ "get", sType.slice(0, -1), "ies" ].join("");
			var aPropertyList = oSelf.oRepresentation[sGetterMethodName]();
			aPropertyList.forEach(function(sProperty) {
				var sLabelKeyMethodName = [ "get", sType, "TextLabelKey" ].join("");
				var sLabelKey = oSelf.oRepresentation[sLabelKeyMethodName](sProperty);
				var oLabel = sLabelKey && oSelf.oTextPool.get(sLabelKey);
				var sLabel = oLabel && oLabel.TextElementDescription;
				if (sLabel === undefined || sLabel.length === 0) { // if label is undefined or an empty string
					sLabel = oSelf.oEntityMetadata.getPropertyMetadata(sProperty).label || oSelf.oEntityMetadata.getPropertyMetadata(sProperty).name;
				}
				var sKindMethodName = [ "get", sType, "Kind" ].join("");
				var sKind = oSelf.oRepresentation[sKindMethodName](sProperty);
				var oRepMetadata = oSelf._getRepresentationMetadata()[sChartName];
				var aSupportedKinds = (sChartName === sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) ? oRepMetadata[sType.slice(0, -1).toLowerCase() + "ies"].supportedKinds
						: oRepMetadata[sType.toLowerCase() + "s"].supportedKinds;
				var nMin, nMax;
				aSupportedKinds.forEach(function(oSupportedKind) {
					if (oSupportedKind.kind === sKind) {
						nMin = oSupportedKind.min;
						nMax = oSupportedKind.max;
					}
				});
				aPropertyRows.push({
					sSelectedProperty : sProperty,
					sAggregationRole : sType.toLowerCase(),
					sLabel : sLabel,
					sKind : sKind,
					nMin : nMin,
					nMax : nMax,
					sLabelDisplayOptionProperty : sType.toLowerCase() === "dimension" ? oSelf.oRepresentation.getLabelDisplayOption(sProperty) : undefined
				});
			});
		};
		fnAddPropertyRowsOfType("Dimension");
		fnAddPropertyRowsOfType("Measure");
		fnAddPropertyRowsOfType("Property");
		return {
			aPropertyRows : aPropertyRows
		};
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_getSortDataset
	* @description Returns the data set to be bound to sort data layout.
	* @returns {Object} Data set for sort data layout of the form
	* {
			aSortRows : [ {
				aAllProperties : [ {
					sName : "None" - "None" value since it is an optional field
				}, {
					sName : Name of the property
				} ],
				sSortProperty : Name of the selected sort property,
				sDirection : Translated text for 'ascending' and 'descending'
			} ]
		}
	* */
	_getSortDataset : function() {
		var oSelf = this;
		var aOrderBySpecs = this.oRepresentation.getOrderbySpecifications();
		var aAllProperties = this.aSelectProperties.slice();
		aAllProperties.unshift({
			sName : this.getText("none")
		});
		if (!aOrderBySpecs.length) {
			aOrderBySpecs.push({});
		}
		var aSortRows = aOrderBySpecs.map(function(oOrderBySpec) {
			var sOrderByProperty = oOrderBySpec.property;
			var sOrderByDirection = oOrderBySpec.ascending !== undefined && !oOrderBySpec.ascending ? oSelf.getText("descending") : oSelf.getText("ascending");
			return {
				sSortProperty : sOrderByProperty,
				sDirection : sOrderByDirection,
				aAllProperties : aAllProperties
			};
		});
		return {
			aSortRows : aSortRows
		};
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_getCornerTextsDataset
	* @description Returns the data set to be bound to corner texts data layout.
	* @returns {Object} Data set for corner texts data layout of the form:
	*          {
	*               LeftUpper - Left Upper corner text.
	*               RightUpper - Right Upper corner text.
	*               LeftLower - Left Lower corner text.
	*               RightLower - Right Lower corner text. 
	*          }
	* */
	_getCornerTextsDataset : function() {
		var mRepresentationCornerText = this._getCornerTextsFromConfigObject(this.oRepresentation);
		var mParentStepCornerText = this._getCornerTextsFromConfigObject(this.oParentStep);
		var oDataset = jQuery.extend({}, mParentStepCornerText, mRepresentationCornerText);
		return oDataset;
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_setDefaultRepresentationType
	* @description Sets the first key from sap.apf.core.representationTypes() list as the default representation type.
	*               Updates the tree node after setting the representation type on the representation object and passes the id of newly created representation.
	* */
	_setDefaultRepresentationType : function() {
		var sDefaultChartType;
		if (this.getRepresentationTypes()[0].metadata) {
			sDefaultChartType = this.getRepresentationTypes()[0].id;
		}
		this.oRepresentation.setRepresentationType(sDefaultChartType);
		this.oRepresentation.setAlternateRepresentationType(sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION);
		// Update Tree Node.
		var sSelectedChartIcon = this._getChartPictureDataset().sSelectedChartPicture;
		var aStepCategories = this.oConfigurationEditor.getCategoriesForStep(this.oParentStep.getId());
		if (aStepCategories.length === 1) {//In case the step of representation is only assigned to one category
			this.oViewData.updateSelectedNode({
				id : this.oRepresentation.getId(),
				icon : sSelectedChartIcon
			});
		} else {
			this.oViewData.updateTree();
		}
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_setDefaultProperties
	* @description Adds the first dimension from parent step's select properties to representation object and gives it xAxis.
	*          Also adds the first measure to the representation object and gives it yAxis.
	* */
	_setDefaultProperties : function() {
		var sFirstDimension, sFirstMeasure;
		this.aSelectProperties.forEach(function(oSelectProperty) {
			if (!sFirstDimension) {
				if (oSelectProperty.sAggregationRole === "dimension") {
					sFirstDimension = oSelectProperty.sName;
				}
			}
			if (!sFirstMeasure) {
				if (oSelectProperty.sAggregationRole === "measure") {
					sFirstMeasure = oSelectProperty.sName;
				}
			}
		});
		// Add dimension
		if (sFirstDimension) {
			this.oRepresentation.addDimension(sFirstDimension);
			this.oRepresentation.setDimensionKind(sFirstDimension, sap.apf.core.constants.representationMetadata.kind.XAXIS);
		}
		// Add measure
		if (sFirstMeasure) {
			this.oRepresentation.addMeasure(sFirstMeasure);
			this.oRepresentation.setMeasureKind(sFirstMeasure, sap.apf.core.constants.representationMetadata.kind.YAXIS);
		}
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_updateAndSetDatasetsByChartType
	* @param {sap.apf.ui.utils.CONSTANTS.representationTypes} sChartName - Representation Type against which the property dataset has to be updated.
	* @description Updates datasets used in different layouts based on chart type.
	*          This method mutates the sap.apf.modeler.ui.controller.representation#mDataset based on the chart type which is passed.
	*          After the mutation it sets the values on the representation object.
	* */
	_updateAndSetDatasetsByChartType : function(sChartName) {
		this._updatePropertyDatasetByChartType(sChartName);
		this.mModel.oPropertyModel.updateBindings();
		this._setPropertiesFromCurrentDataset();
		this._enableDisableItemsInDisplayOptionOrDisplayOptionBox();
		this._updateSortDatasetByChartType(sChartName);
		this.mModel.oSortModel.updateBindings();
		this._setSortFieldsFromCurrentDataset();
		this._updatePictureDataset(sChartName);
		this.mModel.oChartPictureModel.updateBindings();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_updatePropertyDatasetByChartType
	* @param {sap.apf.ui.utils.CONSTANTS.representationTypes} sChartName - Representation Type against which the property dataset has to be updated.
	* @description Property dataset that is used in basic data layout is different for differnt chart types.
	*          This method mutates the sap.apf.modeler.ui.controller.representation#mDataset.oPropertyDataset based on the chart type which is passed.
	*          Contains logic to retain the data rows if old data in row and data row from passed chart type are same.
	* */
	_updatePropertyDatasetByChartType : function(sChartName) {
		var self = this;
		// oDefaultDataset holds the bare-minimum property rows for this particular sChartName.
		var oDefaultDataset = {
			aPropertyRows : []
		};
		var oRepMetadata = this._getRepresentationMetadata()[sChartName];
		var aAggregationRoles = [ "dimensions", "measures", "properties" ];
		aAggregationRoles.forEach(function(sAggregationRole) { // for each aggregation role, check the supported kind
			if (oRepMetadata.hasOwnProperty(sAggregationRole)) {
				var aSupportedKinds = oRepMetadata[sAggregationRole].supportedKinds;
				var sSelectedProperty;
				aSupportedKinds.forEach(function(oSupportedKind) { //for each kind, check all the properties 
					// To chop off the letter 's' form 'dimensions' and 'measures' and 'ies' from table representation
					var sAggRole = (sAggregationRole !== "properties") ? sAggregationRole.slice(0, -1) : [ sAggregationRole.slice(0, -3), "y" ].join("");
					var aAllProperties = (sAggregationRole !== "properties") ? self.aSelectProperties.filter(function(oProperty) {
						return (oProperty.sAggregationRole === sAggRole);
					}) : self.aSelectProperties;
					var oPropertyRow = {
						sAggregationRole : sAggRole,
						sKind : oSupportedKind.kind,
						nMin : oSupportedKind.min,
						nMax : oSupportedKind.max,
						aAllProperties : aAllProperties
					};
					if (oPropertyRow.sAggregationRole === "dimension") {
						oPropertyRow.aLabelDisplayOptionTypes = [ {
							key : "key",
							value : self.getText("key")
						}, {
							key : "text",
							value : self.getText("text")
						}, {
							key : "keyAndText",
							value : self.getText("keyAndText")
						} ];
					}
					if (!parseInt(oSupportedKind.min, 10)) {
						oPropertyRow.aAllProperties.unshift({
							sName : self.getText("none"),
							sAggregationRole : sAggRole
						});
					}
					oPropertyRow.aAllProperties.forEach(function(selectedProperty) { //assign the label to each property in one kind
						sSelectedProperty = selectedProperty.sName;
						if (sSelectedProperty) {
							var sType = sAggRole;
							var sAggregationRoleCamelCase = [ sType.charAt(0).toUpperCase(), sType.substring(1) ].join("");
							var sLabelKeyMethodName = [ "get", sAggregationRoleCamelCase, "TextLabelKey" ].join("");
							var sLabelKey = self.oRepresentation[sLabelKeyMethodName](sSelectedProperty);
							var oLabel = sLabelKey && self.oTextPool.get(sLabelKey);
							var sLabel = oLabel && oLabel.TextElementDescription;
							if (sLabel) { //if the user has given a label manually
								selectedProperty.sLabel = sLabel; // assign the label to the property
							} else { // else read the default label from the metadata
								if (sSelectedProperty !== self.getText("none")) {
									var oPropertyMetadata = self.oEntityMetadata.getPropertyMetadata(sSelectedProperty);
									var sDefaultLabel = oPropertyMetadata.label ? oPropertyMetadata.label : oPropertyMetadata.name;
									if (sDefaultLabel) {
										selectedProperty.sLabel = sDefaultLabel; // assign the label to the property
									}
								}
							}
						}
					});
					oDefaultDataset.aPropertyRows.push(oPropertyRow);
				});
			}
		});
		// oResultDataset combines the oDefaultDataset with the existing mPropertyDataset to retain the similar data entered by the user if any.
		var oResultDataset = {
			aPropertyRows : []
		};
		oDefaultDataset.aPropertyRows.forEach(function(oDefaultPropertyRow) {
			var bExitingRowOfSameKindExists = false;
			self.mDataset.oPropertyDataset.aPropertyRows.forEach(function(oExistingPropertyRow) {
				var bHasSameAggregationRole = oExistingPropertyRow.sAggregationRole === oDefaultPropertyRow.sAggregationRole;
				var bHasSameKind = oExistingPropertyRow.sKind === oDefaultPropertyRow.sKind;
				var bHasSameMinValue = oExistingPropertyRow.nMin === oDefaultPropertyRow.nMin;
				var bHasSameMaxValue = oExistingPropertyRow.nMax === oDefaultPropertyRow.nMax;
				if (bHasSameAggregationRole && bHasSameKind && bHasSameMinValue && bHasSameMaxValue) {
					bExitingRowOfSameKindExists = true;
					var oCompleteRow = jQuery.extend(oExistingPropertyRow, oDefaultPropertyRow);
					oResultDataset.aPropertyRows.push(oCompleteRow);
				}
			});
			if (!bExitingRowOfSameKindExists) {
				oResultDataset.aPropertyRows.push(oDefaultPropertyRow);
			}
		});
		// Update Dataset
		this.mDataset.oPropertyDataset.aPropertyRows = oResultDataset.aPropertyRows;
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_updateSortDatasetByChartType
	* @param {sap.apf.ui.utils.CONSTANTS.representationTypes} sChartName - Representation Type against which the property dataset has to be updated.
	* @description Sort dataset that is used in sort layout is different for differnt chart types.
	*          This method mutates the sap.apf.modeler.ui.controller.representation#mDataset.oPropertyDataset based on the chart type which is passed.
	*          Removes and hides Sort properties if "sortable" is set to false in the metadata of the chart type.
	* */
	_updateSortDatasetByChartType : function(sChartName) {
		var oRepMetadata = this._getRepresentationMetadata()[sChartName];
		if (oRepMetadata.sortable !== undefined && !oRepMetadata.sortable) {
			var aAllProperties = this.aSelectProperties.slice();
			aAllProperties.unshift({
				sName : this.getText("none")
			});
			this.mDataset.oSortDataset.aSortRows = [ {
				aAllProperties : aAllProperties,
				sDirection : this.getText("ascending")
			} ];
			this.byId("idSortLayout").setVisible(false);
			this.byId("idSorting").setVisible(false);
		} else {
			this.byId("idSortLayout").setVisible(true);
			this.byId("idSorting").setVisible(true);
			// <-- Work around to resolve data binding issue while changing visibility. -->
			this.mModel.oSortModel.updateBindings();
			var oSortLayout = this.byId("idSortLayout");
			jQuery.sap.delayedCall(10, oSortLayout, oSortLayout.rerender);
			// <-- Work around to resolve data binding issue while changing visibility. -->
		}
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_setPropertiesFromCurrentDataset
	* @description This function is called on every change event related to properties to adhere to WYSIWYG principle.
	*          Sets new values on the representation object based on the current property model.
	*          Clears the old values from representation object.
	*          Sets new values by iterating through the current property data set.
	* */
	_setPropertiesFromCurrentDataset : function() {
		var oSelf = this;
		// Clear all properties from representation
		var sDimensions = this.oRepresentation.getDimensions();
		sDimensions.forEach(function(sDimension) {
			oSelf.oRepresentation.removeDimension(sDimension);
		});
		var sMeasures = this.oRepresentation.getMeasures();
		sMeasures.forEach(function(sMeasure) {
			oSelf.oRepresentation.removeMeasure(sMeasure);
		});
		var sProperties = this.oRepresentation.getProperties();
		sProperties.forEach(function(sProperty) {
			oSelf.oRepresentation.removeProperty(sProperty);
		});
		// Loop through current dataset and set properties on representation
		this.mDataset.oPropertyDataset.aPropertyRows.forEach(function(oPropertyRow) {
			var sSelectedProperty = oPropertyRow.sSelectedProperty || (oPropertyRow.aAllProperties.length && oPropertyRow.aAllProperties[0].sName);
			if (sSelectedProperty && sSelectedProperty !== oSelf.getText("none")) {
				var sAggregationRole = oPropertyRow.sAggregationRole;
				var sAggregationRoleCamelCase = [ sAggregationRole.charAt(0).toUpperCase(), sAggregationRole.substring(1) ].join("");
				var oPropertyMetadata = oSelf.oEntityMetadata.getPropertyMetadata(sSelectedProperty);
				var sDefaultLabel = oPropertyMetadata.label ? oPropertyMetadata.label : oPropertyMetadata.name;
				var sLabelValue = oPropertyRow.sLabel;
				var sLabelId;
				if (sLabelValue && sLabelValue !== sDefaultLabel) { //if the label exists and it is not same as default label
					var oTranslationFormat = sap.apf.modeler.ui.utils.TranslationFormatMap.REPRESENTATION_LABEL;
					sLabelId = oSelf.oTextPool.setText(sLabelValue, oTranslationFormat);
				}
				var sAddMethodName = [ "add", sAggregationRoleCamelCase ].join("");
				var sSetKindMethondName = [ "set", sAggregationRoleCamelCase, "Kind" ].join("");
				var sSetTextLabelKeyMethodName = [ "set", sAggregationRoleCamelCase, "TextLabelKey" ].join("");
				oSelf.oRepresentation[sAddMethodName](sSelectedProperty);
				oSelf.oRepresentation[sSetKindMethondName](sSelectedProperty, oPropertyRow.sKind);
				oSelf.oRepresentation[sSetTextLabelKeyMethodName](sSelectedProperty, sLabelId);
				if (sAggregationRole === "dimension") {
					var sLabelDisplayOption = oPropertyRow.sLabelDisplayOptionProperty;
					if (!sLabelDisplayOption) {
						oSelf._setDefaultLabelDisplayOption(sSelectedProperty);
						oPropertyRow.sLabelDisplayOptionProperty = oSelf.oRepresentation.getLabelDisplayOption(sSelectedProperty);
					} else {
						oSelf.oRepresentation.setLabelDisplayOption(sSelectedProperty, sLabelDisplayOption);
					}
				}
				oPropertyRow.sSelectedProperty = sSelectedProperty;
			} else {
				oPropertyRow.sLabel = "";//clear the label for "None" from the model, from the property row
				oPropertyRow.sSelectedProperty = oSelf.getText("none");//set the selected property to "none" in the model, from the property row
				oPropertyRow.sLabelDisplayOptionProperty = undefined;
			}
		});
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_setSortFieldsFromCurrentDataset
	* @description This function is called on every change event related to sort layout to adhere to WYSIWYG principle.
	* Sets new values on the representation object based on the current property model.
	* Clears the old values from representation object.
	* Sets new values by iterating through the current sort data set.
	* */
	_setSortFieldsFromCurrentDataset : function() {
		var oSelf = this;
		// Clears current orderBy properties
		this.oRepresentation.getOrderbySpecifications().forEach(function(oOrderBySpec) {
			oSelf.oRepresentation.removeOrderbySpec(oOrderBySpec.property);
		});
		// Loop through current sort model and set orderby properties accordingly.
		this.mDataset.oSortDataset.aSortRows.forEach(function(oSortRow) {
			var sSortProperty = oSortRow.sSortProperty || (oSortRow.aAllProperties.length && oSortRow.aAllProperties[0].sName);
			if (sSortProperty && sSortProperty !== oSelf.getText("none")) {
				var bAscending = !oSortRow.sDirection || (oSortRow.sDirection === oSelf.getText("ascending"));
				oSelf.oRepresentation.addOrderbySpec(sSortProperty, bAscending);
			}
		});
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.representation#_getRepresentationMetadata
	* @description Returns the representation metadata by using the getRepresentationTypes API
	* */
	_getRepresentationMetadata : function() {
		var oRepMetadata = {};
		this.getRepresentationTypes().forEach(function(representationType) {
			if (representationType.metadata) {
				oRepMetadata[representationType.id] = representationType.metadata;
			}
		});
		return oRepMetadata;
	}
});<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
/**
 * @class stepContainer
 * @name stepContainer
 * @memberOf sap.apf.ui.reuse.view
 * @description Holds the step in main area. Includes the step toolbar view and step representation view
 * @returns {stepContainerLayout}
 */
sap.ui.jsview("sap.apf.ui.reuse.view.stepContainer", {
	/**
	 * @this {sap.apf.ui.reuse.view.stepContainer}
	 *
	 */
	/**
	 * @memberOf sap.apf.ui.reuse.view.stepContainer
	 * @method getStepToolbar
	 * @see sap.apf.ui.reuse.view.stepToolbar
	 * @description Getter for step toolbar container 
	 * @returns stepToolbar view 
	 */
	getStepToolbar : function() {
		return this.oStepToolbar;
	},
	getControllerName : function() {
		return "sap.apf.ui.reuse.controller.stepContainer";
	},

	createContent : function(oController) {
		var oViewData = this.getViewData();
		this.oStepToolbar = sap.ui.view({viewName:"sap.apf.ui.reuse.view.stepToolbar", type:sap.ui.core.mvc.ViewType.JS,viewData :oViewData});
		this.stepLayout = new sap.ui.layout.VerticalLayout({
			content : [ this.oStepToolbar],
			width : "100%"
		});
		this.vLayout = new sap.ui.layout.VerticalLayout({
			content : this.stepLayout,
			width : "100%"
		});
		this.vLayout.setBusy(true);
		return this.vLayout; //holds chart and toolbar
	}

});<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

sap.ui.define([
	'jquery.sap.global', 'sap/ui/fl/changeHandler/Base', 'sap/ui/fl/Utils'
], function(jQuery, Base, FlexUtils) {
	"use strict";

	/**
	 * Change handler for moving of groups inside a smart form.
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.MoveGroups
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 */
	var MoveGroups = function() {
	};
	MoveGroups.prototype = jQuery.sap.newObject(Base.prototype);

	/**
	 * Moves group(s) inside a smart form.
	 *
	 * @param {object} oChange change object with instructions to be applied on the control
	 * @param {object} oSmartForm Smart form instance which is referred to in change selector section 
	 * @public
	 */
	MoveGroups.prototype.applyChange = function(oChange, oSmartForm) {

		if (!oChange) {
			throw new Error("No change instance");
		}

		var oChangeJson = oChange.getDefinition();

		if (!oChangeJson.selector || !oChangeJson.content || !oChangeJson.content.moveGroups || oChangeJson.content.moveGroups.length === 0 || Object.keys(oChangeJson.selector).length !== 1) {
			throw new Error("Change format invalid");
		}

		if (!oSmartForm || !oSmartForm.getGroups) {
			throw new Error("No smart form instance supplied");
		}

		// Array of groups of smart form in old order
		var aGroups = [];
		aGroups = oSmartForm.getGroups();
		if (aGroups.length === 0) {
			return;
		}
		var iGroupNumber = aGroups.length;

		// adapt order of groups in aGroups according to the change
		var oGroup = {}, oMoveGroup = {};
		var iMoveGroups = oChangeJson.content.moveGroups.length;
		var iIndex;
		var i, j;

		for (i = 0; i < iMoveGroups; i++) {

			oMoveGroup = oChangeJson.content.moveGroups[i];

			if (!oMoveGroup.id) {
				throw new Error("Change format invalid - moveGroups element has no id attribute");
			}
			if (typeof (oMoveGroup.index) !== "number") {
				throw new Error("Change format invalid - moveGroups element index attribute is no number");
			}

			// determine the index of the group to move in aGroups 
			iIndex = -1;
			for (j = 0; j < iGroupNumber; j++) {
				if (aGroups[j].getId() === oMoveGroup.id) {
					iIndex = j;
					break;
				}
			}

			if (iIndex === oMoveGroup.index || iIndex === -1) {
				continue;
			}

			// memorize the group to move
			oGroup = aGroups[iIndex];

			// remove the group to move from aGroups
			aGroups.splice(iIndex, 1);

			// reinsert the group to aGroups at the new index
			aGroups.splice(oMoveGroup.index, 0, oGroup);

		}

		// remove all groups from smart form
		oSmartForm.removeAllGroups();

		// reinsert groups into smart form in new order
		for (i = 0; i < iGroupNumber; i++) {
			oSmartForm.insertGroup(aGroups[i], i);
		}

	};

	/**
	 * Completes the change by adding change handler specific content
	 *
	 * @param {object} oChange change object to be completed
	 * @param {object} oSpecificChangeInfo with attribute moveGroups which contains an array which holds objects which have attributes
	 * 				   id and index - id is the id of the group to move and index the new position of the group in the smart form 
	 * @public
	 */
	MoveGroups.prototype.completeChangeContent = function(oChange, oSpecificChangeInfo) {

		var oChangeJson = oChange.getDefinition();

		if (oSpecificChangeInfo.moveGroups) {

			var oMoveGroup = {};
			var i, iLength = oSpecificChangeInfo.moveGroups.length;

			if (iLength === 0) {
				throw new Error("MoveGroups array is empty");
			}

			for (i = 0; i < iLength; i++) {
				oMoveGroup = oSpecificChangeInfo.moveGroups[i];
				if (!oMoveGroup.id) {
					throw new Error("MoveGroups element has no id attribute");
				}
				if (typeof (oMoveGroup.index) !== "number") {
					throw new Error("Index attribute at MoveGroups element is no number");
				}
			}

			if (!oChangeJson.content) {
				oChangeJson.content = {};
			}

			if (!oChangeJson.content.moveGroups) {
				oChangeJson.content.moveGroups = [];
			}

			oChangeJson.content.moveGroups = oSpecificChangeInfo.moveGroups;

		} else {

			throw new Error("oSpecificChangeInfo.moveGroups attribute required");

		}

	};

	return MoveGroups;
},
/* bExport= */true);
<file_sep>/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

// Provides control sap.ui.comp.navpopover.SmartLink.
sap.ui.define([
	'jquery.sap.global', 'sap/m/Link', 'sap/m/LinkRenderer', 'sap/ui/comp/navpopover/LinkData'
], function(jQuery, Link, LinkRenderer, LinkData) {
	"use strict";

	/**
	 * Constructor for a new navpopover/SmartLink.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new control
	 * @class The SmartLink control uses a semantic object to display {@link sap.ui.comp.navpopover.NavigationPopover NavigationPopover} for further
	 *        navigation steps.
	 * @extends sap.m.Link
	 * @constructor
	 * @public
	 * @alias sap.ui.comp.navpopover.SmartLink
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var SmartLink = Link.extend("sap.ui.comp.navpopover.SmartLink", /** @lends sap.ui.comp.navpopover.SmartLink.prototype */
	{
		metadata: {

			library: "sap.ui.comp",
			properties: {

				/**
				 * Name of semantic object which is used to fill the navigation popover.
				 *
				 * @since 1.28.0
				 */
				semanticObject: {
					type: "string",
					defaultValue: null
				},

				/**
				 * The semantic object controller controls events for several SmartLink controls. If the controller is not set manually, it tries to
				 * find a SemanticObjectController in its parent hierarchy.
				 *
				 * @since 1.28.0
				 */
				semanticObjectController: {
					type: "any",
					defaultValue: null
				},

				/**
				 * The metadata field name for this SmartLink control.
				 *
				 * @since 1.28.0
				 */
				fieldName: {
					type: "string",
					defaultValue: null
				},

				/**
				 * Shown label of semantic object.
				 *
				 * @since 1.28.0
				 */
				semanticObjectLabel: {
					type: "string",
					defaultValue: null
				},

				/**
				 * Function that enables the SmartLink control to create an alternative control, which is displayed if no navigation targets are
				 * available. The function has no parameters and has to return an instance of sap.ui.core.Control.
				 *
				 * @since 1.28.0
				 */
				createControlCallback: {
					type: "object",
					defaultValue: null
				},

				/**
				 * If set to <code>false</code>, the SmartLink control will not replace its field name with the according
				 * <code>semanticObject</code> property during the calculation of the semantic attributes. This enables the usage of several
				 * SmartLinks on the same semantic object.
				 */
				mapFieldToSemanticObject: {
					type: "boolean",
					defaultValue: true
				},

				/**
				 * If set to <code>true</code>, the SmartLink control will render the <code>innerControl</code> or the control provided by
				 * <code>createControlCallback</code> instead of the actual link. This is used for example by the SemanticObjectController if this
				 * SmartLink is listed in its <code>ignoredFields</code> or no navigation targets were found during prefetch.
				 *
				 * @since 1.28.0
				 */
				ignoreLinkRendering: {
					type: "boolean",
					defaultValue: false
				}
			},
			aggregations: {

				/**
				 * Control that is displayed instead of SmartLink, if the SmartLink is disabled (for example, if no navigation targets are available).
				 * If <code>innerControl</code> is not provided, the SmartLink control tries to create one with property
				 * <code>createControlCallback</code>.
				 *
				 * @since 1.28.0
				 */
				innerControl: {
					type: "sap.ui.core.Control",
					multiple: false
				}
			},
			events: {

				/**
				 * Event is fired before the navigation popover opens and before navigation target links are getting retrieved. Event can be used to
				 * change the parameters used to retrieve the navigation targets. In case of SmartLink, the <code>beforePopoverOpens</code> is fired
				 * after the link has been clicked.
				 *
				 * @since 1.28.0
				 */
				beforePopoverOpens: {
					parameters: {
						/**
						 * The semantic object for which the navigation targets will be retrieved.
						 */
						semanticObject: {
							type: "string"
						},

						/**
						 * Map containing the semantic attributes calculated from the binding that will be used to retrieve the navigation targets.
						 * targets.
						 */
						semanticAttributes: {
							type: "object"
						},

						/**
						 * This callback function enables you to define a changed semantic attributes map. Signatures:
						 * <code>setSemanticAttributes(oSemanticAttributesMap)</code> Parameter:
						 * <ul>
						 * <li>{object} oSemanticAttributesMap New map containing the semantic attributes to be used.</li>
						 * </ul>
						 */
						setSemanticAttributes: {
							type: "function"
						},

						/**
						 * This callback function sets an application state key that is used over the cross-application navigation. Signatures:
						 * <code>setAppStateKey(sAppStateKey)</code> Parameter:
						 * <ul>
						 * <li>{string} sAppStateKey</li>
						 * </ul>
						 */
						setAppStateKey: {
							type: "function"
						},

						/**
						 * The ID of the SmartLink.
						 */
						originalId: {
							type: "string"
						},

						/**
						 * This callback function triggers the retrieval of navigation targets and leads to the opening of the navigation popover.
						 * Signatures: <code>open()</code> If the <code>beforePopoverOpens</code> has been registered, the <code>open</code>
						 * function has to be called manually in order to open the navigation popover.
						 */
						open: {
							type: "function"
						}
					}
				},

				/**
				 * After the navigation targets are retrieved, <code>navigationTargetsObtained</code> is fired and provides the possibility to
				 * change the targets.
				 *
				 * @since 1.28.0
				 */
				navigationTargetsObtained: {
					parameters: {
						/**
						 * The main navigation object.
						 */
						mainNavigation: {
							type: "sap.ui.comp.navpopover.LinkData"
						},

						/**
						 * Array of available navigation target objects.
						 */
						actions: {
							type: "sap.ui.comp.navpopover.LinkData[]"
						},

						/**
						 * The navigation object for the own application. This navigation option is by default not visible on the popover.
						 */
						ownNavigation: {
							type: "sap.ui.comp.navpopover.LinkData"
						},

						/**
						 * The semantic object for which the navigation targets have been retrieved.
						 */
						semanticObject: {
							type: "string"
						},

						/**
						 * The ID of the SmartLink.
						 */
						originalId: {
							type: "string"
						},

						/**
						 * This callback function shows the actual navigation popover. If the <code>navigationTargetsObtained</code> has been
						 * registered, the <code>show</code> function has to be called manually in order to open the navigation popover. Signatures:
						 * <code>show()</code>
						 *  <code>show(oMainNavigation, aAvailableActions, oExtraContent)</code>
						 *  <code>show(sMainNavigationId, oMainNavigation, aAvailableActions, oExtraContent)</code>
						 * Parameters:
						 * <ul>
						 * <li>{string} sMainNavigationId The visible text for the main navigation section. If empty, the main navigation ID is
						 * calculated using binding context of given source object (for example SmartLink).</li>
						 * <li>{sap.ui.comp.navpopover.LinkData} oMainNavigation The main navigation object. If empty, property
						 * <code>mainNavigation</code> will be used.</li>
						 * <li>{sap.ui.comp.navpopover.LinkData[]} aAvailableActions Array containing the cross application navigation links. If
						 * empty, property <code>actions</code> will be used.</li>
						 * <li>{sap.ui.core.Control} oExtraContent Control that will be displayed in extra content section on the popover.</li>
						 * </ul>
						 */
						show: {
							type: "function"
						}
					}
				},

				/**
				 * This event is fired after a navigation link on the navigation popover has been clicked. This event is only fired, if the user
				 * left-clicks the link. Right-clicking the link and selecting 'Open in New Window' etc. in the context menu does not fire the event.
				 *
				 * @since 1.28.0
				 */
				innerNavigate: {
					parameters: {
						/**
						 * The UI text shown in the clicked link.
						 */
						text: {
							type: "string"
						},

						/**
						 * The navigation target of the clicked link.
						 */
						href: {
							type: "string"
						},

						/**
						 * The semantic object used to retrieve this target.
						 */
						semanticObject: {
							type: "string"
						},

						/**
						 * Map containing the semantic attributes used to retrieve this target.
						 */
						semanticAttributes: {
							type: "object"
						},

						/**
						 * The ID of the SmartLink.
						 */
						originalId: {
							type: "string"
						}
					}
				}
			}
		},
		renderer: function(oRm, oControl) {
			var bRenderLink = true;

			if (oControl.getIgnoreLinkRendering()) {
				var oReplaceControl = oControl._getInnerControl();
				if (oReplaceControl) {
					oRm.write("<div ");
					oRm.writeControlData(oControl);
					oRm.writeClasses();
					oRm.write(">");

					oRm.renderControl(oReplaceControl);

					oRm.write("</div>");

					bRenderLink = false;
				}
			}

			if (bRenderLink) {
				LinkRenderer.render.call(LinkRenderer, oRm, oControl);
			}
		}
	});

	SmartLink.prototype.init = function() {
		// sap.m.Link.prototype.init.call(this);
		this.attachPress(this._linkPressed);
		this.addStyleClass("sapUiCompSmartLink");
		this._oSemanticAttributes = null;
	};

	/**
	 * Eventhandler for link's press event
	 *
	 * @param {object} oEvent the event parameters.
	 * @private
	 */
	SmartLink.prototype._linkPressed = function(oEvent) {
		if (this._processingLinkPressed) {
			window.console.warn("SmartLink is still processing last press event. This press event is omitted.");
			return; // avoid multiple link press events while data is still fetched
		}

		if (this.getIgnoreLinkRendering()) {
			window.console.warn("SmartLink should ignore link rendering. Press event is omitted.");
			return; // actual link is not rendered -> ignore press event
		}

		this._processingLinkPressed = true;

		var sAppStateKey;
		this._oSemanticAttributes = this._calculateSemanticAttributes();

		var that = this;
		var fOpen = function() {
			that._createPopover();

			if (that._oSemanticAttributes) {
				that._oPopover.setSemanticAttributes(that._oSemanticAttributes);
			}

			if (sAppStateKey) {
				that._oPopover.setAppStateKey(sAppStateKey);
			}

			that._oPopover.retrieveNavTargets();
		};

		if (this.hasListeners("beforePopoverOpens")) {
			this.fireBeforePopoverOpens({
				semanticObject: this.getSemanticObject(),
				semanticAttributes: that._oSemanticAttributes,
				setSemanticAttributes: function(oMap) {
					that._oSemanticAttributes = oMap;
				},
				setAppStateKey: function(sKey) {
					sAppStateKey = sKey;
				},
				originalId: this.getId(),
				open: fOpen
			});
		} else {
			fOpen();
		}
	};

	/**
	 * Eventhandler for NavigationPopover's targetObtained event, exposes event or - if not registered - directly opens the dialog
	 *
	 * @private
	 */
	SmartLink.prototype._onTargetsObtainedOpenDialog = function() {
		var that = this;

		if (!this._oPopover.getMainNavigation()) { // main navigation could not be resolved, so only set link text as MainNavigation
			this._oPopover.setMainNavigation(new LinkData({
				text: this.getText()
			}));
		}

		this.fireNavigationTargetsObtained({
			actions: this._oPopover.getAvailableActions(),
			mainNavigation: this._oPopover.getMainNavigation(),
			ownNavigation: this._oPopover.getOwnNavigation(),
			semanticObject: this.getSemanticObject(),
			semanticAttributes: this.getSemanticAttributes(),
			originalId: this.getId(),
			show: function(sMainNavigationId, oMainNavigation, aAvailableActions, oExtraContent) {
				if (sMainNavigationId != null && typeof sMainNavigationId === "string") {
					that._oPopover.setMainNavigationId(sMainNavigationId);
				} else {
					oExtraContent = aAvailableActions;
					aAvailableActions = oMainNavigation;
					oMainNavigation = sMainNavigationId;
				}

				if (oMainNavigation) {
					that._oPopover.setMainNavigation(oMainNavigation);
				}

				if (aAvailableActions) {
					that._oPopover.removeAllAvailableActions();
					if (aAvailableActions && aAvailableActions.length) {
						var i, length = aAvailableActions.length;
						for (i = 0; i < length; i++) {
							that._oPopover.addAvailableAction(aAvailableActions[i]);
						}
					}
				}

				if (oExtraContent) {
					that._oPopover.setExtraContent(oExtraContent);
				}

				that._oPopover.show();
				that._processingLinkPressed = false;
			}
		});

		if (!this.hasListeners("navigationTargetsObtained")) {
			this._oPopover.show();
			this._processingLinkPressed = false;
		}
	};

	/**
	 * Eventhandler for NavigationPopover's navigate event, exposes event
	 *
	 * @param {object} oEvent - the event parameters
	 * @private
	 */
	SmartLink.prototype._onInnerNavigate = function(oEvent) {
		var aParameters = oEvent.getParameters();
		this.fireInnerNavigate({
			text: aParameters.text,
			href: aParameters.href,
			originalId: this.getId(),
			semanticObject: this.getSemanticObject(),
			semanticAttributes: this.getSemanticAttributes()
		});
	};

	/**
	 * Creates the NavigationPopover.
	 *
	 * @private
	 */
	SmartLink.prototype._createPopover = function() {
		if (!this._oPopover) {
			var oComponent = this._getComponent();
			jQuery.sap.require("sap.ui.comp.navpopover.NavigationPopover");
			var NavigationPopover = sap.ui.require("sap/ui/comp/navpopover/NavigationPopover");
			this._oPopover = new NavigationPopover({
				title: this.getSemanticObjectLabel(),
				semanticObjectName: this.getSemanticObject(),
				targetsObtained: jQuery.proxy(this._onTargetsObtainedOpenDialog, this),
				navigate: jQuery.proxy(this._onInnerNavigate, this),
				component: oComponent
			});

			this._oPopover.setSource(this);
		}
	};

	/**
	 * Finds the parental component.
	 *
	 * @private
	 * @returns {sap.ui.core.Component} the found parental component or null
	 */
	SmartLink.prototype._getComponent = function() {
		var oParent = this.getParent();
		while (oParent) {

			if (oParent instanceof sap.ui.core.Component) {
				return oParent;
			}
			oParent = oParent.getParent();
		}

		return null;
	};

	/**
	 * Gets the current binding context and creates a copied map where all empty and unnecessary data is deleted from.
	 *
	 * @private
	 */
	SmartLink.prototype._calculateSemanticAttributes = function() {
		var oContext = this.getBindingContext();
		if (!oContext) {
			return null;
		}

		var oBinding = this.getBinding("text");
		var sCurrentField = oBinding.getPath();

		var oResult = {};
		var oContext = oContext.getObject(oContext.getPath());
		for ( var sAttributeName in oContext) {
			// Ignore metadata
			if (sAttributeName === "__metadata") {
				continue;
			}
			// Ignore empty values
			if (!oContext[sAttributeName]) {
				continue;
			}

			// Map attribute name by semantic object name
			var sSemanticObjectName = this._mapFieldToSemanticObject(sAttributeName);
			if (sAttributeName === sCurrentField && this.getSemanticObject()) {
				sSemanticObjectName = this.getSemanticObject();
			}

			// Map all available attribute fields to their semanticObjects excluding SmartLink's own SemanticObject
			if (sSemanticObjectName === this.getSemanticObject() && !this.getMapFieldToSemanticObject()) {
				sSemanticObjectName = sAttributeName;
			}

			// If more then one attribute fields maps to the same semantic object we take the value of the current binding path.
			var oAttributeValue = oContext[sAttributeName];
			if (oResult[sSemanticObjectName]) {
				if (oContext[sCurrentField]) {
					oAttributeValue = oContext[sCurrentField];
				}
			}

			// Copy the value replacing the attribute name by semantic object name
			oResult[sSemanticObjectName] = oAttributeValue;
		}

		return oResult;
	};

	/**
	 * Gets the semantic object calculated at the last Link press event
	 *
	 * @returns {object} Map containing the copy of the available binding context.
	 * @public
	 */
	SmartLink.prototype.getSemanticAttributes = function() {
		if (this._oSemanticAttributes === null) {
			this._oSemanticAttributes = this._calculateSemanticAttributes();
		}
		return this._oSemanticAttributes;
	};

	/**
	 * Maps the given field name to the corresponding semantic object.
	 *
	 * @param {string} sFieldName The field name which should be mapped to a semantic object
	 * @returns {string} Corresponding semantic object, or the original field name if semantic object is not available.
	 * @private
	 */
	SmartLink.prototype._mapFieldToSemanticObject = function(sFieldName) {
		var oSOController = this.getSemanticObjectController();
		if (!oSOController) {
			return sFieldName;
		}
		var oMap = oSOController.getFieldSemanticObjectMap();
		if (!oMap) {
			return sFieldName;
		}
		return oMap[sFieldName] || sFieldName;
	};

	SmartLink.prototype.setFieldName = function(sFieldName) {
		this.setProperty("fieldName", sFieldName);

		var oSemanticController = this.getSemanticObjectController();
		if (oSemanticController) {
			oSemanticController.setIgnoredState(this);
		}
	};

	// BCP 1670108744: when semanticObjectController is set first then semanticObject is still not known in the step where ignoredState is determined
	SmartLink.prototype.setSemanticObject = function(sSemanticObject) {
		this.setProperty("semanticObject", sSemanticObject, true);

		var oSemanticObjectController = this.getSemanticObjectController();
		if (oSemanticObjectController) {
			oSemanticObjectController.setIgnoredState(this);
		}
	};

	SmartLink.prototype.setSemanticObjectController = function(oController) {
		var oOldController = this.getProperty("semanticObjectController");
		if (oOldController) {
			oOldController.unregisterControl(this);
		}

		this.setProperty("semanticObjectController", oController, true);
		if (oController) {
			oController.registerControl(this);
		}
		this._oSemanticAttributes = null;
	};

	SmartLink.prototype.getSemanticObjectController = function() {
		var oController = this.getProperty("semanticObjectController");

		if (!oController) {

			var oParent = this.getParent();
			while (oParent) {
				if (oParent.getSemanticObjectController) {
					oController = oParent.getSemanticObjectController();
					if (oController) {
						this.setSemanticObjectController(oController);
						break;
					}
				}

				oParent = oParent.getParent();
			}
		}

		return oController;
	};

	/**
	 * Gets the current value assigned to the field with the SmartLink's semantic object name.
	 *
	 * @returns {object} The semantic object's value.
	 * @public
	 */
	SmartLink.prototype.getSemanticObjectValue = function() {
		var oSemanticAttributes = this.getSemanticAttributes();
		if (oSemanticAttributes) {
			var sSemanticObjectName = this.getSemanticObject();
			return oSemanticAttributes[sSemanticObjectName];
		}

		return null;
	};

	SmartLink.prototype.setText = function(sText) {
		if (this._isRenderingInnerControl()) {
			// SmartLink renders inner control => overwrite base setText as it changes the DOM directly
			this.setProperty("text", sText, true);
		} else {
			Link.prototype.setText.call(this, sText);
		}
	};

	SmartLink.prototype._isRenderingInnerControl = function() {
		return this.getIgnoreLinkRendering() && this._getInnerControl() != null;
	};

	/**
	 * Gets the inner control which is provided by the CreateControlCallback
	 *
	 * @returns {sap.ui.core.Control} The control.
	 * @private
	 */
	SmartLink.prototype._getInnerControl = function() {
		var oInnerControl = this.getAggregation("innerControl");
		if (!oInnerControl) {
			var fCreate = this.getCreateControlCallback();
			if (fCreate) {
				oInnerControl = fCreate();
				this.setAggregation("innerControl", oInnerControl, true);
			}
		}

		return oInnerControl;
	};

	/**
	 * Gets the inner control's value, if no inner control is available, the SmartLink's text will be returned
	 *
	 * @returns {object} the value
	 * @public
	 */
	SmartLink.prototype.getInnerControlValue = function() {
		if (this._isRenderingInnerControl()) {
			var oInnerControl = this._getInnerControl();

			if (oInnerControl) {
				if (oInnerControl.getText) {
					return oInnerControl.getText();
				}

				if (oInnerControl.getValue) {
					return oInnerControl.getValue();
				}
			}
		}

		return this.getText();
	};

	/**
	 * Called before rendering
	 */
	SmartLink.prototype.onBeforeRendering = function() {
		// ensure that the semantic object controller exists, do this first as retrieving the SemanticObjectController can lead to setting the
		// ignoreLinkRendering flag
		this.getSemanticObjectController();

		// if link should not be rendered, but no inner control is available, deactivate SmartLink
		if (this.getIgnoreLinkRendering() && this._getInnerControl() == null) {
			this.setEnabled(false);
		} else {
			this.setEnabled(true);
		}
	};

	SmartLink.prototype.exit = function() {
		this.setSemanticObjectController(null); // disconnect from SemanticObjectController
	};

	return SmartLink;

}, /* bExport= */true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

sap.ui.define([
	'jquery.sap.global', 'sap/ui/fl/changeHandler/Base', 'sap/ui/fl/Utils'
], function(jQuery, Base, FlexUtils) {
	"use strict";

	/**
	 * Change handler for reordering of groups.
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.OrderGroups
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 */
	var OrderGroups = function() {
	};
	OrderGroups.prototype = jQuery.sap.newObject(Base.prototype);

	/**
	 * Reorders groups.
	 *
	 * @param {object} oChange change object with instructions to be applied on the control
	 * @param {object} oControl control instance which is referred to in change selector section 
	 * @public
	 */
	OrderGroups.prototype.applyChange = function(oChange, oControl) {

		if (!oChange) {
			throw new Error("No change instance");
		}

		var oChangeJson = oChange.getDefinition();

		if (!oChangeJson.selector || !oChangeJson.content || !oChangeJson.content.orderGroups || oChangeJson.content.orderGroups.length === 0 || Object.keys(oChangeJson.selector).length !== 1) {
			throw new Error("Change format invalid");
		}

		if (!oControl || !oControl.getGroups) {
			throw new Error("No control instance or wrong control instance supplied");
		}

		// Array of groups of smart form in old order
		var aGroup = oControl.getGroups();
		var iGroupNumber = aGroup.length;

		// Array of ids of groups in new order as defined in the change
		var aKeyOrderFromChange = oChangeJson.content.orderGroups;

		var iKeyNumberInChange = aKeyOrderFromChange.length;

		// build object of groups of smart form which has their ids as key
		var oGroups = {}, oGroup = {};
		var sKey;
		var i;
		for (i = 0; i < iGroupNumber; i++) {
			oGroup = aGroup[i];
			if (!oGroup.getId()) {
				return;
			}
			sKey = oGroup.getId();
			oGroups[sKey] = oGroup;
		}

		// remove all groups from smart form
		if (iGroupNumber > 0) {
			oControl.removeAllGroups();
		}

		// reinsert groups into smart form in order given by change
		for (i = 0; i < iGroupNumber; i++) {
			sKey = aKeyOrderFromChange[i];
			if (oGroups[sKey]) {
				oControl.insertGroup(oGroups[sKey], i);
				oGroups[sKey] = null;
			}
		}

		// add groups not handled by change at the end
		i = iKeyNumberInChange;
		jQuery.each(oGroups, function(key, group) {
			if (group !== null) {
				i += 1;
				oControl.insertGroup(group, i);
			}
		});

	};

	/**
	 * Completes the change by adding change handler specific content
	 *
	 * @param {object} oChange change object to be completed
	 * @param {object} oSpecificChangeInfo with attribute orderGroups which contains an array which holds the ids of 
	 * 				   the groups of the smart form in the desired order 
	 * @public
	 */
	OrderGroups.prototype.completeChangeContent = function(oChange, oSpecificChangeInfo) {

		var oChangeJson = oChange.getDefinition();

		if (oSpecificChangeInfo.orderGroups) {
			if (!oChangeJson.content) {
				oChangeJson.content = {};
			}
			if (!oChangeJson.content.orderGroups) {
				oChangeJson.content.orderGroups = {};
			}
			oChangeJson.content.orderGroups = oSpecificChangeInfo.orderGroups;
		} else {
			throw new Error("oSpecificChangeInfo.orderGroups attribute required");
		}

	};

	return OrderGroups;
},
/* bExport= */true);
<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */

jQuery.sap.declare("sap.apf.core.utils.uriGenerator");
jQuery.sap.require("sap.apf.core.messageObject");

(function(){
	'use strict';
/**
 * @descriptions Module for uri generation and location helper functions for the resource location
 */
sap.apf.core.utils.uriGenerator = {};

/**
 * @memberOf sap.apf.core.utils.uriGenerator
 * @description Returns the absolute URL path of the service root. The slash as last character is fixed, if not existing.
 * @param {String} sPathToRoot Absolute Path to the service root like /sap/hba/apps/wca/s/odata/wca.xsodata/ .
 * @returns {String}
 */
sap.apf.core.utils.uriGenerator.getAbsolutePath = function(sPathToRoot) {
	if (sPathToRoot.slice(-1) === '/') {
		return sPathToRoot;
	}
	return sPathToRoot + "/";
};

/**
 * @memberOf sap.apf.core.utils.uriGenerator
 * @param {string} sPathToServiceDocument 
 * @description Returns the relative url path of the oadata service.
 * @returns {String}
 */
sap.apf.core.utils.uriGenerator.getODataPath = function(sPathToServiceDocument) {
	var aSplitt = sPathToServiceDocument.split('/');
	var i;
	var aSplittContent = [];
	for(i = 0; i < aSplitt.length; i++) {
		if (aSplitt[i] !== "") {
			aSplittContent.push(aSplitt[i]);
		}
	}
	var sReturn = '';
	var len = aSplittContent.length - 1;
	for(i = 0; i < len; i++) {
		sReturn = sReturn + '/' + aSplittContent[i];
	}
	return sReturn + '/';
};
/**
 * @memberOf sap.apf.core.utils.uriGenerator
 * @description adds a relative url to an absolute url 
 * @param {string} absoluteURL
 * @param {string} relativeURL
 * @returns {string} composedURL
 */
sap.apf.core.utils.uriGenerator.addRelativeToAbsoluteURL = function(absoluteURL, relativeURL) {
	
	var absoluteUrlParts = absoluteURL.split('/');
	var relativeUrlParts = relativeURL.split('/');
	
	relativeUrlParts.forEach(function(part){
		if (part === '..') {
			absoluteUrlParts.pop();
		} else if (part != '.') {
			absoluteUrlParts.push(part);
		}
	});
	
	return absoluteUrlParts.join('/');
};

/**
 * @description returns the url for a given component up to this component (not including).
 * @param (string} componentName
 * @returns {string} absoluteUrlUpToComponent
 */
sap.apf.core.utils.uriGenerator.getBaseURLOfComponent = function(componentName) {
	var baseComponentNameParts = componentName.split('.');
	baseComponentNameParts.pop();
	var base = baseComponentNameParts.join('.');
	return jQuery.sap.getModulePath(base);
};



/**
 * @memberOf sap.apf.core.utils.uriGenerator
 * @description gets the location of the apf libary. sap.apf.core.utils.uriGenerator is required for loading texts, images and so on.
 * @returns {String}
 */
sap.apf.core.utils.uriGenerator.getApfLocation = function() {
	return jQuery.sap.getModulePath("sap.apf") + '/';
};
/**
 * @memberOf sap.apf.core.utils.uriGenerator
 * @description builds a URI based on parameters
 * @param {sap.apf.core.MessageHandler} oMsgHandler
 * @param {string} sEntityType
 * @param [aSelectProperties]
 * @param {object} oFilter
 * @param {object} oParameter - HANA XSE parameter entity set parameters
 * @param {object} [sortingFields]
 * @param {object} oPaging - values of properties 'top','skip' and 'inlineCount' are evaluated and added to '$top','$skip' and '$inlinecount' URI string parameters if available 
 * @param {string} sFormat of HTTP response,e.g. 'json' or 'xml'. If omitted 'json' is taken as default.
 * @param {function} [fnFormatValue] callback method to format the values 
 * @param {sNavigationProperty} Suffix after the parameter - old default is "Results"
 * @returns {string} complete URI
 */
sap.apf.core.utils.uriGenerator.buildUri = function(oMsgHandler, sEntityType, aSelectProperties, oFilter, oParameter, sortingFields, oPaging, sFormat, fnFormatValue, sNavigationProperty) {
	var sReturn = "";
	sReturn += sEntityType;
	sReturn += addParamsToUri(oParameter,sNavigationProperty);
	sReturn = sReturn + "?";
	sReturn += addSelectPropertiesToUri(aSelectProperties);
	sReturn += addFilterToUri(oFilter, fnFormatValue);
	sReturn += addSorting(sortingFields, aSelectProperties);
	sReturn += addPaging(oPaging);
	sReturn += addFormatToUri(sFormat);
	return sReturn;
	function addParamsToUri(oParameter,sNavigationProperty) {
		var sReturn = '';
		var bParametersExist = false;
		var sParameter;
		for(sParameter in oParameter) {
			if (!bParametersExist) {
				sReturn += '(';
				bParametersExist = true;
			} else {
				sReturn += ',';
			}
			sReturn += sParameter.toString() + '=' + oParameter[sParameter];
		}
		if (bParametersExist) {
			sReturn += ')/';
		}
		sReturn += sNavigationProperty || '';	
		return sReturn;
	}
	function addSelectPropertiesToUri(aSelectProperties) {
		if (!aSelectProperties[0]) {
			return '';
		}
		var field;
		var sResult = "$select=";
		for( field in aSelectProperties) {
			sResult += jQuery.sap.encodeURL(sap.apf.utils.escapeOdata(aSelectProperties[field]));
			if (field < aSelectProperties.length - 1) {
				sResult += ",";
			}
		}
		return sResult;
	}
	function addFilterToUri(oFilter, fnFormatValue) {
		if (!(oFilter && oFilter instanceof sap.apf.core.utils.Filter)) {
			return '';
		}
		var sFilterValues = oFilter.toUrlParam( { formatValue : fnFormatValue });
		if (sFilterValues === "" || sFilterValues === '()' ) {
			return '';
		}	
		return '&$filter=' + sFilterValues;	
	}
	function addSorting(sortingFields, aSelectProperties) {
		var sOrderByValues = '';
		var sSingleValue = '';
		var i;
		if (!sortingFields) {
			return '';
		}
		switch (true) {
			case jQuery.isArray(sortingFields):
				for( i = 0; i < sortingFields.length; i++) {
					sSingleValue = makeOrderByValue(sortingFields[i], aSelectProperties);
					if (sOrderByValues.length > 0 && sSingleValue.length > 0) {
						sOrderByValues += ',';
					}
					sOrderByValues += sSingleValue;
				}
				break;
			case jQuery.isPlainObject(sortingFields):
				sOrderByValues += makeOrderByValue(sortingFields, aSelectProperties);
				break;
			case typeof sortingFields === 'string':
				sOrderByValues += makeOrderByValue({
					property : sortingFields
				}, aSelectProperties);
				break;
		}
		if (sOrderByValues.length > 0) {
			return "&$orderby=" + sOrderByValues;
		}
		return '';
		function makeOrderByValue(oOrderBy, aSelectProperties) {
			var sValue = '';
			if (jQuery.inArray(oOrderBy.property, aSelectProperties) > -1) {
				sValue += oOrderBy.property;
				if (oOrderBy.descending === true) {
					sValue += ' desc';
				} else {
					sValue += ' asc';
				}
			} else {
				oMsgHandler.putMessage(oMsgHandler.createMessageObject({
					code : '5019',
					aParameters : [ sEntityType, oOrderBy.property ]
				}));
			}
			return jQuery.sap.encodeURL(sValue);
		}
	}
	function addPaging(oPaging) {
		
		function checkPropertyOptionsConsistency(oPaging) {
			var aPropertyNames, i;
			aPropertyNames = Object.getOwnPropertyNames(oPaging);
			for (i = 0; i < aPropertyNames.length;i++) {
				if (aPropertyNames[i] !== 'top' && aPropertyNames[i] !== 'skip' && aPropertyNames[i] !== 'inlineCount') {
					oMsgHandler.putMessage(oMsgHandler.createMessageObject({
						code : '5032',
						aParameters : [ sEntityType, aPropertyNames[i] ]
					}));
				}
			}
		}
		
		var sReturn = '';
		
		if (!oPaging) {
			return sReturn;
		}
		checkPropertyOptionsConsistency(oPaging);

		if (oPaging.top) {
			sReturn += '&$top=' + oPaging.top;
		}
		if (oPaging.skip) {
			sReturn += '&$skip=' + oPaging.skip;
		}
		if (oPaging.inlineCount === true) {
			sReturn += '&$inlinecount=allpages';
		}
		return sReturn;
	}
	function addFormatToUri(sFormat) {
		if (!sFormat) {
			sFormat = 'json'; // eslint-disable-line
		}
		return '&$format=' + sFormat;
	}
};
}());
<file_sep>/*!
 * SAP APF Analysis Path Framework
 *
 * (c) Copyright 2012-2014 SAP SE. All rights reserved
 */
/*global sap, jQuery*/
jQuery.sap.declare("sap.apf.modeler.core.textHandler");
(function() {
	'use strict';
	/**
	 * @private
	 * @class Provides access to message texts and ui texts for the modeler
	 */
	sap.apf.modeler.core.TextHandler = function() {
		var oBundleApf, oBundleModelerSpecificTexts;
		/**
		 * @description returns a message text for message handling
		 * @param {string} sRessourceKey - Key of the message in the Ressourcefile
		 * @param {string[]} [aParameters] - Parameter for placeholder replacement in the message bundle
		 * @returns {string}
		 */
		this.getMessageText = function(sRessourceKey, aParameters) {
			return this.getText(sRessourceKey, aParameters);
		};
		/**
		 * @description returns text
		 * @param {string} sRessourceKey - Key of the message in the Ressourcefile
		 * @param {string[]} [aParameters] - Parameter for placeholder replacement in the message bundle
		 * @returns {string}
		 */
		this.getText = function(sRessourceKey, aParameters) {
			var sText;
			sText = oBundleModelerSpecificTexts.getText(sRessourceKey, aParameters);
			if (sText !== sRessourceKey) {
				return sText;
			}
			return oBundleApf.getText(sRessourceKey, aParameters);
		};
		function initBundles() {
			var sUrl;
			var sIncludeInfo = sap.ui.getCore().getConfiguration().getOriginInfo();
			var sModulePath = jQuery.sap.getModulePath("sap.apf");
			sUrl = sModulePath + '/modeler/resources/i18n/texts.properties';
			oBundleModelerSpecificTexts = jQuery.sap.resources({
				url : sUrl,
				includeInfo : sIncludeInfo
			});
			sUrl = sModulePath + '/resources/i18n/apfUi.properties';
			oBundleApf = jQuery.sap.resources({
				url : sUrl,
				includeInfo : sIncludeInfo
			});
		}
		initBundles();
	};
}());<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
jQuery.sap.require('sap.apf.modeler.ui.utils.nullObjectChecker');
jQuery.sap.declare('sap.apf.modeler.ui.utils.staticValuesBuilder');
(function() {
	'use strict';
	/**
	* @class staticValuesBuilder
	* @memberOf sap.apf.modeler.ui.utils
	* @name staticValuesBuilder
	* @description builds static model data
	*/
	sap.apf.modeler.ui.utils.staticValuesBuilder = function(oTextReader) {
		/**
		* @private
		* @function
		* @name sap.apf.modeler.ui.utils.staticValuesBuilder#getNavTargetTypeData
		* @returns an array of values of navigation target types
		* */
		sap.apf.modeler.ui.utils.staticValuesBuilder.prototype.getNavTargetTypeData = function() {
			var arr = [ oTextReader("globalNavTargets"), oTextReader("stepSpecific") ];
			return arr;
		};
	};
})();<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

// Provides the Design Time Metadata for the sap.ui.comp.smarttable.SmartTable control
sap.ui.define([],
	function() {
	"use strict";

	return {
		aggregations : {
			customToolbar : {
				ignore : true
			},
			semanticObjectController : {
				ignore : true
			},
			noData : {
				ignore : true
			}
		}
	
	};

}, /* bExport= */ false);<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
jQuery.sap.declare('sap.apf.modeler.ui.utils.constants');sap.apf.modeler.ui.utils.CONSTANTS={configurationObjectTypes:{CONFIGURATION:"configuration",FACETFILTER:"facetFilter",CATEGORY:"category",STEP:"step",REPRESENTATION:"representation",NAVIGATIONTARGET:"navigationTarget",ISNEWCONFIG:"apf1972-"}};
<file_sep>/*!
 * 
 * 		SAP UI development toolkit for HTML5 (SAPUI5)
 * 		(c) Copyright 2009-2015 SAP SE. All rights reserved
 * 	
 */

/* ----------------------------------------------------------------------------------
 * Hint: This is a derived (generated) file. Changes should be done in the underlying 
 * source files only (*.control, *.js) or they will be lost after the next generation.
 * ---------------------------------------------------------------------------------- */

// Provides control sap.suite.ui.commons.ChartContainer.
jQuery.sap.declare("sap.suite.ui.commons.ChartContainer");
jQuery.sap.require("sap.suite.ui.commons.library");
jQuery.sap.require("sap.ui.core.Control");


/**
 * Constructor for a new ChartContainer.
 * 
 * Accepts an object literal <code>mSettings</code> that defines initial 
 * property values, aggregated and associated objects as well as event handlers. 
 * 
 * If the name of a setting is ambiguous (e.g. a property has the same name as an event), 
 * then the framework assumes property, aggregation, association, event in that order. 
 * To override this automatic resolution, one of the prefixes "aggregation:", "association:" 
 * or "event:" can be added to the name of the setting (such a prefixed name must be
 * enclosed in single or double quotes).
 *
 * The supported settings are:
 * <ul>
 * <li>Properties
 * <ul>
 * <li>{@link #getShowPersonalization showPersonalization} : boolean (default: false)</li>
 * <li>{@link #getShowFullScreen showFullScreen} : boolean (default: false)</li>
 * <li>{@link #getFullScreen fullScreen} : boolean (default: false)</li>
 * <li>{@link #getShowLegend showLegend} : boolean (default: true)</li>
 * <li>{@link #getTitle title} : string (default: '')</li>
 * <li>{@link #getSelectorGroupLabel selectorGroupLabel} : string</li>
 * <li>{@link #getAutoAdjustHeight autoAdjustHeight} : boolean (default: false)</li>
 * <li>{@link #getShowZoom showZoom} : boolean (default: true)</li>
 * <li>{@link #getShowLegendButton showLegendButton} : boolean (default: true)</li></ul>
 * </li>
 * <li>Aggregations
 * <ul>
 * <li>{@link #getDimensionSelectors dimensionSelectors} : sap.ui.core.Control[]</li>
 * <li>{@link #getContent content} <strong>(default aggregation)</strong> : sap.suite.ui.commons.ChartContainerContent[]</li>
 * <li>{@link #getCustomIcons customIcons} : sap.ui.core.Icon[]</li></ul>
 * </li>
 * <li>Associations
 * <ul></ul>
 * </li>
 * <li>Events
 * <ul>
 * <li>{@link sap.suite.ui.commons.ChartContainer#event:personalizationPress personalizationPress} : fnListenerFunction or [fnListenerFunction, oListenerObject] or [oData, fnListenerFunction, oListenerObject]</li>
 * <li>{@link sap.suite.ui.commons.ChartContainer#event:contentChange contentChange} : fnListenerFunction or [fnListenerFunction, oListenerObject] or [oData, fnListenerFunction, oListenerObject]</li>
 * <li>{@link sap.suite.ui.commons.ChartContainer#event:customZoomInPress customZoomInPress} : fnListenerFunction or [fnListenerFunction, oListenerObject] or [oData, fnListenerFunction, oListenerObject]</li>
 * <li>{@link sap.suite.ui.commons.ChartContainer#event:customZoomOutPress customZoomOutPress} : fnListenerFunction or [fnListenerFunction, oListenerObject] or [oData, fnListenerFunction, oListenerObject]</li></ul>
 * </li>
 * </ul> 

 *
 * @param {string} [sId] id for the new control, generated automatically if no id is given 
 * @param {object} [mSettings] initial settings for the new control
 *
 * @class
 * Provides a toolbar with generic functions for tables and charts based on the VizFrame control like zoom, display in fullscreen mode, toggle the legend, switch between chart types, and changes of the chart dimension. The controls of the content aggregation are positioned below the toolbar. Additional functions can be added to the toolbar with the customIcons aggregation.
 * @extends sap.ui.core.Control
 * @version 1.36.8
 *
 * @constructor
 * @public
 * @name sap.suite.ui.commons.ChartContainer
 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
 */
sap.ui.core.Control.extend("sap.suite.ui.commons.ChartContainer", { metadata : {

	publicMethods : [
		// methods
		"switchChart", "updateChartContainer", "getSelectedContent"
	],
	library : "sap.suite.ui.commons",
	properties : {
		"showPersonalization" : {type : "boolean", group : "Misc", defaultValue : false},
		"showFullScreen" : {type : "boolean", group : "Misc", defaultValue : false},
		"fullScreen" : {type : "boolean", group : "Misc", defaultValue : false},
		"showLegend" : {type : "boolean", group : "Misc", defaultValue : true},
		"title" : {type : "string", group : "Misc", defaultValue : ''},
		"selectorGroupLabel" : {type : "string", group : "Misc", defaultValue : null, deprecated: true},
		"autoAdjustHeight" : {type : "boolean", group : "Misc", defaultValue : false},
		"showZoom" : {type : "boolean", group : "Misc", defaultValue : true},
		"showLegendButton" : {type : "boolean", group : "Misc", defaultValue : true}
	},
	defaultAggregation : "content",
	aggregations : {
		"dimensionSelectors" : {type : "sap.ui.core.Control", multiple : true, singularName : "dimensionSelector"}, 
		"content" : {type : "sap.suite.ui.commons.ChartContainerContent", multiple : true, singularName : "content"}, 
		"toolBar" : {type : "sap.m.OverflowToolbar", multiple : false, visibility : "hidden"}, 
		"customIcons" : {type : "sap.ui.core.Icon", multiple : true, singularName : "customIcon"}
	},
	events : {
		"personalizationPress" : {}, 
		"contentChange" : {}, 
		"customZoomInPress" : {}, 
		"customZoomOutPress" : {}
	}
}});


/**
 * Creates a new subclass of class sap.suite.ui.commons.ChartContainer with name <code>sClassName</code> 
 * and enriches it with the information contained in <code>oClassInfo</code>.
 * 
 * <code>oClassInfo</code> might contain the same kind of informations as described in {@link sap.ui.core.Element.extend Element.extend}.
 *   
 * @param {string} sClassName name of the class to be created
 * @param {object} [oClassInfo] object literal with informations about the class  
 * @param {function} [FNMetaImpl] constructor function for the metadata object. If not given, it defaults to sap.ui.core.ElementMetadata.
 * @return {function} the created class / constructor function
 * @public
 * @static
 * @name sap.suite.ui.commons.ChartContainer.extend
 * @function
 */

sap.suite.ui.commons.ChartContainer.M_EVENTS = {'personalizationPress':'personalizationPress','contentChange':'contentChange','customZoomInPress':'customZoomInPress','customZoomOutPress':'customZoomOutPress'};


/**
 * Getter for property <code>showPersonalization</code>.
 * Set to true to display the personalization icon. Set to false to hide it.
 *
 * Default value is <code>false</code>
 *
 * @return {boolean} the value of property <code>showPersonalization</code>
 * @public
 * @name sap.suite.ui.commons.ChartContainer#getShowPersonalization
 * @function
 */

/**
 * Setter for property <code>showPersonalization</code>.
 *
 * Default value is <code>false</code> 
 *
 * @param {boolean} bShowPersonalization  new value for property <code>showPersonalization</code>
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#setShowPersonalization
 * @function
 */


/**
 * Getter for property <code>showFullScreen</code>.
 * Set to true to display the full screen icon. Set to false to hide it.
 *
 * Default value is <code>false</code>
 *
 * @return {boolean} the value of property <code>showFullScreen</code>
 * @public
 * @name sap.suite.ui.commons.ChartContainer#getShowFullScreen
 * @function
 */

/**
 * Setter for property <code>showFullScreen</code>.
 *
 * Default value is <code>false</code> 
 *
 * @param {boolean} bShowFullScreen  new value for property <code>showFullScreen</code>
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#setShowFullScreen
 * @function
 */


/**
 * Getter for property <code>fullScreen</code>.
 * Display the chart and the toolbar in full screen or normal mode.
 *
 * Default value is <code>false</code>
 *
 * @return {boolean} the value of property <code>fullScreen</code>
 * @public
 * @name sap.suite.ui.commons.ChartContainer#getFullScreen
 * @function
 */

/**
 * Setter for property <code>fullScreen</code>.
 *
 * Default value is <code>false</code> 
 *
 * @param {boolean} bFullScreen  new value for property <code>fullScreen</code>
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#setFullScreen
 * @function
 */


/**
 * Getter for property <code>showLegend</code>.
 * Set to true to display the charts' legends. Set to false to hide them.
 *
 * Default value is <code>true</code>
 *
 * @return {boolean} the value of property <code>showLegend</code>
 * @public
 * @name sap.suite.ui.commons.ChartContainer#getShowLegend
 * @function
 */

/**
 * Setter for property <code>showLegend</code>.
 *
 * Default value is <code>true</code> 
 *
 * @param {boolean} bShowLegend  new value for property <code>showLegend</code>
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#setShowLegend
 * @function
 */


/**
 * Getter for property <code>title</code>.
 * String shown if there are no dimensions to display.
 *
 * Default value is empty/<code>undefined</code>
 *
 * @return {string} the value of property <code>title</code>
 * @public
 * @name sap.suite.ui.commons.ChartContainer#getTitle
 * @function
 */

/**
 * Setter for property <code>title</code>.
 *
 * Default value is empty/<code>undefined</code> 
 *
 * @param {string} sTitle  new value for property <code>title</code>
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#setTitle
 * @function
 */


/**
 * Getter for property <code>selectorGroupLabel</code>.
 * Custom Label for Selectors Group.
 *
 * Default value is empty/<code>undefined</code>
 *
 * @return {string} the value of property <code>selectorGroupLabel</code>
 * @public
 * @deprecated Since version 1.32.0. 
 * Obsolete property as sap.m.Toolbar is replaced by sap.m.OverflowToolbar.
 * @name sap.suite.ui.commons.ChartContainer#getSelectorGroupLabel
 * @function
 */

/**
 * Setter for property <code>selectorGroupLabel</code>.
 *
 * Default value is empty/<code>undefined</code> 
 *
 * @param {string} sSelectorGroupLabel  new value for property <code>selectorGroupLabel</code>
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @deprecated Since version 1.32.0. 
 * Obsolete property as sap.m.Toolbar is replaced by sap.m.OverflowToolbar.
 * @name sap.suite.ui.commons.ChartContainer#setSelectorGroupLabel
 * @function
 */


/**
 * Getter for property <code>autoAdjustHeight</code>.
 * Determine whether to stretch the chart height to the maximum possible height of ChartContainer's parent container. As a prerequisite, the parent container needs to have a fixed value height or be able to determine height from its parent.
 *
 * Default value is <code>false</code>
 *
 * @return {boolean} the value of property <code>autoAdjustHeight</code>
 * @public
 * @name sap.suite.ui.commons.ChartContainer#getAutoAdjustHeight
 * @function
 */

/**
 * Setter for property <code>autoAdjustHeight</code>.
 *
 * Default value is <code>false</code> 
 *
 * @param {boolean} bAutoAdjustHeight  new value for property <code>autoAdjustHeight</code>
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#setAutoAdjustHeight
 * @function
 */


/**
 * Getter for property <code>showZoom</code>.
 * Set to true to display zoom icons. Set to false to hide them.
 *
 * Default value is <code>true</code>
 *
 * @return {boolean} the value of property <code>showZoom</code>
 * @public
 * @name sap.suite.ui.commons.ChartContainer#getShowZoom
 * @function
 */

/**
 * Setter for property <code>showZoom</code>.
 *
 * Default value is <code>true</code> 
 *
 * @param {boolean} bShowZoom  new value for property <code>showZoom</code>
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#setShowZoom
 * @function
 */


/**
 * Getter for property <code>showLegendButton</code>.
 * Set to true/false to display/hide a button for controlling the visbility of the chart's legend.
 *
 * Default value is <code>true</code>
 *
 * @return {boolean} the value of property <code>showLegendButton</code>
 * @public
 * @name sap.suite.ui.commons.ChartContainer#getShowLegendButton
 * @function
 */

/**
 * Setter for property <code>showLegendButton</code>.
 *
 * Default value is <code>true</code> 
 *
 * @param {boolean} bShowLegendButton  new value for property <code>showLegendButton</code>
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#setShowLegendButton
 * @function
 */


/**
 * Getter for aggregation <code>dimensionSelectors</code>.<br/>
 * Dimension Selects.
 * 
 * @return {sap.ui.core.Control[]}
 * @public
 * @name sap.suite.ui.commons.ChartContainer#getDimensionSelectors
 * @function
 */


/**
 * Inserts a dimensionSelector into the aggregation named <code>dimensionSelectors</code>.
 *
 * @param {sap.ui.core.Control}
 *          oDimensionSelector the dimensionSelector to insert; if empty, nothing is inserted
 * @param {int}
 *             iIndex the <code>0</code>-based index the dimensionSelector should be inserted at; for 
 *             a negative value of <code>iIndex</code>, the dimensionSelector is inserted at position 0; for a value 
 *             greater than the current size of the aggregation, the dimensionSelector is inserted at 
 *             the last position        
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#insertDimensionSelector
 * @function
 */

/**
 * Adds some dimensionSelector <code>oDimensionSelector</code> 
 * to the aggregation named <code>dimensionSelectors</code>.
 *
 * @param {sap.ui.core.Control}
 *            oDimensionSelector the dimensionSelector to add; if empty, nothing is inserted
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#addDimensionSelector
 * @function
 */

/**
 * Removes an dimensionSelector from the aggregation named <code>dimensionSelectors</code>.
 *
 * @param {int | string | sap.ui.core.Control} vDimensionSelector the dimensionSelector to remove or its index or id
 * @return {sap.ui.core.Control} the removed dimensionSelector or null
 * @public
 * @name sap.suite.ui.commons.ChartContainer#removeDimensionSelector
 * @function
 */

/**
 * Removes all the controls in the aggregation named <code>dimensionSelectors</code>.<br/>
 * Additionally unregisters them from the hosting UIArea.
 * @return {sap.ui.core.Control[]} an array of the removed elements (might be empty)
 * @public
 * @name sap.suite.ui.commons.ChartContainer#removeAllDimensionSelectors
 * @function
 */

/**
 * Checks for the provided <code>sap.ui.core.Control</code> in the aggregation named <code>dimensionSelectors</code> 
 * and returns its index if found or -1 otherwise.
 *
 * @param {sap.ui.core.Control}
 *            oDimensionSelector the dimensionSelector whose index is looked for.
 * @return {int} the index of the provided control in the aggregation if found, or -1 otherwise
 * @public
 * @name sap.suite.ui.commons.ChartContainer#indexOfDimensionSelector
 * @function
 */
	

/**
 * Destroys all the dimensionSelectors in the aggregation 
 * named <code>dimensionSelectors</code>.
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#destroyDimensionSelectors
 * @function
 */


/**
 * Getter for aggregation <code>content</code>.<br/>
 * ChartToolBar Content aggregation. Only vizFrame, sap.m.Table and sap.ui.table.Table can be embedded.
 * If not specified explicitly, the rendering order of the charts is determined by the sequence of contents provided by the application via this aggregation. That means, per default the first chart of the aggregation will be rendered within the container.
 * 
 * <strong>Note</strong>: this is the default aggregation for ChartContainer.
 * @return {sap.suite.ui.commons.ChartContainerContent[]}
 * @public
 * @name sap.suite.ui.commons.ChartContainer#getContent
 * @function
 */


/**
 * Inserts a content into the aggregation named <code>content</code>.
 *
 * @param {sap.suite.ui.commons.ChartContainerContent}
 *          oContent the content to insert; if empty, nothing is inserted
 * @param {int}
 *             iIndex the <code>0</code>-based index the content should be inserted at; for 
 *             a negative value of <code>iIndex</code>, the content is inserted at position 0; for a value 
 *             greater than the current size of the aggregation, the content is inserted at 
 *             the last position        
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#insertContent
 * @function
 */

/**
 * Adds some content <code>oContent</code> 
 * to the aggregation named <code>content</code>.
 *
 * @param {sap.suite.ui.commons.ChartContainerContent}
 *            oContent the content to add; if empty, nothing is inserted
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#addContent
 * @function
 */

/**
 * Removes an content from the aggregation named <code>content</code>.
 *
 * @param {int | string | sap.suite.ui.commons.ChartContainerContent} vContent the content to remove or its index or id
 * @return {sap.suite.ui.commons.ChartContainerContent} the removed content or null
 * @public
 * @name sap.suite.ui.commons.ChartContainer#removeContent
 * @function
 */

/**
 * Removes all the controls in the aggregation named <code>content</code>.<br/>
 * Additionally unregisters them from the hosting UIArea.
 * @return {sap.suite.ui.commons.ChartContainerContent[]} an array of the removed elements (might be empty)
 * @public
 * @name sap.suite.ui.commons.ChartContainer#removeAllContent
 * @function
 */

/**
 * Checks for the provided <code>sap.suite.ui.commons.ChartContainerContent</code> in the aggregation named <code>content</code> 
 * and returns its index if found or -1 otherwise.
 *
 * @param {sap.suite.ui.commons.ChartContainerContent}
 *            oContent the content whose index is looked for.
 * @return {int} the index of the provided control in the aggregation if found, or -1 otherwise
 * @public
 * @name sap.suite.ui.commons.ChartContainer#indexOfContent
 * @function
 */
	

/**
 * Destroys all the content in the aggregation 
 * named <code>content</code>.
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#destroyContent
 * @function
 */


/**
 * Getter for aggregation <code>customIcons</code>.<br/>
 * This aggregation contains the custom icons that should be displayed additionally on the toolbar.
 * It is not guaranteed that the same instance of the sap.ui.core.Icon control will be used within the toolbar,
 * but the toolbar will contain a sap.m.OverflowToolbarButton with an icon property equal to the src property
 * of the sap.ui.core.Icon provided in the aggregation.
 * If a press event is triggered by the icon displayed on the toolbar, then the press handler of
 * the original sap.ui.core.Icon control is used. The instance of the control, that has triggered the press event,
 * can be accessed using the "controlReference" parameter of the event object.
 * 
 * @return {sap.ui.core.Icon[]}
 * @public
 * @name sap.suite.ui.commons.ChartContainer#getCustomIcons
 * @function
 */


/**
 * Inserts a customIcon into the aggregation named <code>customIcons</code>.
 *
 * @param {sap.ui.core.Icon}
 *          oCustomIcon the customIcon to insert; if empty, nothing is inserted
 * @param {int}
 *             iIndex the <code>0</code>-based index the customIcon should be inserted at; for 
 *             a negative value of <code>iIndex</code>, the customIcon is inserted at position 0; for a value 
 *             greater than the current size of the aggregation, the customIcon is inserted at 
 *             the last position        
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#insertCustomIcon
 * @function
 */

/**
 * Adds some customIcon <code>oCustomIcon</code> 
 * to the aggregation named <code>customIcons</code>.
 *
 * @param {sap.ui.core.Icon}
 *            oCustomIcon the customIcon to add; if empty, nothing is inserted
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#addCustomIcon
 * @function
 */

/**
 * Removes an customIcon from the aggregation named <code>customIcons</code>.
 *
 * @param {int | string | sap.ui.core.Icon} vCustomIcon the customIcon to remove or its index or id
 * @return {sap.ui.core.Icon} the removed customIcon or null
 * @public
 * @name sap.suite.ui.commons.ChartContainer#removeCustomIcon
 * @function
 */

/**
 * Removes all the controls in the aggregation named <code>customIcons</code>.<br/>
 * Additionally unregisters them from the hosting UIArea.
 * @return {sap.ui.core.Icon[]} an array of the removed elements (might be empty)
 * @public
 * @name sap.suite.ui.commons.ChartContainer#removeAllCustomIcons
 * @function
 */

/**
 * Checks for the provided <code>sap.ui.core.Icon</code> in the aggregation named <code>customIcons</code> 
 * and returns its index if found or -1 otherwise.
 *
 * @param {sap.ui.core.Icon}
 *            oCustomIcon the customIcon whose index is looked for.
 * @return {int} the index of the provided control in the aggregation if found, or -1 otherwise
 * @public
 * @name sap.suite.ui.commons.ChartContainer#indexOfCustomIcon
 * @function
 */
	

/**
 * Destroys all the customIcons in the aggregation 
 * named <code>customIcons</code>.
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#destroyCustomIcons
 * @function
 */


/**
 * Event fired when a user clicks on the personalization icon.
 *
 * @name sap.suite.ui.commons.ChartContainer#personalizationPress
 * @event
 * @param {sap.ui.base.Event} oControlEvent
 * @param {sap.ui.base.EventProvider} oControlEvent.getSource
 * @param {object} oControlEvent.getParameters
 * @public
 */
 
/**
 * Attach event handler <code>fnFunction</code> to the 'personalizationPress' event of this <code>sap.suite.ui.commons.ChartContainer</code>.<br/>.
 * When called, the context of the event handler (its <code>this</code>) will be bound to <code>oListener<code> if specified
 * otherwise to this <code>sap.suite.ui.commons.ChartContainer</code>.<br/> itself. 
 *  
 * Event fired when a user clicks on the personalization icon.
 *
 * @param {object}
 *            [oData] An application specific payload object, that will be passed to the event handler along with the event object when firing the event.
 * @param {function}
 *            fnFunction The function to call, when the event occurs.  
 * @param {object}
 *            [oListener] Context object to call the event handler with. Defaults to this <code>sap.suite.ui.commons.ChartContainer</code>.<br/> itself.
 *
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#attachPersonalizationPress
 * @function
 */

/**
 * Detach event handler <code>fnFunction</code> from the 'personalizationPress' event of this <code>sap.suite.ui.commons.ChartContainer</code>.<br/>
 *
 * The passed function and listener object must match the ones used for event registration.
 *
 * @param {function}
 *            fnFunction The function to call, when the event occurs.
 * @param {object}
 *            oListener Context object on which the given function had to be called.
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#detachPersonalizationPress
 * @function
 */

/**
 * Fire event personalizationPress to attached listeners.
 *
 * @param {Map} [mArguments] the arguments to pass along with the event.
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @protected
 * @name sap.suite.ui.commons.ChartContainer#firePersonalizationPress
 * @function
 */


/**
 * Event fired when a user changes the displayed content.
 *
 * @name sap.suite.ui.commons.ChartContainer#contentChange
 * @event
 * @param {sap.ui.base.Event} oControlEvent
 * @param {sap.ui.base.EventProvider} oControlEvent.getSource
 * @param {object} oControlEvent.getParameters
 * @param {string} oControlEvent.getParameters.selectedItemId Id of the selected item.
 * @public
 */
 
/**
 * Attach event handler <code>fnFunction</code> to the 'contentChange' event of this <code>sap.suite.ui.commons.ChartContainer</code>.<br/>.
 * When called, the context of the event handler (its <code>this</code>) will be bound to <code>oListener<code> if specified
 * otherwise to this <code>sap.suite.ui.commons.ChartContainer</code>.<br/> itself. 
 *  
 * Event fired when a user changes the displayed content.
 *
 * @param {object}
 *            [oData] An application specific payload object, that will be passed to the event handler along with the event object when firing the event.
 * @param {function}
 *            fnFunction The function to call, when the event occurs.  
 * @param {object}
 *            [oListener] Context object to call the event handler with. Defaults to this <code>sap.suite.ui.commons.ChartContainer</code>.<br/> itself.
 *
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#attachContentChange
 * @function
 */

/**
 * Detach event handler <code>fnFunction</code> from the 'contentChange' event of this <code>sap.suite.ui.commons.ChartContainer</code>.<br/>
 *
 * The passed function and listener object must match the ones used for event registration.
 *
 * @param {function}
 *            fnFunction The function to call, when the event occurs.
 * @param {object}
 *            oListener Context object on which the given function had to be called.
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#detachContentChange
 * @function
 */

/**
 * Fire event contentChange to attached listeners.
 * 
 * Expects following event parameters:
 * <ul>
 * <li>'selectedItemId' of type <code>string</code> Id of the selected item.</li>
 * </ul>
 *
 * @param {Map} [mArguments] the arguments to pass along with the event.
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @protected
 * @name sap.suite.ui.commons.ChartContainer#fireContentChange
 * @function
 */


/**
 * Custom event for zoom in.
 *
 * @name sap.suite.ui.commons.ChartContainer#customZoomInPress
 * @event
 * @param {sap.ui.base.Event} oControlEvent
 * @param {sap.ui.base.EventProvider} oControlEvent.getSource
 * @param {object} oControlEvent.getParameters
 * @public
 */
 
/**
 * Attach event handler <code>fnFunction</code> to the 'customZoomInPress' event of this <code>sap.suite.ui.commons.ChartContainer</code>.<br/>.
 * When called, the context of the event handler (its <code>this</code>) will be bound to <code>oListener<code> if specified
 * otherwise to this <code>sap.suite.ui.commons.ChartContainer</code>.<br/> itself. 
 *  
 * Custom event for zoom in.
 *
 * @param {object}
 *            [oData] An application specific payload object, that will be passed to the event handler along with the event object when firing the event.
 * @param {function}
 *            fnFunction The function to call, when the event occurs.  
 * @param {object}
 *            [oListener] Context object to call the event handler with. Defaults to this <code>sap.suite.ui.commons.ChartContainer</code>.<br/> itself.
 *
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#attachCustomZoomInPress
 * @function
 */

/**
 * Detach event handler <code>fnFunction</code> from the 'customZoomInPress' event of this <code>sap.suite.ui.commons.ChartContainer</code>.<br/>
 *
 * The passed function and listener object must match the ones used for event registration.
 *
 * @param {function}
 *            fnFunction The function to call, when the event occurs.
 * @param {object}
 *            oListener Context object on which the given function had to be called.
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#detachCustomZoomInPress
 * @function
 */

/**
 * Fire event customZoomInPress to attached listeners.
 *
 * @param {Map} [mArguments] the arguments to pass along with the event.
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @protected
 * @name sap.suite.ui.commons.ChartContainer#fireCustomZoomInPress
 * @function
 */


/**
 * Custom event for zoom out.
 *
 * @name sap.suite.ui.commons.ChartContainer#customZoomOutPress
 * @event
 * @param {sap.ui.base.Event} oControlEvent
 * @param {sap.ui.base.EventProvider} oControlEvent.getSource
 * @param {object} oControlEvent.getParameters
 * @public
 */
 
/**
 * Attach event handler <code>fnFunction</code> to the 'customZoomOutPress' event of this <code>sap.suite.ui.commons.ChartContainer</code>.<br/>.
 * When called, the context of the event handler (its <code>this</code>) will be bound to <code>oListener<code> if specified
 * otherwise to this <code>sap.suite.ui.commons.ChartContainer</code>.<br/> itself. 
 *  
 * Custom event for zoom out.
 *
 * @param {object}
 *            [oData] An application specific payload object, that will be passed to the event handler along with the event object when firing the event.
 * @param {function}
 *            fnFunction The function to call, when the event occurs.  
 * @param {object}
 *            [oListener] Context object to call the event handler with. Defaults to this <code>sap.suite.ui.commons.ChartContainer</code>.<br/> itself.
 *
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#attachCustomZoomOutPress
 * @function
 */

/**
 * Detach event handler <code>fnFunction</code> from the 'customZoomOutPress' event of this <code>sap.suite.ui.commons.ChartContainer</code>.<br/>
 *
 * The passed function and listener object must match the ones used for event registration.
 *
 * @param {function}
 *            fnFunction The function to call, when the event occurs.
 * @param {object}
 *            oListener Context object on which the given function had to be called.
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ChartContainer#detachCustomZoomOutPress
 * @function
 */

/**
 * Fire event customZoomOutPress to attached listeners.
 *
 * @param {Map} [mArguments] the arguments to pass along with the event.
 * @return {sap.suite.ui.commons.ChartContainer} <code>this</code> to allow method chaining
 * @protected
 * @name sap.suite.ui.commons.ChartContainer#fireCustomZoomOutPress
 * @function
 */


/**
 * Switch display content in the container.
 *
 * @name sap.suite.ui.commons.ChartContainer#switchChart
 * @function
 * @type sap.suite.ui.commons.ChartContainerContent
 * @public
 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
 */


/**
 * Update ChartContainer rerendering all its contents.
 *
 * @name sap.suite.ui.commons.ChartContainer#updateChartContainer
 * @function
 * @type void
 * @public
 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
 */


/**
 * Returns the currently selected content control.
 *
 * @name sap.suite.ui.commons.ChartContainer#getSelectedContent
 * @function
 * @type sap.ui.core.Control
 * @public
 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
 */

// Start of sap/suite/ui/commons/ChartContainer.js
jQuery.sap.require("sap.m.Button");
jQuery.sap.require("sap.m.Select");
jQuery.sap.require("sap.ui.core.ResizeHandler");
jQuery.sap.require("sap.ui.Device");
jQuery.sap.require("sap.m.OverflowToolbarButton");
jQuery.sap.require("sap.ui.core.delegate.ScrollEnablement");
sap.ui.getCore().loadLibrary("sap.viz");

/////////////////////////// PUBLIC SECTION ///////////////////////////

sap.suite.ui.commons.ChartContainer.prototype.setFullScreen = function(fullscreen){
	if (this._firstTime) {
		// can't set the full screen and toggle since dom is not loaded yet
		return;
	}
	if (this.getFullScreen() == fullscreen) { //check setter is overridden, if not, no need to set the property
		return;
	}
	var fullScreen = this.getProperty("fullScreen");
	if (fullScreen !== fullscreen) {
		this._toggleFullScreen();
	}
};

/**
 * Switch currently viewed content (causes rerendering)
 *
 * @public
 * @param {sap.ui.core.Control} chart The new content (Chart or Table) to be displayed
 */
sap.suite.ui.commons.ChartContainer.prototype.switchChart = function(chart) {
	this._setSelectedContent(chart);
	// fire the change event with id of the newly selected item..
	this.rerender(); //invalidate();
};

sap.suite.ui.commons.ChartContainer.prototype.setTitle = function(value) {
	this._oChartTitle.setText(value);
	this.setProperty("title", value, true);
};

sap.suite.ui.commons.ChartContainer.prototype.setShowLegendButton = function(value) {
	//no need to re-set the property to the same value as before
	if (this.getShowLegendButton() === value) {
		return;
	}
	this.setProperty("showLegendButton", value, false);
	if (!this.getShowLegendButton()) {
		this.setShowLegend(false);
	}
};

sap.suite.ui.commons.ChartContainer.prototype.setShowLegend = function(value) {
	this.setProperty("showLegend", value, false);

	//propagate to all charts
	var aContents = this.getAggregation("content");

	if (aContents) {
		for (var i = 0; i < aContents.length; i++) {
			var innerChart = aContents[i].getContent();
			if (jQuery.isFunction(innerChart.setLegendVisible)) {
				innerChart.setLegendVisible(value);
			} else {
				jQuery.sap.log.info("ChartContainer: chart id " + innerChart.getId() + " is missing the setVizProperties property");
			}
		}
	}
};

sap.suite.ui.commons.ChartContainer.prototype.addAggregation = function(sAggregationName, oObject, bSuppressInvalidate) {
	if (sAggregationName === "dimensionSelectors") {
		return this.addDimensionSelector(oObject);
	} else {
		return sap.ui.base.ManagedObject.prototype.addAggregation.apply(this, arguments);
	}
};

sap.suite.ui.commons.ChartContainer.prototype.getAggregation = function(sAggregationName, oDefaultForCreation) {
	if (sAggregationName === "dimensionSelectors") {
		return this.getDimensionSelectors();
	} else {
		return sap.ui.base.ManagedObject.prototype.getAggregation.apply(this, arguments);
	}
};

sap.suite.ui.commons.ChartContainer.prototype.indexOfAggregation = function(sAggregationName, oObject) {
	if (sAggregationName === "dimensionSelectors") {
		return this.indexOfDimensionSelector(oObject);
	} else {
		return sap.ui.base.ManagedObject.prototype.indexOfAggregation.apply(this, arguments);
	}
};

sap.suite.ui.commons.ChartContainer.prototype.insertAggregation = function(sAggregationName, oObject, iIndex, bSuppressInvalidate) {
	if (sAggregationName === "dimensionSelectors") {
		return this.insertDimensionSelector(oObject, iIndex);
	} else {
		return sap.ui.base.ManagedObject.prototype.insertAggregation.apply(this, arguments);
	}
};

sap.suite.ui.commons.ChartContainer.prototype.destroyAggregation = function(sAggregationName, bSuppressInvalidate) {
	if (sAggregationName === "dimensionSelectors") {
		return this.destroyDimensionSelectors();
	} else {
		return sap.ui.base.ManagedObject.prototype.destroyAggregation.apply(this, arguments);
	}
};

sap.suite.ui.commons.ChartContainer.prototype.removeAggregation = function(sAggregationName, vObject, bSuppressInvalidate) {
	if (sAggregationName === "dimensionSelectors") {
		return this.removeDimensionSelector(vObject);
	} else {
		return sap.ui.base.ManagedObject.prototype.removeAggregation.apply(this, arguments);
	}
};

sap.suite.ui.commons.ChartContainer.prototype.removeAllAggregation = function(sAggregationName, bSuppressInvalidate) {
	if (sAggregationName === "dimensionSelectors") {
		return this.removeAllDimensionSelectors();
	} else {
		return sap.ui.base.ManagedObject.prototype.removeAllAggregation.apply(this, arguments);
	}
};

sap.suite.ui.commons.ChartContainer.prototype.addDimensionSelector = function(obj) {
	this._dimSelectorsAll.push(obj);
	return this;
};

sap.suite.ui.commons.ChartContainer.prototype.getDimensionSelectors = function() {
	return this._dimSelectorsAll;
};

sap.suite.ui.commons.ChartContainer.prototype.indexOfDimensionSelector = function(oDimensionSelector) {
	for (var i = 0; i < this._dimSelectorsAll.length; i++) {
		if (this._dimSelectorsAll[i] === oDimensionSelector) {
			return i;
		}
	}
	return -1;
};

sap.suite.ui.commons.ChartContainer.prototype.insertDimensionSelector = function(oDimensionSelector, iIndex) {
	if (!oDimensionSelector) {
		return this;
	}
	var i;
	if (iIndex < 0) {
		i = 0;
	} else if (iIndex > this._dimSelectorsAll.length) {
		i = this._dimSelectorsAll.length;
	} else {
		i = iIndex;
	}
	if (i !== iIndex) {
		jQuery.sap.log.warning("ManagedObject.insertAggregation: index '" + iIndex + "' out of range [0," + this._dimSelectorsAll.length + "], forced to " + i);
	}
	this._dimSelectorsAll.splice(i, 0, oDimensionSelector);
	return this;
};

sap.suite.ui.commons.ChartContainer.prototype.destroyDimensionSelectors = function() {
	if (this._oToolBar) {
		for (var i = 0; i < this._dimSelectorsAll.length; i++) {
			if (this._dimSelectorsAll[i]) {
				this._oToolBar.removeContent(this._dimSelectorsAll[i]);
				this._dimSelectorsAll[i].destroy();
			}
		}
	}
	this._dimSelectorsAll = [];
	return this;
};

sap.suite.ui.commons.ChartContainer.prototype.removeDimensionSelector = function(vDimensionSelector) {
	if (this._oToolBar) {
		this._oToolBar.removeContent(vDimensionSelector);
	}
	if (!vDimensionSelector) {
		return null;
	} else {
		var index = this.indexOfDimensionSelector(vDimensionSelector);
		if (index === -1) {
			return null;
		} else {
			var aReturn = this._dimSelectorsAll.splice(index, 1);
			return aReturn[0];
		}
	}
};

sap.suite.ui.commons.ChartContainer.prototype.removeAllDimensionSelectors = function() {
	var aReturn = this._dimSelectorsAll.slice();
	if (this._oToolBar) {
		for (var i = 0; i < this._dimSelectorsAll.length; i++) {
			if (this._dimSelectorsAll[i]) {
				this._oToolBar.removeContent(this._dimSelectorsAll[i]);
			}
		}
	}
	this._dimSelectorsAll = [];
	return aReturn;
};

sap.suite.ui.commons.ChartContainer.prototype.addContent = function(obj) {
	this.addAggregation("content", obj);
	this._chartContentChange = true;
};

sap.suite.ui.commons.ChartContainer.prototype.insertContent = function(obj, index) {
	this.insertAggregation("content", obj, index);
	this._chartContentChange = true;
};

/**
 * @deprecated Not used anymore
 */
sap.suite.ui.commons.ChartContainer.prototype.updateContent = function() {
	this.updateAggregation("content");
	this._chartContentChange = true;
};

/**
 * Updates ChartContainer and rerenders all its contents.
 *
 * @public
 */
sap.suite.ui.commons.ChartContainer.prototype.updateChartContainer = function() {
	this._chartContentChange = true;
	this.rerender();
};

/**
 * Set selectorGroupLabel without causing a rerendering of the ChartContainer
 * @deprecated
 * @param {String} selectorGroupLabel The new selectorGroupLabel to be set
 */
sap.suite.ui.commons.ChartContainer.prototype.setSelectorGroupLabel = function(selectorGroupLabel) {
	this.setProperty("selectorGroupLabel", selectorGroupLabel, true);
};

/**
 * Returns the currently selected content control.
 *
 * @public
 * @return {sap.ui.core.Control} The currently selected content
 */
sap.suite.ui.commons.ChartContainer.prototype.getSelectedContent = function() {
	return this._oSelectedContent;
};

/**
 * Returns the currently instance of the delegate to other controls.
 *
 * @public
 * @return {sap.ui.core.delegate.ScrollEnablement} The currently instance of the delegate
 */
sap.suite.ui.commons.ChartContainer.prototype.getScrollDelegate = function() {
	return this._oScrollEnablement;
};
////////////////////////// Life cycle methods ///////////////////////////

sap.suite.ui.commons.ChartContainer.prototype.init = function() {
	var that = this;
	this._bValue = null;
	this._firstTime = true;
	this._aChartIcons = [];
	this._selectedChart = null;
	this._dimSelectorsAll = [];
	this._customIconsAll = [];
	this._oShowLegendButton = null;
	this._oActiveChartButton = null;
	this._oSelectedContent = null;
	this._bSegmentedButtonSaveSelectState = false;
	this._mOriginalVizFrameHeights = {};

	this.oResBundle = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.commons");

	//Right side..

	//Full screen button
	this._oFullScreenButton = new sap.m.OverflowToolbarButton({
		icon : "sap-icon://full-screen",
		type : sap.m.ButtonType.Transparent,
		text : this.oResBundle.getText("CHARTCONTAINER_FULLSCREEN"),
		tooltip : this.oResBundle.getText("CHARTCONTAINER_FULLSCREEN"),
		press: function() {
			that._bSegmentedButtonSaveSelectState = true;
			that._toggleFullScreen();
		}
	});

	//Popup for chart content
	this._oPopup = new sap.ui.core.Popup({
		modal : true,
		shadow : false,
		autoClose : false
	});

	//legend button
	this._oShowLegendButton = new sap.m.OverflowToolbarButton({
		icon : "sap-icon://legend",
		type : sap.m.ButtonType.Transparent,
		text : this.oResBundle.getText("CHARTCONTAINER_LEGEND"),
		tooltip : this.oResBundle.getText("CHARTCONTAINER_LEGEND"),
		press: function() {
			that._bSegmentedButtonSaveSelectState = true;
			that._onLegendButtonPress();
		}
	});

	//personalization button
	this._oPersonalizationButton = new sap.m.OverflowToolbarButton({
		icon : "sap-icon://action-settings",
		type : sap.m.ButtonType.Transparent,
		text : this.oResBundle.getText("CHARTCONTAINER_PERSONALIZE"),
		tooltip : this.oResBundle.getText("CHARTCONTAINER_PERSONALIZE"),
		press: function() {
			that._oPersonalizationPress();
		}
	});

	//zoom in button
	this._oZoomInButton = new sap.m.OverflowToolbarButton({
		icon : "sap-icon://zoom-in",
		type : sap.m.ButtonType.Transparent,
		text : this.oResBundle.getText("CHARTCONTAINER_ZOOMIN"),
		tooltip : this.oResBundle.getText("CHARTCONTAINER_ZOOMIN"),
		press: function() {
			that._zoom(true);
		}
	});

	//zoom out button
	this._oZoomOutButton = new sap.m.OverflowToolbarButton({
		icon : "sap-icon://zoom-out",
		type : sap.m.ButtonType.Transparent,
		text : this.oResBundle.getText("CHARTCONTAINER_ZOOMOUT"),
		tooltip : this.oResBundle.getText("CHARTCONTAINER_ZOOMOUT"),
		press: function() {
			that._zoom(false);
		}
	});

	//segmentedButton for chart and table
	this._oChartSegmentedButton = new sap.m.SegmentedButton({
		select: function(oEvent) {
			var sChartId = oEvent.getParameter("button").getCustomData()[0].getValue();
			that._bSegmentedButtonSaveSelectState = true;
			that._switchChart(sChartId);
		}
	});

	//Left side...
	//display title if no dimensionselectors
	this._oChartTitle = new sap.m.Label();

	//overflow toolbar
	this._oToolBar = new sap.m.OverflowToolbar({
	// Use ToolBarDesign.Auto
		content : [new sap.m.ToolbarSpacer()],
		width: "auto"
	});
	this.setAggregation("toolBar", this._oToolBar);

	this._currentRangeName = sap.ui.Device.media.getCurrentRange(sap.ui.Device.media.RANGESETS.SAP_STANDARD).name;
	sap.ui.Device.media.attachHandler(this._handleMediaChange, this, sap.ui.Device.media.RANGESETS.SAP_STANDARD);

	this.sResizeListenerId = null;
	if (jQuery.device.is.desktop) {
		this.sResizeListenerId = sap.ui.core.ResizeHandler.register(this, jQuery.proxy(this._performHeightChanges, this));
	} else {
		sap.ui.Device.orientation.attachHandler(this._performHeightChanges, this);
		sap.ui.Device.resize.attachHandler(this._performHeightChanges, this);
	}
};

sap.suite.ui.commons.ChartContainer.prototype.onAfterRendering = function() {
	var that = this;
	if ((this.sResizeListenerId === null) && (jQuery.device.is.desktop)) {
		this.sResizeListenerId = sap.ui.core.ResizeHandler.register(this, jQuery.proxy(this._performHeightChanges, this));
	}
	if (this.getAutoAdjustHeight() || this.getFullScreen()) {
		//fix the flickering issue when switch chart in full screen mode
		jQuery.sap.delayedCall(500, this, function() {
			that._performHeightChanges();
		});
	}
	var bVizFrameSelected = this.getSelectedContent() && this.getSelectedContent().getContent() instanceof sap.viz.ui5.controls.VizFrame;
	this._oScrollEnablement = new sap.ui.core.delegate.ScrollEnablement(this, this.getId() + "-wrapper", {
		horizontal : !bVizFrameSelected,
		vertical : !bVizFrameSelected
	});
	this._firstTime = false;
};

sap.suite.ui.commons.ChartContainer.prototype.onBeforeRendering = function() {
	var onPress = function(oEvent, oData) {
		oData.icon.firePress({
			controlReference : oEvent.getSource()
		});
	};
	if (this._chartContentChange || this._firstTime) {
		this._chartChange();
	}
	if (this.getAggregation("customIcons") && this.getAggregation("customIcons").length > 0) {
		if (this._customIconsAll.length === 0) {
			for (var i = 0; i < this.getAggregation("customIcons").length; i++) {
				var oIcon = this.getAggregation("customIcons")[i];
				var oButton = new sap.m.OverflowToolbarButton({
					icon : oIcon.getSrc(),
					text : oIcon.getTooltip(),
					tooltip : oIcon.getTooltip(),
					type : sap.m.ButtonType.Transparent,
					width : "3rem"
				});
				oButton.attachPress({
					icon : oIcon
				}, onPress);
				this._customIconsAll.push(oButton);
			}
		}
	} else {
		this._customIconsAll = [];
	}
	this._adjustDisplay();
};

sap.suite.ui.commons.ChartContainer.prototype.exit = function() {
	sap.ui.Device.media.detachHandler(this._handleMediaChange, this, sap.ui.Device.media.RANGESETS.SAP_STANDARD);
	if (this._oFullScreenButton) {
		this._oFullScreenButton.destroy();
		this._oFullScreenButton = undefined;
	}
	if (this._oPopup) {
		this._oPopup.destroy();
		this._oPopup = undefined;
	}
	if (this._oShowLegendButton) {
		this._oShowLegendButton.destroy();
		this._oShowLegendButton = undefined;
	}
	if (this._oPersonalizationButton) {
		this._oPersonalizationButton.destroy();
		this._oPersonalizationButton = undefined;
	}
	if (this._oActiveChartButton) {
		this._oActiveChartButton.destroy();
		this._oActiveChartButton = undefined;
	}
	if (this._oChartSegmentedButton) {
		this._oChartSegmentedButton.destroy();
		this._oChartSegmentedButton = undefined;
	}
	if (this._oSelectedContent) {
		this._oSelectedContent.destroy();
		this._oSelectedContent = undefined;
	}
	if (this._oToolBar) {
		this._oToolBar.destroy();
		this._oToolBar = undefined;
	}
	if (this._dimSelectorsAll) {
		for (var i = 0; i < this._dimSelectorsAll.length; i++){
			if (this._dimSelectorsAll[i]) {
				this._dimSelectorsAll[i].destroy();
			}
		}
		this._dimSelectorsAll = undefined;
	}
	if (this._oScrollEnablement) {
		this._oScrollEnablement.destroy();
		this._oScrollEnablement = undefined;
	}
	if (jQuery.device.is.desktop && this.sResizeListenerId) {
		sap.ui.core.ResizeHandler.deregister(this.sResizeListenerId);
		this.sResizeListenerId = null;
	} else {
		sap.ui.Device.orientation.detachHandler(this._performHeightChanges, this);
		sap.ui.Device.resize.detachHandler(this._performHeightChanges, this);
	}
	if (this._oZoomInButton) {
		this._oZoomInButton.destroy();
		this._oZoomInButton = undefined;
	}
	if (this._oZoomOutButton) {
		this._oZoomOutButton.destroy();
		this._oZoomOutButton = undefined;
	}
};

////////////////////////// PRIVATE SECTION ///////////////////////////

/**
 * Toggle normal and full screen mode
 *
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._toggleFullScreen = function() {
	var bFullScreen,
		sId,
		sHeight,
		aContent,
		oObjectContent;

	bFullScreen = this.getProperty("fullScreen");
	if (bFullScreen) {
		aContent = this.getAggregation("content");
		this._closeFullScreen();
		this.setProperty("fullScreen", false, true);
		for (var i = 0; i < aContent.length; i++) {
			oObjectContent = aContent[i].getContent();
			oObjectContent.setWidth("100%");
			sHeight = this._mOriginalVizFrameHeights[oObjectContent.getId()];
			if (sHeight) {
				oObjectContent.setHeight(sHeight);
			}
		}
		this.invalidate();
	} else {
		//fix chart disappear when toggle chart with full screen button
		//by surpressing the invalid for the setProperty, this delay shouldn't be needed.
		this._openFullScreen();
		this.setProperty("fullScreen", true, true);
	}
	var sIcon = (bFullScreen ? "sap-icon://full-screen" : "sap-icon://exit-full-screen");
	this._oFullScreenButton.setIcon(sIcon);
	this._oFullScreenButton.focus();
};

/**
 * Open chartcontainer content with Full Screen
 *
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._openFullScreen = function() {
	this.$content = this.$();
	if (this.$content) {
		this.$tempNode = jQuery("<div></div>"); // id='" + this.$content.attr("id")+"-overlay"+ "'
		this.$content.before(this.$tempNode);
		this._$overlay = jQuery("<div id='" + jQuery.sap.uid() + "'></div>");
		this._$overlay.addClass("sapSuiteUiCommonsChartContainerOverlay");
		this._$overlay.append(this.$content);
		this._oPopup.setContent(this._$overlay);
	} else {
		jQuery.sap.log.warn("Overlay: content does not exist or contains more than one child");
	}
	this._oPopup.open(200, null, jQuery("body"));
};

/**
 * Close Full Screen and return to normal mode
 *
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._closeFullScreen = function() {
	if (this._oScrollEnablement !== null) {
		this._oScrollEnablement.destroy();
		this._oScrollEnablement = null;
	}
	this.$tempNode.replaceWith(this.$content);
	this._oToolBar.setDesign(sap.m.ToolbarDesign.Auto);
	this._oPopup.close();
	this._$overlay.remove();
};

/**
 * Height change when toggle full and normal mode
 * Mobile swap between portrait and landscape will execute height change too
 *
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._performHeightChanges = function() {
	var $this,
		iChartContainerHeight,
		iToolBarHeight,
		iToolbarBottomBorder,
		iNewChartHeight,
		iExistingChartHeight,
		oInnerChart;

	if (this.getAutoAdjustHeight() || this.getFullScreen()) {
		$this = this.$();
		// Only adjust height after both toolbar and chart are rendered in DOM
		if (($this.find('.sapSuiteUiCommonsChartContainerToolBarArea').children()[0]) && ($this.find('.sapSuiteUiCommonsChartContainerChartArea').children()[0])) {
			iChartContainerHeight = $this.height();
			iToolBarHeight = $this.find('.sapSuiteUiCommonsChartContainerToolBarArea').children()[0].clientHeight;
			iToolbarBottomBorder = Math.round(parseFloat($this.find('.sapSuiteUiCommonsChartContainerToolBarArea').children().css("border-bottom")));
			if (isNaN(iToolbarBottomBorder)) {
				iToolbarBottomBorder = 0;
			}
			iNewChartHeight = iChartContainerHeight - iToolBarHeight - iToolbarBottomBorder;
			iExistingChartHeight = $this.find('.sapSuiteUiCommonsChartContainerChartArea').children()[0].clientHeight;
			oInnerChart = this.getSelectedContent().getContent();
			if ((oInnerChart instanceof sap.viz.ui5.controls.VizFrame) || (sap.chart && sap.chart.Chart && oInnerChart instanceof sap.chart.Chart)) {
				if (iNewChartHeight > 0 && iNewChartHeight !== iExistingChartHeight) {
					this._rememberOriginalHeight(oInnerChart);
					oInnerChart.setHeight(iNewChartHeight + "px");
				}
			} else if (oInnerChart.getDomRef().offsetWidth !== this.getDomRef().clientWidth) {
				// For table/non-vizFrame case, if width changes during resize event, force a rerender to have it fit 100% width
				this.rerender();
			}
		}
	}
};

/**
 * In the fullscreen mode it is necessary to remember the original height of the current chart
 * to be able to restore it later on in non fullscreen mode
 *
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._rememberOriginalHeight = function(chart) {
	var sId,
		sHeight;

	sId = chart.getId();
	if (jQuery.isFunction(chart.getHeight)) {
		sHeight = chart.getHeight();
	} else {
		sHeight = 0;
	}
	this._mOriginalVizFrameHeights[sId] = sHeight;
};

/**
 * Legend button pressed
 *
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._onLegendButtonPress = function() {
	if (this.getSelectedContent()) {
		var selectedChart = this.getSelectedContent().getContent();
		//only support if content has legendVisible property
		if (jQuery.isFunction(selectedChart.getLegendVisible)) {
			var legendOn = selectedChart.getLegendVisible();
			selectedChart.setLegendVisible(!legendOn);
			this.setShowLegend(!legendOn);
		} else {
			this.setShowLegend(!this.getShowLegend());
		}
	} else {
		this.setShowLegend(!this.getShowLegend());
	}
};

/**
 * Personalization button pressed
 *
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._oPersonalizationPress = function() {
	this.firePersonalizationPress();
};

/**
 * Switch Chart - i.e. default with bubble chart and click bar chart button
 *
 * @private
 * @param {String} chartId The ID of the chart to be searched
 */
sap.suite.ui.commons.ChartContainer.prototype._switchChart = function(chartId) {

	var oChart = this._findChartById(chartId);

	this._setSelectedContent(oChart);

	this.fireContentChange({
		selectedItemId : chartId
	}); // fire the change event with id of the newly selected item..
	this.rerender(); //invalidate();
};

/**
 * Collect all charts
 *
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._chartChange = function() {
	var aCharts = this.getContent();
	this._destroyButtons(this._aChartIcons);
	this._aChartIcons = [];
	if (this.getContent().length === 0) {
		this._oChartSegmentedButton.removeAllButtons();
		this._setDefaultOnSegmentedButton();
		this.switchChart(null);
	}
	if (aCharts) {
		for (var i = 0; i < aCharts.length; i++) {
			var innerChart = aCharts[i].getContent();
			// In case the content is not visible, skip this content.
			if (!aCharts[i].getVisible()) {
				continue;
			}
			if (innerChart.setVizProperties) {
				innerChart.setVizProperties({
					legend : {
						visible : this.getShowLegend()
					},
					sizeLegend : {
						visible : this.getShowLegend()
					}
				});
			}
			if (innerChart.setWidth) {
				innerChart.setWidth("100%");
			}
			if (jQuery.isFunction(innerChart.setHeight) && this._mOriginalVizFrameHeights[innerChart.getId()]) {
				innerChart.setHeight(this._mOriginalVizFrameHeights[innerChart.getId()]);
			}
			var oButtonIcon = new sap.m.Button({
				icon : aCharts[i].getIcon(),
				type : sap.m.ButtonType.Transparent,
				//fix the chart button and chart itself disappear when switch chart in full screen mode
				width: "3rem",
				tooltip : aCharts[i].getTitle(),
				customData : [new sap.ui.core.CustomData({
					key : 'chartId',
					value : innerChart.getId()
				})],
				press : jQuery.proxy(function(oEvent) {
					var sChartId = oEvent.getSource().getCustomData()[0].getValue();
					this._switchChart(sChartId);
				}, this)
			});
			this._aChartIcons.push(oButtonIcon);

			if (i === 0) {
				this._setSelectedContent(aCharts[i]);
				this._oActiveChartButton = oButtonIcon;
			}
		}
	}
	this._chartContentChange = false;
};

/**
 * Set selected content
 * @param {sap.ui.core.Control} obj The object to be set as currently viewed
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._setSelectedContent = function(obj) {
	if (obj === null) {
		this._oShowLegendButton.setVisible(false);
		return;
	}
	var oChart = obj.getContent();
	var sChartId = oChart.getId();
	var oRelatedButton = null;
	for (var i = 0; !oRelatedButton && i < this._aChartIcons.length; i++) {
		if (this._aChartIcons[i].getCustomData()[0].getValue() === sChartId &&
				oChart.getVisible() === true) {
			oRelatedButton = this._aChartIcons[i];
			this._oChartSegmentedButton.setSelectedButton(oRelatedButton);
			break;
		}
	}
	//show/hide the showLegend buttons
	var bShowChart = (oChart instanceof sap.viz.ui5.controls.VizFrame) || (jQuery.isFunction(oChart.setLegendVisible)); //hide legend icon if table, show if chart
	if (this.getShowLegendButton()){
		this._oShowLegendButton.setVisible(bShowChart);
	}
	var bShowZoom = (this.getShowZoom()) && (sap.ui.Device.system.desktop) && (oChart instanceof sap.viz.ui5.controls.VizFrame);
	this._oZoomInButton.setVisible(bShowZoom);
	this._oZoomOutButton.setVisible(bShowZoom);
	this._oSelectedContent = obj;
};

/**
 * Get chart inside the content aggregation by id
 *
 * @private
 * @param {String} id The ID of the content control being searched for
 * @returns {sap.ui.core.Control} The object found or null
 */
sap.suite.ui.commons.ChartContainer.prototype._findChartById = function(id) {
	var aObjects = this.getAggregation("content");
	if (aObjects) {
		for (var i = 0; i < aObjects.length; i++) {
			if (aObjects[i].getContent().getId() === id) {
				return aObjects[i];
			}
		}
	}
	return null;
};

/**
 * Adjusts customizable icons of overflow toolbar, displays chart buttons
 *
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._adjustIconsDisplay = function() {
	for (var i = 0; i < this._customIconsAll.length; i++ )	{
		this._oToolBar.addContent(this._customIconsAll[i]);
	}
	if (!this._firstTime) {
		this._oChartSegmentedButton.removeAllButtons();
	}

	var iLength = this._aChartIcons.length;
	if (iLength > 1) {
		for (var i = 0; i < iLength; i++) {
			this._oChartSegmentedButton.addButton(this._aChartIcons[i]);
		}
		this._oToolBar.addContent(this._oChartSegmentedButton);
	}

	if (this.getShowLegendButton()){
		this._oToolBar.addContent(this._oShowLegendButton);
	}
	if (this.getShowPersonalization()) {
		this._oToolBar.addContent(this._oPersonalizationButton);
	}
	if (this.getShowZoom() && (sap.ui.Device.system.desktop)) {
		this._oToolBar.addContent(this._oZoomInButton);
		this._oToolBar.addContent(this._oZoomOutButton);
	}
	if (this.getShowFullScreen()) {
		this._oToolBar.addContent(this._oFullScreenButton);
	}
};

/**
 * The first button inside the segmented button is only set as default if the
 * user did not click explicitly on another button inside the segmented button
 *
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._setDefaultOnSegmentedButton = function() {
	if (!this._bSegmentedButtonSaveSelectState) {
		this._oChartSegmentedButton.setSelectedButton(null);
	}
	this._bSegmentedButtonSaveSelectState = false;
};

/**
 * Adjust dimensionselector display
 *
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._adjustSelectorDisplay = function() {
	var dimensionSelectors = this.getDimensionSelectors();
	if (dimensionSelectors.length === 0) {
		this._oChartTitle.setVisible(true);
		this._oToolBar.addContent(this._oChartTitle);
		return;
	}

	for (var i = 0; i < dimensionSelectors.length; i++) {
		if (jQuery.isFunction(dimensionSelectors[i].setAutoAdjustWidth)) {
			dimensionSelectors[i].setAutoAdjustWidth(true);
		}
		this._oToolBar.insertContent(dimensionSelectors[i], i);
	}
};

/**
 * Adjust toolbar dimensionselector, customicons, buttons ...
 *
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._adjustDisplay = function() {
	this._oToolBar.removeAllContent();
	this._adjustSelectorDisplay();
	this._oToolBar.addContent(new sap.m.ToolbarSpacer());
	this._adjustIconsDisplay();
};

/**
 * @param  {sap.ui.base.Event} evt The SAPUI5 Event Object
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._handleMediaChange = function(evt) {
	this._currentRangeName = sap.ui.Device.media.getCurrentRange(sap.ui.Device.media.RANGESETS.SAP_STANDARD).name;
	this._adjustDisplay();
};

/**
 * Zoom in or out ChartContainer content
 *
 * @param {Boolean} zoomin Set to true to perform zoom-in action. Set to false (or omit) to zoom out.
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._zoom = function(zoomin) {
	var oChart = this.getSelectedContent().getContent();
	if (oChart instanceof sap.viz.ui5.controls.VizFrame) {
		if (zoomin) {
			oChart.zoom({"direction": "in"});
		} else {
			oChart.zoom({"direction": "out"});
		}
	}
	if (zoomin){
		this.fireCustomZoomInPress();
	} else {
		this.fireCustomZoomOutPress();
	}
};

/**
 * Buttons which are not needed anymore are destroyed here.
 *
 * @param {sap.ui.core.Control[]} buttons The buttons which need to be destroyed.
 * @private
 */
sap.suite.ui.commons.ChartContainer.prototype._destroyButtons = function(buttons) {
	buttons.forEach(function(oButton) {
		oButton.destroy();
	});
};
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2015 SAP SE. All rights reserved
	
 */
sap.ui.define([
	"sap/ui/core/Control", "sap/ui/core/Core", "sap/m/OverflowToolbar", "sap/m/OverflowToolbarLayoutData", "sap/m/OverflowToolbarPriority", "sap/m/ToolbarSpacer", "sap/m/FlexBox", "sap/m/FlexDirection", "sap/m/FlexJustifyContent",
	"sap/m/Button", "sap/m/ButtonType", "sap/m/SegmentedButton", "sap/m/Select", 
	"sap/ui/core/Item", "sap/m/ViewSettingsDialog", "sap/m/ViewSettingsCustomTab", "sap/m/PlacementType",
	"sap/m/CheckBox", "sap/ui/core/Orientation", "./AssociateContainer", "sap/gantt/legend/LegendContainer", "sap/gantt/misc/Utility", "sap/m/Slider", "sap/m/Popover"
], function (Control, Core, OverflowToolbar, OverflowToolbarLayoutData, OverflowToolbarPriority, ToolbarSpacer, FlexBox, FlexDirection, FlexJustifyContent,
		Button, ButtonType, SegmentedButton, Select, CoreItem, ViewSettingsDialog, ViewSettingsCustomTab, PlacementType, CheckBox,
		Orientation, AssociateContainer, LegendContainer, Utility, Slider, Popover) {
	"use strict";

	var Toolbar = Control.extend("sap.gantt.control.Toolbar", {
		metadata : {
			properties : {
				width : {type : "CSSSize", defaultValue: "100%"},
				height : {type : "CSSSize", defaultValue: "100%"},
				type: {type: "string", defaultValue: sap.gantt.control.ToolbarType.Global},
				sourceId:{type: "string"},
				zoomRate:{type: "float"},
				zoomInfo: {type: "object"},
				sliderStep: {type: "int"},
				enableTimeScrollSync: {type: "boolean", defaultValue: true},
				enableRowScrollSync: {type: "boolean", defaultValue: false},
				enableCursorLine: {type: "boolean", defaultValue: true},
				enableNowLine: {type: "boolean", defaultValue: true},
				enableVerticalLine: {type: "boolean", defaultValue: true},
				/*
				 * Configuration property.
				 */
				modes: {
					type: "array",
					defaultValue: [sap.gantt.config.DEFAULT_MODE]
				},
				mode: {
					type: "string",
					defaultValue: sap.gantt.config.DEFAULT_MODE_KEY
				},
				/*
				 * Configuration property.
				 */
				toolbarSchemes: {
					type: "array",
					defaultValue: [
						sap.gantt.config.DEFAULT_CONTAINER_TOOLBAR_SCHEME,
						sap.gantt.config.DEFAULT_GANTTCHART_TOOLBAR_SCHEME,
						sap.gantt.config.EMPTY_TOOLBAR_SCHEME
					]
				},
				/*
				 * Configuration property.
				 */
				hierarchies: {
					type: "array", 
					defaultValue: [sap.gantt.config.DEFAULT_HIERARCHY]
				},
				/*
				 * Configuration property.
				 */
				containerLayouts: {
					type: "array",
					defaultValue: [
						sap.gantt.config.DEFAULT_CONTAINER_SINGLE_LAYOUT,
						sap.gantt.config.DEFAULT_CONTAINER_DUAL_LAYOUT
					]
				}
			},
			aggregations : {
				legend: {type: "sap.ui.core.Control", multiple: false, visibility: "public"},
				customToolbarItems: {type: "sap.ui.core.Control", multiple: true, visibility: "public", singularName: "customToolbarItem"},
				_toolbar : {type: "sap.m.OverflowToolbar", multiple: false, visibility: "hidden"}
			},
			events: {
				sourceChange: {
					parameters: {
						id: {type: "string"}
					}
				},
				layoutChange: {
					parameters: {
						id: {type: "string"},
						value: {type: "string"}
					}
				},
				expandChartChange: {
					parameters: {
						action: {type: "string"},
						expandedChartSchemes: {type: "[]"}
					}
				},
				expandTreeChange: {
					parameters: {
						action: {type: "string"}
					}
				},
				zoomRateChange: {
					parameters:{
						zoomRate: {type : "float"}
					}
				},
				settingsChange: {
					parameters: {
						id: {type: "string"},
						value: {type: "boolean"}
					}
				},
				modeChange: {
					parameters: {
						mode: {type: "string"}
					}
				}
			}
		}
	});
	
	// shrinkable class name
	Toolbar.ToolbarItemPosition = {
		Left: "Left",
		Right: "Right"
	};

	Toolbar.prototype.init = function() {
		this._oToolbar = new OverflowToolbar({
			width: "auto",
			design: sap.m.ToolbarDesign.Auto
		});
		this.setAggregation("_toolbar", this._oToolbar, true);

		this._initCustomToolbarInfo();

		this._oModesConfigMap = {};
		this._oModesConfigMap[sap.gantt.config.DEFAULT_MODE_KEY] = sap.gantt.config.DEFAULT_MODE;

		this._oToolbarSchemeConfigMap = {};
		this._oToolbarSchemeConfigMap[sap.gantt.config.DEFAULT_CONTAINER_TOOLBAR_SCHEME_KEY] = sap.gantt.config.DEFAULT_CONTAINER_TOOLBAR_SCHEME;
		this._oToolbarSchemeConfigMap[sap.gantt.config.DEFAULT_GANTTCHART_TOOLBAR_SCHEME_KEY] = sap.gantt.config.DEFAULT_GANTTCHART_TOOLBAR_SCHEME;
		this._oToolbarSchemeConfigMap[sap.gantt.config.EMPTY_TOOLBAR_SCHEME_KEY] = sap.gantt.config.EMPTY_TOOLBAR_SCHEME;

		this._oHierarchyConfigMap = {};
		this._oHierarchyConfigMap[sap.gantt.config.DEFAULT_HIERARCHY_KEY] = sap.gantt.config.DEFAULT_HIERARCHY;

		this._oContainerLayoutConfigMap = {};
		this._oContainerLayoutConfigMap[sap.gantt.config.DEFAULT_CONTAINER_SINGLE_LAYOUT_KEY] = sap.gantt.config.DEFAULT_CONTAINER_SINGLE_LAYOUT;
		this._oContainerLayoutConfigMap[sap.gantt.config.DEFAULT_CONTAINER_DUAL_LAYOUT_KEY] = sap.gantt.config.DEFAULT_CONTAINER_DUAL_LAYOUT;

		this._oZoomSlider = null;
		this._iLastChartWidth = -1;
		
		this._iCustomItemInsertIndex = -1;
		this._aCustomItems = [];

		// iLiveChangeTimer is used to accumulate zoomRate change event in order to reduce shapes drawing cycle
		this._iLiveChangeTimer = -1;

		this._aTimers = [];
		this._oRb = sap.ui.getCore().getLibraryResourceBundle("sap.gantt");

	};

	Toolbar.prototype._initCustomToolbarInfo = function(){
		this._oItemConfiguration = {
			Left: [],
			Right: []
		};
		// pos 0 is list left controls, 1 is list of right controls
		this._oAllCustomItems = {
			Left: [],
			Right: []
		};
		this._iCustomItemInsertIndex = -1;
		this._aCustomItems = [];
	};

	/*
	 * This method happens after init run. It receives config from constructor.
	 * If it's a binding, the super method would resolve binding, and the right
	 * timing to access properties is after super call and before returning.
	 */
	Toolbar.prototype.applySettings = function (mSettings, oScope){
		if (this.getSourceId() && this.getType()) {
			this._resetAllCompositeControls();
		}

		var oRetVal = Control.prototype.applySettings.apply(this, arguments);
		return oRetVal;
	};

	Toolbar.prototype.setLegend = function (oLegendContainer){
		this.setAggregation("legend", oLegendContainer);

		if (!this._oLegendPop) {
			this._oLegendPop = new Popover({
				placement: PlacementType.Bottom,
				showArrow: false,
				showHeader: false
			});
		}

		if (oLegendContainer) {
			this._oLegendPop.removeAllContent();
			this._oLegendPop.addContent(oLegendContainer);
			var iOffsetX;
			if (Core.getConfiguration().getRTL() === true) {
				iOffsetX = 100;
			} else {
				var oLegend = sap.ui.getCore().byId(oLegendContainer.getContent());
				iOffsetX = 100 - parseInt(oLegend.getWidth(), 10);
			}
			this._oLegendPop.setOffsetX(iOffsetX);
		}
	};


	Toolbar.prototype.setZoomInfo = function(oZoomInfo) {
		if (oZoomInfo && oZoomInfo.iChartWidth > 0 && this._oZoomSlider) {
			var fMinZoomRate = oZoomInfo.determinedByChartWidth.fMinRate > oZoomInfo.determinedByConfig.fMinRate ?
					oZoomInfo.determinedByChartWidth.fMinRate : oZoomInfo.determinedByConfig.fMinRate,
			fMaxZoomRate = oZoomInfo.determinedByConfig.fMaxRate,
			fSuitableZoomRate = oZoomInfo.determinedByChartWidth.fSuitableRate ?
					oZoomInfo.determinedByChartWidth.fSuitableRate :
					oZoomInfo.determinedByConfig.fRate;

			var fFinalZoomRate = fSuitableZoomRate,
				oZoomSlider = this._oZoomSlider,
				iLastChartWidth = this._iLastChartWidth;

			oZoomSlider.setMin(Math.log(fMinZoomRate));
			oZoomSlider.setMax(Math.log(fMaxZoomRate));
			var fZoomRate = this.getProperty("zoomRate");
			if (fZoomRate && fZoomRate > 0) {
				fFinalZoomRate = fZoomRate;
			} else {
				if (iLastChartWidth === -1) {
					// the Last chart Width is -1 which is set in init method indicates that
					// This is the first time load, use the default suitable zoom rate
					fFinalZoomRate = fSuitableZoomRate;
				} else if (iLastChartWidth !== oZoomInfo.iChartWidth) {
					fFinalZoomRate = fMinZoomRate;
				}
				fFinalZoomRate = Math.max(fFinalZoomRate, oZoomSlider.getMin());
				fFinalZoomRate = Math.min(fFinalZoomRate, oZoomSlider.getMax());
				this.setProperty("zoomRate", fFinalZoomRate);
			}
			this.setProperty("zoomInfo", oZoomInfo);

			oZoomSlider.setValue(Math.log(fFinalZoomRate));
			oZoomSlider.setStep((oZoomSlider.getMax() - oZoomSlider.getMin()) / this.getSliderStep());
			this.fireZoomRateChange({ zoomRate: fFinalZoomRate});
			this._iLastChartWidth = oZoomInfo.iChartWidth;
			
		}
		return this;
	};

	Toolbar.prototype.setMode = function(sMode) {
		this.setProperty("mode", sMode);
		//update mode button value, when the toolbar is empty, then there is no _oModeSegmentButton.
		if (this._oModeSegmentButton) {
			this._oModeSegmentButton.setSelectedButton(this._oModeButtonMap[sMode]);
		}
		return this;
	};

	Toolbar.prototype.setHierarchies = function (aHierarchies) {
		this.setProperty("hierarchies", aHierarchies);
		this._oHierarchyConfigMap = {};
		if (aHierarchies) {
			for (var i = 0; i < aHierarchies.length; i++) {
				this._oHierarchyConfigMap[aHierarchies[i].getKey()] = aHierarchies[i];
			}
		}
		this._resetAllCompositeControls();
		return this;
	};

	Toolbar.prototype.setContainerLayouts = function (aContainerLayouts) {
		this.setProperty("containerLayouts", aContainerLayouts);
		this._oContainerLayoutConfigMap = {};
		if (aContainerLayouts) {
			for (var i = 0; i < aContainerLayouts.length; i++) {
				this._oContainerLayoutConfigMap[aContainerLayouts[i].getKey()] = aContainerLayouts[i];
			}
		}
		this._resetAllCompositeControls();
		return this;
	};

	Toolbar.prototype.setModes = function (aModes) {
		this.setProperty("modes", aModes);
		this._oModesConfigMap = {};
		if (aModes) {
			for (var i = 0; i < aModes.length; i++) {
				this._oModesConfigMap[aModes[i].getKey()] = aModes[i];
			}
		}
		return this;
	};

	Toolbar.prototype.setToolbarDesign = function (sToolbarDesign) {
		this._oToolbar.setDesign(sToolbarDesign);
		return this;
	};
	Toolbar.prototype.setToolbarSchemes = function (aToolbarSchemes) {
		this.setProperty("toolbarSchemes", aToolbarSchemes);
		this._oToolbarSchemeConfigMap = {};
		if (aToolbarSchemes) {
			for (var i = 0; i < aToolbarSchemes.length; i++) {
				this._oToolbarSchemeConfigMap[aToolbarSchemes[i].getKey()] = aToolbarSchemes[i];
			}
		}
		this._resetAllCompositeControls();
		return this;
	};

	Toolbar.prototype.setSourceId = function (sSourceId) {
		this.setProperty("sourceId", sSourceId);
		this._resetAllCompositeControls();
		return this;
	};

	Toolbar.prototype.setType = function (sType) {
		this.setProperty("type", sType);
		this._resetAllCompositeControls();
		return this;
	};

	Toolbar.prototype.addCustomToolbarItem = function (oCustomToolbarItem) {

		if (this._iCustomItemInsertIndex == -1) {
			// -1 means no other items found, so put the item at first!
			// and move the index cursor to next
			this._oToolbar.insertContent(oCustomToolbarItem, 0);
			this._iCustomItemInsertIndex++;

		} else {
			this._oToolbar.insertContent(oCustomToolbarItem, this._iCustomItemInsertIndex + 1);
			this._iCustomItemInsertIndex++;
		}
		this._aCustomItems.push(oCustomToolbarItem);
		return this;
	};

	Toolbar.prototype.insertCustomToolbarItem = function (oCustomToolbarItem, iIndex) {

		var iMaxLength = this._aCustomItems.length;
		if (iIndex >= iMaxLength) {
			iIndex = iMaxLength;
		}
		if (this._iCustomItemInsertIndex === -1) {
			//-1 means no other items found, put the item at first
			this._oToolbar.insertContent(oCustomToolbarItem, 0);
			this._aCustomItems.push(oCustomToolbarItem);
		} else {
			//this._iCustomItemInsertIndex - this._aCustomItems.length + 1 is the start position of the custom item
			this._oToolbar.insertContent(oCustomToolbarItem, this._iCustomItemInsertIndex - this._aCustomItems.length + 1 + iIndex);
			this._aCustomItems.splice(iIndex, 0, oCustomToolbarItem);
		}
		this._iCustomItemInsertIndex++;
		return this;
	};

	Toolbar.prototype.removeCustomToolbarItem = function (vCustomToolbarItem) {
		if (this._aCustomItems.length === 0) {
			return this._aCustomItems;
		}
		if ((typeof vCustomToolbarItem) === "number") {
			var iCustomItemCount = this._aCustomItems.length;
			var iRemoveCustomIndex = vCustomToolbarItem > iCustomItemCount ? iCustomItemCount : vCustomToolbarItem;
			this._oToolbar.removeContent(this._iCustomItemInsertIndex - iCustomItemCount + iRemoveCustomIndex + 1);
			this._iCustomItemInsertIndex--;
			return this._aCustomItems.splice(iRemoveCustomIndex, 1);
		} else if (vCustomToolbarItem) {
			this._oToolbar.removeContent(vCustomToolbarItem);
			this._iCustomItemInsertIndex--;
			return this._aCustomItems.splice(jQuery.inArray(vCustomToolbarItem, this._aCustomItems), 1);
		}
	};

	Toolbar.prototype.removeAllCustomToolbarItems = function () {
		var aRemovedItems = [];
		for (var iIndex = 0; iIndex < this._aCustomItems.length; iIndex++) {
			aRemovedItems.push(this._oToolbar.removeContent(this._aCustomItems[iIndex]));
		}
		this._iCustomItemInsertIndex = this._iCustomItemInsertIndex - this._aCustomItems.length;
		this._aCustomItems.splice(0, this._aCustomItems.length);
		return aRemovedItems;
	};

	Toolbar.prototype._resetAllCompositeControls = function() {
		// determine this._sToolbarSchemeKey, this._sInitMode and this._oToolbarScheme
		this._determineToolbarSchemeConfig(this.getSourceId());
		this._destroyCompositeControls();
		if (!this._sToolbarSchemeKey) {
			return;
		}
		// sort group config into this._oItemConfiguration
		this._resolvePositions();

		var iIndex,
			oContent,
			sLeft = Toolbar.ToolbarItemPosition.Left,
			sRight = Toolbar.ToolbarItemPosition.Right;
		var aLeftItemsConfig = this._oItemConfiguration[sLeft];
		for (iIndex = 0; iIndex < aLeftItemsConfig.length; iIndex++) {
			if (aLeftItemsConfig[iIndex]) {
				// the index might come consecutive 
				this._createCompositeControl(sLeft, iIndex, aLeftItemsConfig[iIndex]);
			}
		}
		
		var aRightItemsConfig = this._oItemConfiguration[sRight];
		for (iIndex = 0; iIndex < aRightItemsConfig.length; iIndex++) {
			if (aRightItemsConfig[iIndex]) {
				this._createCompositeControl(sRight, iIndex, aRightItemsConfig[iIndex]);
			}
		}
		
		var fnAddToolbarContent = function (oContent) {
			if (jQuery.isArray(oContent)) {
				for (var m = 0; m < oContent.length; m++) {
					this._oToolbar.addContent(oContent[m]);
				}
			} else if (oContent) {
				this._oToolbar.addContent(oContent);
			}
		};

		// add left items
		for (iIndex = 0; iIndex < this._oAllCustomItems[sLeft].length; iIndex++) {
			oContent = this._oAllCustomItems[sLeft][iIndex];
			fnAddToolbarContent.call(this, oContent);
		}
		// add spacer
		if (this._oAllCustomItems[sLeft].length !== 0 || this._oAllCustomItems[sRight].length !== 0) {
			this._oToolbar.addContent(new ToolbarSpacer());
		}
		// add right items, reverse order
		for (iIndex = this._oAllCustomItems[sRight].length - 1; iIndex >= 0; iIndex--) {
			oContent = this._oAllCustomItems[sRight][iIndex];
			fnAddToolbarContent.call(this, oContent);
		}
		
		var oZoomInfo = this.getProperty("zoomInfo");
		if (oZoomInfo) {
			this.setZoomInfo(oZoomInfo);
		}
	};

	Toolbar.prototype.getAllToolbarItems = function () {
		return this._oToolbar.getContent();
	};

	Toolbar.prototype._determineToolbarSchemeConfig = function (sSourceId) {
		this._sToolbarSchemeKey = null;
		// determine toolbarSchemeId
		if (this.getType() === sap.gantt.control.ToolbarType.Global && this._oContainerLayoutConfigMap[sSourceId]) {
			this._sToolbarSchemeKey = this._oContainerLayoutConfigMap[sSourceId].getToolbarSchemeKey();
			this._sInitMode = this.getMode() != sap.gantt.config.DEFAULT_MODE_KEY ? this.getMode() : this._oContainerLayoutConfigMap[sSourceId].getActiveModeKey();
		} else if (this.getType() === sap.gantt.control.ToolbarType.Local && this._oHierarchyConfigMap[sSourceId]) {
			this._sToolbarSchemeKey = this._oHierarchyConfigMap[sSourceId].getToolbarSchemeKey();
			this._sInitMode = this.getMode() != sap.gantt.config.DEFAULT_MODE_KEY ? this.getMode() : this._oHierarchyConfigMap[sSourceId].getActiveModeKey();
		}
		// determine toolbar scheme config
		this._oToolbarScheme = this._oToolbarSchemeConfigMap[this._sToolbarSchemeKey];
		if (this._oToolbarScheme && this._oToolbarScheme.getProperty("toolbarDesign")) {
			this.setToolbarDesign(this._oToolbarScheme.getProperty("toolbarDesign"));
		}
	};

	Toolbar.prototype._destroyCompositeControls = function() {
		this._oToolbar.removeAllContent();
		this._initCustomToolbarInfo();
	};
	
	Toolbar.prototype._resolvePositions = function() {
		if (this._oToolbarScheme) {
			jQuery.each(this._oToolbarScheme.getMetadata().getAllProperties(), function (sProperty) {
				if (sProperty !== "key" && sProperty !== "toolbarDesign") {
					var oProperty = this._oToolbarScheme.getProperty(sProperty);
					if (oProperty) {
						var oPosition = this._parsePosition(oProperty.getPosition());
						this._oItemConfiguration[oPosition.position][oPosition.idx] = $.extend({}, {groupId: sProperty}, oProperty);
					}
				}
			}.bind(this));
			
			var oSchemeConfiguration = this._oItemConfiguration;
			var aAlignments = Object.keys(oSchemeConfiguration);
			aAlignments.forEach(function(sAlignmentKey) {
				var aSchemes = oSchemeConfiguration[sAlignmentKey],
					newSchemes = [];
				
				var aSchemeSortedKeys = Object.keys(aSchemes).sort();
				aSchemeSortedKeys.forEach(function(sSchemeKey, aSelf) {
					newSchemes.push(aSchemes[sSchemeKey]);
				});
				
				oSchemeConfiguration[sAlignmentKey] = newSchemes;
			});
		}
		
	};

	Toolbar.prototype._parsePosition = function(sPosition) {
		return {
			position: sPosition.toUpperCase().substr(0, 1) === "L" ? Toolbar.ToolbarItemPosition.Left : Toolbar.ToolbarItemPosition.Right,
			idx: parseInt(sPosition.substr(1, sPosition.length - 1), 10)
		};
	};

	Toolbar.prototype._createCompositeControl = function(sPosition, iIndex, oGroupConfig) {
		var vControl;
		switch (oGroupConfig.groupId) {
			case "sourceSelect":
				vControl = this._genSourceSelectGroup(oGroupConfig);
				break;
			case "layout":
				vControl = this._genLayoutGroup(oGroupConfig);
				break;
			case "expandChart":
				vControl = this._genExpandChartGroup(oGroupConfig);
				break;
			case "expandTree":
				vControl = this._genExpandTreeGroup(oGroupConfig);
				break;
			case "customToolbarItems":
				vControl = this._genCustomToolbarItemGroup(sPosition, oGroupConfig);
				break;
			case "mode":
				vControl = this._genModeButtonGroup(oGroupConfig);
				break;
			case "timeZoom":
				vControl = this._genZoomSliderGroupControls(oGroupConfig);
				break;
			case "legend":
				vControl = this._genLegend(oGroupConfig);
				break;
			case "settings":
				vControl = this._genSettings(oGroupConfig);
				break;
			default:
				break;
		}
		if (vControl) {
			this._oAllCustomItems[sPosition] = this._oAllCustomItems[sPosition].concat(vControl);
		}
	};

	Toolbar.prototype._genSourceSelectGroup = function(oGroupConfig) {
		var sSourceId = this.getSourceId();
		// that is toolbar itself
		var that = this;
		var aSource;

		this._oSourceSelectBox = new Select({
			layoutData: new OverflowToolbarLayoutData({priority: oGroupConfig.getOverflowPriority()}),
			width: "200px",
			change: function (oEvent) {
				var oItem = oEvent.getParameter("selectedItem");
				var oSourceConfig = oItem.oSourceConfig;
				that.fireSourceChange({
					id: oItem.getKey(),
					config: oSourceConfig
				});
			}
		});

		switch (this.getType()){
			case sap.gantt.control.ToolbarType.Global:
				aSource = this.getContainerLayouts();
				this._oSourceSelectBox.setTooltip(this._oRb.getText("TLTP_GLOBAL_HIERARCHY_RESOURCES"));
				break;
			case sap.gantt.control.ToolbarType.Local:
				aSource = this.getHierarchies();
				this._oSourceSelectBox.setTooltip(this._oRb.getText("TLTP_LOCAL_HIERARCHY_RESOURCES"));
				break;
			default:
				return null;
		}

		var oCoreItem;
		for (var iIndex = 0; iIndex < aSource.length; iIndex++) {
			oCoreItem = new CoreItem({
				key: aSource[iIndex].getKey(),
				text: aSource[iIndex].getText()
			});
			oCoreItem.oSourceConfig = aSource[iIndex];
			this._oSourceSelectBox.addItem(oCoreItem);

			if (oCoreItem.getKey() === sSourceId) {
				this._oSourceSelectBox.setSelectedItem(oCoreItem);
			}
		}

		return this._oSourceSelectBox;
	};

	Toolbar.prototype._genLayoutGroup = function(oGroupConfig) {
		if (this.getType === "LOCAL") {
			return null;
		}

		var that = this,
			aHierarchies = this.getHierarchies(),
			oCoreItem,
			i;

		// addGanttChart Select
		this._oAddGanttChartSelect = new Select({
			icon : "sap-icon://add",
			type: sap.m.SelectType.IconOnly,
			autoAdjustWidth: true,
			tooltip: this._oRb.getText("TLTP_ADD_GANTTCHART"),
			forceSelection: false,
			layoutData: new OverflowToolbarLayoutData({priority: oGroupConfig.getOverflowPriority()}),
			change: function (oEvent) {
				if (oEvent.getParameter("selectedItem")) {
					that.fireLayoutChange({
						id: "add",
						value: {
							hierarchyKey: oEvent.getParameter("selectedItem").getKey(),
							hierarchyConfig: oEvent.getParameter("selectedItem").data("hierarchyConfig")
						}
					});
					oEvent.getSource().setSelectedItemId("");
				}
			}
		});
		// add items if exist
		if (aHierarchies && aHierarchies.length > 0) {
			for (i = 0; i < aHierarchies.length; i++) {
				oCoreItem = new CoreItem({
					text: aHierarchies[i].getText(),
					key: aHierarchies[i].getKey()
				});
				oCoreItem.data("hierarchyConfig", aHierarchies[i]);
				this._oAddGanttChartSelect.addItem(oCoreItem);
			}
		}

		// lessGanttChartSelect
		this._oLessGanttChartSelect = new Select({
			icon: "sap-icon://less",
			type: sap.m.SelectType.IconOnly,
			tooltip: this._oRb.getText("TLTP_REMOVE_GANTTCHART"),
			autoAdjustWidth: true,
			forceSelection: false,
			layoutData: new OverflowToolbarLayoutData({priority: oGroupConfig.getOverflowPriority()}),
			change: function (oEvent) {
				if (oEvent.getParameter("selectedItem")) {
					that.fireLayoutChange({
						id: "less",
						value: {
							hierarchyKey: oEvent.getParameter("selectedItem").getKey(),
							hierarchyConfig: oEvent.getParameter("selectedItem").data("hierarchyConfig"),
							ganttChartIndex: oEvent.getParameter("selectedItem").data("ganttChartIndex")
						}
					});
				}
			}
		});
		this._oLessGanttChartSelect.addEventDelegate({
			onclick: this._fillLessGanttChartSelectItem
		}, this);

		// VH Layout Button
		var sIcon = this._oContainerLayoutConfigMap[this.getSourceId()].getOrientation() === Orientation.Vertical ?
				"sap-icon://resize-vertical" : "sap-icon://resize-horizontal";
		this._oVHButton = new Button({
			icon: sIcon,
			tooltip: this._oRb.getText("TLTP_SWITCH_GANTTCHART"),
			type: oGroupConfig.getEnableRichStyle() ? ButtonType.Emphasized : ButtonType.Default,
			layoutData: new OverflowToolbarLayoutData({priority: oGroupConfig.getOverflowPriority()}),
			press: function (oEvent) {
				switch (this.getIcon()){
					case "sap-icon://resize-vertical":
						this.setIcon("sap-icon://resize-horizontal");
						that.fireLayoutChange({
							id: "orientation",
							value: Orientation.Horizontal
						});
						break;
					case "sap-icon://resize-horizontal":
						this.setIcon("sap-icon://resize-vertical");
						that.fireLayoutChange({
							id: "orientation",
							value: Orientation.Vertical
						});
						break;
					default:
						break;
				}
			}
		});

		// Segmented Button
		this._oLayoutButton = [this._oAddGanttChartSelect, this._oLessGanttChartSelect, this._oVHButton];

		return this._oLayoutButton;
	};
	
	Toolbar.prototype._fillLessGanttChartSelectItem = function () {
		var aGanttCharts = this.data("holder").getGanttCharts(),
			oItem;

		this._oLessGanttChartSelect.removeAllItems();
		if (aGanttCharts && aGanttCharts.length > 0) {
			for (var i = 0; i < aGanttCharts.length; i++) {
				oItem = new CoreItem({
					text: this._oHierarchyConfigMap[aGanttCharts[i].getHierarchyKey()].getText(),
					key: aGanttCharts[i].getHierarchyKey()
				});
				oItem.data("hierarchyConfig",
						this._oHierarchyConfigMap[aGanttCharts[i].getHierarchyKey()]);
				oItem.data("ganttChartIndex", i);
				this._oLessGanttChartSelect.insertItem(oItem, i);
			}
		}
	};

	Toolbar.prototype._genExpandChartGroup = function (oGroupConfig) {
		this._aChartExpandButtons = [];

		var fnPressEventHanlder =  function(oEvent) {
			this.fireExpandChartChange({
				isExpand: oEvent.getSource().data("isExpand"),
				expandedChartSchemes: oEvent.getSource().data("chartSchemeKeys")
			});
		};

		var aExpandChartButtonConfig = oGroupConfig.getExpandCharts(),
			oButton;
		for (var i = 0; i < aExpandChartButtonConfig.length; i++) {
			var oConfig = aExpandChartButtonConfig[i];
			
			oButton = new Button({
				icon: oConfig.getIcon(),
				tooltip: oConfig.getTooltip(),
				layoutData: new OverflowToolbarLayoutData({priority: oGroupConfig.getOverflowPriority()}),
				press: fnPressEventHanlder.bind(this),
				type: oGroupConfig.getEnableRichType() && oConfig.getIsExpand() ?
						ButtonType.Emphasized : ButtonType.Default,
				customData : [
					new sap.ui.core.CustomData({
						key : "isExpand",
						value : oConfig.getIsExpand()
					}),
					new sap.ui.core.CustomData({
						key : "chartSchemeKeys",
						value : oConfig.getChartSchemeKeys()
					})
				]
			});
			if (oGroupConfig.getShowArrowText()) {
				oButton.setText(oConfig.getIsExpand() ? "ꜜ" : "ꜛ");
				//"￬" : "￪",// "⬇" : "⬆",//"⤓" : "⤒",//"⇊" : "⇈",//"↓" : "↑", //"⇩" : "⇧"
			}
			this._aChartExpandButtons.push(oButton);
		}
		return this._aChartExpandButtons;
	};

	Toolbar.prototype._genCustomToolbarItemGroup = function (sPosition, oGroupConfig) {

		if (this._iCustomItemInsertIndex === -1) {
			// Because the order had been sorted, the position for the custom tool bar item
			// is right after the previous items.
			var iTotalBeforeLength = this._oAllCustomItems[sPosition].length;
			if (iTotalBeforeLength === 0) {
				// If there is no item at all before custom items, set the cursor to -1
				// It's not only an index but also a flag to indicate the current situation.
				this._iCustomItemInsertIndex = -1;
			} else {
				// Otherwise, the position is the end of the previous items.
				this._iCustomItemInsertIndex = iTotalBeforeLength - 1;
			}
		}
		return this._aCustomItems;
	};

	Toolbar.prototype._genExpandTreeGroup = function (oGroupConfig) {
		var that = this; // tool bar itself
		this._oTreeGroup = [new Button({
				icon: "sap-icon://expand",
				tooltip: this._oRb.getText("TLTP_EXPAND"),
				layoutData: new OverflowToolbarLayoutData({priority: oGroupConfig.getOverflowPriority()}),
				press: function (oEvent) {
					that.fireExpandTreeChange({
						action: "expand"
					});
				}
			}), new Button({
				icon: "sap-icon://collapse",
				tooltip: this._oRb.getText("TLTP_COLLAPSE"),
				layoutData: new OverflowToolbarLayoutData({priority: oGroupConfig.getOverflowPriority()}),
				press: function (oEvent) {
					that.fireExpandTreeChange({
						action: "collapse"
					});
				}
			})];
		return this._oTreeGroup;
	};

	Toolbar.prototype._genModeButtonGroup = function (oGroupConfig) {
		var fnModeButtonGroupSelectHandler = function(oEvent) {
			var selected = oEvent.getParameter("button");
			this.fireModeChange({
				mode: selected.data("mode")
			});
		};
		this._oModeSegmentButton = new SegmentedButton({select: fnModeButtonGroupSelectHandler.bind(this)});
		this._oModeButtonMap = {};	
		var fnJqueryeachFunction =  function (iIndex, sMode) {
			if (this._oModesConfigMap[sMode]) {
				var oButton = new Button({
					icon: this._oModesConfigMap[sMode].getIcon(),
					activeIcon: this._oModesConfigMap[sMode].getActiveIcon(),
					tooltip: this._oModesConfigMap[sMode].getText(),
					layoutData: new OverflowToolbarLayoutData({priority: oGroupConfig.getOverflowPriority()}),
					customData : [
						new sap.ui.core.CustomData({
							key : "mode",
							value : sMode
						})
					]
				});
				this._oModeButtonMap[sMode] = oButton;
				this._oModeSegmentButton.addButton(oButton);
			}
		};
		jQuery.each(oGroupConfig.getModeKeys(), fnJqueryeachFunction.bind(this));
		if (this._sInitMode) {
			this._oModeSegmentButton.setSelectedButton(this._oModeButtonMap[this._sInitMode]);
		}
		return this._oModeSegmentButton;
	};


	Toolbar.prototype._genZoomSliderGroupControls = function (oGroupConfig) {
		

		var oLayoutData = new OverflowToolbarLayoutData({
			priority: oGroupConfig.getOverflowPriority()
		});

		var fnCalculateZoomRate = function(fSliderValue) {
			return Math.pow(Math.E, fSliderValue);
		};

		var fnFireZoomRateChange = function(fZoomRate) {
			jQuery.sap.clearDelayedCall(this._iLiveChangeTimer);
			this._iLiveChangeTimer = -1;

			var fLastZoomRate = this.getZoomRate();
			this.setProperty("zoomRate", fZoomRate);
			if (fZoomRate === fLastZoomRate) {
				return ;
			}

			this.fireZoomRateChange({ zoomRate: fZoomRate });
			jQuery.sap.log.debug("Toolbar Zoom Rate was changed, zoomRate is: " + fZoomRate);
		};

		var oZoomSlider = new Slider({
			width: "200px",
			layoutData: oLayoutData,
			liveChange: function(oEvent) {
				var fZoomRate = fnCalculateZoomRate(oEvent.getSource().getValue());
				// Clear the previous accumulated event
				jQuery.sap.clearDelayedCall(this._iLiveChangeTimer);
				this._iLiveChangeTimer = jQuery.sap.delayedCall(200, this, fnFireZoomRateChange, [fZoomRate]);
			}.bind(this)
		});

		var fnZoomButtonPressHandler = function(bZoomIn) {
			return function(oEvent){
				var fZoomRate = 0.0, 
					sSliderValue = 0.0;
				if (bZoomIn) {
					sSliderValue = this._oZoomSlider.stepUp(1).getValue();
				} else {
					sSliderValue = this._oZoomSlider.stepDown(1).getValue();
				}
				fZoomRate = fnCalculateZoomRate(sSliderValue);
				this._oZoomSlider.setValue(Math.log(fZoomRate));

				this._iLiveChangeTimer = jQuery.sap.delayedCall(200, this, fnFireZoomRateChange, [fZoomRate]);
			};
		};

		var oZoomInButton = new sap.m.Button({
			icon: "sap-icon://zoom-in",
			tooltip: this._oRb.getText("TLTP_SLIDER_ZOOM_IN"),
			layoutData: oLayoutData.clone(),
			press: fnZoomButtonPressHandler(true /**bZoomIn*/).bind(this)
		});

		var oZoomOutButton = new Button({
			icon: "sap-icon://zoom-out",
			tooltip: this._oRb.getText("TLTP_SLIDER_ZOOM_OUT"),
			layoutData: oLayoutData.clone(),
			press: fnZoomButtonPressHandler(false /**bZoomIn*/).bind(this)
		});
		this._oZoomSlider = oZoomSlider;
		return [oZoomInButton, oZoomSlider, oZoomOutButton];
	};

	Toolbar.prototype._genLegend = function (oGroupConfig) {
		if (!this._oLegendPop) {
			this._oLegendPop = new Popover({
				placement: PlacementType.Bottom,
				showArrow: false,
				showHeader: false
			});
		}

		if (this.getLegend()) {
			this._oLegendPop.removeAllContent();
			this._oLegendPop.addContent(this.getLegend());
		}
		
		this._oLegendButton = new Button({
			icon: "sap-icon://legend",
			tooltip: this._oRb.getText("TLTP_SHOW_LEGEND"),
			layoutData: new OverflowToolbarLayoutData({priority: oGroupConfig.getOverflowPriority()}),
			press: function (oEvent) {
				var oLegendPop = this._oLegendPop;
				if (oLegendPop.isOpen()){
					oLegendPop.close();
				} else {
					oLegendPop.openBy(this._oLegendButton);
				}
			}.bind(this)
		});
		return this._oLegendButton;
	};

	Toolbar.prototype._genSettings = function (oGroupConfig) {
		var aSettingGroupItems = oGroupConfig.getItems() || [];

		var that = this;

		var aAllSettingItems = aSettingGroupItems.map(function(oGroupItem){
			return new CheckBox({
				name: oGroupItem.getKey(),
				text: oGroupItem.getDisplayText(),
				tooltip: oGroupItem.getTooltip(),
				selected: oGroupItem.getChecked()
			}).addStyleClass("sapUiSettingBoxItem");
		});

		// Need set the old setting state on the toolbar instance for reference
		this._aOldSettingState = aAllSettingItems.map(function(oItem){
			return oItem.getSelected();
		});
		
		this._setSettingItemStates(aAllSettingItems);
		
		this._oSettingsBox = new FlexBox({
			direction: FlexDirection.Column,
			items: aAllSettingItems
		}).addStyleClass("sapUiSettingBox");

		this._oSettingsDialog = new ViewSettingsDialog({
			title: this._oRb.getText("SETTINGS_DIALOG_TITLE"),
			customTabs: [new ViewSettingsCustomTab({content: this._oSettingsBox})],
			confirm: function() {
				var aSettingItems = /*that.aSharedSettingItemStatus ? 
						that.aSharedSettingItemStatus : */this._oSettingsBox.getItems();
				var parameters = [];
				for (var i = 0; i < aSettingItems.length; i++) {
					parameters.push({
						id: aSettingItems[i].getName(),
						value: aSettingItems[i].getSelected()
					});
					that._aOldSettingState[i] = aSettingItems[i].getSelected();
				}
				//store the custom setting item status in toolbar to keep the data consistency when switching views
				that.aCustomSettingItems = that._getCustomSettingItems(aSettingItems);
				this.fireSettingsChange(parameters);
			}.bind(this),
			cancel: function() {
				// when cancel, the selected state should be restored when reopen
				that._setSettingItemStates(aAllSettingItems);
				that._restoreCustomOldStates(aAllSettingItems);
			}
		});
		
		this._oSettingsButton = new Button({
			icon: "sap-icon://action-settings",
			tooltip: this._oRb.getText("TLTP_CHANGE_SETTINGS"),
			layoutData: new OverflowToolbarLayoutData({priority: oGroupConfig.getOverflowPriority()}),
			press: function (oEvent) {
				this._oSettingsDialog.open();
			}.bind(this)
		});

		return this._oSettingsButton;
	};
	
	Toolbar.prototype._setSettingItemStates = function (aAllSettingItems) {
		for (var i = 0; i < aAllSettingItems.length; i++) {
			switch (aAllSettingItems[i].getName()) {
			case sap.gantt.config.SETTING_ITEM_ENABLE_NOW_LINE_KEY:
				aAllSettingItems[i].setSelected(this.getEnableNowLine());
				break;
			case sap.gantt.config.SETTING_ITEM_ENABLE_CURSOR_LINE_KEY:
				aAllSettingItems[i].setSelected(this.getEnableCursorLine());
				break;
			case sap.gantt.config.SETTING_ITEM_ENABLE_VERTICAL_LINE_KEY:
				aAllSettingItems[i].setSelected(this.getEnableVerticalLine());
				break;
			case sap.gantt.config.SETTING_ITEM_ENABLE_TIME_SCROLL_SYNC_KEY:
				aAllSettingItems[i].setSelected(this.getEnableTimeScrollSync());
				break;
			case sap.gantt.config.SETTING_ITEM_ROW_SCROLL_SYNC_KEY:
				aAllSettingItems[i].setSelected(this.getEnableRowScrollSync());
				break;
			default:
				this._handleCustomSettingItemStates(aAllSettingItems[i]);
				break;
			}
		}
	};
	//need to loop and find custom setting items and set them here
	Toolbar.prototype._handleCustomSettingItemStates = function (settingItem) {
		if (this.aCustomSettingItems && this.aCustomSettingItems.length > 0) {
			for (var j = 0; j < this.aCustomSettingItems.length; j++) {
				if (settingItem.getName() === this.aCustomSettingItems[j].getName()) {
					settingItem.setSelected(this.aCustomSettingItems[j].getSelected());
					break;
				}
			}
		}
	};
	//need to restore the old custom setting item status if canceled.
	Toolbar.prototype._restoreCustomOldStates = function (aAllSettingItems) {
		var settingItemLength = sap.gantt.config.DEFAULT_TOOLBAR_SETTING_ITEMS.length;
		for (var i = settingItemLength; i < aAllSettingItems.length; i++){
			aAllSettingItems[i].setSelected(this._aOldSettingState[i]);
		}

	};
	
	Toolbar.prototype._getCustomSettingItems = function (aSettingItems) {
		var customSettingItems = [];
		var settingItemLength = sap.gantt.config.DEFAULT_TOOLBAR_SETTING_ITEMS.length;
		for (var i = settingItemLength; i < aSettingItems.length; i++){
			customSettingItems.push(aSettingItems[i]);
		}
		return customSettingItems;
	};

	Toolbar.prototype.getToolbarSchemeKey = function () {
		return this._sToolbarSchemeKey;
	};
	
	Toolbar.prototype.setEnableNowLine = function(bEnableNowLine) {
		this.setProperty("enableNowLine", bEnableNowLine);
		if (this._oSettingsBox && this._oSettingsBox.getItems().length > 0) {
			this._setSettingItemProperties(sap.gantt.config.SETTING_ITEM_ENABLE_NOW_LINE_KEY, bEnableNowLine);
		}
		return this;
	};
	
	Toolbar.prototype.setEnableCursorLine = function(bEnableCursorLine) {
		this.setProperty("enableCursorLine", bEnableCursorLine);
		if (this._oSettingsBox && this._oSettingsBox.getItems().length > 0) {
			this._setSettingItemProperties(sap.gantt.config.SETTING_ITEM_ENABLE_CURSOR_LINE_KEY, bEnableCursorLine);
		}
		return this;
	};
	
	Toolbar.prototype.setEnableVerticalLine = function(bEnableVerticalLine) {
		this.setProperty("enableVerticalLine", bEnableVerticalLine);
		if (this._oSettingsBox && this._oSettingsBox.getItems().length > 0) {
			this._setSettingItemProperties(sap.gantt.config.SETTING_ITEM_ENABLE_VERTICAL_LINE_KEY, bEnableVerticalLine);
		}
		return this;
	};
	
	Toolbar.prototype.setEnableRowScrollSync = function(bEnableRowScrollSync) {
		this.setProperty("enableRowScrollSync", bEnableRowScrollSync);
		if (this._oSettingsBox && this._oSettingsBox.getItems().length > 0) {
			this._setSettingItemProperties(sap.gantt.config.SETTING_ITEM_ROW_SCROLL_SYNC_KEY, bEnableRowScrollSync);
		}
		return this;
	};
	
	Toolbar.prototype.setEnableTimeScrollSync = function(bEnableTimeScrollSync) {
		this.setProperty("enableTimeScrollSync", bEnableTimeScrollSync);
		if (this._oSettingsBox && this._oSettingsBox.getItems().length > 0) {
			this._setSettingItemProperties(sap.gantt.config.SETTING_ITEM_ENABLE_TIME_SCROLL_SYNC_KEY, bEnableTimeScrollSync);
		}
		return this;
	};
	
	Toolbar.prototype._setSettingItemProperties = function(settingItemKey, settingItemStatus) {
		var settingItems = this._oSettingsBox.getItems();
		for (var i = 0; i < settingItems.length; i++) {
			if (settingItems[i].getName() === settingItemKey) {
				settingItems[i].setSelected(settingItemStatus);
				break;
			}	
		}
	};

	Toolbar.prototype.exit = function () {
		if (this._oLegendPop) {
			this._oLegendPop.destroy(false);
		}
		if (this._oSettingsPop) {
			this._oSettingsPop.destroy(false);
		}
	};

	return Toolbar;
}, true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2015 SAP SE. All rights reserved
	
 */
sap.ui.define([
	"sap/gantt/drawer/Drawer", "sap/gantt/misc/Utility", "sap/ui/core/Core",
	// 3rd party lib
	"sap/ui/thirdparty/d3"
], function (Drawer, Utility, Core) {
	"use strict";

	var SelectionPanel = Drawer.extend("sap.gantt.drawer.SelectionPanel");
	
	SelectionPanel.prototype.drawSvg = function (aTableSvg, aSelectionSvg, aData, oGanttChartWithTable) {
		// temp save param
		this._oGanttChartWithTable = oGanttChartWithTable;
		// create top g
		
//		append row_g
		if (aData.length == 0){
			return null;
		}
		
		var dummyData = [];
		
		for (var i = 0; i < aData.length; i++){
			if (aData[i].data.__dummy && !aData[i].data.previousNodeNum && !aData[i].data.afterNodeNum){
				dummyData.push(aData[i]);
			}
		}
		

		var aTableRowG = aTableSvg.selectAll(".selectionpanel").data(dummyData);
		aTableRowG.enter().append("g").classed("selectionpanel",true);
		aTableRowG.exit().remove();
		
		var aSelectionRowG = aSelectionSvg.selectAll(".selectionpanel").data(dummyData);
		aSelectionRowG.enter().append("g").classed("selectionpanel",true);
		aSelectionRowG.exit().remove();
		
		// draw
		if (!aTableRowG.empty() && !aSelectionRowG.empty()) {
			var iSelectionWidth = $(aSelectionSvg[0][0]).width();
			var iTableWidth = $(aTableSvg[0][0]).width();
			this._drawExpandedBackground(aSelectionSvg,iSelectionWidth);
			this._drawExpandedBackground(aTableSvg,iTableWidth);
			this._drawExpandedContent(aTableSvg, iTableWidth);
		}
	};

	SelectionPanel.prototype._drawExpandedBackground = function (aSvg, iWidth) {		
		aSvg.selectAll(".selectionpanel").selectAll("rect").remove();
		aSvg.selectAll(".selectionpanel").append("rect").classed("sapGanttExpandChartBG",true)
			.attr("x", function (d) {
				return 0;
			})
			.attr("y", function (d) {
				return d.y;
			})
			.attr("height", function (d) {
				// -1 just for show parent container border 
				return d.rowHeight - 1;
			})
			.attr("width", function (d) {
				// -1 just for show parent container border
				return iWidth - 1;
			});
		
	};
	
	SelectionPanel.prototype._drawExpandedContent = function (aSvg, iWidth) {
		aSvg.selectAll(".selectionpanel").selectAll("g").remove();

		var that = this;
		aSvg.selectAll(".selectionpanel").append("g").classed("sapGanttExpandChartContent",true);
		var gShape = aSvg.selectAll(".sapGanttExpandChartContent");
		var filterGroup = gShape.filter(function(d, i) { return d.index === 1; });
		filterGroup.append("image")
		.classed("hasTitle", function (d) {
			return "image";
		})
		.attr("xlink:href", function (d) {
			return d.icon;
		})
		.attr("x", function (d) {
			if (Core.getConfiguration().getRTL() === true) {
				//right width to the parent container for RTL mode
				return iWidth - 19 - 16;
			} else {
				//left width to the parent container
				return 19;
			}
			
		})
		.attr("y", function (d) {
			//top height to parent container
			return d.y + 4.25;
		})
		.attr("width", function (d) {
			//icon width
			return 16;
		})
		.attr("height", function (d) {
			//icon height
			return 16;
		});

		filterGroup.append("text")
		.attr("x", function (d) {
			if (Core.getConfiguration().getRTL() === true) {
				//right width to the parent container for RTL mode
				return iWidth - 93 + 56;
			} else {
				//left width to the parent container
				return 38;
			}
			
		})
		.attr("y", function (d) {
			//top height to parent container
			return d.y + 16.5;
		})
		.attr("font-size", function (d) {
			return "0.75em";
		})
		.text(function (d) {
			return d.name;
		});
		filterGroup.append("g")
					.attr("transform", function(d){
						var sInitialX = 0, sInitialY = d.y + 7;
						if (Core.getConfiguration().getRTL() === true) {
							//right width to the parent container for RTL mode
							sInitialX =  iWidth - 93 - 4;
						} else {
							//left width to the parent container, plus half width of the close button
							sInitialX =  93 + 8;
						}
						return "translate(" + sInitialX + "," + sInitialY + ")";
					});
		filterGroup.select("g").append("path")
			.classed("sapGanttExpandChartCloseButton", true)
			.attr("d", "M1 0 h3 v4 h4 v3 h-4 v4 h-3 v-4 h-4 v-3 h4 v-4 z")
			.attr("transform", "rotate(45)")
			.on("click", function (d) {
				var aChartScheme = [];
				aChartScheme.push(d.chartScheme);
				var oBinding = that._oGanttChartWithTable._oTT.getBinding("rows");
				var aRows = oBinding.getContexts(0, oBinding.getLength());
				for (var i = 0; i < aRows.length; i++) {
					var oContext = aRows[i].getProperty();
					if (oContext && d.data.parentData && oContext.id == d.data.parentData.id) {
						that._oGanttChartWithTable.fireEvent("collapseDummyRow",{isExpand : false, expandedChartSchemes: aChartScheme, aExpandedIndices : [i]});
					}
				}
			});
		var aClosePath = filterGroup.selectAll("path");
		aClosePath.select("title").remove();
		aClosePath.insert("title", ":first-child")
		.text(function(d) {
			return sap.ui.getCore().getLibraryResourceBundle("sap.gantt").getText("TLTP_CLOSE");
		});
	};

	return SelectionPanel;
},true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

sap.ui.define([
	'jquery.sap.global', 'sap/ui/fl/changeHandler/Base'
], function(jQuery, Base) {
	"use strict";

	/**
	 * Change handler for removing a smart form group element.
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.RemoveField
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 */
	var RemoveField = function() {
	};
	RemoveField.prototype = jQuery.sap.newObject(Base.prototype);

	/**
	 * Removes a smart form group element.
	 *
	 * @param {sap.ui.fl.Change} oChangeWrapper change wrapper object with instructions to be applied on the control map
	 * @param {sap.ui.comp.smartform.GroupElement} oField GroupElement control that matches the change selector for applying the change
	 * @public
	 */
	RemoveField.prototype.applyChange = function(oChangeWrapper, oField) {
		if (oField.getParent) {
			var oGroup = oField.getParent();
			if (oGroup.removeGroupElement) {
				oGroup.removeGroupElement(oField);
			}
		} else {
			throw new Error("no GroupElement control provided for removing the field");
		}
	};

	/**
	 * Completes the change by adding change handler specific content
	 *
	 * @param {sap.ui.fl.Change} oChangeWrapper change wrapper object to be completed
	 * @param {object} oSpecificChangeInfo as an empty object since no additional attributes are required for this operation
	 * @public
	 */
	RemoveField.prototype.completeChangeContent = function(oChangeWrapper, oSpecificChangeInfo) {
		var oChange = oChangeWrapper.getDefinition();
		if (!oChange.content) {
			oChange.content = {};
		}
	};

	return RemoveField;
},
/* bExport= */true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

// Provides control sap.ui.comp.smartform.flexibility.DialogContent.
sap.ui.define(['jquery.sap.global', 'sap/m/Button', 'sap/m/FlexAlignItems', 'sap/m/FlexAlignSelf', 'sap/m/FlexDirection', 'sap/m/FlexItemData', 'sap/m/FlexJustifyContent', 'sap/m/HBox', 'sap/m/VBox', 'sap/ui/comp/library', 'sap/ui/comp/odata/FieldSelector', './FieldList', 'sap/ui/core/Control', 'sap/ui/core/ResizeHandler', 'sap/ui/fl/registry/Settings', 'sap/ui/layout/Grid'],
	function(jQuery, Button, FlexAlignItems, FlexAlignSelf, FlexDirection, FlexItemData, FlexJustifyContent, HBox, VBox, library, FieldSelector, FieldList, Control, ResizeHandler, Settings, Grid) {
	"use strict";



	/**
	 * Constructor for a new smartform/flexibility/DialogContent.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * The content of the personalization dialog of the SmartForm
	 * @extends sap.ui.core.Control
	 *
	 * @constructor
	 * @public
	 * @alias sap.ui.comp.smartform.flexibility.DialogContent
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var DialogContent = Control.extend("sap.ui.comp.smartform.flexibility.DialogContent", /** @lends sap.ui.comp.smartform.flexibility.DialogContent.prototype */ { metadata : {

		library : "sap.ui.comp",
		aggregations : {

			/**
			 * Content of the control itself
			 */
			content : {type : "sap.ui.core.Control", multiple : false}
		}
	}});


	/**
	 * Initialisation
	 *
	 * @public
	 */
	DialogContent.prototype.init = function() {
		this._oScrollView = new sap.m.ScrollContainer();
		var smartFormDialog = sap.ui.getCore().byId("smartFormPersDialog");
		if (smartFormDialog) {
			this._oResizeDialogHandlerId = ResizeHandler.register(smartFormDialog, jQuery.proxy(this._handleResizeDialog, this));
		}

		this._textResources = sap.ui.getCore().getLibraryResourceBundle("sap.ui.comp");
		this._constructLayout();
		this._createButtons();
		this._createFieldList();
		this._createFieldSelector();
		this._createModels();
		this._initiateBinding();
		this.addStyleClass("sapUiSizeCompact");
		this._sFirstIdPart = undefined;
	};

	DialogContent.prototype._handleResizeDialog = function() {
		if (this._oScrollView) {
			var height = jQuery("#smartFormPersDialog-cont").height();
			var headerHeight = jQuery("#smartFormPersDialogFieldListHeader").height();
			this._oScrollView.setHeight(height - headerHeight + "px");
		}
	};

	/**
	 * Initialises the binding of the subordinate controls like move up/down button, field list, field selector
	 *
	 * @private
	 */
	DialogContent.prototype._initiateBinding = function() {

		this._oFieldList.bindAggregation("nodes", {
			path: "/children",
			factory: this._createNodeFactoryFunction.bind(this)
		});

		this._oFieldList.attachSelectionChanged(this._onSelectionChanged.bind(this));
		this._oFieldList.attachLabelChanged(this._onLabelChanged.bind(this));
		this._oFieldList.attachNodeHidden(this._onNodeAddedOrHidden.bind(this));

		this._oBtnMoveDown.bindProperty("enabled", {
			path: "/isMoveDownButtonEnabled"
		});
		this._oBtnMoveUp.bindProperty("enabled", {
			path: "/isMoveUpButtonEnabled"
		});

		this._oBtnMoveBottom.bindProperty("enabled", {
			path: "/isMoveBottomButtonEnabled"
		});
		this._oBtnMoveTop.bindProperty("enabled", {
			path: "/isMoveTopButtonEnabled"
		});
		this._oBtnAddField.bindProperty("enabled", {
			parts: [
				{path: "addFieldButtonDependencies>/selectedField"},
				{path: "addFieldButtonDependencies>/groups"}
			],
			formatter: this._isAddFieldEnabled.bind(this)
		});
	};

	/**
	 * Initialises the models for controling the display of the "add field" button
	 *
	 * @private
	 */
	DialogContent.prototype._createModels = function() {
		this._oAddFieldButtonDependenciesModel = new sap.ui.model.json.JSONModel({
			"selectedField": undefined,
			"groups": undefined
		});
		this.setModel(this._oAddFieldButtonDependenciesModel, 'addFieldButtonDependencies');
		// used to force retriggering of the binding when visibility of a group within the groups has changed
		// (workaround for UI5) the fact that the group stays the same object(reference) let the _oAddFieldButtonDependenciesModel think nothing has chanced
		this._emptyModel = new sap.ui.model.json.JSONModel();

	};

	/**
	 * Sets the first part of new control ids for the view context
	 *
	 * @param {string} sId	Control Id
	 * @public
	 */
	DialogContent.prototype.setViewId = function(sId) {
		this._sViewId = sId;
	};

	/**
	 * Returns Ids of the assigned changes of the component (correctly sorted)
	 *
	 * @param {sap.ui.model.odata.ODataModel} oODataModel The list of fields will be extracetd from the models metadata
	 * @param {string} sEntityType The entity type whose fields could be selected
	 * @param {string} sComponentName The name of the SAPUI5 component
	 * @param {array} aIgnoredFields List of fields which should be ignored
	 * @param {Object.<bindingPath:string, fieldListElement:Object>} mBindingPathToFieldListElement Map absolute odata binding paths to the field list elements
	 * @param {Object.<id:string, fieldListElement:Object>} mIdToFieldListElement Map field list element ids to the field list elements
	 * @param {map} mPropertyBag - (optional) contains additional data that are needed for reading of changes
	 * - appDescriptor that belongs to actual component
	 * - siteId that belongs to actual component   
	 * @public
	 */
	DialogContent.prototype.initialiseODataFieldSelector = function(oODataModel, sEntityType, sComponentName, aIgnoredFields, mBindingPathToFieldListElement, mIdToFieldListElement, mPropertyBag) {
		var oODataFieldSelector;
		var bShowCreateExtFieldButton = false;
		oODataFieldSelector = this._oFieldSelector;
		if (oODataFieldSelector) {
			// get the information of the
			Settings.getInstance(sComponentName, mPropertyBag).then(function(oSettings) {
				if (oSettings.isModelS) {
					bShowCreateExtFieldButton = oSettings.isModelS();
				}
				oODataFieldSelector.setModel(oODataModel, sEntityType, bShowCreateExtFieldButton, aIgnoredFields, mBindingPathToFieldListElement, mIdToFieldListElement);
			});
		}
	};

	/**
	 * Factory function used for the recursive binding of the FieldListNode
	 *
	 * @param {string} sId	id of the to-be-created FieldListNode
	 * @param {object} oContext Binding Context
	 * @returns {FieldListNode} Newly created FieldListNode
	 * @private
	 */
	DialogContent.prototype._createNodeFactoryFunction = function(sId, oContext) {

		var nodeBindingSettings, oNode;

		nodeBindingSettings = {
			label: {
				path: "label"
			},
			nodes: {
				path: oContext.getPath() + "/children",
				factory: this._createNodeFactoryFunction.bind(this)
			},
			isSelected: {
				path: "isSelected"
			},
			isVisible: {
				path: "isVisible"
			}
		};
		oNode = new sap.ui.comp.smartform.flexibility.FieldListNode(sId, nodeBindingSettings);
		return oNode;
	};

	/**
	 * Event handler called when the selection of a root FieldListNode has changed
	 *
	 * @param {object} oEvent Event
	 * @private
	 */
	DialogContent.prototype._onSelectionChanged = function(oEvent) {
		var oSelectedFieldListNode, oNode;
		oSelectedFieldListNode = oEvent.getParameter('node');
		oNode = oSelectedFieldListNode.getBindingContext().getObject();

		this._changeSelection(oNode);

		this.getModel().updateBindings();
	};

	/**
	 * Event handler called when a label contained in the field list has changed
	 *
	 * @param {object} oEvent Event
	 * @private
	 */
	DialogContent.prototype._onLabelChanged = function(oEvent) {
		var oChangedFieldListNode, oFieldListElement;
		oChangedFieldListNode = oEvent.getParameter('node');
		oFieldListElement = oChangedFieldListNode.getBindingContext().getObject();

		this._oFieldSelector.updateFieldLabel(oFieldListElement);
	};

	/**
	 * Event handler called when a node in the field list was hidden
	 *
	 * @param {object} oEvent Event
	 * @private
	 */
	DialogContent.prototype._onNodeAddedOrHidden = function(oEvent) {
		this._oAddFieldButtonDependenciesModel.setProperty("/groups", this.getModel().getData().children);
		this._triggerAddFieldButtonDependenciesBindings();
	};

	/**
	 * Changes the selected FieldListNode. Unselects previously selected FieldListNode
	 *
	 * @param {object} oNodeToBeSelected	JSON object from the model representing the newly selected node
	 * @private
	 */
	DialogContent.prototype._changeSelection = function(oNodeToBeSelected) {


		// Deselect previously selected node
		if (this._oSelectedFieldListNodeData) {
			this._oSelectedFieldListNodeData.isSelected = false;
		}

		// select newly selected node
		this._oSelectedFieldListNodeData = oNodeToBeSelected;
		this._oSelectedFieldListNodeData.isSelected = true;

		this._readDataFromModelAndUpdateMoveButtonEnabledState();

		this.getModel().updateBindings();
	};

	/**
	 * Reads the data from the model and recalculate the move button enabled state
	 *
	 * @private
	 */
	DialogContent.prototype._readDataFromModelAndUpdateMoveButtonEnabledState = function() {

		var oData;
		oData = this._getDataFromModel();
		this._updateMoveButtonEnabledState(oData);

	};

	/**
	 * Checks if node can be moved down
	 *
	 * @param {object} oNode Field list node to be moved
	 * @param {number} nLevelInAdjacenceList Level of node to be moved in field list tree
	 * @param {array} aAdjacenceList Adjacence list
	 * @returns {object} object which holds information if the move is possible, how many places
	 *                   the node has to be moved in the field list and on the new parent node
	 *                   if the move leads to a new one
	 * @private
	 */
	DialogContent.prototype._checkMoveDown = function(oNode, nLevelInAdjacenceList, aAdjacenceList) {

		var i, oMoveDown = {};

		oMoveDown.enabled = false;
		oMoveDown.moveStep = 0;
		oMoveDown.newParent = undefined;

		// moving down possible ?
		// first check - are there any children at higher index than the selected node ?
		oMoveDown.enabled = oNode.parent.children.length - 1 > oNode.index;
		// there is at least one child at higher index - but is it visible ?
		if (oMoveDown.enabled) {
			for (i = oNode.index + 1; i < oNode.parent.children.length; i++) {
				oMoveDown.moveStep += 1;
			    // found a visible child - moving down possible
				if (!oNode.parent.children[i].hasOwnProperty('isVisible') || oNode.parent.children[i].isVisible) {
					return oMoveDown;
			    }
			    // no visible child at higher index - have to check if moving down to new parent is possible
				if (i === (oNode.parent.children.length - 1)) {
					oMoveDown.enabled = false;
			    }
			}
		}

		// no move down possible at the same parent - check if moving down to new parent is possible
		if (!oMoveDown.enabled) {
			// first check - is there any parent at higher index than the current parent ?
			var nParentIndex = aAdjacenceList[nLevelInAdjacenceList - 1].indexOf(oNode.parent);
			oMoveDown.enabled = aAdjacenceList[nLevelInAdjacenceList - 1].length - 1 > nParentIndex;
			// there is at least one parent at a higher index - but is it visible ?
			if (oMoveDown.enabled) {
				for (i = nParentIndex + 1; i < aAdjacenceList[nLevelInAdjacenceList - 1].length; i++) {
				    // found a visible parent - moving down possible
					if (!aAdjacenceList[nLevelInAdjacenceList - 1][i].hasOwnProperty('isVisible') || aAdjacenceList[nLevelInAdjacenceList - 1][i].isVisible) {
                        oMoveDown.newParent = aAdjacenceList[nLevelInAdjacenceList - 1][i];
						return oMoveDown;
				    }
				    // no visible parent at higher index - moving down is not possible
					if (i === (aAdjacenceList[nLevelInAdjacenceList - 1].length - 1)) {
						oMoveDown.enabled = false;
				    }
				}
			}
		}

		return oMoveDown;

	};

	/**
	 * Checks if node can be moved up
	 *
	 * @param {object} oNode Field list node to be moved
	 * @param {number} nLevelInAdjacenceList Level of node to be moved in field list tree
	 * @param {array} aAdjacenceList Adjacence list
	 * @returns {object} object which holds information if the move is possible, how many places
	 *                   the node has to be moved in the field list and on the new parent node
	 *                   if the move leads to a new one
	 * @private
	 */
	DialogContent.prototype._checkMoveUp = function(oNode, nLevelInAdjacenceList, aAdjacenceList) {

		var i, oMoveUp = {};

		oMoveUp.enabled = false;
		oMoveUp.moveStep = 0;
		oMoveUp.newParent = undefined;

		// moving up possible ?
		// first check - is selected node not the top child ?
		oMoveUp.enabled = oNode.index > 0;
		// not the top child - but is there a visible child above the selected node ?
		if (oMoveUp.enabled) {
			for (i = oNode.index - 1; i >= 0; i--) {
				oMoveUp.moveStep += 1;
			    // found a visible child - moving up possible
				if (!oNode.parent.children[i].hasOwnProperty('isVisible') || oNode.parent.children[i].isVisible) {
                    return oMoveUp;
			    }
				// no visible child found - have to check if the node can be moved up to a new parent
				if (i === 0) {
					oMoveUp.enabled = false;
				}
			}
		}
		// moving up at the same parent not possible - check if the node can be moved up to a new parent
		if (!oMoveUp.enabled) {
			var nParentIndex = aAdjacenceList[nLevelInAdjacenceList - 1].indexOf(oNode.parent);
			oMoveUp.enabled = nParentIndex > 0;
			// there is at least one parent at lower index - but is it visible ?
			if (oMoveUp.enabled) {
				for (i = nParentIndex - 1; i >= 0; i--) {
				    // found a visible parent - moving up possible
					if (!aAdjacenceList[nLevelInAdjacenceList - 1][i].hasOwnProperty('isVisible') || aAdjacenceList[nLevelInAdjacenceList - 1][i].isVisible) {
                        oMoveUp.newParent = aAdjacenceList[nLevelInAdjacenceList - 1][i];
						return oMoveUp;
				    }
				    // no visible parent at lower index - moving up is not possible
					if (i === 0) {
						oMoveUp.enabled = false;
				    }
				}
			}
		}

		return oMoveUp;

	};

	/**
	 * Recalculates the move button enabled state
	 *
	 * @param {object} oData The data of the whole JSON model
	 * @private
	 */
	DialogContent.prototype._updateMoveButtonEnabledState = function(oData) {

		var fn, bIsMoveDownEnabled, bIsMoveUpEnabled, bIsMoveBottomEnabled, bIsMoveTopEnabled;

		var that = this;

		fn = function(oNode, nLevelInAdjacenceList, aAdjacenceList) {

			var oMoveDown = that._checkMoveDown(oNode, nLevelInAdjacenceList, aAdjacenceList);
			var oMoveUp = that._checkMoveUp(oNode, nLevelInAdjacenceList, aAdjacenceList);

			bIsMoveDownEnabled = oMoveDown.enabled;
			bIsMoveUpEnabled = oMoveUp.enabled;

			bIsMoveBottomEnabled = bIsMoveDownEnabled;
			bIsMoveTopEnabled = bIsMoveUpEnabled;

		};

		if (this._oSelectedFieldListNodeData) {
			this._findNodeInDataModel(oData, this._oSelectedFieldListNodeData.id, fn);
		} else { // nothing selected
			bIsMoveDownEnabled = false;
			bIsMoveUpEnabled = false;
			bIsMoveBottomEnabled = false;
			bIsMoveTopEnabled = false;
		}

		oData.isMoveDownButtonEnabled = bIsMoveDownEnabled;
		oData.isMoveUpButtonEnabled = bIsMoveUpEnabled;
		oData.isMoveBottomButtonEnabled = bIsMoveBottomEnabled;
		oData.isMoveTopButtonEnabled = bIsMoveTopEnabled;
	};

	DialogContent.prototype._constructLayout = function() {
		this.oLayout = new HBox({
			direction: FlexDirection.Row
		});
		this.oLayoutLeft = new VBox({
			direction: FlexDirection.Column,
			layoutData: new FlexItemData({
				order: 1,
				growFactor: 2
			})
		});
		this.oLayoutLeft.addStyleClass("sapUiCompDialogContentFieldListContainer");

		this.oLayoutMiddle = new VBox({
			direction: FlexDirection.Column,
			layoutData: new FlexItemData({
				order: 2,
				growFactor: 1
			})
		});
		this.oLayoutMiddle.addStyleClass("sapUiCompDialogContentMiddle");

		this.oLayoutTopLeft = new Grid("smartFormPersDialogFieldListHeader");
		this.oLayoutTopLeft.addStyleClass("sapUiCompDialogContentFieldListContainerTop");

		this.oLayoutLeft.addItem(this.oLayoutTopLeft);

		this.oLayoutRight = new VBox({
			direction: FlexDirection.Column,
			layoutData: new FlexItemData({
				order: 3,
				growFactor: 9
			})
		});

		this.oLayout.addItem(this.oLayoutLeft);
		this.oLayout.addItem(this.oLayoutMiddle);
		this.oLayout.addItem(this.oLayoutRight);
		this.setContent(this.oLayout);
	};

	/**
	 * Creates an instance of the FieldList Control
	 *
	 * @private
	 */
	DialogContent.prototype._createFieldList = function() {
		this._oScrollView.setWidth("100%");
		this._oScrollView.setVertical(true);

		this._oFieldList = new FieldList(this.getId() + '-FieldList');
		this._oScrollView.addContent(this._oFieldList);
		this._handleResizeDialog();

		this.oLayoutLeft.addItem(this._oScrollView);
	};

	/**
	 * Creates an instance of the FieldSelector Control
	 *
	 * @private
	 */
	DialogContent.prototype._createFieldSelector = function() {
		this._oFieldSelector = new FieldSelector({
			layoutData: new FlexItemData({
				order: 3,
				growFactor: 9
			})
		});

		this._oFieldSelector.attachFieldSelectionChanged(this._writeSelectedFieldToModel.bind(this));
		this.oLayoutRight.addItem(this._oFieldSelector);
	};

	DialogContent.prototype._writeSelectedFieldToModel = function (oSelection) {
		this._oAddFieldButtonDependenciesModel.setProperty("/selectedField", oSelection.mParameters);
		this._triggerAddFieldButtonDependenciesBindings();
	};

	DialogContent.prototype._triggerAddFieldButtonDependenciesBindings = function () {
		this.setModel(this._emptyModel, 'addFieldButtonDependencies');
		if (!this._oAddFieldButtonDependenciesModel.getData().groups) {
			this._oAddFieldButtonDependenciesModel.setProperty("groups", this.getModel().getData().children);
		}
		this.setModel(this._oAddFieldButtonDependenciesModel, 'addFieldButtonDependencies');
	};

	/**
	 * Reacts on a change within the intanciated FieldSelector Control
	 *
	 * @private
	 */
	DialogContent.prototype._isAddFieldEnabled = function(oSelectedField, aGroups) {
		var bValidFieldSelected = !!oSelectedField && !!oSelectedField.name;
		return bValidFieldSelected && aGroups && this._containsVisibleGroups(aGroups);
	};

	DialogContent.prototype._containsVisibleGroups = function(oGroups) {
		var oVisibleFieldListGroups = this._getVisibleGroups(oGroups);
		return oVisibleFieldListGroups.length > 0;
	};

	DialogContent.prototype._getVisibleGroups = function(oGroups) {
		var oVisibleFieldListGroups = [];

		oGroups.forEach(function (oNode) {
			if (oNode.isVisible) {
				oVisibleFieldListGroups.push(oNode);
			}
		});

		return oVisibleFieldListGroups;
	};

	/**
	 * Creates the Move up/down buttons, add group button, add field button
	 *
	 * @private
	 */
	DialogContent.prototype._createButtons = function() {
		var sText, sTooltip;

		this._oBtnMoveBottom = new Button(this.getId() + '-MoveBottomButton', {
			layoutData : new sap.ui.layout.GridData({
				span : "L2 M3 S3"
			})
		});
		this._oBtnMoveBottom.setIcon("sap-icon://expand-group");
		this._oBtnMoveBottom.attachPress(this._onMoveBottomClick.bind(this));
		sTooltip = this._textResources.getText("FORM_PERS_DIALOG_MOVE_BOTTOM");
		this._oBtnMoveBottom.setTooltip(sTooltip);
		this.oLayoutTopLeft.addContent(this._oBtnMoveBottom);

		this._oBtnMoveDown = new Button(this.getId() + '-MoveDownButton', {
			layoutData : new sap.ui.layout.GridData({
				span : "L2 M3 S3"
			})
		});
		this._oBtnMoveDown.setIcon("sap-icon://slim-arrow-down");
		this._oBtnMoveDown.attachPress(this._onMoveDownClick.bind(this));
		sTooltip = this._textResources.getText("FORM_PERS_DIALOG_MOVE_DOWN");
		this._oBtnMoveDown.setTooltip(sTooltip);
		this.oLayoutTopLeft.addContent(this._oBtnMoveDown);

		this._oBtnMoveUp = new Button(this.getId() + '-MoveUpButton', {
			layoutData : new sap.ui.layout.GridData({
				span : "L2 M3 S3"
			})
		});
		this._oBtnMoveUp.setIcon("sap-icon://slim-arrow-up");
		this._oBtnMoveUp.attachPress(this._onMoveUpClick.bind(this));
		sTooltip = this._textResources.getText("FORM_PERS_DIALOG_MOVE_UP");
		this._oBtnMoveUp.setTooltip(sTooltip);
		this.oLayoutTopLeft.addContent(this._oBtnMoveUp);

		this._oBtnMoveTop = new Button(this.getId() + '-MoveTopButton', {
			layoutData : new sap.ui.layout.GridData({
				span : "L2 M3 S3"
			})
		});
		this._oBtnMoveTop.setIcon("sap-icon://collapse-group");
		this._oBtnMoveTop.attachPress(this._onMoveTopClick.bind(this));
		sTooltip = this._textResources.getText("FORM_PERS_DIALOG_MOVE_TOP");
		this._oBtnMoveTop.setTooltip(sTooltip);
		this.oLayoutTopLeft.addContent(this._oBtnMoveTop);

		this._oBtnAddGroup = new Button(this.getId() + '-AddGroupButton', {
			layoutData : new sap.ui.layout.GridData({
				span : "L4 M12 S12"
			})
		});
		sText = this._textResources.getText("FORM_PERS_DIALOG_ADD_GROUP");
		this._oBtnAddGroup.setText(sText);
		this._oBtnAddGroup.attachPress(this._onAddGroupClick.bind(this));
		sTooltip = this._textResources.getText("FORM_PERS_DIALOG_ADD_GROUP");
		this._oBtnAddGroup.setTooltip(sTooltip);
		this.oLayoutTopLeft.addContent(this._oBtnAddGroup);

		this._oBtnAddField = new Button(this.getId() + '-AddFieldButton');
		this._oBtnAddField.setIcon("sap-icon://slim-arrow-left");
		this._oBtnAddField.attachPress(this._onAddFieldClick.bind(this));
		sTooltip = this._textResources.getText("FORM_PERS_DIALOG_ADD_FIELD");
		this._oBtnAddField.setTooltip(sTooltip);
		this.oLayoutMiddle.addItem(this._oBtnAddField);
	};

	/**
	 * Event handler called when the move up button is clicked
	 *
	 * @private
	 */
	DialogContent.prototype._onMoveUpClick = function() {

		var oModel, oData, sId;

		oModel = this.getModel();
		if (oModel) {
			sId = this._getIdOfSelectedFieldListNode();
			oData = this._getDataFromModel();
			this._executeMoveUp(oData, sId);
			this._updateMoveButtonEnabledState(oData);
			oModel.setData(oData);
		}
	};

	/**
	 * Event handler called when the move down button is clicked
	 *
	 * @private
	 */
	DialogContent.prototype._onMoveDownClick = function() {

		var oData, sId, oModel;

		oModel = this.getModel();
		if (oModel) {
			sId = this._getIdOfSelectedFieldListNode();
			oData = this._getDataFromModel();
			this._executeMoveDown(oData, sId);
			this._updateMoveButtonEnabledState(oData);
			oModel.setData(oData);
		}
	};

	/**
	 * Event handler called when the move top button is clicked
	 *
	 * @private
	 */
	DialogContent.prototype._onMoveTopClick = function() {

		var oModel, oData, sId;

		oModel = this.getModel();
		if (oModel) {
			sId = this._getIdOfSelectedFieldListNode();
			oData = this._getDataFromModel();
			this._executeMoveTop(oData, sId);
			this._updateMoveButtonEnabledState(oData);
			oModel.setData(oData);
		}
	};

	/**
	 * Event handler called when the move bottom button is clicked
	 *
	 * @private
	 */
	DialogContent.prototype._onMoveBottomClick = function() {

		var oData, sId, oModel;

		oModel = this.getModel();
		if (oModel) {
			sId = this._getIdOfSelectedFieldListNode();
			oData = this._getDataFromModel();
			this._executeMoveBottom(oData, sId);
			this._updateMoveButtonEnabledState(oData);
			oModel.setData(oData);
		}
	};

	/**
	 * Event handler called when the add group button is clicked
	 *
	 * @private
	 */
	DialogContent.prototype._onAddGroupClick = function() {

		var oData, oModel;

		oModel = this.getModel();
		if (oModel) {
			oData = this._getDataFromModel();
			this._executeAddGroup(oData);
			oModel.setData(oData);
			this._onNodeAddedOrHidden();
		}
	};

	/**
	 * Returns the id of the currently selected FieldListNode. Undefined if no FieldListNode is selected
	 *
	 * @returns {string} Id of selected FieldListNode
	 * @private
	 */
	DialogContent.prototype._getIdOfSelectedFieldListNode = function() {

		var oNode;
		oNode = this._oSelectedFieldListNodeData;

		if (oNode) {
			return oNode.id;
		}
	};

	/**
	 * Event handler, called when add field button was clicked
	 *
	 * @param {object} oEvent Event
	 * @private
	 */
	DialogContent.prototype._onAddFieldClick = function(oEvent) {
		var oModel, oData;

		oModel = this.getModel();
		if (oModel) {
			oData = this._getDataFromModel();
			this._executeAddField(oData);
			oModel.setData(oData);
		}
	};

	/**
	 * Calculates position where a new field would be added to. Basis for this calculation is the currently selected node.
	 *
	 * @param {object} oData JSON data from model
	 * @returns {object} Map having a member 'parent' (new parent node) and 'index' (Position in parent's children collection)
	 * @private
	 */
	DialogContent.prototype._getParentAndIndexNodeForNewField = function(oData) {
		var sId, nIndex, oParentNode;

		// Search for the currently selected field list node and determine new parent
		sId = this._getIdOfSelectedFieldListNode();
		this._findNodeInDataModel(oData, sId, function(oNode) {
			if (oNode.type === 'group') {
				oParentNode = oNode;
				if (oParentNode.children && oParentNode.children.length) {
					nIndex = oParentNode.children.length;
				}
			} else {
				oParentNode = oNode.parent;
				nIndex = oNode.index + 1;
			}
		});
		// if no FieldNode was selected, append to last group
		if (!oParentNode) {
			oParentNode = this._getBottomGroup(oData);
			nIndex = oParentNode.children.length;
		}

		return {
			parent: oParentNode,
			index: nIndex
		};

	};

	/**
	 * Returns the last group
	 *
	 * @param {object} oData JSON data from model returns {object} The very last group. Undefined if there are no groups.
	 * @returns {object} Parent node instance
	 * @private
	 */
	DialogContent.prototype._getBottomGroup = function(oData) {
		var oBottomGroup;

		if (oData && oData.children && oData.children.length > 0) {
			var oVisibleGroups = this._getVisibleGroups(oData.children);
			oBottomGroup = oVisibleGroups[oVisibleGroups.length - 1]; // get last element
		}
		return oBottomGroup;
	};

	/**
	 * Gets the data from the model
	 *
	 * @returns {object} JSON data from model
	 * @private
	 */
	DialogContent.prototype._getDataFromModel = function() {

		var oModel;

		oModel = this.getModel();
		if (oModel) {
			return oModel.getData();
		}
	};

	/**
	 * Creates an adjacence list from the provided JSON tree. The data has a single root node and multiple children. Each child can have multiple children
	 * too. The tree depth is not limited. The adjacence list is an array of arrays. list[i] contains an ordered list of all nodes of the tree, having the
	 * depth i. This means list[0] equals the root node. As a side effect two additional properties will be added to all nodes of the model: - index:
	 * Contains the position of this node in the parent's children collection - parent: The parent of this node These properties can be removed with
	 * _destroyAdjacenceList
	 *
	 * @param {object} oData The data from the JSON model
	 * @returns {Array} Adjacence list
	 * @private
	 */
	DialogContent.prototype._createAdjacenceList = function(oData) {

		var aAdjacenceList, fCreateAdjacenceList;

		aAdjacenceList = [];
		fCreateAdjacenceList = function(oNode, oParent, nIndex, nDepth) {
			oNode.index = nIndex;
			oNode.parent = oParent;
			aAdjacenceList[nDepth] = aAdjacenceList[nDepth] || [];
			aAdjacenceList[nDepth].push(oNode);
		};

		this._dfs(oData, fCreateAdjacenceList);

		return aAdjacenceList;
	};

	/**
	 * Removes the properties from the data model added, which were added when calling _createAdjacenceList
	 *
	 * @param {object} oData The data from the JSON model
	 * @private
	 */
	DialogContent.prototype._destroyAdjacenceList = function(oData) {

		var fDestroyAdjacenceList;

		fDestroyAdjacenceList = function(oNode, oParent, nIndex, nDepth) {
			delete oNode.index;
			delete oNode.parent;
		};

		this._dfs(oData, fDestroyAdjacenceList);
	};

	/**
	 * DFS (depth first search) traverses the full graph an calls fn for each node. Method is recursive
	 *
	 * @param {object} oData The data of the current node
	 * @param {function} fn Function to be called for each node
	 * @param {object} oParent The parent node
	 * @param {number} nIndex The index of the cirrent node within the parent's children collection
	 * @param {number} nDepth The depth within the tree of the current node
	 * @private
	 */
	DialogContent.prototype._dfs = function(oData, fn, oParent, nIndex, nDepth) {

		var i;

		if (!oData) {
			return;
		}

		nDepth = nDepth || 0;
		nIndex = nIndex || 0;

		fn(oData, oParent, nIndex, nDepth);

		if (oData && oData.children) {
			for (i = 0; i < oData.children.length; i++) {
				this._dfs(oData.children[i], fn, oData, i, nDepth + 1);
			}
		}
	};

	/**
	 * Searches for a node in the data tree and executes the funtion fn for this node
	 *
	 * @param {object} oData The data of the JSON model
	 * @param {String} sId oParent The parent node
	 * @param {function} fn Function to be executed for this node. Function will be called with these parameters: fn(oNode, nDepth, aAdjacenceList).
	 * @private
	 */
	DialogContent.prototype._findNodeInDataModel = function(oData, sId, fn) {

		var aAdjacenceList;

		aAdjacenceList = this._createAdjacenceList(oData);

		(function() {
			var nDepth, j, nMaxHierarchyDepth, length, oNode;

			nMaxHierarchyDepth = aAdjacenceList.length;
			for (nDepth = 0; nDepth < nMaxHierarchyDepth; nDepth++) {
				length = aAdjacenceList[nDepth].length;
				for (j = 0; j < length; j++) {
					oNode = aAdjacenceList[nDepth][j];
					if (oNode.id === sId) {
						fn(oNode, nDepth, aAdjacenceList);
						return;
					}
				}
			}
		}());

		this._destroyAdjacenceList(oData);
	};

	/**
	 * Moves a node down in the data model
	 *
	 * @param {object} oNode The JSON node representing a FieldListNode to be moved down
	 * @param {number} nLevelInAdjacenceList Depth of the node in the tree
	 * @param {Array} aAdjacenceList Adjacence List
	 * @private
	 */
	DialogContent.prototype._moveDownNode = function(oNode, nLevelInAdjacenceList, aAdjacenceList) {

		var oMoveDown = this._checkMoveDown(oNode, nLevelInAdjacenceList, aAdjacenceList);

		if (oMoveDown.enabled) {
			// move leads to new parent node
			if (oMoveDown.newParent) {
				oNode.parent.children.splice(oNode.index, 1);
				oMoveDown.newParent.children = oMoveDown.newParent.children || [];
				oMoveDown.newParent.children.splice(0, 0, oNode);
			// move within the same parent
			} else {
				oNode.parent.children.splice(oNode.index, 1);
				oNode.parent.children.splice(oNode.index + oMoveDown.moveStep, 0, oNode);
			}
		}

	};

	/**
	 * Moves a node up in the data model
	 *
	 * @param {object} oNode The JSON node representing a FieldListNode to be moved up
	 * @param {number} nLevelInAdjacenceList Depth of the node in the tree
	 * @param {Array} aAdjacenceList Adjacence List
	 * @private
	 */
	DialogContent.prototype._moveUpNode = function(oNode, nLevelInAdjacenceList, aAdjacenceList) {

		var oMoveUp = this._checkMoveUp(oNode, nLevelInAdjacenceList, aAdjacenceList);

		if (oMoveUp.enabled) {
			// move leads to new parent node
			if (oMoveUp.newParent) {
				oNode.parent.children.splice(oNode.index, 1);
				oMoveUp.newParent.children = oMoveUp.newParent.children || [];
				oMoveUp.newParent.children.push(oNode);
			// move within the same parent
			} else {
				oNode.parent.children.splice(oNode.index, 1);
				oNode.parent.children.splice(oNode.index - oMoveUp.moveStep, 0, oNode);
			}
		}

	};

	/**
	 * Moves a node down to the bottom in the data model
	 *
	 * @param {object} oNode The JSON node representing a FieldListNode to be moved down to the bottom
	 * @param {number} nLevelInAdjacenceList Depth of the node in the tree
	 * @param {Array} aAdjacenceList Adjacence List
	 * @private
	 */
	DialogContent.prototype._moveBottomNode = function(oNode, nLevelInAdjacenceList, aAdjacenceList) {

		var oMoveDown = this._checkMoveDown(oNode, nLevelInAdjacenceList, aAdjacenceList);

		if (oMoveDown.enabled) {
			// move leads to new parent node
			if (oMoveDown.newParent) {
				oNode.parent.children.splice(oNode.index, 1);
				oMoveDown.newParent.children = oMoveDown.newParent.children || [];
				oMoveDown.newParent.children.push(oNode);
			// move within the same parent
			} else {
				oNode.parent.children.splice(oNode.index, 1);
				oNode.parent.children.push(oNode);
			}
		}

	};

	/**
	 * Moves a node up to the top in the data model
	 *
	 * @param {object} oNode The JSON node representing a FieldListNode to be moved up to the top
	 * @param {number} nLevelInAdjacenceList Depth of the node in the tree
	 * @param {Array} aAdjacenceList Adjacence List
	 * @private
	 */
	DialogContent.prototype._moveTopNode = function(oNode, nLevelInAdjacenceList, aAdjacenceList) {

		var oMoveUp = this._checkMoveUp(oNode, nLevelInAdjacenceList, aAdjacenceList);

		if (oMoveUp.enabled) {
			// move leads to new parent node
			if (oMoveUp.newParent) {
				oNode.parent.children.splice(oNode.index, 1);
				oMoveUp.newParent.children = oMoveUp.newParent.children || [];
				oMoveUp.newParent.children.splice(0, 0, oNode);
			// move within the same parent
			} else {
				oNode.parent.children.splice(oNode.index, 1);
				oNode.parent.children.splice(0, 0, oNode);
			}
		}

	};

	/**
	 * Moves a node down in the data model
	 *
	 * @param {object} oData The data of the JSON model
	 * @param {String} sId The id of the node to be moved down
	 * @returns {object} Node in data model after move
	 * @private
	 */
	DialogContent.prototype._executeMoveDown = function(oData, sId) {

		return this._findNodeInDataModel(oData, sId, this._moveDownNode.bind(this));
	};

	/**
	 * Moves a node up in the data model
	 *
	 * @param {object} oData The data of the JSON model
	 * @param {String} sId The id of the node to be moved up
	 * @returns {object} Node in the data model after the move
	 * @private
	 */
	DialogContent.prototype._executeMoveUp = function(oData, sId) {

		return this._findNodeInDataModel(oData, sId, this._moveUpNode.bind(this));
	};

	/**
	 * Moves a node down to the bottom in the data model
	 *
	 * @param {object} oData The data of the JSON model
	 * @param {String} sId The id of the node to be moved down to the bottom
	 * @return {object} Bottom node in the data model
	 * @private
	 */
	DialogContent.prototype._executeMoveBottom = function(oData, sId) {

		return this._findNodeInDataModel(oData, sId, this._moveBottomNode.bind(this));
	};

	/**
	 * Moves a node up to the top in the data model
	 *
	 * @param {object} oData The data of the JSON model
	 * @param {String} sId The id of the node to be moved up to the top
	 * @returns {object} Top node in the data model
	 * @private
	 */
	DialogContent.prototype._executeMoveTop = function(oData, sId) {

		return this._findNodeInDataModel(oData, sId, this._moveTopNode.bind(this));
	};

	/**
	 * Reads the selected field from the field selector and adds it to the data
	 *
	 * @param {object} oData The data of the JSON model
	 * @private
	 */
	DialogContent.prototype._executeAddField = function(oData) {
		var oNewPosition, oNewNode, that = this;

		oNewPosition = this._getParentAndIndexNodeForNewField(oData);

		oNewNode = this._getNewNodeFromSelectedODataField(oData, this._getSelectedFieldFromFieldSelector());

		// check if the field is already delivered as hidden but with configuration. If not add a new field
		var oExistingField = this._getExistingField(oNewNode, oData);
		if (oExistingField) {
			this._findNodeInDataModel(oData, oExistingField.id, function(oNode, nLevelInAdjacenceList, aAdjacenceList){
				// set the existing field to visible
				oNode.isVisible = true;
				// remove the existing node
				oNode.parent.children.splice(oNode.index, 1);
				// check if the old node will be removed before the new position
				if (oNode.parent === oNewPosition.parent) {
					if (oNode.index < oNewPosition.index) {
						oNewPosition.index--;
					}
				}
				// add the existing node to the new position
				that._addField(oNode, oNewPosition.parent, oNewPosition.index);

			});
		} else {
			this._addField(oNewNode, oNewPosition.parent, oNewPosition.index);
		}
	};

	/**
	 * Tries to add a predefined field
	 *
	 * @param {object} oNewNode The node to be added
	 * @param {object} oData - internal data structure
	 *
	 * @returns {boolean} true if the predefined field was added
	 */
	DialogContent.prototype._getExistingField = function(oNewNode, oData) {
		var bFound = false;
		var sReferenceValue = '';

		if (oNewNode.isBoundToODataService) { // used to identifying existing field which is bound to the odata service
			sReferenceValue = oNewNode.entityType + '/' + oNewNode.fieldValue;
		} else { // used to identifying existing field which is not bound to the odata service
			sReferenceValue = oNewNode.id;
		}

		var fnCheckIfBoundToODataService = function(index, bindingPath) {
			if (bindingPath.path === sReferenceValue) {
				bFound = true;
			}
		};
		var fnCheckIfNotBoundToODataService = function(id) {
			if (id === sReferenceValue) {
				bFound = true;
			}
		};
		if (oData.children) {
			for (var i = 0; i < oData.children.length; i++) {
				var oChild = oData.children[i];
				if (oChild.type === "field") {
					if (oChild.isBoundToODataService) {
						jQuery.each(oChild.bindingPaths, fnCheckIfBoundToODataService);
					} else {
						fnCheckIfNotBoundToODataService(oChild.id);
					}
				}
				if (bFound) {
					return oChild;
				}

				var oFoundChild = this._getExistingField(oNewNode, oChild);
				if (oFoundChild) {
					return oFoundChild;
				}
			}
		}
	};


	/**
	 * Adds the new node to the specified position
	 *
	 * @param {object} oNewNode The node to be added
	 * @param {object} oParentNode The new parent of the node
	 * @param {number} nIndex The position where the new node will be added into the parent's children collection. If undefined, the new node will be
	 *        appended as last node.
	 * @private
	 */
	DialogContent.prototype._addField = function(oNewNode, oParentNode, nIndex) {

		if (!oNewNode) {
			return;
		}

		// Add new field
		oParentNode.children = oParentNode.children || [];
		if (nIndex || nIndex === 0) {
			oParentNode.children.splice(nIndex, 0, oNewNode);
		} else {
			oParentNode.children.push(oNewNode);
		}
	};

	/**
	 * Gets the currently selected field from the OData Field Selector and creates and returns a new node which can be added to the model
	 * @param {object} oData	Data object
	 * @param {object} oSelectedField	Selected field instance
	 * @returns {object} The new node for the OData field
	 * @private
	 */
	DialogContent.prototype._getNewNodeFromSelectedODataField = function(oData, oSelectedField) {
		var oNewNode;

		if (!oSelectedField) {
			return null;
		}

	// create new entry
		oNewNode = {
			bindingPaths : (oSelectedField.isBoundToODataService) ? [ { path : oSelectedField.entityName + '/' + oSelectedField.path } ] : [ { path : '' } ],
			isBoundToODataService: oSelectedField.isBoundToODataService, // used in _getExistingField
			id: (oSelectedField.isBoundToODataService) ? oData.id + "_" + oSelectedField.entityType + "_" + oSelectedField.path.replace("/","_") : oSelectedField.id, // oSelectedField.id only available for fields which are not bound to odata service (are already on the UI view and therefore have an id)
			entitySet: oSelectedField.entitySet,
			entityType: oSelectedField.entityType,
			entityName: oSelectedField.entityName,
			label: oSelectedField.field, // "{" + oSelectedField.name + "/@sap:label}"
			valueProperty: "value",
			fieldValue: oSelectedField.path,
			jsType: "sap.ui.comp.smartfield.SmartField",
			isVisible: true,
			type: "field"
		};

		return oNewNode;
	};

	/**
	 * Gets the currently selected field from the OData Field Selector
	 *
	 * @returns {object} Selected OData field as JSON object
	 * @private
	 */
	DialogContent.prototype._getSelectedFieldFromFieldSelector = function() {
		return this._oFieldSelector.getSelectedField();
	};

	/**
	 * Adds a new group as first element to the data
	 *
	 * @param {object} oData The data of the JSON model
	 * @private
	 */
	DialogContent.prototype._executeAddGroup = function(oData) {
		var sText, oNewGroup;
		sText = this._textResources.getText("FORM_PERS_DIALOG_NEW_GROUP");

		// create new entry
		oNewGroup = {
			id: this._sViewId + jQuery.sap.uid(),
			label: sText,
			isVisible: true,
			type: "group",
			children: []
		};

		oData.children.splice(0, 0, oNewGroup); // Insert new group as first group
		this._changeSelection(oNewGroup);
	};

	DialogContent.prototype.exit = function() {
		if (this._oScrollView) {
			this._oScrollView.destroy();
			this._oScrollView = null;
		}
		if (this._oBtnMoveBottom) {
			this._oBtnMoveBottom.destroy();
			this._oBtnMoveBottom = null;
		}
		if (this._oBtnMoveDown) {
			this._oBtnMoveDown.destroy();
			this._oBtnMoveDown = null;
		}
		if (this._oBtnMoveUp) {
			this._oBtnMoveUp.destroy();
			this._oBtnMoveUp = null;
		}
		if (this._oBtnMoveTop) {
			this._oBtnMoveTop.destroy();
			this._oBtnMoveTop = null;
		}
		if (this._oBtnAddGroup) {
			this._oBtnAddGroup.destroy();
			this._oBtnAddGroup = null;
		}
		if (this._oBtnAddField) {
			this._oBtnAddField.destroy();
			this._oBtnAddField = null;
		}

		if (this._oFieldSelector) {
			this._oFieldSelector.destroy();
			this._oFieldSelector = null;
		}
		if (this.oLayoutRight) {
			this.oLayoutRight.destroy();
			this.oLayoutRight = null;
		}
		if (this.oLayoutMiddle) {
			this.oLayoutMiddle.destroy();
			this.oLayoutMiddle = null;
		}
		if (this.oLayoutTopLeft) {
			this.oLayoutTopLeft.destroy();
			this.oLayoutTopLeft = null;
		}
		if (this.oLayoutLeft) {
			this.oLayoutLeft.destroy();
			this.oLayoutLeft = null;
		}
		if (this.oLayout) {
			this.oLayout.destroy();
			this.oLayout = null;
		}

	};


	return DialogContent;

}, /* bExport= */ true);
<file_sep>/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5) (c) Copyright 2009-2012 SAP AG. All rights reserved
 */

// Provides control sap.ui.vbm.Cluster.
sap.ui.define([
	'jquery.sap.global', './library', 'sap/ui/core/Control', 'sap/ui/core/IconPool'
], function(jQuery, library, Control, IconPool) {
	"use strict";

	/**
	 * Constructor for a new Cluster.
	 * 
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 * @class Cluster control to visualize clustered objects on a map. The Cluster control does not cluster anything itself, instead it only shows a
	 *        predefined image. The image can be configured with the properties <i>type</i>, <i>color</i>, <i>icon</i> and <i>text</i>. If a
	 *        <i>text</i> is given it is shown in the upper right corner of the control with a rounded border around. With the <i>color</i> property
	 *        any color can be chosen. The <i>type</i> property overwrites a property <i>color</i> with semantic color of the type and provides a
	 *        particular semantic icon in the middle of the control. With the <i>icon</i> property an icon can be defined and may overrule the
	 *        semantic icon; if no icon is defined ( and no type) then the semantic icon for type inactive is chosen.
	 * @extends sap.ui.core.Control
	 * @author SAP SE
	 * @constructor
	 * @public
	 * @alias sap.ui.vbm.Cluster
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var Cluster = Control.extend("sap.ui.vbm.Cluster", /** @lends sap.ui.vbm.Cluster.prototype */
	{
		metadata: {

			library: "sap.ui.vbm",
			properties: {

				/**
				 * Set the color of the control. If a type is set then the semantic color of the type is taken instead.
				 */
				color: {
					type: "sap.ui.core.CSSColor",
					group: "Misc",
					defaultValue: null
				},
				/**
				 * Set the icon of the control. If a type is set then the semantic icon of the type can be overwritten with this property. If no icon
				 * and no type is set then the icon for the semantic type 'inactive' is taken.
				 */
				icon: {
					type: "string",
					group: "Misc",
					defaultValue: null
				},
				/**
				 * Set the text of the control.
				 */
				text: {
					type: "string",
					group: "Misc",
					defaultValue: null
				},
				/**
				 * semantic type for cluster. The type specifies the icon and the color of the cluster control.
				 */
				type: {
					type: "sap.ui.vbm.SemanticType",
					group: "Behavior",
					defaultValue: sap.ui.vbm.SemanticType.None
				}

			}
		}
	});

	jQuery.sap.require("sap.ui.core.IconPool");
	jQuery.sap.require("sap.ui.core.theming.Parameters");

	// ...........................................................................//
	// This file defines behavior for the control,...............................//
	// ...........................................................................//

	Cluster.prototype.exit = function() {
	};

	Cluster.prototype.init = function() {
	};

	// ...........................................................................//

	Cluster.prototype.onAfterRendering = function() {
		// when there is preserved content restore it.............................//
		if (this.$oldContent.length > 0) {
			this.$().append(this.$oldContent);
		}
		var col = this.getColor();
		var type = this.getType();
		if (col && type == sap.ui.vbm.SemanticType.None) {
			// color manipulation needed

			var Id1 = this.getId() + "-" + "backgroundcircle";
			var Id2 = Id1 + "-" + "innercircle";

			var backgroundcircle = document.getElementById(Id1);
			var innercircle = document.getElementById(Id2);
			var c = jQuery(backgroundcircle).css("border-bottom-color");
			var rgba = Cluster.prototype.string2rgba(c);
			rgba = "rgba(" + rgba[0] + "," + rgba[1] + "," + rgba[2] + "," + 0.5 + ")";
			jQuery(backgroundcircle).css("border-color", rgba);
			jQuery(innercircle).css("border-color", rgba);

		}

	};

	Cluster.prototype.onBeforeRendering = function() {
		// this is called before the renderer is called...........................//

		this.$oldContent = sap.ui.core.RenderManager.findPreservedContent(this.getId());
	};

	// ...........................................................................//
	// re implement property setters.............................................//

	Cluster.prototype.setColor = function(col) {
		this.setProperty("color", col);
	};

	Cluster.prototype.setIcon = function(ic) {
		this.setProperty("icon", ic);
	};

	Cluster.prototype.setText = function(txt) {
		this.setProperty("text", txt);
	};

	Cluster.prototype.string2rgba = function(a) {
		var cache;

		if ((cache = /^rgb\(([\d]+)[,;]\s*([\d]+)[,;]\s*([\d]+)\)/.exec(a))) {
			return [
				+cache[1], +cache[2], +cache[3], 1.0, 0
			];
		} else {
			return [
				94, 105, 110
			];
		}
	};

	return Cluster;

});
<file_sep>/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5) (c) Copyright 2009-2012 SAP AG. All rights reserved
 */

// Provides control sap.ui.vbm.FeatureCollection.
sap.ui.define([
	'sap/ui/core/theming/Parameters', './GeoJsonLayer', './library'
], function(Parameters, GeoJsonLayer, library) {
	"use strict";

	/**
	 * Constructor for a new FeatureCollection.
	 * 
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 * @class FeatureCollection aggregation container. A FeatureCollection can render the content of an assigned GeoJSON. The naming is associated to
	 *        the GeoJSON standard. All features found in the GeoJSON are rendered as separated objects. From the possible feature types only
	 *        <ul>
	 *        <li>Polygon and
	 *        <li>Multipolygon
	 *        </ul>
	 *        are supported so far. The feature type support will be extended in the upcoming releases.<br>
	 *        All features from the GeoJSON will be rendered with the given default colors and are inactive. They do not react on mouse over, except
	 *        with tooltip, or raise any events on click or right click.<br>
	 *        By adding <i>Feature elements</i> to the items aggregation you can make the match (by id) feature from the GeoJSON interactive and give
	 *        it alternative colors.
	 * @extends sap.ui.vbm.GeoJsonLayer
	 * @constructor
	 * @public
	 * @alias sap.ui.vbm.FeatureCollection
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var FeatureCollection = GeoJsonLayer.extend("sap.ui.vbm.FeatureCollection", /** @lends sap.ui.vbm.FeatureCollection.prototype */
	{
		metadata: {

			library: "sap.ui.vbm",
			properties: {},
			defaultAggregation: "items",
			aggregations: {

				/**
				 * Feature object aggregation
				 */
				items: {
					type: "sap.ui.vbm.Feature",
					multiple: true,
					singularName: "item"
				}
			},
			events: {

				/**
				 * The event is raised when there is a click action on an aggregated Feature. Clicks on other Features from the GeoJSON are ignored.
				 */
				click: {
					parameters: {
						/**
						 * Id of clicked Feature
						 */
						featureId: {
							type: "string"
						}
					}
				},

				/**
				 * The event is raised when there is a right click or a tap and hold action on an aggregated Feature. Clicks on other Features from
				 * the GeoJSON are ignored.
				 */
				contextMenu: {
					parameters: {
						/**
						 * Id of clicked Feature
						 */
						featureId: {
							type: "string"
						}
					}
				}
			}
		}
	});

	// /**
	// * This file defines behavior for the control,
	// */

	// ...........................................................................//
	// model creators............................................................//

	FeatureCollection.prototype.getDataObjects = function() {
		if (this.mbGeoJSONDirty) {
			this._triggerFeatureCreation();
		}

		// apply the feature properties to the vbi datacontext.....................//
		// do a clone of the original data, to be able to handle complete....//
		// model changes..........................................................//

		var aElements = [], aPolys = [], aLines = [], aPoints = [];
		jQuery.extend(aElements, this.mFeatureColl); // shallow copy of array -> need to copy elements before change!

		var oOverlayMap = {};
		if (aElements.length) {
			// create lookup for overlayed features..................................//
			var aOverlayFeatures = this.getItems();
			for (var nJ = 0, len = aOverlayFeatures ? aOverlayFeatures.length : 0, item; nJ < len; ++nJ) {
				item = aOverlayFeatures[nJ];
				oOverlayMap[item.getFeatureId()] = item;
			}
		}

		// iterate over feature table.............................................//
		for (var nK = 0, oElement, oOverlay, tmp; nK < aElements.length; ++nK) {
			oElement = aElements[nK];

			if ((oOverlay = oOverlayMap[oElement.K])) {
				// Overlay found, apply properties.....................................//
				// do not change original element -> make copy first!
				var oCopy = {};
				jQuery.extend(oCopy, oElement);
				oElement = aElements[nK] = oCopy;
				// apply changes
				oElement.C = oOverlay.getColor();
				if ((tmp = oOverlay.getTooltip())) {
					oElement.TT = tmp;
				}
			}
			switch (oElement.type) {
				case "Polygon":
				case "MultiPolygon":
					aPolys.push(oElement);
					break;
				case "LineString":
				case "MultiLineString":
					aLines.push(oElement);
					break;
				case "Point":
				case "MultiPoint":
					aPoints.push(oElement);
					break;
				default:
					jQuery.sap.log.error("FeatureCollection: Unknown feature type: " + oElement.type);
			}
		}

		return [
			{
				"name": this.getId() + "_Polys",
				"type": "N",
				"E": aPolys
			}, {
				"name": this.getId() + "_Lines",
				"type": "N",
				"E": aLines
			}, {
				"name": this.getId() + "_Points",
				"type": "N",
				"E": aPoints
			}
		];
	};

	FeatureCollection.prototype.getDataRemoveObjects = function() {
		return [
			{
				"name": this.getId() + "_Polys",
				"type": "N"
			}, {
				"name": this.getId() + "_Lines",
				"type": "N"
			}, {
				"name": this.getId() + "_Points",
				"type": "N"
			}
		];
	};

	/**
	 * Returns Properties for Features like name, bounding box, and midpoint
	 * 
	 * @param {string[]} aFeatureIds Array of Feature Ids. The Feature Id must match the GeoJSON tag.
	 * @returns {array} Array of Feature Information Objects. Each object in the array has the properties BBox: Bounding Box for the Feature in format
	 *          "lonMin;latMin;lonMax;latMax", Midpoint: Centerpoint for Feature in format "lon;lat", Name: Name of the Feature, and Properties: Array
	 *          of name-value-pairs associated with the Feature
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	FeatureCollection.prototype.getFeaturesInfo = function(aFeatureIds) {
		var result = [];
		for (var nJ = 0, len = aFeatureIds.length, featureId; nJ < len; ++nJ) {
			featureId = aFeatureIds[nJ];
			result[featureId] = {};
			result[featureId].BBox = this.mFeatureBBox[featureId];
			result[featureId].Midpoint = [
				(this.mFeatureBBox[featureId][0] + this.mFeatureBBox[featureId][1]) / 2, (this.mFeatureBBox[featureId][2] + this.mFeatureBBox[featureId][3]) / 2
			];
			result[featureId].Name = this.mNames[featureId];
			result[featureId].Properties = this.mFeatureProps[featureId];
		}
		return result;
	};

	FeatureCollection.prototype.handleEvent = function(event) {
		var s = event.Action.name;

		var funcname = "fire" + s[0].toUpperCase() + s.slice(1);

		// first we try to get the event on a FeatureCollection instance......................//
		var oOverlay, sInstance = event.Action.instance;
		if ((oOverlay = this.findInstance(sInstance))) {

			if (oOverlay.mEventRegistry[s]) {
				if (s === "click") {
					oOverlay.mClickGeoPos = event.Action.AddActionProperties.AddActionProperty[0]['#'];
				}
				if (s === "contextMenu") {
					oOverlay.mClickPos = [
						event.Action.Params.Param[0]['#'], event.Action.Params.Param[1]['#']
					];
					// create an empty menu
					jQuery.sap.require("sap.ui.unified.Menu");

					if (this.oParent.mVBIContext.m_Menus) {
						this.oParent.mVBIContext.m_Menus.deleteMenu("DynContextMenu");
					}

					var oMenuObject = new sap.ui.unified.Menu();
					oMenuObject.vbi_data = {};
					oMenuObject.vbi_data.menuRef = "CTM";
					oMenuObject.vbi_data.VBIName = "DynContextMenu";

					// fire the contextMenu..................................................//
					oOverlay.fireContextMenu({
						menu: oMenuObject
					});
				} else if (s === "handleMoved") {
					oOverlay[funcname]({
						data: event
					});
				} else {
					oOverlay[funcname]({});
				}
			}
		}
		// check wether event is registered on Feature Collection and fire in case of
		if (this.mEventRegistry[s]) {
			this[funcname]({
				featureId: sInstance.split(".")[1]
			});
		}
	};

	/**
	 * open a Detail Window
	 * 
	 * @param {sap.ui.vbm.Feature} oFeature VO instance for which the Detail Window should be opened
	 * @param {object} oParams Parameter object
	 * @param {string} oParams.caption Text for Detail Window caption
	 * @param {string} oParams.offsetX position offset in x-direction from the anchor point
	 * @param {string} oParams.offsetY position offset in y-direction from the anchor point
	 * @returns {void}
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	FeatureCollection.prototype.openDetailWindow = function(oFeature, oParams) {
		var oParent = this.getParent();
		oParent.mDTWindowCxt.bUseClickPos = true;
		oParent.mDTWindowCxt.open = true;
		oParent.mDTWindowCxt.src = oFeature;
		oParent.mDTWindowCxt.key = oFeature.getFeatureId();
		oParent.mDTWindowCxt.params = oParams;
		oParent.m_bWindowsDirty = true;
		oParent.invalidate(this);
	};

	/**
	 * open the context menu
	 * 
	 * @param {sap.ui.vbm.Feature} oFeature VO instance for which the Detail Window should be opened
	 * @param {object} oMenu the context menu to be opened
	 * @returns {void}
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	FeatureCollection.prototype.openContextMenu = function(oFeature, oMenu) {
		this.oParent.openContextMenu("Area", oFeature, oMenu);
	};

	FeatureCollection.prototype.handleChangedData = function(aElements) {
		if (aElements && aElements.length) {
			for (var nI = 0, oElement, oInst; nI < aElements.length; ++nI) {
				oElement = aElements[nI];
				oInst = this.findInstance(oElement.K);
				if (oInst) {
					oInst.handleChangedData(oElement);
				}
			}
		}
	};

	return FeatureCollection;

});
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

sap.ui.define([
	"sap/ui/fl/Utils", "jquery.sap.global"
], function(Utils, $) {
	"use strict";

	/**
	 * Base class for all change handler subclasses which provides some reuse methods
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.Base
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 *
	 */
	var Base = function() {
	};

	/**
	 * @param {sap.ui.core.Control} oControl - the control for which the properties shall be returned
	 * @param {String} sName - name of property
	 * @returns {Object} property object
	 * @private
	 */
	Base.prototype._getProperty = function(oControl, sName) {
		if (oControl) {
			if (oControl.getMetadata) {
				var oMetadata = oControl.getMetadata();
				var oProperties = oMetadata.getProperties();
				if (oProperties) {
					var oProperty = oProperties[sName];
					if (oProperty) {
						return oProperty;
					}
				}
			}
		}
	};

	/**
	 * Changes a property of the control 
	 *
	 * @param {sap.ui.core.Control} oControl - the control for which the changes should be fetched
	 * @param {string} sName - property name
	 * @param {object} oValue - new value of the property
	 *
	 * @public
	 */
	Base.prototype.changeProperty = function(oControl, sName, oValue) {
		var oProperty = this._getProperty(oControl, sName);
		if (oProperty) {
			oControl.setProperty(sName, oValue);
		}
	};

	/**
	 * Sets a property of the control back to its default value
	 *
	 * @param {sap.ui.core.Control} oControl - the control for which the changes should be fetched
	 * @param {string} sName - property name
	 *
	 * @public
	 */
	Base.prototype.clearProperty = function(oControl, sName) {
		var oProperty = this._getProperty(oControl, sName);
		if (oProperty) {
			oControl.setProperty(sName, oProperty.defaultValue);
		}
	};

	/**
	 * Adds an additional item of the aggregation or changes it in case it is not a multiple one
	 *
	 * @param {sap.ui.core.Control} oControl - the control for which the changes should be fetched
	 * @param {string} sName - aggregation name
	 * @param {string} oObject - aggregated object to be set
	 * @param {integer} iIndex <optional> - index to which it should be added/inserted
	 *
	 * @public
	 */
	Base.prototype.addAggregation = function(oControl, sName, oObject, iIndex) {
		if (oControl) {
			if (oControl.getMetadata) {
				var oMetadata = oControl.getMetadata();
				var oAggregations = oMetadata.getAllAggregations();
				if (oAggregations) {
					var oAggregation = oAggregations[sName];
					if (oAggregation) {
						//						if(oAggregation.multiple === false) {
						//							oControl.destroyAggregation(sName);
						//						}
						if (oAggregation.multiple) {
							var iInsertIndex = iIndex || oAggregations.length || 0;
							oControl[oAggregation._sInsertMutator](oObject, iInsertIndex);
						} else {
							oControl[oAggregation._sMutator](oObject);
						}
					}
				}
			}
		}
	};
	
	Base.prototype.removeAggregation = function(oControl, sName, oObject) {
		if (oControl) {
			if (oControl.getMetadata) {
				var oMetadata = oControl.getMetadata();
				var oAggregations = oMetadata.getAllAggregations();
				if (oAggregations) {
					var oAggregation = oAggregations[sName];
					if (oAggregation) {
						oControl[oAggregation._sRemoveMutator](oObject);
					}
				}
			}
		}
	};
	/**
	 * Sets a text in a change.
	 *
	 * @param {object} oChange - change object
	 * @param {string} sKey - text key
	 * @param {string} sText - text value
	 * @param {string} sType - translation text type e.g. XBUT, XTIT, XTOL, XFLD
	 *
	 * @public
	 */
	Base.prototype.setTextInChange = function(oChange, sKey, sText, sType) {
		if (!oChange.texts) {
			oChange.texts = {};
		}
		if (!oChange.texts[sKey]) {
			oChange.texts[sKey] = {};
		}
		oChange.texts[sKey].value = sText;
		oChange.texts[sKey].type = sType;
	};

	return Base;
}, /* bExport= */true);
<file_sep>// This file has been generated by the SAPUI5 'AllInOne' Builder
(function () {
	"use strict";
	/*global sap, jQuery */

	sap.ui.controller("sap.ovp.cards.charts.bubble.BubbleChart", {
		onInit: function () {
			sap.ovp.cards.charts.Utils.formatChartYaxis();
			var vizFrame = this.getView().byId("bubbleChartCard");
			if (vizFrame) {
			vizFrame.attachBrowserEvent("click", this.onHeaderClick.bind(this));
			}
			this.delegate1 = {
					onBeforeRendering: function(){
						this.setBusy(true);
					}
				};
						
			this.delegate2 = {
					onAfterRendering: function(){
						this.setBusy(false);
					}
				};
		},
		onBeforeRendering : function() {
			sap.ovp.cards.charts.Utils.validateCardConfiguration(this);
			var vizFrame = this.getView().byId("bubbleChartCard");
			if (!vizFrame) {
				jQuery.sap.log.error(sap.ovp.cards.charts.Utils.constants.ERROR_NO_CHART +
						": (" + this.getView().getId() + ")");
			} else {
				vizFrame.addEventDelegate(this.delegate1, vizFrame);
				var binding = vizFrame.getDataset().getBinding("data");
				binding.attachDataReceived(jQuery.proxy(this.onDataReceived, this));
				sap.ovp.cards.charts.Utils.validateMeasuresDimensions(vizFrame, "Bubble");
			}
		},
		onDataReceived: function(oEvent) {
			var vizFrame = this.getView().byId("bubbleChartCard");
			vizFrame.addEventDelegate(this.delegate2, vizFrame);
			sap.ovp.cards.charts.Utils.hideDateTimeAxis(vizFrame, "valueAxis");
			sap.ovp.cards.charts.Utils.checkNoData(oEvent, this.getCardContentContainer(), vizFrame);
		}
	});
})();
(function () {
	"use strict";
	/*global sap, jQuery */

	sap.ui.controller("sap.ovp.cards.charts.donut.DonutChart", {
		onInit: function() {
			var vizFrame = this.getView().byId("donutChartCard");
			if (vizFrame) {
			vizFrame.attachBrowserEvent("click", this.onHeaderClick.bind(this));
			}
			this.delegate1 = {
					onBeforeRendering: function(){
						this.setBusy(true);
					}
				};
						
			this.delegate2 = {
					onAfterRendering: function(){
						this.setBusy(false);
					}
				};
		},
		onBeforeRendering: function () {
			var utils = sap.ovp.cards.charts.Utils;
			utils.validateCardConfiguration(this);
			var measureArrNames = [];
			var dimensionArrayNames = [];
			var vizFrame = this.getView().byId("donutChartCard");
			if (!vizFrame) {
				jQuery.sap.log.error(utils.constants.ERROR_NO_CHART +
						": (" + this.getView().getId() + ")");
			} else {
				vizFrame.addEventDelegate(this.delegate1, vizFrame);
				var binding = vizFrame.getDataset().getBinding("data");
				binding.attachDataReceived(jQuery.proxy(this.onDataReceived, this));
				sap.ovp.cards.charts.Utils.validateMeasuresDimensions(vizFrame, "Donut");
				var entityTypeObject = this.getCardPropertiesModel().getProperty("/entityType");
				var columnLabels = utils.getAllColumnLabels(entityTypeObject);
				var measuresArr = vizFrame.getDataset().getMeasures();
				var dimensionsArr = vizFrame.getDataset().getDimensions();
	
				measureArrNames.push(measuresArr[0].getName());
				var dimensionName = columnLabels[dimensionsArr[0].getName()];
				dimensionArrayNames.push(dimensionName ? dimensionName : dimensionsArr[0].getName());

				vizFrame.removeAllFeeds();
				vizFrame.addFeed(new sap.viz.ui5.controls.common.feeds.FeedItem({
					'uid': "size",
					'type': "Measure",
					'values': measureArrNames
				}));
				vizFrame.addFeed(new sap.viz.ui5.controls.common.feeds.FeedItem({
					'uid': "color",
					'type': "Dimension",
					'values': dimensionArrayNames
				}));
	
				vizFrame.setVizProperties({
					size:{
						title:{
							visible:false
						}
					},
					color:{
						title:{
							visible:false
						}
					},
					legend: {
						isScrollable: false
					},
	
					title: {
						visible: false
					},
					interaction:{
						noninteractiveMode: true,
						selectability: {
							legendSelection: false,
							axisLabelSelection: false,
							mode: "NONE",
							plotLassoSelection: false,
							plotStdSelection: false
						}
					}
				});
				utils.formatChartYaxis();
			}
		},
		onDataReceived: function(oEvent) {
			var vizFrame = this.getView().byId("donutChartCard");
			vizFrame.addEventDelegate(this.delegate2, vizFrame);
			sap.ovp.cards.charts.Utils.checkNoData(oEvent, this.getCardContentContainer(), vizFrame);
		}
	});
})();
(function () {
	"use strict";
	/*global sap, jQuery */

	sap.ui.controller("sap.ovp.cards.charts.line.LineChart", {
		onInit: function () {
			sap.ovp.cards.charts.Utils.formatChartYaxis();
			var vizFrame = this.getView().byId("lineChartCard");
			if (vizFrame) {
			vizFrame.attachBrowserEvent("click", this.onHeaderClick.bind(this));
			}
			this.delegate1 = {
					onBeforeRendering: function(){
						this.setBusy(true);
					}
				};
						
			this.delegate2 = {
					onAfterRendering: function(){
						this.setBusy(false);
					}
				};
		},
		onBeforeRendering : function() {
			sap.ovp.cards.charts.Utils.validateCardConfiguration(this);
			var vizFrame = this.getView().byId("lineChartCard");
			if (!vizFrame) {
				jQuery.sap.log.error(sap.ovp.cards.charts.Utils.constants.ERROR_NO_CHART +
						": (" + this.getView().getId() + ")");
			} else {
				vizFrame.addEventDelegate(this.delegate1, vizFrame);
				var binding = vizFrame.getDataset().getBinding("data");
				binding.attachDataReceived(jQuery.proxy(this.onDataReceived, this));
				sap.ovp.cards.charts.Utils.validateMeasuresDimensions(vizFrame, "Line");
			}
		},
		onDataReceived: function(oEvent) {
			var vizFrame = this.getView().byId("lineChartCard");
			sap.ovp.cards.charts.Utils.hideDateTimeAxis(vizFrame, "categoryAxis");
			sap.ovp.cards.charts.Utils.checkNoData(oEvent, this.getCardContentContainer(), vizFrame);
			vizFrame.addEventDelegate(this.delegate2, vizFrame);


		}
	});
})();
(function () {
    "use strict";
    /*global sap, jQuery */

    sap.ui.controller("sap.ovp.cards.image.Image", {
        onInit: function () {
        },

        onImagePress: function (oEvent) {
            this.doNavigation(oEvent.getSource().getBindingContext());
        }

    });
})();
(function () {
    "use strict";
    /*global sap, jQuery */

    sap.ui.controller("sap.ovp.cards.list.List", {
        maxValue: -1,
        counter: 0,
        arrayLength: 0,
        onInit: function () {
            this.counter = 0;
        },

        onListItemPress: function (oEvent) {
            var aNavigationFields = this.getEntityNavigationEntries(oEvent.getSource().getBindingContext(), this.getCardPropertiesModel().getProperty("/annotationPath"));
            this.doNavigation(oEvent.getSource().getBindingContext(), aNavigationFields[0]);
        },

        normalizeValueToPercentage: function (value) {
            var oEntityType = this.getEntityType(),
                sAnnotationPath = this.getCardPropertiesModel().getProperty("/annotationPath"),
                aRecords = oEntityType[sAnnotationPath],
                context = this.getMetaModel().createBindingContext(oEntityType.$path + "/" + sAnnotationPath);
            if (sap.ovp.cards.AnnotationHelper.isFirstDataPointPercentageUnit(context, aRecords)) {
                var iPercent = parseInt(value, 10);
                return iPercent <= 100 ? iPercent : 100;
            }
            var maxV = this._getMaxValue();
            if (this.counter == this.arrayLength) {
                this.counter = 0;
                this.maxValue = -1;
            }
            if (value > maxV) {
                return 100;
            } else {
                var iValue = (parseInt(value, 10) * 100) / maxV;
                if (iValue != 0) {
                    return iValue;
                } else { //if the value is 0 we want to show some minimal value in the bar
                    return 0.5;
                }
            }
        },

        _getMaxValue: function () {
            this.counter++;
            if (this.maxValue != -1) {
                return this.maxValue;
            }
            var oEntityType = this.getEntityType(),
                sAnnotationPath = this.getCardPropertiesModel().getProperty("/annotationPath"),
                aRecords = oEntityType[sAnnotationPath],
                context = this.getMetaModel().createBindingContext(oEntityType.$path + "/" + sAnnotationPath);
            var dataPointValue = sap.ovp.cards.AnnotationHelper.getFirstDataPointValue(context, aRecords);
            var barList = this.getView().byId("ovpList"),
                listItems = barList.getBinding("items"),
                itemsContextsArray = listItems.getCurrentContexts();
            this.arrayLength = itemsContextsArray.length;

            for (var i = 0; i < itemsContextsArray.length; i++) {
                if (parseInt(itemsContextsArray[i].getObject()[dataPointValue], 10) > this.maxValue) {
                    this.maxValue = parseInt(itemsContextsArray[i].getObject()[dataPointValue], 10);
                }
            }
            return this.maxValue;
        },

        /**
         * Gets the card items binding object for the count footer
         */
        getCardItemsBinding: function() {
            var list = this.getView().byId("ovpList");
            return list.getBinding("items");
        }


    });
})();
(function () {
    "use strict";
    /*global sap, jQuery */

    sap.ui.controller("sap.ovp.cards.loading.Loading", {

        onInit: function () {
        },

        onAfterRendering: function(){
            var oView = this.getView();
            oView.addStyleClass("sapOvpLoadingCard");
            var loadingFooter = oView.byId("ovpLoadingFooter");

            var sState = this.getCardPropertiesModel().getProperty("/state");

            if (sState === sap.ovp.cards.loading.State.ERROR){
                loadingFooter.setText(sap.ui.getCore().getLibraryResourceBundle("sap.ovp").getText("cannotLoadCard"));
            } else {
                //sState === sap.ovp.cards.loading.State.LOADING
                setTimeout(function () {
                    loadingFooter.setBusy(true);
                }, 6000);

                setTimeout(function(){
                    loadingFooter.setBusy(false);
                    loadingFooter.setText(sap.ui.getCore().getLibraryResourceBundle("sap.ovp").getText("cannotLoadCard"));
                }, 9000);
            }
        }
    });
})();
(function () {
    "use strict";
    /*global sap, jQuery */

    sap.ui.controller("sap.ovp.cards.table.Table", {

        onInit: function () {
        },

        onColumnListItemPress: function (oEvent) {
            var aNavigationFields = this.getEntityNavigationEntries(oEvent.getSource().getBindingContext(), this.getCardPropertiesModel().getProperty("/annotationPath"));
            this.doNavigation(oEvent.getSource().getBindingContext(), aNavigationFields[0]);
        },

        /**
         * Gets the card items binding object for the count footer
         */
        getCardItemsBinding: function() {
            var table = this.getView().byId("ovpTable");
            return table.getBinding("items");
        }
    });
})();
jQuery.sap.declare('sap.ovp.library-all');
jQuery.sap.declare('sap.ovp.cards.charts.bubble.BubbleChart.controller'); // raw module, declared by SAPUI5 'AllInOne' Builder
jQuery.sap.declare('sap.ovp.cards.charts.donut.DonutChart.controller'); // raw module, declared by SAPUI5 'AllInOne' Builder
jQuery.sap.declare('sap.ovp.cards.charts.line.LineChart.controller'); // raw module, declared by SAPUI5 'AllInOne' Builder
jQuery.sap.declare('sap.ovp.cards.image.Image.controller'); // raw module, declared by SAPUI5 'AllInOne' Builder
jQuery.sap.declare('sap.ovp.cards.list.List.controller'); // raw module, declared by SAPUI5 'AllInOne' Builder
jQuery.sap.declare('sap.ovp.cards.loading.Loading.controller'); // raw module, declared by SAPUI5 'AllInOne' Builder
jQuery.sap.declare('sap.ovp.cards.table.Table.controller'); // raw module, declared by SAPUI5 'AllInOne' Builder
if ( !jQuery.sap.isDeclared('sap.ovp.app.Component') ) {
(function () {
    "use strict";
    /*global sap, jQuery */

    /**
     * @fileOverview Application component to display information on entities from the GWSAMPLE_BASIC
     *   OData service.
     * @version 1.36.12
     */
    jQuery.sap.declare("sap.ovp.app.Component");
    jQuery.sap.require('sap.ui.model.odata.AnnotationHelper'); // unlisted dependency retained


    sap.ui.core.UIComponent.extend("sap.ovp.app.Component", {
        // use inline declaration instead of component.json to save 1 round trip
        metadata: {
            routing : {
                config: {
                    routerClass : sap.ui.core.routing.Router
                },
                targets: {},
                routes : []
            },

            properties: {
                "cardContainerFragment": {
                    "type": "string",
                    "defaultValue": "sap.ovp.app.CardContainer"
                }
            },

            version: "1.36.12",

            library: "sap.ovp.app",

            dependencies: {
                libs: [ "sap.m",
                    "sap.ui.comp",
                    "sap.uxap"
                ],
                components: []
            },
            config: {
                fullWidth: true,
                hideLightBackground: true
            }
        },

        _addModelsMeasurements: function(){
            var oModels = this.oModels;
            var oModel, sModel;
            for (sModel in oModels){
                oModel = this.getModel(sModel);
                if (oModel.getMetaModel()){
                    this._addModelMeasurements(oModel, sModel);
                }
            }
        },

        _addModelMeasurements: function(oModel, sModel) {
            var sId = "ovp:ModelLoading-" + sModel;
            var sIdBatch = "ovp:ModelBatchCall-" + sModel + ":";
            jQuery.sap.measure.start(sId, "Component createContent -> MetaData loaded", "ovp");
            oModel.getMetaModel().loaded().then(function(){
                    jQuery.sap.measure.end(sId);
                }
            );

            oModel.attachBatchRequestSent(function(oEvent){
                jQuery.sap.measure.start(sIdBatch + oEvent.getParameter("ID"), "BatchRequestSent -> BatchRequestCompleted", "ovp");
            });
            oModel.attachBatchRequestCompleted(function(oEvent){
                jQuery.sap.measure.end(sIdBatch + oEvent.getParameter("ID"));
            });

        },

        /**
         * get the merged sap.ovp section from all component hierarchy
         * @returns merged sap.ovp section from manifes files
         */
        getOvpConfig: function(){
            var oOvpConfig;
            var aExtendArgs = [];
            var oManifest = this.getMetadata();
            //loop over the manifest hierarchy till we reach the current generic component
            while (oManifest && oManifest.getComponentName() !== "sap.ovp.app"){
                oOvpConfig = oManifest.getManifestEntry("sap.ovp");
                if (oOvpConfig){
                    //as the last object is the dominant one we use unshift and not push
                    aExtendArgs.unshift(oOvpConfig);
                }
                oManifest = oManifest.getParent();
            }
            //add an empty object for the merged config as we don't whant to change the actual manifest objects
            aExtendArgs.unshift({});
            //add deep flag so the merge would be recurcive
            aExtendArgs.unshift(true);
            oOvpConfig = jQuery.extend.apply(jQuery, aExtendArgs);
            return oOvpConfig;
        },

        createXMLView: function (ovpConfig) {
            jQuery.sap.measure.start("ovp:AppCreateContent", "OVP app Component createContent", "ovp");
            this._addModelsMeasurements();

            this.getRouter().initialize();
            var appConfig = this.getMetadata().getManifestEntry("sap.app");
            var uiConfig = this.getMetadata().getManifestEntry("sap.ui");
            var sIcon = jQuery.sap.getObject("icons.icon", undefined, uiConfig);

            var sComponentName = this.getMetadata().getComponentName();
            ovpConfig.baseUrl = jQuery.sap.getModulePath(sComponentName);
            var uiModel = new sap.ui.model.json.JSONModel(ovpConfig);

            uiModel.setProperty("/title", jQuery.sap.getObject("title", undefined, appConfig));
            uiModel.setProperty("/description", jQuery.sap.getObject("description", undefined, appConfig));
            uiModel.setProperty("/cardContainerFragment", this.getCardContainerFragment());

            if (sIcon){
                if (sIcon.indexOf("sap-icon") < 0 && sIcon.charAt(0) !== '/'){
                    sIcon = ovpConfig.baseUrl + "/" + sIcon;
                }
                uiModel.setProperty("/icon", sIcon);
            }

            //convert cards object into sorted array
            var oCards = ovpConfig.cards;
            var aCards = [];
            var oCard;
            for (var cardKey in oCards){
                if (oCards.hasOwnProperty(cardKey) && oCards[cardKey]) {
                    oCard = oCards[cardKey];
                    oCard.id = cardKey;
                    aCards.push(oCard);
                }
            }

            aCards.sort(function(card1, card2){
                if (card1.id < card2.id){
                    return -1;
                } else if (card1.id > card2.id){
                    return 1;
                } else {
                    return 0;
                }
            });

            uiModel.setProperty("/cards", aCards);

            this.setModel(uiModel, "ui");
            var oFilterModel = this.getModel(ovpConfig.globalFilterModel);
            this.setModel(oFilterModel);
            var oEntityType = oFilterModel.getMetaModel().getODataEntityType(oFilterModel.getMetaModel().oModel.oData.dataServices.schema[0].namespace + "." + ovpConfig.globalFilterEntityType, true);
            var oView = sap.ui.view({
                height: "100%",
                preprocessors: {
                    xml: {
                        bindingContexts: {ui: uiModel.createBindingContext("/"),
                            meta: oFilterModel.getMetaModel().createBindingContext(oEntityType)},
                        models: {ui: uiModel,
                            meta: oFilterModel.getMetaModel()}
                    }
                },
                type: sap.ui.core.mvc.ViewType.XML,
                viewName: "sap.ovp.app.Main"
            });

            jQuery.sap.measure.end("ovp:AppCreateContent");

            return oView;
        },

        setContainer: function () {
            var ovpConfig = this.getOvpConfig();
            var oFilterModel = this.getModel(ovpConfig.globalFilterModel);
            // call overwritten setContainer (sets this.oContainer)
            sap.ui.core.UIComponent.prototype.setContainer.apply(this, arguments);

            if (oFilterModel) {
                oFilterModel.getMetaModel().loaded().then(function () {
                    // Do the templating once the metamodel is loaded
                    this.runAsOwner(function () {
                        var oView = this.createXMLView(ovpConfig);
                        this.setAggregation("rootControl", oView);
                        this.getUIArea().invalidate();
                    }.bind(this));
                }.bind(this));
            }

        }
    });
}());

}; // end of sap/ovp/app/Component.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.ActionUtils') ) {

(function () {
    "use strict";
    /*global dispatchEvent, document, jQuery, localStorage, sap */

    jQuery.sap.declare("sap.ovp.cards.ActionUtils");

    sap.ovp.cards.ActionUtils = {};

    sap.ovp.cards.ActionUtils.getActionInfo = function(oContext, action, oEntityType) {

        var metaModel = oContext.getModel().getMetaModel();
        var sFunctionName = action.action.split('/')[1];
        var oContextObject = oContext.getObject();
        var actionData = {
            oContext: oContext,
            sFunctionImportPath: action.action,
            sFunctionLabel: action.label,
            oFunctionImport: metaModel.getODataFunctionImport(sFunctionName),
            parameterData: {},
            allParameters: []
        };
        var oParameterValue;

        if (actionData.oFunctionImport.parameter) {
            var keyMap = this._getKeyProperties(oEntityType);
            for (var i = 0; i < actionData.oFunctionImport.parameter.length; i++) {
                var oParameter = actionData.oFunctionImport.parameter[i];
                this._addParamLabel(oParameter, oEntityType, metaModel);
                if (keyMap[oParameter.name]) {
                    oParameter.isKey = true;
                }

                if (typeof oParameter.nullable === 'undefined') {
                    oParameter.nullable = true;// default is not mandatory parameter == could be null
                }
                if (oContextObject.hasOwnProperty(oParameter.name)) {
                    oParameterValue = oContextObject[oParameter.name];
                } else {
                    oParameterValue = "";
                }

                actionData.parameterData[oParameter.name] = oParameterValue;
                actionData.allParameters.push(oParameter);
            }
        }
        return actionData;
    };

    sap.ovp.cards.ActionUtils._getKeyProperties = function(oEntityType){
        var oKeyMap = {};

        if (oEntityType && oEntityType.key && oEntityType.key.propertyRef){
            for (var i = 0; i < oEntityType.key.propertyRef.length; i++) {
                var sKeyName = oEntityType.key.propertyRef[i].name;
                oKeyMap[sKeyName] = true;
            }
        }

        return oKeyMap;
    };

    sap.ovp.cards.ActionUtils._addParamLabel = function (oParameter, oEntityType, metaModel){
        if (oEntityType && oParameter && !oParameter["com.sap.vocabularies.Common.v1.Label"]) {

            var oProperty = metaModel.getODataProperty(oEntityType, oParameter.name, false);
            if (oProperty && oProperty["com.sap.vocabularies.Common.v1.Label"]) {
                // copy label from property to parameter with same name as default if no label is set for function import parameter
                oParameter["com.sap.vocabularies.Common.v1.Label"] = oProperty["com.sap.vocabularies.Common.v1.Label"];
            } else if (oProperty && oProperty["sap:label"]) {
                oParameter["sap:label"] = oProperty["sap:label"];
            }
        }
    };

    sap.ovp.cards.ActionUtils.buildParametersForm = function(actionData, onFieldChangeCB) {

        function getParamLabel(oParameter){
            var sLabel = "";
            if (oParameter["com.sap.vocabularies.Common.v1.Label"]) {
                sLabel = oParameter["com.sap.vocabularies.Common.v1.Label"].String;
            } else if (oParameter["sap:label"]) {
                sLabel = oParameter["sap:label"];
            } else {
                sLabel = oParameter.name;
            }

            return sLabel;
        }

        jQuery.sap.require("sap.ui.layout.form.SimpleForm");
        jQuery.sap.require("sap.ui.comp.smartfield.SmartField");

        var oForm = new sap.ui.layout.form.SimpleForm({
            editable: true
        });
        var aFields = [];

        for (var i = 0; i < actionData.allParameters.length; i++) {
            var oParameter = actionData.allParameters[i];

            var sParameterLabel = getParamLabel(oParameter);
            var sBinding = '{/' + oParameter.name + '}';
            var sJSONType = null;
            var sEdmType = oParameter.type;

            // max length - default undefined if not set in OData metadata
            var iMaxLength = oParameter.maxLength ? parseInt(oParameter.maxLength, 10) : undefined;

            // covers Edm.Byte, Edm.SByte, Edm.Boolean, Edm.Int16, Edm.Int32, Edm.Time
            if (sEdmType === 'Edm.Boolean') {
                sJSONType = sap.ui.comp.smartfield.JSONType.Boolean;
            } else if (sEdmType === 'Edm.Byte' || sEdmType === 'Edm.SByte' || sEdmType === 'Edm.Int16' || sEdmType === 'Edm.Int32') {
                sJSONType = sap.ui.comp.smartfield.JSONType.Integer;
            } else {
                sJSONType = sap.ui.comp.smartfield.JSONType.String;
            }

            var isMandatory = sap.ovp.cards.ActionUtils._isMandatoryParameter(oParameter);

            var oField = new sap.ui.comp.smartfield.SmartField({
                value: sBinding,
                mandatory: isMandatory,
                jsontype: sJSONType,
                maxLength: iMaxLength,
                editable:!oParameter.isKey
            });
            oField.attachChange(onFieldChangeCB);
            aFields.push(oField);
            var oLabel = new sap.ui.comp.smartfield.SmartLabel();
            oLabel.setRequired(isMandatory && !oParameter.isKey);

            oLabel.setText(sParameterLabel);
            oLabel.setLabelFor(oField);

            oForm.addContent(oLabel);
            oForm.addContent(oField);
        }

        return oForm;
    };

    sap.ovp.cards.ActionUtils.getParameters = function (oParameterModel, functionImport){
        var paramObject = sap.ovp.cards.ActionUtils._validateParametersValue(oParameterModel, functionImport);
        return paramObject.preparedParameterData;
    };

    sap.ovp.cards.ActionUtils.mandatoryParamsMissing = function(oParameterModel, functionImport) {
        var oValidatedParams = sap.ovp.cards.ActionUtils._validateParametersValue(oParameterModel, functionImport);
        return oValidatedParams.missingMandatoryParameters && oValidatedParams.missingMandatoryParameters.length > 0;
    };

    sap.ovp.cards.ActionUtils._validateParametersValue = function(oParameterModel, functionImport) {
        var aMissingMandatoryParameters = [];
        var oModelParameterData = oParameterModel.getObject('/');
        var oPreparedParameterData = {};
        var oValue, isMandatory;
        for (var i = 0; i < functionImport.parameter.length; i++) {
            var oParameter = functionImport.parameter[i];
            var sParameterName = oParameter.name;
            if (oModelParameterData.hasOwnProperty(sParameterName)) {

                oValue = oModelParameterData[sParameterName];
                isMandatory = sap.ovp.cards.ActionUtils._isMandatoryParameter(oParameter);
                if (oValue === undefined || oValue === "") {
                    if (isMandatory) {
                        if (oParameter.type === 'Edm.Boolean'){
                            oPreparedParameterData[sParameterName] = false;
                        } else {
                            aMissingMandatoryParameters.push(oParameter);
                        }
                    }
                } else {
                    oPreparedParameterData[sParameterName] = oValue;
                }
            } else {
                throw new Error("Unknown parameter: " + sParameterName);
            }
        }
        return {
            preparedParameterData: oPreparedParameterData,
            missingMandatoryParameters: aMissingMandatoryParameters
        };
    };

    sap.ovp.cards.ActionUtils._isMandatoryParameter = function(oParameter) {
        return !sap.ovp.cards.ActionUtils._toBoolean(oParameter.nullable);
    };

    sap.ovp.cards.ActionUtils._toBoolean = function(oParameterValue) {
        if (typeof oParameterValue === "string"){
            var oValue = oParameterValue.toLowerCase();
            return !(oValue == "false" || oValue == "" || oValue == " ");
        }

        return !!oParameterValue;
    };
}());

}; // end of sap/ovp/cards/ActionUtils.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.AnnotationHelper') ) {
// Copyright (c) 2009-2014 SAP SE, All Rights Reserved
/**
 * @fileOverview This file contains miscellaneous utility functions.
 */

(function () {
    "use strict";
    /*global dispatchEvent, document, jQuery, localStorage, sap */

    // ensure that sap.ushell exists
    jQuery.sap.declare("sap.ovp.cards.AnnotationHelper");

    sap.ovp.cards.AnnotationHelper = {};
    sap.ovp.cards.AnnotationHelper.formatFunctions = {count: 0};
    sap.ovp.cards.AnnotationHelper.NumberFormatFunctions = {};

    sap.ovp.cards.AnnotationHelper.criticalityConstants = {
        StateValues : {
            None : "None",
            Negative : "Error",
            Critical : "Warning",
            Positive : "Success"
        },
        ColorValues : {
            None : "Neutral",
            Negative : "Error",
            Critical : "Critical",
            Positive : "Good"
        }
    };

    function getCacheEntry(iContext, sKey) {
        if (iContext.getSetting) {
            var oCache = iContext.getSetting("_ovpCache");
            return oCache[sKey];
        }
        return undefined;
    }

    function setCacheEntry(iContext, sKey, oValue) {
        if (iContext.getSetting) {
            var oCache = iContext.getSetting("_ovpCache");
            oCache[sKey] = oValue;
        }
    }

    function criticality2state(criticality, oCriticalityConfigValues) {
        var sState = oCriticalityConfigValues.None;
        if (criticality && criticality.EnumMember) {
            var val = criticality.EnumMember;
            if (endsWith(val, 'Negative')) {
                sState = oCriticalityConfigValues.Negative;
            } else if (endsWith(val, 'Critical')) {
                sState = oCriticalityConfigValues.Critical;
            } else if (endsWith(val, 'Positive')) {
                sState = oCriticalityConfigValues.Positive;
            }
        }
        return sState;
    }

    function endsWith(sString, sSuffix) {
        return sString && sString.indexOf(sSuffix, sString.length - sSuffix.length) !== -1;
    }

    function generateCriticalityCalculationStateFunction(criticalityCalculation, oCriticalityConfigValues) {

        return function (value) {

            value = Number(value);
            var sDirection = criticalityCalculation.ImprovementDirection.EnumMember;
            var oCriticality = {};
            var deviationLow = getNumberValue(criticalityCalculation.DeviationRangeLowValue);
            var deviationHigh = getNumberValue(criticalityCalculation.DeviationRangeHighValue);
            var toleranceLow = getNumberValue(criticalityCalculation.ToleranceRangeLowValue);
            var toleranceHigh = getNumberValue(criticalityCalculation.ToleranceRangeHighValue);
            if (endsWith(sDirection, "Minimize") || endsWith(sDirection, "Minimizing")) {
                if (value <= toleranceHigh) {
                    oCriticality.EnumMember = "Positive";
                } else if (value > deviationHigh) {
                    oCriticality.EnumMember = "Negative";
                } else {
                    oCriticality.EnumMember = "Critical";
                }
            } else if (endsWith(sDirection, "Maximize") || endsWith(sDirection, "Maximizing")) {
                if (value >= toleranceLow) {
                    oCriticality.EnumMember = "Positive";
                } else if (value < deviationLow) {
                    oCriticality.EnumMember = "Negative";
                } else {
                    oCriticality.EnumMember = "Critical";
                }
            } else if (endsWith(sDirection, "Target")) {
                if (value >= toleranceLow && value <= toleranceHigh) {
                    oCriticality.EnumMember = "Positive";
                } else if (value < deviationLow || value > deviationHigh) {
                    oCriticality.EnumMember = "Negative";
                } else {
                    oCriticality.EnumMember = "Critical";
                }
            }

            return criticality2state(oCriticality, oCriticalityConfigValues);
        };
    }

    function getSortedDataFields(iContext, aCollection) {
        var sCacheKey = iContext.getPath() + "-DataFields-Sorted";
        var aSortedFields = getCacheEntry(iContext, sCacheKey);
        if (!aSortedFields) {
            var aDataPoints = getSortedDataPoints(iContext, aCollection);
            var aDataPointsValues = aDataPoints.map(function (oDataPoint) {
                return oDataPoint.Value.Path;
            });
            aDataPointsValues = aDataPointsValues.filter(function (element) {
                return !!element;
            });
            aSortedFields = aCollection.filter(function (item) {
                if (item.RecordType === "com.sap.vocabularies.UI.v1.DataField" && aDataPointsValues.indexOf(item.Value.Path) === -1) {
                    return true;
                }
                return false;
            });
            sortCollectionByImportance(aSortedFields);
            setCacheEntry(iContext, sCacheKey, aSortedFields);
        }
        return aSortedFields;
    }

    function getSortedDataPoints(iContext, aCollection) {
        var sCacheKey = iContext.getPath() + "-DataPoints-Sorted";
        var aSortedFields = getCacheEntry(iContext, sCacheKey);
        if (!aSortedFields) {
            aSortedFields = aCollection.filter(isDataFieldForAnnotation);
            sortCollectionByImportance(aSortedFields);
            var sEntityTypePath;
            for (var i = 0; i < aSortedFields.length; i++) {
                sEntityTypePath = iContext.getPath().substr(0, iContext.getPath().lastIndexOf("/") + 1);
                aSortedFields[i] = iContext.getModel().getProperty(getTargetPathForDataFieldForAnnotation(sEntityTypePath,aSortedFields[i]));
                sEntityTypePath = "";
            }
            setCacheEntry(iContext, sCacheKey, aSortedFields);
        }
        return aSortedFields;
    }

    function isDataFieldForAnnotation(oItem) {
        if (oItem.RecordType === "com.sap.vocabularies.UI.v1.DataFieldForAnnotation"
            &&
            oItem.Target.AnnotationPath.match(/@com.sap.vocabularies.UI.v1.DataPoint.*/)) {
            return true;
        }
        return false;
    }

    function getTargetPathForDataFieldForAnnotation(sEntityTypePath, oDataFieldForAnnotation) {
        if (sEntityTypePath && !endsWith(sEntityTypePath,'/')) {
            sEntityTypePath += '/';
        }
        return sEntityTypePath + oDataFieldForAnnotation.Target.AnnotationPath.slice(1);
    }

    function getImportance(oDataField) {
        var sImportance;
        if (oDataField["com.sap.vocabularies.UI.v1.Importance"]) {
            sImportance = oDataField["com.sap.vocabularies.UI.v1.Importance"].EnumMember;
        }
        return sImportance;
    }

    function sortCollectionByImportance(aCollection) {
        aCollection.sort(function (a, b) {
            var aImportance = getImportance(a),
                bImportance = getImportance(b);

            if (aImportance === bImportance) {
                return 0;
            }

            if (aImportance === "com.sap.vocabularies.UI.v1.ImportanceType/High") {
                return -1;
            } else if (bImportance === "com.sap.vocabularies.UI.v1.ImportanceType/High") {
                return 1;
            } else if (aImportance === "com.sap.vocabularies.UI.v1.ImportanceType/Medium") {
                return -1;
            } else if (bImportance === "com.sap.vocabularies.UI.v1.ImportanceType/Medium") {
                return 1;
            } else if (aImportance === "com.sap.vocabularies.UI.v1.ImportanceType/Low") {
                return -1;
            } else if (bImportance === "com.sap.vocabularies.UI.v1.ImportanceType/Low") {
                return 1;
            }
            return -1;
        });
        return aCollection;
    }

    function formatDataField(iContext, aCollection, index) {
        var item = getSortedDataFields(iContext, aCollection)[index];
        if (item) {
            return formatField(iContext, item);
        }
        return "";
    }

    function getDataFieldName(iContext, aCollection, index) {
        var item = getSortedDataFields(iContext, aCollection)[index];

        if (item) {
            return item.Label.String;
        }
        return "";
    }

    function getDataPointName(iContext, aCollection, index) {
        var item = getSortedDataPoints(iContext, aCollection)[index];

        if (item && item.Title) {
            return item.Title.String;
        }
        return "";
    }

    function formatDataPoint(iContext, aCollection, index) {
        var item = getSortedDataPoints(iContext, aCollection)[index];
        if (!item) {
            return "";
        }

        var oModel = iContext.getSetting('ovpCardProperties');
        var oEntityType = oModel.getProperty("/entityType");
        var oMetaModel = oModel.getProperty("/metaModel");

        return _formatDataPoint(iContext, item, oEntityType, oMetaModel);
    }

    function _formatDataPoint(iContext, oItem, oEntityType, oMetaModel) {

        if (!oItem || !oItem.Value) {
            return "";
        }

        var oEntityTypeProperty = oMetaModel.getODataProperty(oEntityType, oItem.Value.Path);
        //Support sap:text attribute
        if (oEntityTypeProperty && oEntityTypeProperty["sap:text"]) {
            oEntityTypeProperty = oMetaModel.getODataProperty(oEntityType, oEntityTypeProperty["sap:text"]);
            oItem = {Value: {Path: oEntityTypeProperty.name}};
        }
        return formatField(iContext, oItem);
    }

    function formatField(iContext, item, bDontIncludeUOM, bIncludeOnlyUOM) {

        if (item.Value.Apply) {
            return sap.ui.model.odata.AnnotationHelper.format(iContext, item.Value);
        }

        var oModel = iContext.getSetting('ovpCardProperties');
        var oEntityType = oModel.getProperty("/entityType");
        var oMetaModel = oModel.getProperty("/metaModel");

        return _formatField(iContext, item, oEntityType, oMetaModel, bDontIncludeUOM, bIncludeOnlyUOM);
    }

    function _formatField(iContext, oItem, oEntityType, oMetaModel, bDontIncludeUOM, bIncludeOnlyUOM) {

        if (oItem.Value.Apply) {
            return sap.ui.model.odata.AnnotationHelper.format(iContext, oItem.Value);
        }

        var oEntityTypeProperty = oMetaModel.getODataProperty(oEntityType, oItem.Value.Path);
        var result = "";
        var functionName;

        if (!bIncludeOnlyUOM) {

            //Support association
            if (oItem.Value.Path.split("/").length > 1) {
                oEntityTypeProperty = getNavigationSuffix(oMetaModel, oEntityType, oItem.Value.Path);
            }

            if (!oEntityTypeProperty) {
                return "";
            }

            //Item has ValueFormat annotation
            if (oItem.ValueFormat && oItem.ValueFormat.NumberOfFractionalDigits) {
                functionName = getNumberFormatFunctionName(oItem.ValueFormat.NumberOfFractionalDigits.Int);
                result = "{path:'" + oItem.Value.Path + "', formatter: '" + functionName + "'}";
            } else if (oEntityTypeProperty["scale"]) {
                //If there is no value format annotation, we will use the metadata scale property
                functionName = getNumberFormatFunctionName(oEntityTypeProperty["scale"]);
                result = "{path:'" + oEntityTypeProperty.name + "', formatter: '" + functionName + "'}";
            } else {
                result = sap.ui.model.odata.AnnotationHelper.format(iContext, oItem.Value);
            }
        }

        if (!bDontIncludeUOM) {
            //Add currency using path or string
            if (oEntityTypeProperty["Org.OData.Measures.V1.ISOCurrency"]) {
                var oCurrency = oEntityTypeProperty["Org.OData.Measures.V1.ISOCurrency"];
                if (oCurrency.Path) {
                    result = result + " {path: '" + oCurrency.Path + "'}";
                } else if (oCurrency.String) {
                    result = result + " " + oCurrency.String;
                }
            }

            //Add unit using path or string
            if (oEntityTypeProperty["Org.OData.Measures.V1.Unit"]) {
                var oUnit = oEntityTypeProperty["Org.OData.Measures.V1.Unit"];
                if (oUnit.Path) {
                    result = result + " {path: '" + oUnit.Path + "'}";
                } else if (oUnit.String) {
                    result = result + " " + oUnit.String;
                }
            }
        }

        if (result[0] === " "){
            result = result.substring(1);
        }

        return result;
    }

    function getNumberFormatFunctionName(numberOfFractionalDigits) {
        var functionName = "formatNumberCalculation" + numberOfFractionalDigits;
        if (!sap.ovp.cards.AnnotationHelper.NumberFormatFunctions[functionName]) {
            sap.ovp.cards.AnnotationHelper.NumberFormatFunctions[functionName] = generateNumberFormatFunc(Number(numberOfFractionalDigits));
        }
        return "sap.ovp.cards.AnnotationHelper.NumberFormatFunctions." + functionName;
    }

    function generateNumberFormatFunc(numOfFragmentDigit) {
        return function (value) {
            jQuery.sap.require("sap.ui.core.format.NumberFormat");
            var formatNumber = sap.ui.core.format.NumberFormat.getFloatInstance({
                style: 'short',
                showMeasure: false,
                minFractionDigits: numOfFragmentDigit,
                maxFractionDigits: numOfFragmentDigit
            });
            return formatNumber.format(Number(value));
        };
    }

    function getNavigationSuffix(oMetaModel, oEntityType, sProperty) {
        var aParts = sProperty.split("/");

        if (aParts.length > 1) {
            for (var i = 0; i < (aParts.length - 1); i++) {
                var oAssociationEnd = oMetaModel.getODataAssociationEnd(oEntityType, aParts[i]);
                if (oAssociationEnd) {
                    oEntityType = oMetaModel.getODataEntityType(oAssociationEnd.type);
                }
            }

            return oMetaModel.getODataProperty(oEntityType, aParts[aParts.length - 1]);
        }
    }

    function formatDataPointState(iContext, aCollection, index) {
        var aDataPoints = getSortedDataPoints(iContext, aCollection);
        var sState = "None";
        if (aDataPoints.length > index) {
            var item = aDataPoints[index];
           sState = formatDataPointToValue(iContext, item, sap.ovp.cards.AnnotationHelper.criticalityConstants.StateValues);
        }
        return sState;
    }

    function formatDataPointToValue(iContext, oDataPoint, oCriticalityConfigValues) {
        var sState = oCriticalityConfigValues.None;
        if (oDataPoint.Criticality) {
            sState = criticality2state(oDataPoint.Criticality, oCriticalityConfigValues);
        } else if (oDataPoint.CriticalityCalculation) {
            var sFormattedPath = sap.ui.model.odata.AnnotationHelper.format(iContext, oDataPoint.Value);
            var sPath = sFormattedPath.match(/path *: *'.*?',/g);
            if (sPath) {
                var fFormatFunc = generateCriticalityCalculationStateFunction(oDataPoint.CriticalityCalculation, oCriticalityConfigValues);
                sap.ovp.cards.AnnotationHelper.formatFunctions.count++;
                var fName = "formatCriticalityCalculation" + sap.ovp.cards.AnnotationHelper.formatFunctions.count;
                sap.ovp.cards.AnnotationHelper.formatFunctions[fName] = fFormatFunc;
                sState = "{" + sPath + " formatter: 'sap.ovp.cards.AnnotationHelper.formatFunctions." + fName + "'}";
            }
        }

        return sState;
    }

    function getNavigationPrefix(oMetaModel, oEntityType, sProperty) {
        var sExpand = "";
        var aParts = sProperty.split("/");

        if (aParts.length > 1) {
            for (var i = 0; i < (aParts.length - 1); i++) {
                var oAssociationEnd = oMetaModel.getODataAssociationEnd(oEntityType, aParts[i]);
                if (oAssociationEnd) {
                    oEntityType = oMetaModel.getODataEntityType(oAssociationEnd.type);
                    if (sExpand) {
                        sExpand = sExpand + "/";
                    }
                    sExpand = sExpand + aParts[i];
                } else {
                    return sExpand;
                }
            }
        }

        return sExpand;
    }

    sap.ovp.cards.AnnotationHelper.formatField = function (iContext, oItem) {
        return formatField(iContext,oItem);
    };

    /*
     * This formatter method parses the List-Card List's items aggregation path in the Model.
     * The returned path may contain also sorter definition (for the List) sorting is defined
     * appropriately via respected Annotations.
     *
     * @param iContext
     * @param itemsPath
     * @returns List-Card List's items aggregation path in the Model
     */
    sap.ovp.cards.AnnotationHelper.formatItems = function (iContext, oEntitySet) {
        var oModel = iContext.getSetting('ovpCardProperties');

        var bAddODataSelect = oModel.getProperty("/addODataSelect");
        var oMetaModel = oModel.getProperty("/metaModel");
        var oEntityType = oMetaModel.getODataEntityType(oEntitySet.entityType);
        var oSelectionVariant = oEntityType[oModel.getProperty('/selectionAnnotationPath')];
        var oPresentationVariant = oEntityType[oModel.getProperty('/presentationAnnotationPath')];
        var sEntitySetPath = "/" + oEntitySet.name;
        var aAnnotationsPath = Array.prototype.slice.call(arguments, 2);

        //check if entity set needs parameters
        // if selection-annotations path is supplied - we need to resolve it in order to resolve the full entity-set path
        if (oSelectionVariant) {
            if (oSelectionVariant && oSelectionVariant.Parameters) {
                // in case we have UI.SelectionVariant annotation defined on the entityType including Parameters - we need to resolve the entity-set path to include it
                sEntitySetPath = sap.ovp.cards.AnnotationHelper.resolveParameterizedEntitySet(iContext.getSetting('dataModel'), oEntitySet, oSelectionVariant);
            }
        }

        var result = "{path: '" + sEntitySetPath + "', length: " + getItemsLength(oModel);


        //prepare the select fields in case flag is on
        var aSelectFields = [];
        if (bAddODataSelect) {
            aSelectFields = getSelectFields(iContext, oMetaModel, oEntityType, aAnnotationsPath);
        }
        //prepare the expand list if navigation properties are used
        var aExpand = getExpandList(oMetaModel, oEntityType, aAnnotationsPath);

        //add select and expand parameters to the binding info string if needed
        if (aSelectFields.length > 0 || aExpand.length > 0) {
            result = result + ", parameters: {";
            if (aSelectFields.length > 0) {
                result = result + "select: '" + aSelectFields.join(',') + "'";
            }

            if (aExpand.length > 0) {
                if (aSelectFields.length > 0) {
                    result = result + ", ";
                }
                result = result + "expand: '" + aExpand.join(',') + "'";
            }
            result = result + "}";
        }

        //apply sorters information
        var aSorters = getSorters(oModel, oPresentationVariant);
        if (aSorters.length > 0) {
            result = result + ", sorter:" + JSON.stringify(aSorters);
        }

        //apply filters information
        var aFilters = getFilters(oModel, oSelectionVariant);
        if (aFilters.length > 0) {
            result = result + ", filters:" + JSON.stringify(aFilters);
        }
        result = result + "}";

        // returning the parsed path for the Card's items-aggregation binding
        return result;
    };

    /**
     * returns an array of navigation properties prefixes to be used in an odata $expand parameter
     *
     * @param oMetaModel - metamodel to get the annotations to query
     * @param oEntityType - the relevant entityType
     * @param aAnnotationsPath - an array of annotation path to check
     * @returns {Array} of navigation properties prefixes to be used in an odata $expand parameter
     */
    function getExpandList(oMetaModel, oEntityType, aAnnotationsPath) {
        var aExpand = [];
        var sAnnotationPath, oBindingContext, aColl, sExpand;

        //loop over the annotation paths
        for (var i = 0; i < aAnnotationsPath.length; i++) {
            if (!aAnnotationsPath[i]) {
                continue;
            }
            sAnnotationPath = oEntityType.$path + "/" + aAnnotationsPath[i];
            oBindingContext = oMetaModel.createBindingContext(sAnnotationPath);
            aColl = oBindingContext.getObject();
            //if the annotationPath does not exists there is no BindingContext
            aColl = aColl ? aColl : [];
            for (var j = 0; j < aColl.length; j++) {
                if (aColl[j].Value && aColl[j].Value.Path) {
                    sExpand = getNavigationPrefix(oMetaModel, oEntityType, aColl[j].Value.Path);
                    if (sExpand && aExpand.indexOf(sExpand) === -1) {
                        aExpand.push(sExpand);
                    }
                }
            }
        }
        return aExpand;
    }

    /**
     * returns an array of properties paths to be used in an odata $select parameter
     *
     * @param oMetaModel - metamodel to get the annotations to query
     * @param oEntityType - the relevant entityType
     * @param aAnnotationsPath - an array of annotation path to check
     * @returns {Array} of properties paths to be used in an odata $select parameter
     */
    function getSelectFields(iContext, oMetaModel, oEntityType, aAnnotationsPath) {

        var aSelectFields = [];
        var sAnnotationPath, oBindingContext, aColl;

        //loop over the annotation paths
        for (var i = 0; i < aAnnotationsPath.length; i++) {
            if (!aAnnotationsPath[i]) {
                continue;
            }
            sAnnotationPath = oEntityType.$path + "/" + aAnnotationsPath[i];
            oBindingContext = oMetaModel.createBindingContext(sAnnotationPath);
            aColl = oBindingContext.getObject();
            //if the annotationPath does not exists there is no BindingContext
            aColl = aColl ? aColl : [];

            var oItem;
            var aItemValue;
            var sFormattedField;
            var sRecordType;
            for (var j = 0; j < aColl.length; j++) {

                aItemValue = [];
                oItem = aColl[j];
                sFormattedField = "";

                sRecordType = oItem.RecordType;

                if (sRecordType === "com.sap.vocabularies.UI.v1.DataField") {
                    // in case of a DataField we format the field to get biding string
                    sFormattedField = _formatField(iContext,oItem,oEntityType,oMetaModel);

                } else if (sRecordType === "com.sap.vocabularies.UI.v1.DataFieldForAnnotation") {

                    // in case of DataFieldForAnnotation we resolve the DataPoint target path of the DataField and format the field to get biding string
                    var sTargetPath = getTargetPathForDataFieldForAnnotation(oEntityType.$path, oItem);
                    sFormattedField = _formatDataPoint(iContext, oMetaModel.getProperty(sTargetPath), oEntityType, oMetaModel);

                } else if (sRecordType === "com.sap.vocabularies.UI.v1.DataFieldWithUrl" && oItem.Url) {

                    // format the URL ONLY IN CASE NO UrlRef member resides under it
                    var sFormattedUrl;
                    if (!oItem.Url.UrlRef) {
                        sFormattedUrl = sap.ui.model.odata.AnnotationHelper.format(iContext, oItem.Url);
                    }

                    // meaning binding which needs to be evaluated at runtime
                    if (sFormattedUrl && sFormattedUrl.substring(0,2) === "{=") {
                        sFormattedField = sFormattedUrl;
                    }
                }

                // if we have found a relevant binding-info-string this iteration then parse it to get binded properties
                if (sFormattedField) {
                    aItemValue = getPropertiesFromBindingString(sFormattedField);
                }

                if (aItemValue && aItemValue.length > 0) {
                    // for each property found we check if has sap:unit and sap:text
                    var sItemValue;
                    for (var k = 0; k < aItemValue.length; k++) {
                        sItemValue = aItemValue[k];

                        // if this property is found for the first time - look for its unit and text properties as well
                        if (!aSelectFields[sItemValue]) {

                            aSelectFields[sItemValue] = true;

                            // checking if we need to add also the sap:unit property of the field's value
                            var sUnitPropName = getUnitColumn(sItemValue, oEntityType);
                            if (sUnitPropName && sUnitPropName !== sItemValue) {
                                aSelectFields[sUnitPropName] = true;
                            }

                            // checking if we need to add also the sap:text property of the field's value
                            var sTextPropName = getTextPropertyForEntityProperty(oMetaModel, oEntityType, sItemValue);
                            if (sTextPropName && sTextPropName !== sItemValue) {
                                aSelectFields[sTextPropName] = true;
                            }
                        }
                    }
                }
            }
        }
        // return all relevant property names
        return Object.keys(aSelectFields);
    }

    function getPropertiesFromBindingString(sBinding) {

        var regexBindingEvaluation = /\${([a-zA-Z0-9|\/]*)/g;
        var regexBindingNoPath = /[^[{]*[a-zA-Z0-9]/g;
        var regexBindingPath = /path *\: *\'([a-zA-Z0-9]+)*\'/g;

        var regex, index, matches = [];

        if (sBinding.substring(0, 2) === "{=") {
            /*
             meaning binding string looks like "{= <rest of the binding string>}"
             which is a binding which needs to be evaluated using some supported function
             properties appear as ${propertyName} inside the string
             */
            regex = regexBindingEvaluation;

            /* index is 1 as each match found by this regular expression (by invoking regex.exec(string) below) */
            /* is an array of 2 items, for example ["${Address}", "Address"] so we need the 2nd result each match found */
            index = 1;

        } else if (sBinding.indexOf("path") !== -1) {

            /* In a scenario where binding contains string like "{propertyName} {path:'propertyName'}" */
            /* Here we get the properties without path and add it to array matches*/
            var matchWithNoPath = regexBindingNoPath.exec(sBinding);
            while (matchWithNoPath) {
                if (matchWithNoPath[0].indexOf("path") === -1) {
                    matches.push(matchWithNoPath[0]);
                }
                matchWithNoPath = regexBindingNoPath.exec(sBinding);
            }

            /* meaning binding contains string like "{path:'propertyName'}" */
            regex = regexBindingPath;

            /* index is 1 as each match found by this regular expression (by invoking regex.exec(string) below) */
            /* is an array of 2 items, for example ["{path: 'Address'}", "Address"] so we need the 2nd result each match found */
            index = 1;

        } else {
            /* meaning binding contains string like "{'propertyName'}" */
            regex = regexBindingNoPath;

            /* index is 0 as each match found by this regular expression (by invoking regex.exec(string) below) */
            /* is an array of one item, for example ["Address"] so we need the 1st result each match found */
            index = 0;
        }

        var match = regex.exec(sBinding);
        while (match) {
            if (match[index]) {
                matches.push(match[index]);
            }
            match = regex.exec(sBinding);
        }
        return matches;
    }

    /**
     * return the sorters that need to be applyed on an aggregation
     *
     * @param ovpCardProperties - card properties model which might contains sort configurations
     * @param oPresentationVariant - optional presentation variant annotation with SortOrder configuration
     * @returns {Array} of model sorters
     */
    function getSorters(ovpCardProperties, oPresentationVariant) {
        var aSorters = [];
        var oSorter, bDescending;

        //get the configured sorter if exist and append them to the sorters array
        var sPropertyPath = ovpCardProperties.getProperty("/sortBy");
        if (sPropertyPath) {
            // If sorting is enabled by card configuration
            var sSortOrder = ovpCardProperties.getProperty('/sortOrder');
            if (sSortOrder && sSortOrder.toLowerCase() !== 'descending') {
                bDescending = false;
            } else {
                bDescending = true;
            }
            oSorter = {
                path: sPropertyPath,
                descending: bDescending
            };
            aSorters.push(oSorter);
        }

        //get the sorters from the presentation variant annotations if exists
        var aSortOrder = oPresentationVariant && oPresentationVariant.SortOrder || undefined;
        var oSortOrder, sPropertyPath;
        if (aSortOrder) {
            for (var i = 0; i < aSortOrder.length; i++) {
                oSortOrder = aSortOrder[i];
                sPropertyPath = oSortOrder.Property.PropertyPath;
                bDescending = getBooleanValue(oSortOrder.Descending, true);
                oSorter = {
                    path: sPropertyPath,
                    descending: bDescending
                };
                aSorters.push(oSorter);
            }
        }

        return aSorters;
    }


    sap.ovp.cards.AnnotationHelper.getCardFilters = function (ovpCardProperties) {
        var oEntityType = ovpCardProperties.getProperty('/entityType');
        var oSelectionVariant = oEntityType[ovpCardProperties.getProperty('/selectionAnnotationPath')];

        return getFilters(ovpCardProperties, oSelectionVariant);
    };

    /**
     * return the filters that need to be applyed on an aggregation
     *
     * @param ovpCardProperties - card properties model which might contains filters configurations
     * @param oSelectionVariant - optional selection variant annotation with SelectOptions configuration
     * @returns {Array} of model filters
     */
    function getFilters(ovpCardProperties, oSelectionVariant) {
        var aFilters = [];
        //get the configured filters if exist and append them to the filter array
        var aConfigFilters = ovpCardProperties.getProperty("/filters");
        if (aConfigFilters) {
            aFilters = aFilters.concat(aConfigFilters);
        }

        //get the filters from the selection variant annotations if exists
        var aSelectOptions = oSelectionVariant && oSelectionVariant.SelectOptions;
        var oSelectOption, sPropertyPath, oRange;
        if (aSelectOptions) {
            for (var i = 0; i < aSelectOptions.length; i++) {
                oSelectOption = aSelectOptions[i];
                sPropertyPath = oSelectOption.PropertyName.PropertyPath;
                //a select option might contains more then one filter in the Ranges array
                for (var j = 0; j < oSelectOption.Ranges.length; j++) {
                    oRange = oSelectOption.Ranges[j];
                    if (oRange.Sign.EnumMember === "com.sap.vocabularies.UI.v1.SelectionRangeSignType/I") {
                        //create the filter. the Low value is mandatory
                        var oFilter = {
                            path: sPropertyPath,
                            operator: oRange.Option.EnumMember.split("/")[1],
                            value1: getPrimitiveValue(oRange.Low),
                            value2: getPrimitiveValue(oRange.High)
                        };
                        //append the filter to the filters array
                        aFilters.push(oFilter);
                    }
                }
            }
        }

        return aFilters;
    }

    function getBooleanValue(oValue, bDefault) {
        if (oValue && oValue.Boolean) {
            if (oValue.Boolean.toLowerCase() === "true") {
                return true;
            } else if (oValue.Boolean.toLowerCase() === "false") {
                return false;
            }
        }
        return bDefault;
    }

    function getNumberValue(oValue) {
        var value;

        if (oValue) {
            if (oValue.String) {
                value = Number(oValue.String);
            } else if (oValue.Int) {
                value = Number(oValue.Int);
            } else if (oValue.Decimal) {
                value = Number(oValue.Decimal);
            } else if (oValue.Double) {
                value = Number(oValue.Double);
            } else if (oValue.Single) {
                value = Number(oValue.Single);
            }
        }

        return value;
    }

    function getPrimitiveValue(oValue) {
        var value;

        if (oValue) {
            if (oValue.String) {
                value = oValue.String;
            } else if (oValue.Boolean) {
                value = getBooleanValue(oValue);
            } else {
                value = getNumberValue(oValue);
            }
        }

        return value;
    }


    //This object is responsive for devices
    //the id build by Type-ListType-flavor
    var ITEM_LENGTH = {
        "List_condensed": {phone: 5, tablet: 5, desktop: 5},
        "List_extended": {phone: 3, tablet: 3, desktop: 3},
        "List_condensed_bar": {phone: 5, tablet: 5, desktop: 5},
        "List_extended_bar": {phone: 3, tablet: 3, desktop: 3},
        "Table": {phone: 5, tablet: 5, desktop: 5},
        "Stack_simple": {phone: 20, tablet: 20, desktop: 20},
        "Stack_complex": {phone: 5, tablet: 5, desktop: 5}
    };

    function getItemsLength(oOvpCardPropertiesModel) {
        var type = oOvpCardPropertiesModel.getProperty('/contentFragment');
        var listType = oOvpCardPropertiesModel.getProperty('/listType');
        var flavor = oOvpCardPropertiesModel.getProperty('/listFlavor');
        var oItemSizes;

        var device = "desktop";

        //get current device
        if (sap.ui.Device.system.phone) {
            device = "phone";
        } else if (sap.ui.Device.system.tablet) {
            device = "tablet";
        }

        //check the current card type and get the sizes objects
        if (type == "sap.ovp.cards.list.List") {
            if (listType == "extended") {
                if (flavor == "bar") {
                    oItemSizes = ITEM_LENGTH["List_extended_bar"];
                } else {
                    oItemSizes = ITEM_LENGTH["List_extended"];
                }
            } else if (flavor == "bar") {
                oItemSizes = ITEM_LENGTH["List_condensed_bar"];
            } else {
                oItemSizes = ITEM_LENGTH["List_condensed"];
            }
        } else if (type == "sap.ovp.cards.table.Table") {
            oItemSizes = ITEM_LENGTH["Table"];
        } else if (type == "sap.ovp.cards.stack.Stack") {

            if (oOvpCardPropertiesModel.getProperty('/objectStreamCardsNavigationProperty')) {
                oItemSizes = ITEM_LENGTH["Stack_complex"];
            } else {
                oItemSizes = ITEM_LENGTH["Stack_simple"];
            }
        }

        if (oItemSizes) {
            return oItemSizes[device];
        }

        return 5;
    }

    sap.ovp.cards.AnnotationHelper.formatUrl = function (iContext, sUrl) {
        if (sUrl.charAt(0) === '/' || sUrl.indexOf("http") === 0) {
            return sUrl;
        }
        var sBaseUrl = iContext.getModel().getProperty("/baseUrl");
        if (sBaseUrl) {
            return sBaseUrl + "/" + sUrl;
        }
        return sUrl;
    };

    sap.ovp.cards.AnnotationHelper.getDataPointsCount = function (iContext, aCollection) {
        var aDataPoints = getSortedDataPoints(iContext, aCollection);
        return aDataPoints.length;
    };

    sap.ovp.cards.AnnotationHelper.getFirstDataPointValue = function (iContext, aCollection) {
        return sap.ovp.cards.AnnotationHelper.getDataPointValue(iContext, aCollection, 0);
    };

    sap.ovp.cards.AnnotationHelper.getSecondDataPointValue = function (iContext, aCollection) {
        return sap.ovp.cards.AnnotationHelper.getDataPointValue(iContext, aCollection, 1);
    };

    sap.ovp.cards.AnnotationHelper.getDataPointValue = function (iContext, aCollection, index) {
        var aDataPoints = getSortedDataPoints(iContext, aCollection),
            oDataPoint = aDataPoints[index];

        if (oDataPoint && oDataPoint.Value && oDataPoint.Value.Path) {
            return oDataPoint.Value.Path;
        }
        return "";
    };

    sap.ovp.cards.AnnotationHelper.getFirstDataFieldName = function (iContext, aCollection) {
        return getDataFieldName(iContext, aCollection, 0);
    };

    sap.ovp.cards.AnnotationHelper.getSecondDataFieldName = function (iContext, aCollection) {
        return getDataFieldName(iContext, aCollection, 1);
    };

    sap.ovp.cards.AnnotationHelper.getThirdDataFieldName = function (iContext, aCollection) {
        return getDataFieldName(iContext, aCollection, 2);
    };

    sap.ovp.cards.AnnotationHelper.formatFirstDataFieldValue = function (iContext, aCollection) {
        return formatDataField(iContext, aCollection, 0);
    };

    sap.ovp.cards.AnnotationHelper.formatSecondDataFieldValue = function (iContext, aCollection) {
        return formatDataField(iContext, aCollection, 1);
    };

    sap.ovp.cards.AnnotationHelper.formatThirdDataFieldValue = function (iContext, aCollection) {
        return formatDataField(iContext, aCollection, 2);
    };

    sap.ovp.cards.AnnotationHelper.formatFourthDataFieldValue = function (iContext, aCollection) {
        return formatDataField(iContext, aCollection, 3);
    };

    sap.ovp.cards.AnnotationHelper.formatFifthDataFieldValue = function (iContext, aCollection) {
        return formatDataField(iContext, aCollection, 4);
    };

    sap.ovp.cards.AnnotationHelper.formatSixthDataFieldValue = function (iContext, aCollection) {
        return formatDataField(iContext, aCollection, 5);
    };

    sap.ovp.cards.AnnotationHelper.getFirstDataPointName = function (iContext, aCollection) {
        return getDataPointName(iContext, aCollection, 0);
    };

    sap.ovp.cards.AnnotationHelper.getSecondDataPointName = function (iContext, aCollection) {
        return getDataPointName(iContext, aCollection, 1);
    };

    sap.ovp.cards.AnnotationHelper.getThirdDataPointName = function (iContext, aCollection) {
        return getDataPointName(iContext, aCollection, 2);
    };

    sap.ovp.cards.AnnotationHelper.formatFirstDataPointValue = function (iContext, aCollection) {
        return formatDataPoint(iContext, aCollection, 0);
    };

    sap.ovp.cards.AnnotationHelper.formatSecondDataPointValue = function (iContext, aCollection) {
        return formatDataPoint(iContext, aCollection, 1);
    };

    sap.ovp.cards.AnnotationHelper.formatThirdDataPointValue = function (iContext, aCollection) {
        return formatDataPoint(iContext, aCollection, 2);
    };

    sap.ovp.cards.AnnotationHelper.formatFirstDataPointState = function (iContext, aCollection) {
        return formatDataPointState(iContext, aCollection, 0);
    };

    sap.ovp.cards.AnnotationHelper.formatSecondDataPointState = function (iContext, aCollection) {
        return formatDataPointState(iContext, aCollection, 1);
    };

    sap.ovp.cards.AnnotationHelper.formatThirdDataPointState = function (iContext, aCollection) {
        return formatDataPointState(iContext, aCollection, 2);
    };

    sap.ovp.cards.AnnotationHelper.formatKPIHeaderState = function (iContext, oDataPoint) {
        return formatDataPointToValue(iContext, oDataPoint, sap.ovp.cards.AnnotationHelper.criticalityConstants.ColorValues);
    };

    /*
     * @param iContext
     * @returns 0 for false - there are no actions for this context
     *          1 for true - there are actions for this context
     *          does not return actual boolean - so we won't need to parse the result in the xml
     */
    sap.ovp.cards.AnnotationHelper.hasActions = function (iContext, aCollection) {
        var oItem;
        for (var i = 0; i < aCollection.length; i++){
            oItem = aCollection[i];
            if (oItem.RecordType === "com.sap.vocabularies.UI.v1.DataFieldForIntentBasedNavigation" ||
                oItem.RecordType === "com.sap.vocabularies.UI.v1.DataFieldForAction" ||
                oItem.RecordType === "com.sap.vocabularies.UI.v1.DataFieldWithUrl"){
                return 1;
            }
        }
        return 0;
    };

    sap.ovp.cards.AnnotationHelper.isFirstDataPointPercentageUnit = function (iContext, aCollection) {
        var oDataPoint = getSortedDataPoints(iContext, aCollection)[0];

        if (oDataPoint && oDataPoint.Value && oDataPoint.Value.Path) {
            var sEntityTypePath = iContext.getPath().substr(0, iContext.getPath().lastIndexOf("/") + 1);
            var oModel = iContext.getModel();
            var oEntityType = oModel.getProperty(sEntityTypePath);
            var oProperty = oModel.getODataProperty(oEntityType, oDataPoint.Value.Path);
            if (oProperty && oProperty["Org.OData.Measures.V1.Unit"]) {
                return oProperty["Org.OData.Measures.V1.Unit"].String === "%";
            }
        }
        return false;
    };

    sap.ovp.cards.AnnotationHelper.resolveEntityTypePath = function (oAnnotationPathContext) {
        var sAnnotationPath = oAnnotationPathContext.getObject();
        var oModel = oAnnotationPathContext.getModel();
        var oMetaModel = oModel.getProperty("/metaModel");
        var oEntitySet = oMetaModel.getODataEntitySet(oModel.getProperty("/entitySet"));
        var oEntityType = oMetaModel.getODataEntityType(oEntitySet.entityType);
        sAnnotationPath = oEntityType.$path + "/" + sAnnotationPath;
        return oMetaModel.createBindingContext(sAnnotationPath);
    };

    sap.ovp.cards.AnnotationHelper.resolveParameterizedEntitySet = function (oDataModel, oEntitySet, oSelectionVariant) {

        jQuery.sap.require("sap.ui.model.analytics.odata4analytics");
        var path = "";
        var o4a = new sap.ui.model.analytics.odata4analytics.Model(sap.ui.model.analytics.odata4analytics.Model.ReferenceByModel(oDataModel));
        var queryResult = o4a.findQueryResultByName(oEntitySet.name);
        var queryResultRequest = new sap.ui.model.analytics.odata4analytics.QueryResultRequest(queryResult);
        var parameterization = queryResult.getParameterization();

        if (parameterization) {
            queryResultRequest.setParameterizationRequest(new sap.ui.model.analytics.odata4analytics.ParameterizationRequest(parameterization));
            jQuery.each(oSelectionVariant.Parameters, function () {
                if (this.RecordType === "com.sap.vocabularies.UI.v1.IntervalParameter") {
                    queryResultRequest.getParameterizationRequest().setParameterValue(
                        this.PropertyName.PropertyPath,
                        this.PropertyValueFrom.String,
                        this.PropertyValueTo.String
                    );
                } else {
                    queryResultRequest.getParameterizationRequest().setParameterValue(
                        this.PropertyName.PropertyPath,
                        this.PropertyValue.String
                    );
                }
            });
        }

        try {
            path = queryResultRequest.getURIToQueryResultEntitySet();
        } catch (exception) {
            queryResult = queryResultRequest.getQueryResult();
            path = "/" + queryResult.getEntitySet().getQName();
            jQuery.sap.log.error("getEntitySetPathWithParameters", "binding path with parameters failed - " + exception
                || exception.message);
        }
        return path;
    };

    sap.ovp.cards.AnnotationHelper.getAssociationObject = function (oModel, sAssociation, ns) {
        // find a nicer way of getting association set entry in meta model
        var aAssociations = oModel.getServiceMetadata().dataServices.schema[0].association;
        for (var i = 0; i < aAssociations.length; i++) {
            if (ns + "." + aAssociations[i].name === sAssociation) {
                return aAssociations[i];
            }
        }
    };


    /**************************** Formatters & Helpers for KPI-Header logic  ****************************/

    /* Returns binding path for singleton */
    sap.ovp.cards.AnnotationHelper.getAggregateNumber = function (iContext, oEntitySet, oDataPoint, oSelectionVariant) {
        var measure = oDataPoint.Value.Path;
        var ret = "";
        var bParams = oSelectionVariant && oSelectionVariant.Parameters;
        var filtersString = "";

        if (bParams) {
            var dataModel = iContext.getSetting("dataModel");
            var path = sap.ovp.cards.AnnotationHelper.resolveParameterizedEntitySet(dataModel, oEntitySet, oSelectionVariant);
            ret += "{path: '" + path + "'";
        } else {
            ret += "{path: '/" + oEntitySet.name + "'";
        }

        ret += ", length: 1";
        var oOvpCardSettings = iContext.getSetting('ovpCardProperties');
        var oEntityType = oOvpCardSettings.getProperty("/entityType");
        var unitColumn = getUnitColumn(measure, oEntityType);
        var aFilters = getFilters(oOvpCardSettings, oSelectionVariant);

        if (aFilters.length > 0) {
            filtersString += ", filters: " + JSON.stringify(aFilters);
        }

        var selectArr = [];
        selectArr.push(measure);
        if (unitColumn) {
            selectArr.push(unitColumn);
        }
        if (oDataPoint.TrendCalculation && oDataPoint.TrendCalculation.ReferenceValue && oDataPoint.TrendCalculation.ReferenceValue.Path) {
            selectArr.push(oDataPoint.TrendCalculation.ReferenceValue.Path);
        }

        return ret + ", parameters:{select:'" + selectArr.join(",") + "'}" + filtersString + "}";
    };


    /* Creates binding path for NumericContent value */
    sap.ovp.cards.AnnotationHelper.formThePathForAggregateNumber = function (iContext, dataPoint) {
        if (!dataPoint || !dataPoint.Value || !dataPoint.Value.Path) {
            return "";
        }

        return formatField(iContext, dataPoint, true, false);
    };


    /* Creates binding path for trend icon */
    sap.ovp.cards.AnnotationHelper.formThePathForTrendIcon = function (dataPoint) {
        if (!dataPoint || !dataPoint.Value || !dataPoint.Value.Path || !dataPoint.TrendCalculation) {
            return "";
        }

        if (dataPoint.TrendCalculation &&
            dataPoint.TrendCalculation.ReferenceValue &&
            dataPoint.TrendCalculation.ReferenceValue.Path) {
            return "{parts: [{path:'" + dataPoint.Value.Path + "'}, {path:'" + dataPoint.TrendCalculation.ReferenceValue.Path + "'}], formatter: 'sap.ovp.cards.AnnotationHelper.returnTrendDirection'}";
        } else {
            return "{parts: [{path:'" + dataPoint.Value.Path + "'}], formatter: 'sap.ovp.cards.AnnotationHelper.returnTrendDirection'}";
        }
    };

    /* Formatter for Trend Direction for Header */
    sap.ovp.cards.AnnotationHelper.returnTrendDirection = function (aggregateValue, referenceValue) {
        aggregateValue = Number(aggregateValue);
        var ovpModel = this.getModel("ovpCardProperties");
        if (!ovpModel) {
            return;
        }
        var fullQualifier = ovpModel.getProperty("/dataPointAnnotationPath");
        var dataPoint = ovpModel.getProperty("/entityType")[fullQualifier];
        var finalReferenceValue, upDifference, downDifference;

        if (dataPoint.TrendCalculation.ReferenceValue) {
            if (dataPoint.TrendCalculation.ReferenceValue.Path) {
                finalReferenceValue = Number(referenceValue);
            } else {
                finalReferenceValue = getNumberValue(dataPoint.TrendCalculation.ReferenceValue);
            }
        }
        if (dataPoint.TrendCalculation.UpDifference) {
            upDifference = getNumberValue(dataPoint.TrendCalculation.UpDifference);
        }
        if (dataPoint.TrendCalculation.DownDifference) {
            downDifference = getNumberValue(dataPoint.TrendCalculation.DownDifference);
        }
        if (!dataPoint.TrendCalculation.UpDifference && (aggregateValue - finalReferenceValue >= 0)) {
            return "Up";
        }
        if (!dataPoint.TrendCalculation.DownDifference && (aggregateValue - finalReferenceValue <= 0)) {
            return "Down";
        }

        if (finalReferenceValue && upDifference && (aggregateValue - finalReferenceValue >= upDifference)) {
            return "Up";
        }
        if (finalReferenceValue && downDifference && (aggregateValue - finalReferenceValue <= downDifference)) {
            return "Down";
        }
    };

    /* Creates binding path for UOM placeholder */
    sap.ovp.cards.AnnotationHelper.formThePathForUOM = function (iContext, dataPoint) {
        if (!dataPoint || !dataPoint.Value || !dataPoint.Value.Path) {
            return "";
        }

        return formatField(iContext, dataPoint, false, true);
    };


    /* Creates binding path for % change */
    sap.ovp.cards.AnnotationHelper.formPathForPercentageChange = function (dataPoint) {
        if (!dataPoint || !dataPoint.TrendCalculation || !dataPoint.TrendCalculation.ReferenceValue) {
            return "";
        }
        if (dataPoint.TrendCalculation.ReferenceValue.Path) {
            return "{parts: [{path:'" + dataPoint.Value.Path + "'}, {path:'" + dataPoint.TrendCalculation.ReferenceValue.Path + "'}], formatter: 'sap.ovp.cards.AnnotationHelper.returnPercentageChange'}";
        } else {
            return "{parts: [{path:'" + dataPoint.Value.Path + "'}], formatter: 'sap.ovp.cards.AnnotationHelper.returnPercentageChange'}";
        }
    };


    /* Formatter for % change for Header */
    sap.ovp.cards.AnnotationHelper.returnPercentageChange = function (aggregateValue, referenceValuePath) {
        jQuery.sap.require("sap.ui.core.format.NumberFormat");
        var ret = "";
        aggregateValue = Number(aggregateValue);
        var ovpModel = this.getModel("ovpCardProperties");
        if (!ovpModel) {
            return ret;
        }
        var fullQualifier = ovpModel.getProperty("/dataPointAnnotationPath");
        var dataPoint = ovpModel.getProperty("/entityType")[fullQualifier];
        var referenceValue;
        if (!dataPoint.TrendCalculation) {
            return ret;
        }
        if (dataPoint.TrendCalculation.ReferenceValue) {
            if (dataPoint.TrendCalculation.ReferenceValue.String) {
                referenceValue = Number(dataPoint.TrendCalculation.ReferenceValue.String);
            }
            if (dataPoint.TrendCalculation.ReferenceValue.Path) {
                referenceValue = Number(referenceValuePath);
            }
            if (!referenceValue || referenceValue == 0) {
                return ret;
            }
            var percentNumber = ((Number(aggregateValue) - referenceValue) / referenceValue);
            var percentFormatter = sap.ui.core.format.NumberFormat.getPercentInstance({
                style: 'short',
                minFractionDigits: 2,
                maxFractionDigits: 2
            });
         
            return percentFormatter.format(percentNumber);
        }
    };


    /*
     * Reads groupBy from annotation and prepares comma separated list
     */
    sap.ovp.cards.AnnotationHelper.listGroupBy = function (oPresentationVariant) {
        var result = "";
        var bPV = oPresentationVariant && oPresentationVariant.GroupBy;
        if (!bPV) {
            return result;
        }

        var metaModel = this.getModel('ovpCardProperties').getProperty("/metaModel");
        var oEntityType = this.getModel('ovpCardProperties').getProperty("/entityType");
        var groupByList;

        if (oPresentationVariant.GroupBy.constructor === Array) {
            groupByList = oPresentationVariant.GroupBy;
        } else if (!oPresentationVariant.GroupBy.Collection) {
            return result;
        } else {
            groupByList = oPresentationVariant.GroupBy.Collection;
        }


        var propVal;
        jQuery.each(groupByList, function () {

            propVal = getLabelForEntityProperty(metaModel, oEntityType, this.PropertyPath);
            if (!propVal) {
                return;
            }

            result += propVal;
            result += ", ";
        });
        if (result[result.length - 1] === " " && result[result.length - 2] === ",") {
            result = result.substring(0, result.length - 2);
        }
        return result == "" ? "" : sap.ui.getCore().getLibraryResourceBundle("sap.ovp").getText("By", [result]);
    };

    /*
    * returns the string for the filter-by values of the KPI Header
    * */
    sap.ovp.cards.AnnotationHelper.formTheFilterByString = function(iContext, oSelectionVariant) {
        var oCardPropsModel = iContext.getSetting('ovpCardProperties');
        var oEntityType = oCardPropsModel.getProperty("/entityType");
        var oMetaModel = oCardPropsModel.getProperty("/metaModel");
        var aFilters = getFilters(oCardPropsModel, oSelectionVariant);
        var sProp;
        var sTextPropKey;

        //Clean from Filter array all the filters with sap-text that the filter array contains there sap-text
        for (var i = 0; i < aFilters.length; i++ ) {
            sProp = aFilters[i].path;
            sTextPropKey = getTextPropertyForEntityProperty(oMetaModel, oEntityType, sProp);

            //Check if there is sap-text, in case there is checks that the Filter array contains it
            if (sTextPropKey !== sProp) {
                for (var j = 0; j < aFilters.length; j++ ) {

                    // if there is sap test - we won't show the original filter (instead we will show the sap-text) and we clean it from the array
                    if ((aFilters[j].path == sTextPropKey)){
                        aFilters.splice(i, 1);
                        break;
                    }
                }
            }
        }
        // build the filter string
        return generateStringForFilters(aFilters);
    };

    /************************ METADATA PARSERS ************************/

    function generateStringForFilters(aFilters) {
        var aFormatterFilters = [];

        for (var i = 0; i < aFilters.length; i++ ) {
            aFormatterFilters.push(generateSingleFilter(aFilters[i]));
        }

        return aFormatterFilters.join(', ');
    }

    function generateSingleFilter(oFilter) {
        var bNotOperator = false;
        var sFormattedFilter = oFilter.value1;

        if (oFilter.operator[0] === "N") {
            bNotOperator = true;
        }

        if (oFilter.value2) {
            sFormattedFilter += " - " + oFilter.value2;
        }

        if (bNotOperator) {
            sFormattedFilter = sap.ui.getCore().getLibraryResourceBundle("sap.ovp").getText("kpiHeader_Filter_NotOperator", [sFormattedFilter]);
        }

        return sFormattedFilter;
    }


    /* Returns column name that contains the unit for the measure */
    function getUnitColumn (measure, oEntityType) {
        var properties = oEntityType.property;
        for (var i = 0, len = properties.length; i < len; i++) {
            if (properties[i].name == measure) {
                if (properties[i].hasOwnProperty("sap:unit")) {
                    return properties[i]["sap:unit"];
                }
                break;
            }
        }
        return null;
    }

    function getLabelForEntityProperty(oMetadata, oEntityType, sPropertyName) {
        return getAttributeValueForEntityProperty(oMetadata, oEntityType,
            sPropertyName, "com.sap.vocabularies.Common.v1.Label");
    }

    function getTextPropertyForEntityProperty(oMetamodel, oEntityType, sPropertyName) {
        return getAttributeValueForEntityProperty(oMetamodel, oEntityType,
            sPropertyName, "sap:text");
    }

    function getAttributeValueForEntityProperty(oMetamodel, oEntityType, sPropertyName, sAttributeName) {
        var oProp = oMetamodel.getODataProperty(oEntityType, sPropertyName);
        if (!oProp) {
            jQuery.sap.log.error("No Property Found for with Name '" + sPropertyName
                + " For Entity-Type '" + oEntityType.name + "'");
            return;
        }
        var oPropAttVal = oProp[sAttributeName];
        if (oPropAttVal) {
            if (sAttributeName === "com.sap.vocabularies.Common.v1.Label") {
                return oPropAttVal.String;
            }
            return oPropAttVal;
        }

        return oProp.name;
    }

    sap.ovp.cards.AnnotationHelper._criticality2state = criticality2state;
    sap.ovp.cards.AnnotationHelper._generateCriticalityCalculationStateFunction = generateCriticalityCalculationStateFunction;
    sap.ovp.cards.AnnotationHelper._getPropertiesFromBindingString = getPropertiesFromBindingString;
    sap.ovp.cards.AnnotationHelper.sortCollectionByImportance = sortCollectionByImportance;

    sap.ovp.cards.AnnotationHelper.formatField.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formThePathForAggregateNumber.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formThePathForUOM.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formTheFilterByString.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getAggregateNumber.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getFirstDataFieldName.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getSecondDataFieldName.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getThirdDataFieldName.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatFirstDataFieldValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatSecondDataFieldValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatThirdDataFieldValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatFourthDataFieldValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatFifthDataFieldValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatSixthDataFieldValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getDataPointsCount.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getFirstDataPointName.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getSecondDataPointName.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getThirdDataPointName.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatFirstDataPointValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatSecondDataPointValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatThirdDataPointValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatFirstDataPointState.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatSecondDataPointState.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatThirdDataPointState.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatKPIHeaderState.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatItems.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatUrl.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.hasActions.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getFirstDataPointValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getSecondDataPointValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.isFirstDataPointPercentageUnit.requiresIContext = true;

}());

}; // end of sap/ovp/cards/AnnotationHelper.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.CommonUtils') ) {
(function () {
    "use strict";
    jQuery.sap.declare("sap.ovp.cards.CommonUtils");
    sap.ovp.cards.CommonUtils = {
        app : undefined,
        navigationHandler : undefined,

        enable : function(app, oNavHandler) {
            this.app = app;
            this.navigationHandler = oNavHandler;
        },

        getApp : function() {
            return this.app;
        },

        getNavigationHandler : function() {
            return this.navigationHandler;
        }
    };
}());
}; // end of sap/ovp/cards/CommonUtils.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.charts.Utils') ) {
/**
 * @fileOverview This file contains miscellaneous utility functions.
 */

(function () {
	"use strict";
	jQuery.sap.declare("sap.ovp.cards.charts.Utils");


	sap.ovp.cards.charts.Utils = sap.ovp.cards.charts.Utils || {};


	/* All constants feature here */
	sap.ovp.cards.charts.Utils.constants = {
			/* qualifiers for annotation terms */
			CHART_QUALIFIER_KEY: "chartAnnotationPath",
			SELVAR_QUALIFIER_KEY: "selectionAnnotationPath",
			PREVAR_QUALIFIER_KEY: "presentationAnnotationPath",
			/* size of the collection to be rendered on chart */
			CHART_DATA_SIZE: "4",
			/* DEBUG MESSAGES */
			ERROR_NO_CHART: "Analytic cards require valid \"chartAnnotationPath\" " +
					"configured in manifest.json"
	};

	/* retrieve qualifier from iContext */
	sap.ovp.cards.charts.Utils.getQualifier = function (iContext, annoTerm) {
		/* see sap.ovp.cards.charts.Utils.constants for legal values of annoTerm */
		if (!annoTerm) {
			return "";
		}
		var settingsModel = iContext.getSetting('ovpCardProperties');
		if (!settingsModel) {
			return "";
		}
		var oSettings = settingsModel.oData;
		if (!oSettings) {
			return "";
		}
		var fullQualifier = oSettings && oSettings[annoTerm] ? oSettings[annoTerm] : "";
		return fullQualifier === "" ? "" : fullQualifier.split("#")[1];
	};

	/************************ FORMATTERS ************************/

	sap.ovp.cards.charts.Utils.wrapInBraces = function(whateverNeedsToBeInBraces) {
		return "{" + whateverNeedsToBeInBraces + "}";
	};

	sap.ovp.cards.charts.Utils.getSapLabel = function(property) {
		var entityTypeObject = this.getModel('ovpCardProperties').getProperty("/entityType");
		var label = sap.ovp.cards.charts.Utils.getAllColumnLabels(entityTypeObject)[property];
		return label ? label : property;
	};

	sap.ovp.cards.charts.Utils.formDimensionPath = function(dimension) {
		var ret = "{" + dimension + "}";
		var entityTypeObject = this.getModel('ovpCardProperties').getProperty("/entityType");
		if (!entityTypeObject) {
			return ret;
		}
		var edmTypes = sap.ovp.cards.charts.Utils.getEdmTypeOfAll(entityTypeObject);
		if (!edmTypes || !edmTypes[dimension]) {
			return ret;
		}
		var type = edmTypes[dimension];
		if (type == "Edm.DateTime") {
			return "{path:'" + dimension + "', formatter: 'sap.ovp.cards.charts.Utils.returnDateFormat'}";
		}
		var columnTexts = sap.ovp.cards.charts.Utils.getAllColumnTexts(entityTypeObject);
		if (!columnTexts) {
			return ret;
		}
		ret = "{" + (columnTexts[dimension] || dimension) + "}";
		return ret;
	};

	sap.ovp.cards.charts.Utils.returnDateFormat = function(date) {
		if (date) {
			jQuery.sap.require("sap.ui.core.format.DateFormat");
			var oDateFormat = sap.ui.core.format.DateFormat.getDateTimeInstance({pattern: "dd-MMM"});
			return oDateFormat.format(new Date(date));
		}
		return "";
	};

	/*
	 * Reads filters from annotation and prepares data binding path
	 */
	sap.ovp.cards.charts.Utils.formatItems = function(iContext, oEntitySet, oSelectionVariant, oPresentationVariant, oDimensions, oMeasures) {
		var ret = "";
		var dimensionsList = [];
		var measuresList = [];
		var sorterList = [];
		var bFilter = oSelectionVariant && oSelectionVariant.SelectOptions;
		var bParams = oSelectionVariant && oSelectionVariant.Parameters;
		var bSorter = oPresentationVariant && oPresentationVariant.SortOrder;
		var maxItemTerm = oPresentationVariant && oPresentationVariant.MaxItems, maxItems = null;
		var columnsWithText;
		var tmp;
		var aConfigFilters;

		if (bParams) {
			var dataModel = iContext.getSetting("dataModel");
			var path = sap.ovp.cards.AnnotationHelper.resolveParameterizedEntitySet(dataModel, oEntitySet, oSelectionVariant);
			ret += "{path: '" + path + "'";
		} else {
			ret += "{path: '/" + oEntitySet.name + "'";
		}

		var filters = [];
		var entityTypeObject = null;
		var edmTypes = null;
		if (!iContext || !iContext.getSetting('ovpCardProperties')) {
			jQuery.sap.log.error("Analytic card configuration error");
			ret += "}";
			return ret;
		}
		entityTypeObject = iContext.getSetting('ovpCardProperties').getProperty("/entityType");
		edmTypes = sap.ovp.cards.charts.Utils.getEdmTypeOfAll(entityTypeObject);
		columnsWithText = sap.ovp.cards.charts.Utils.getAllColumnTexts(entityTypeObject);
		aConfigFilters = iContext.getSetting('ovpCardProperties').getProperty("/filters");

		if (bFilter) {
			jQuery.each(oSelectionVariant.SelectOptions, function() {
				var prop = this.PropertyName.PropertyPath;
				jQuery.each(this.Ranges, function() {
					if (this.Sign.EnumMember === "com.sap.vocabularies.UI.v1.SelectionRangeSignType/I") {
						var filtervalue = this.Low.String;
						if (edmTypes &&
								(edmTypes[prop].substring(0, 7) === "Edm.Int" ||
										edmTypes[prop].substring(0, 11) === 'Edm.Decimal')) {
							filtervalue = Number(filtervalue);
						}
						var filter = {
								path : prop,
								operator : this.Option.EnumMember.split("/")[1],
								value1 : filtervalue
						};
						if (this.High) {
							filter.value2 = this.High.String;
						}
						filters.push(filter);
					}
				});
			});
		}

		/* 
		 * code for ObjectStream
		 */
		if (aConfigFilters && aConfigFilters.length > 0){
			filters = filters.concat(aConfigFilters);
		}

		if (filters.length > 0) {
			ret += ", filters: " + JSON.stringify(filters);
		}

		if (bSorter) {
			var oSortAnnotationCollection = oPresentationVariant.SortOrder;
			if (oSortAnnotationCollection.length < 1) {
				jQuery.sap.log.warning("OVP-AC: Analytic card: Warning: SortOrder is present in PresentationVariant, " +
				"but it is empty or not well formed.");
			} else {
				var sSorterValue = "";
				var oSortOrder;
				var sSortOrder;
				var sSortBy;
				for (var i = 0; i < oSortAnnotationCollection.length; i++) {
					oSortOrder = oSortAnnotationCollection[i];
					sSortBy = oSortOrder.Property.PropertyPath;
					sorterList.push(sSortBy);
					if (typeof oSortOrder.Descending == "undefined") {
						sSortOrder = 'true';
					} else {
						var checkFlag = oSortOrder.Descending.Bool || oSortOrder.Descending.Boolean;
						if (!checkFlag) {
							jQuery.sap.log.warning("OVP-AC: Analytic card: Warning: Boolean value is not present in PresentationVariant ");
							sSortOrder = 'true';
						} else {
							sSortOrder = checkFlag.toLowerCase() == 'true' ? 'true' : 'false';
						}
					}
					sSorterValue = sSorterValue + "{path: '" + sSortBy + "',descending: " + sSortOrder + "},";
				}
				/* trim the last ',' */
				ret += ", sorter: [" + sSorterValue.substring(0, sSorterValue.length - 1) + "]";
			}
		}

		if (maxItemTerm) {
			maxItems = maxItemTerm.Int32 ? maxItemTerm.Int32 : maxItemTerm.Int;
		}

		jQuery.each(oMeasures, function(i, m){
			tmp = m.Measure.PropertyPath;
			measuresList.push(tmp);
			if (columnsWithText && tmp != columnsWithText[tmp]) {
				measuresList.push(columnsWithText[tmp] ? columnsWithText[tmp] : tmp);
			}
		});
		jQuery.each(oDimensions, function(i, d){
			tmp = d.Dimension.PropertyPath;
			dimensionsList.push(tmp);
			if (columnsWithText && tmp != columnsWithText[tmp]) {
				dimensionsList.push(columnsWithText[tmp] ? columnsWithText[tmp] : tmp);
			}
		});
		ret += ", parameters: {select:'" + [].concat(dimensionsList, measuresList).join(",");
		if (sorterList.length > 0) {
			ret += "," + sorterList.join(",");
		}
		/* close `parameters` */
		ret += "'}";

		if (maxItems) {
			if (/^\d+$/.test(maxItems)) {
				ret += ", length: " + maxItems;
			} else {
				jQuery.sap.log.error("OVP-AC: Analytic card Error: maxItems is Invalid. " +
					"Please enter an Integer.");
			}
		}
		ret += "}";
		return ret;
	};

	sap.ovp.cards.charts.Utils.formatItems.requiresIContext = true;


	/************************ METADATA PARSERS ************************/

	/* Returns the set of all properties in the metadata */
	sap.ovp.cards.charts.Utils.getAllColumnProperties = function(prop, entityTypeObject) {
		var finalObject = {};
		var properties = entityTypeObject.property;
		for (var i = 0, len = properties.length; i < len; i++) {
			if (properties[i].hasOwnProperty(prop) && prop == "com.sap.vocabularies.Common.v1.Label") {
				finalObject[properties[i].name] = properties[i][prop].String;
			} else if (properties[i].hasOwnProperty(prop)) {
				finalObject[properties[i].name] = properties[i][prop];
			} else {
				finalObject[properties[i].name] = properties[i].name;
			}
		}
		return finalObject;
	};

	/* Returns column name that contains the sap:label(s) for all properties in the metadata*/
	sap.ovp.cards.charts.Utils.getAllColumnLabels = function(entityTypeObject) {
		return sap.ovp.cards.charts.Utils.getAllColumnProperties("com.sap.vocabularies.Common.v1.Label", entityTypeObject);
	};


	/* Returns column name that contains the sap:text(s) for all properties in the metadata*/
	sap.ovp.cards.charts.Utils.getAllColumnTexts = function(entityTypeObject) {
		return sap.ovp.cards.charts.Utils.getAllColumnProperties("sap:text", entityTypeObject);
	};


	/* get EdmType of all properties from $metadata */
	sap.ovp.cards.charts.Utils.getEdmTypeOfAll = function(entityTypeObject) {
		return sap.ovp.cards.charts.Utils.getAllColumnProperties("type", entityTypeObject);
	};

	/************************ Format Chart Axis ************************/
	sap.ovp.cards.charts.Utils.formatChartYaxis = function() {
		jQuery.sap.require("sap.ui.core.format.NumberFormat");
		var customFormatter = {
				locale: function(){},
				format: function(value, pattern) {
					if (pattern == "yValueAxisFormatter") {
						var numberFormat = sap.ui.core.format.NumberFormat.getFloatInstance( 
								{style: 'short', 
									minFractionDigits: 2,
									maxFractionDigits: 2}
						);
						return numberFormat.format(Number(value)); 
					}
				}
		};

		jQuery.sap.require("sap.viz.ui5.api.env.Format");
		sap.viz.ui5.api.env.Format.numericFormatter(customFormatter);
	};

	sap.ovp.cards.charts.Utils.hideDateTimeAxis = function(vizFrame, feedName) {
		var entityTypeObject = vizFrame.getModel('ovpCardProperties').getProperty("/entityType");
		var edmTypes = sap.ovp.cards.charts.Utils.getEdmTypeOfAll(entityTypeObject);
		var feeds = vizFrame.getFeeds();
		for (var i = 0; i < feeds.length; i++) {
			if (feeds[i].getUid() == feedName) {
				var feedValues = feeds[i].getValues();
				if (!feedValues) {
					return;
				}
				for (var j = 0; j < feedValues.length; j++) {
					if (edmTypes[feedValues[j]] != "Edm.DateTime") {
						return;
					}
				}
				vizFrame.setVizProperties({categoryAxis:{
					title:{
						visible: false
					}
				}});
				return;
			}
		}
	};
	/************************ Line Chart functions ************************/

	sap.ovp.cards.charts.Utils.LineChart = sap.ovp.cards.charts.Utils.LineChart || {};
	sap.ovp.cards.charts.Utils.LineChart.categoryAxisFeedList = {};

	sap.ovp.cards.charts.Utils.LineChart.getVizProperties = function(iContext, dimensions, measures) {
		var rawValueAxisTitles = sap.ovp.cards.charts.Utils.LineChart.getValueAxisFeed(iContext, measures).split(",");
		var rawCategoryAxisTitles = sap.ovp.cards.charts.Utils.LineChart.getCategoryAxisFeed(iContext, dimensions).split(",");
		var valueAxisTitles = [];
		jQuery.each(rawValueAxisTitles, function(i, m){
			valueAxisTitles.push(m);
		});
		var categoryAxisTitles = [];
		jQuery.each(rawCategoryAxisTitles, function(i, d){
			categoryAxisTitles.push(d);
		});
		/*
		 //Readable version for debugging
		 //eslint can't multiline strings
		 return "{\
				valueAxis:{\
					title:{\
						visible:true,\
						text: '" + valueAxisTitles.join(",") + "'\
					},\
					label:{\
						formatString:'yValueAxisFormatter'\
					}\
				},\
				categoryAxis:{\
					title:{\
						visible:true,\
						text: '" + categoryAxisTitles.join(",") + "'\
					},\
					label:{\
						formatString:'yValueAxisFormatter'\
					}\
				},\
				legend: {\
					isScrollable: false\
				},\
				title: {\
					visible: false\
				},\
				interaction:{\
					noninteractiveMode: true,\
					selectability: {\
						legendSelection: false,\
						axisLabelSelection: false,\
						mode: 'NONE',\
						plotLassoSelection: false,\
						plotStdSelection: false\
					}\
				}\
			}";
		*/
		return "{ valueAxis:{  title:{   visible:true,   text: '" + valueAxisTitles.join(",") + "'  },  label:{   formatString:'yValueAxisFormatter'  } }, categoryAxis:{  title:{   visible:true,   text: '" + categoryAxisTitles.join(",") + "'  },  label:{   formatString:'yValueAxisFormatter'  } }, legend: {  isScrollable: false }, title: {  visible: false }, interaction:{  noninteractiveMode: true,  selectability: {   legendSelection: false,   axisLabelSelection: false,   mode: 'NONE',   plotLassoSelection: false,   plotStdSelection: false  } } }";
	};
	sap.ovp.cards.charts.Utils.LineChart.getVizProperties.requiresIContext = true;

	sap.ovp.cards.charts.Utils.LineChart.getValueAxisFeed = function(iContext, measures) {
		var entityTypeObject = iContext.getSetting('ovpCardProperties').getProperty("/entityType");
		if (!entityTypeObject) {
			return "";
		}
		var columnLabels = sap.ovp.cards.charts.Utils.getAllColumnLabels(entityTypeObject);
		var ret = [];
		jQuery.each(measures, function(i, m){
			ret.push(columnLabels[m.Measure.PropertyPath] || m.Measure.PropertyPath);
		});
		return ret.join(",");
	};
	sap.ovp.cards.charts.Utils.LineChart.getValueAxisFeed.requiresIContext = true;


	sap.ovp.cards.charts.Utils.LineChart.getCategoryAxisFeed = function(iContext, dimensions) {
		var entityTypeObject = iContext.getSetting('ovpCardProperties').getProperty("/entityType");
		if (!entityTypeObject) {
			return "";
		}
		var columnLabels = sap.ovp.cards.charts.Utils.getAllColumnLabels(entityTypeObject);
		var ret = [];
		var qualifier;
		var feedValue;
		jQuery.each(dimensions, function(i, d){
			if (d.Role.EnumMember.split("/")[1] === "Category") {
				feedValue = columnLabels[d.Dimension.PropertyPath];
				ret.push(feedValue ? feedValue : d.Dimension.PropertyPath);
			}
		});
		/*
		 * If no dimensions are given as category, pick first dimension as category
		 * (see Software Design Description UI5 Chart Control 3.1.2.2.1.1)
		 */
		if (ret.length < 1) {
			feedValue = columnLabels[dimensions[0].Dimension.PropertyPath];
			ret.push(feedValue ? feedValue : dimensions[0].Dimension.PropertyPath);
		}
		qualifier = sap.ovp.cards.charts.Utils.getQualifier(iContext,
				sap.ovp.cards.charts.Utils.constants.CHART_QUALIFIER_KEY);
		sap.ovp.cards.charts.Utils.LineChart.categoryAxisFeedList[qualifier] = ret;
		return ret.join(",");
	};
	sap.ovp.cards.charts.Utils.LineChart.getCategoryAxisFeed.requiresIContext = true;


	sap.ovp.cards.charts.Utils.LineChart.getColorFeed = function(iContext, dimensions) {
		var ret = [];
		var qualifier;
		var entityTypeObject = iContext.getSetting('ovpCardProperties').getProperty("/entityType");
		if (!entityTypeObject) {
			return "";
		}
		var columnLabels = sap.ovp.cards.charts.Utils.getAllColumnLabels(entityTypeObject);
		var feedValue;
		jQuery.each(dimensions, function(i, d){
			if (d.Role.EnumMember.split("/")[1] === "Series") {
				feedValue = columnLabels[d.Dimension.PropertyPath];
				ret.push(feedValue ? feedValue : d.Dimension.PropertyPath);
			}
		});
		/*
		 * If the dimensions is picked up for category feed as no category is given in the annotation,
		 * remove it from color feed.
		 * (see Software Design Description UI5 Chart Control 3.1.2.2.1.1)
		 */
		qualifier = sap.ovp.cards.charts.Utils.getQualifier(iContext,
				sap.ovp.cards.charts.Utils.constants.CHART_QUALIFIER_KEY);
		ret = jQuery.grep(ret, function(value) {
			if (!sap.ovp.cards.charts.Utils.LineChart.categoryAxisFeedList[qualifier]) {
				return true;
			}
			return value != sap.ovp.cards.charts.Utils.LineChart.categoryAxisFeedList[qualifier][0];
		});
		return ret.join(",");
	};
	sap.ovp.cards.charts.Utils.LineChart.getColorFeed.requiresIContext = true;


	sap.ovp.cards.charts.Utils.LineChart.testColorFeed = function(iContext, dimensions) {
		return sap.ovp.cards.charts.Utils.LineChart.getColorFeed(iContext, dimensions) !== "";
	};
	sap.ovp.cards.charts.Utils.LineChart.testColorFeed.requiresIContext = true;



	/************************ Bubble Chart Functions ************************/

	sap.ovp.cards.charts.Utils.BubbleChart = sap.ovp.cards.charts.Utils.BubbleChart || {};

	sap.ovp.cards.charts.Utils.BubbleChart.getVizProperties = function(iContext, dimensions, measures) {
		var rawValueAxisTitles = sap.ovp.cards.charts.Utils.BubbleChart.getValueAxisFeed(iContext, measures).split(",");
		var rawValueAxis2Titles = sap.ovp.cards.charts.Utils.BubbleChart.getValueAxis2Feed(iContext, measures).split(",");
		var valueAxisTitles = [];
		jQuery.each(rawValueAxisTitles, function(i, m){
			valueAxisTitles.push(m);
		});
		var valueAxis2Titles = [];
		jQuery.each(rawValueAxis2Titles, function(i, m){
			valueAxis2Titles.push(m);
		});
		/*
		 //Readable version for debugging
		 //eslint can't multiline strings
		return "{\
				valueAxis:{\
					title:{\
						visible:true,\
						text: '" + valueAxisTitles.join(",") + "'\
					},\
					label:{\
						formatString:'yValueAxisFormatter'\
					}\
				},\
				valueAxis2:{\
					title:{\
						visible:true,\
						text: '" + valueAxis2Titles.join(",") + "'\
					},\
					label:{\
						formatString:'yValueAxisFormatter'\
					}\
				},\
				categoryAxis:{\
					title:{\
						visible:true\
					},\
					label:{\
						formatString:'yValueAxisFormatter'\
					}\
				},\
				legend: {\
					isScrollable: false\
				},\
				title: {\
					visible: false\
				},\
				interaction:{\
					noninteractiveMode: true,\
					selectability: {\
						legendSelection: false,\
						axisLabelSelection: false,\
						mode: 'NONE',\
						plotLassoSelection: false,\
						plotStdSelection: false\
					}\
				}\
			}";
		*/
		return "{ valueAxis:{  title:{ visible:true, text: '" + valueAxisTitles.join(",") + "'  },  label:{ formatString:'yValueAxisFormatter'  } }, valueAxis2:{  title:{ visible:true, text: '" + valueAxis2Titles.join(",") + "'  },  label:{ formatString:'yValueAxisFormatter'  } }, categoryAxis:{  title:{ visible:true  },  label:{ formatString:'yValueAxisFormatter'  } }, legend: {  isScrollable: false }, title: {  visible: false }, interaction:{  noninteractiveMode: true,  selectability: { legendSelection: false, axisLabelSelection: false, mode: 'NONE', plotLassoSelection: false, plotStdSelection: false  } } }";
	};
	sap.ovp.cards.charts.Utils.BubbleChart.getVizProperties.requiresIContext = true;

	sap.ovp.cards.charts.Utils.BubbleChart.getMeasurePriorityList = function(iContext, measures) {
		/* (see Software Design Description UI5 Chart Control - Bubble Chart) */
		var ovpCardPropertiesModel;
		if (!iContext ||
				!iContext.getSetting ||
				!(ovpCardPropertiesModel = iContext.getSetting('ovpCardProperties'))) {
			return [""];
		}
		var entityTypeObject = ovpCardPropertiesModel.getProperty("/entityType");
		if (!entityTypeObject) {
			return [""];
		}
		var columnLabels = sap.ovp.cards.charts.Utils.getAllColumnLabels(entityTypeObject);
		var ret = [null, null, null];
		jQuery.each(measures, function(i, m){
			if (m.Role.EnumMember.split("/")[1] === "Axis1") {
				if (ret[0] === null) {
					ret[0] = columnLabels[m.Measure.PropertyPath] || m.Measure.PropertyPath;
				} else if (ret[1] === null) {
					ret[1] = columnLabels[m.Measure.PropertyPath] || m.Measure.PropertyPath;
				} else if (ret[2] == null) {
					ret[2] = columnLabels[m.Measure.PropertyPath] || m.Measure.PropertyPath;
				}
			}
		});
		jQuery.each(measures, function(i, m){
			if (m.Role.EnumMember.split("/")[1] === "Axis2") {
				if (ret[0] === null) {
					ret[0] = columnLabels[m.Measure.PropertyPath] || m.Measure.PropertyPath;
				} else if (ret[1] === null) {
					ret[1] = columnLabels[m.Measure.PropertyPath] || m.Measure.PropertyPath;
				} else if (ret[2] == null) {
					ret[2] = columnLabels[m.Measure.PropertyPath] || m.Measure.PropertyPath;
				}
			}
		});
		jQuery.each(measures, function(i, m){
			if (m.Role.EnumMember.split("/")[1] === "Axis3") {
				if (ret[0] === null) {
					ret[0] = columnLabels[m.Measure.PropertyPath] || m.Measure.PropertyPath;
				} else if (ret[1] === null) {
					ret[1] = columnLabels[m.Measure.PropertyPath] || m.Measure.PropertyPath;
				} else if (ret[2] == null) {
					ret[2] = columnLabels[m.Measure.PropertyPath] || m.Measure.PropertyPath;
				}
			}
		});
		return ret;
	};
	sap.ovp.cards.charts.Utils.BubbleChart.getMeasurePriorityList.requiresIContext = true;


	sap.ovp.cards.charts.Utils.BubbleChart.getValueAxisFeed = function(iContext, measures) {
		return sap.ovp.cards.charts.Utils.BubbleChart.getMeasurePriorityList(iContext, measures)[0];
	};
	sap.ovp.cards.charts.Utils.BubbleChart.getValueAxisFeed.requiresIContext = true;


	sap.ovp.cards.charts.Utils.BubbleChart.getValueAxis2Feed = function(iContext, measures) {
		return sap.ovp.cards.charts.Utils.BubbleChart.getMeasurePriorityList(iContext, measures)[1];
	};
	sap.ovp.cards.charts.Utils.BubbleChart.getValueAxis2Feed.requiresIContext = true;


	sap.ovp.cards.charts.Utils.BubbleChart.getBubbleWidthFeed = function(iContext, measures) {
		return sap.ovp.cards.charts.Utils.BubbleChart.getMeasurePriorityList(iContext, measures)[2];
	};
	sap.ovp.cards.charts.Utils.BubbleChart.getBubbleWidthFeed.requiresIContext = true;


	sap.ovp.cards.charts.Utils.BubbleChart.getColorFeed = function(iContext, dimensions) {
		var entityTypeObject = iContext.getSetting('ovpCardProperties').getProperty("/entityType");
		if (!entityTypeObject) {
			return "";
		}
		var columnLabels = sap.ovp.cards.charts.Utils.getAllColumnLabels(entityTypeObject);
		var ret = [];
		var feedValue;
		jQuery.each(dimensions, function(i, d){
			if (d.Role.EnumMember.split("/")[1] === "Series") {
				feedValue = columnLabels[d.Dimension.PropertyPath];
				ret.push(feedValue ? feedValue : d.Dimension.PropertyPath);
			}
		});
		return ret.join(",");
	};
	sap.ovp.cards.charts.Utils.BubbleChart.getColorFeed.requiresIContext = true;

	sap.ovp.cards.charts.Utils.BubbleChart.getShapeFeed = function(iContext, dimensions) {
		var entityTypeObject = iContext.getSetting('ovpCardProperties').getProperty("/entityType");
		if (!entityTypeObject) {
			return "";
		}
		var columnLabels = sap.ovp.cards.charts.Utils.getAllColumnLabels(entityTypeObject);
		var ret = [];
		var feedValue;
		jQuery.each(dimensions, function(i, d){
			if (d.Role.EnumMember.split("/")[1] === "Category") {
				feedValue = columnLabels[d.Dimension.PropertyPath];
				ret.push(feedValue ? feedValue : d.Dimension.PropertyPath);
			}
		});
		return ret.join(",");
	};
	sap.ovp.cards.charts.Utils.BubbleChart.getShapeFeed.requiresIContext = true;


	sap.ovp.cards.charts.Utils.BubbleChart.testColorFeed = function(iContext, dimensions) {
		return sap.ovp.cards.charts.Utils.BubbleChart.getColorFeed(iContext, dimensions) !== "";
	};
	sap.ovp.cards.charts.Utils.BubbleChart.testColorFeed.requiresIContext = true;


	sap.ovp.cards.charts.Utils.BubbleChart.testShapeFeed = function(iContext, dimensions) {
		return sap.ovp.cards.charts.Utils.BubbleChart.getShapeFeed(iContext, dimensions) !== "";
	};
	sap.ovp.cards.charts.Utils.BubbleChart.testShapeFeed.requiresIContext = true;


	sap.ovp.cards.charts.Utils.validateMeasuresDimensions = function(vizFrame, type) {
		var measuresArr = null;
		var dimensionsArr = null;
		if (!vizFrame.getDataset()) {
			jQuery.sap.log.error("OVP-AC: " + type + " Card Error: No Dataset defined for chart.");
			return false;
		}
		measuresArr = vizFrame.getDataset().getMeasures();
		dimensionsArr = vizFrame.getDataset().getDimensions();

		switch (type) {
		case "Bubble":
			if (measuresArr.length !== 3 || dimensionsArr.length < 1 ||
					!measuresArr[0].getName() || !measuresArr[1].getName() || !measuresArr[2].getName() ||
					!dimensionsArr[0].getName()) {
				jQuery.sap.log.error("OVP-AC: Bubble Card Error: Enter exactly 3 measures and at least 1 dimension.");
				return false;
			}
			break;

		case "Donut":
			if (measuresArr.length !== 1 || dimensionsArr.length !== 1 ||
					!measuresArr[0].getName() || !dimensionsArr[0].getName()) {
				jQuery.sap.log.error("OVP-AC: Donut Card Error: Enter exactly 1 measure and 1 dimension.");
				return false;
			}
			break;

		case "Line":
			if (measuresArr.length < 1 || dimensionsArr.length < 1 ||
					!measuresArr[0].getName() || !dimensionsArr[0].getName()) {
				jQuery.sap.log.error("OVP-AC: Line Card Error: Configure at least 1 dimensions and 1 measure.");
				return false;
			}
			break;
		}
		return true;
	};

	/*
	 * Check if annotations exist vis-a-vis manifest
	 * @param {String} term - Annotation with Qualifier
	 * @param {Object} annotation - Annotation Data
	 * @param {String} type - Type of Annotation
	 * @param {Boolean} [bMandatory=false] - Whether the term is mandatory
	 * @returns {Boolean}
	 */
	sap.ovp.cards.charts.Utils.checkExists = function(term, annotation, type, bMandatory, logViewId) {
		bMandatory = typeof bMandatory === "undefined" ? false : bMandatory;
		var ret = false;
		var annoTerm;
		if (!term && bMandatory) {
			jQuery.sap.log.error(logViewId + "OVP-AC: Analytic card: Error: " + type + " is mandatory.");
			return ret;
		}
		if (!term) {
			/* Optional parameters can be blank */
			jQuery.sap.log.warning(logViewId + "OVP-AC: Analytic card: Warning: " + type + " is missing.");
			ret = true;
			return ret;
		}
		annoTerm = annotation[term];
		if (!annoTerm || typeof annoTerm !== "object") {
			var logger = bMandatory ? jQuery.sap.log.error : jQuery.sap.log.warning;
			logger(logViewId + "OVP-AC: Analytic card: Error in " + type +
					". (" + term + " is not found or not well formed)");
			return ret;
		}
		ret = true;
		return ret;
	};

	/*
	 * Check and log errors/warnings if any.
	 */
	sap.ovp.cards.charts.Utils.validateCardConfiguration = function(oController) {
		var ret = false;
		if (!oController) {
			return ret;
		}
		var selVar;
		var chartAnno;
		var preVar;
		var idAnno;
		var dPAnno;
		var entityTypeData;
		var logViewId = "";
		var oCardsModel;
		var oView = oController.getView();
		if (oView) {
			logViewId = "[" + oView.getId() + "] ";
		}

		if (!(oCardsModel = oController.getCardPropertiesModel())) {
			jQuery.sap.log.error(logViewId + "OVP-AC: Analytic card: Error in card configuration." +
					"Could not obtain Cards model.");
			return ret;
		}

		entityTypeData = oCardsModel.getProperty("/entityType");
		if (!entityTypeData || jQuery.isEmptyObject(entityTypeData)) {
			jQuery.sap.log.error(logViewId + "OVP-AC: Analytic card: Error in card annotation.");
			return ret;
		}

		selVar = oCardsModel.getProperty("/selectionAnnotationPath");
		chartAnno = oCardsModel.getProperty("/chartAnnotationPath");
		preVar = oCardsModel.getProperty("/presentationAnnotationPath");
		idAnno = oCardsModel.getProperty("/identificationAnnotationPath");
		dPAnno = oCardsModel.getProperty("/dataPointAnnotationPath");
		

		ret = this.checkExists(selVar, entityTypeData, "Selection Variant", false, logViewId);
		ret = this.checkExists(chartAnno, entityTypeData, "Chart Annotation", true, logViewId) && ret;
		ret = this.checkExists(preVar, entityTypeData, "Presentation Variant", false, logViewId) && ret;
		ret = this.checkExists(idAnno, entityTypeData, "Identification Annotation", true, logViewId) && ret;
		ret = this.checkExists(dPAnno, entityTypeData, "Data Point", false, logViewId) && ret;
		return ret;
	};


	sap.ovp.cards.charts.Utils.checkNoData = function(oEvent, cardContainer, vizFrame) {
		var data, noDataDiv;
		if (!cardContainer) {
			jQuery.sap.log.error("OVP-AC: Analytic card Error: Could not obtain card container. " +
					"(" + vizFrame.getId() + ")");
			return;
		}
		data = oEvent.getParameter("data");
		if (!data || jQuery.isEmptyObject(data) ||
			!data.results || !data.results.length) {

			jQuery.sap.log.error("OVP-AC: Analytic card Error: No data available. " +
					"(" + vizFrame.getId() + ")");
			noDataDiv = sap.ui.xmlfragment("sap.ovp.cards.charts.generic.noData");
			cardContainer.removeAllItems();
			cardContainer.addItem(noDataDiv);
		}
	};

}());
}; // end of sap/ovp/cards/charts/Utils.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.generic.Card.controller') ) {
  jQuery.sap.declare('sap.ovp.cards.generic.Card.controller');
(function () {
    "use strict";
    /*global sap, jQuery */
    
    jQuery.sap.require('sap.ui.generic.app.navigation.service.NavigationHandler'); // unlisted dependency retained

    
    var ActionUtils = sap.ovp.cards.ActionUtils;

    sap.ui.controller("sap.ovp.cards.generic.Card", {

        onInit: function () {
            var oHeader = this.getView().byId("ovpCardHeader");
            oHeader.attachBrowserEvent("click", this.onHeaderClick.bind(this));
            oHeader.addEventDelegate({
                onkeydown: function (oEvent) {
                    if (!oEvent.shiftKey && (oEvent.keyCode == 13 || oEvent.keyCode == 32)) {
                        oEvent.preventDefault();
                        this.onHeaderClick();
                    }
                }.bind(this)
            });

            var oNumericControl = this.getView().byId("kpiNumberValue");
            if (oNumericControl) {
                oNumericControl.addEventDelegate({
                    onAfterRendering: function() {
                        var $numericControl = oNumericControl.$();
                        var $number = $numericControl.find(".sapMNCValueScr");
                        var $scale =  $numericControl.find(".sapMNCScale");
                        $number.attr("aria-label", $number.text());
                        $scale.attr("aria-label", $scale.text());
                    }
                });
            }
        },

        onAfterRendering: function(){
            var footer = this.getCardPropertiesModel().getProperty("/footerFragment");
            if (footer){
                this._handleActionFooter();
                this._handleCountFooter();
            }
        },

        onHeaderClick: function(){
            //call the navigation with the binded context to support single object cards such as quickview card
            this.doNavigation(this.getView().getBindingContext());
        },

        _handleActionFooter: function(footer){
            var actionFooter = this.getView().byId("ovpActionFooter");
            if (actionFooter) {
                var aActions = actionFooter.getContent();
                //remove the 'ToolbarSpacer'
                aActions = aActions.splice(1, aActions.length);
                var oLayoutData = aActions[0].getLayoutData();
                oLayoutData.setMoveToOverflow(false);
                oLayoutData.setStayInOverflow(false);
                if (aActions.length === 2) {
                    oLayoutData = aActions[1].getLayoutData();
                    oLayoutData.setMoveToOverflow(false);
                    oLayoutData.setStayInOverflow(false);
                }
            }
        },
        _handleCountFooter: function(){
            var countFooter = this.getView().byId("ovpCountFooter");
            if (countFooter) {
                //Gets the card items binding object
                var oItemsBinding = this.getCardItemsBinding();
                if (oItemsBinding) {
                    oItemsBinding.attachDataReceived(function () {
                        var iTotal = oItemsBinding.getLength();
                        var iCurrent = oItemsBinding.getCurrentContexts().length;
                        var countFooterText = sap.ui.getCore().getLibraryResourceBundle("sap.ovp").getText("Count_Footer", [iCurrent, iTotal]);
                        countFooter.setText(countFooterText);
                    });
                }
            }
        },

        /**
         * default empty implementation for the count footer
         */
        getCardItemsBinding: function(){
        },

        onActionPress: function(oEvent) {
            var sourceObject = oEvent.getSource(),
                oCustomData = this._getActionObject(sourceObject),
                context = sourceObject.getBindingContext();
            if (oCustomData.type.indexOf("DataFieldForAction") !== -1) {
                this.doAction(context, oCustomData);
            } else {
                this.doNavigation(context, oCustomData);
            }
        },
        _getActionObject: function(sourceObject) {
            var aCustomData = sourceObject.getCustomData();
            var oCustomData = {};
            for (var i = 0; i < aCustomData.length; i++) {
                oCustomData[aCustomData[i].getKey()] = aCustomData[i].getValue();
            }
            return oCustomData;
        },

        doNavigation: function (oContext, oNavigationField) {

            if (!oNavigationField) {
                oNavigationField = this.getEntityNavigationEntries(oContext)[0];
            }

            if ( oNavigationField ){
                switch ( oNavigationField.type ){
                    case "com.sap.vocabularies.UI.v1.DataFieldWithUrl":
                        this.doNavigationWithUrl(oContext,oNavigationField);
                        break;
                    case "com.sap.vocabularies.UI.v1.DataFieldForIntentBasedNavigation":
                        this.doIntentBasedNavigation(oContext, oNavigationField);
                        break;
                }
            }
        },

        doNavigationWithUrl: function (oContext, oNavigationField) {
            var oParsingSerivce = sap.ushell.Container.getService("URLParsing");

            //Checking if navigation is external or IntentBasedNav with paramters
            //If Not a internal navigation, navigate in a new window
            if (!(oParsingSerivce.isIntentUrl(oNavigationField.url))){
                window.open(oNavigationField.url);
            } else {
                var oParsedShellHash = oParsingSerivce.parseShellHash(oNavigationField.url);
                this.doIntentBasedNavigation(oContext, oParsedShellHash);
            }
        },

        doIntentBasedNavigation: function (oContext, oIntent) {
            var oParametersPromise,
                oNavArguments,
                oEntity = oContext ? oContext.getObject() : null;

            var oNavigationHandler = sap.ovp.cards.CommonUtils.getNavigationHandler();

            if (oNavigationHandler) {
                if (oIntent) {
                    oParametersPromise = this._getEntityNavigationParameters(oEntity);
                    oParametersPromise.done(function (oParameters, oAppDataForSave) {
                        oNavArguments = {
                            target: {
                                semanticObject: oIntent.semanticObject,
                                action: oIntent.action
                            },
                            appSpecificRoute: oIntent.appSpecificRoute,
                            params: oParameters
                        };
                        var oAppInnerData = {};

                        if (oAppDataForSave) {
                            oAppInnerData = oAppDataForSave;
                        }

                        function fnHandleError(oError) {
                            if (oError instanceof Error) {
                                oError.showMessageBox();
                            }
                        }
                        oNavigationHandler.navigate(oNavArguments.target.semanticObject, oNavArguments.target.action, oNavArguments.params,
                            oAppInnerData, fnHandleError);

                    });
                }
            }
        },

        doAction: function (oContext, action) {
            this.actionData = ActionUtils.getActionInfo(oContext, action, this.getEntityType());
            if (this.actionData.allParameters.length > 0) {
                this._loadParametersForm();
            } else {
                this._callFunction();
            }
        },

        getEntityNavigationEntries: function (oContext, sAnnotationPath) {
            var aNavigationFields = [];
            var oEntityType = this.getEntityType();

            if (!sAnnotationPath){
                var oCardPropsModel = this.getCardPropertiesModel();
                var sIdentificationAnnotationPath = oCardPropsModel.getProperty("/identificationAnnotationPath");
                sAnnotationPath = sIdentificationAnnotationPath;
            }

            // if we have an array object e.g. we have records
            var aRecords = oEntityType[sAnnotationPath];
            if (Array.isArray(aRecords)) {

                // sort the records by Importance - before we initialize the navigation-actions of the card
                aRecords = sap.ovp.cards.AnnotationHelper.sortCollectionByImportance(aRecords);

                for (var i = 0; i < aRecords.length; i++) {
                    if (aRecords[i].RecordType === "com.sap.vocabularies.UI.v1.DataFieldForIntentBasedNavigation") {
                        aNavigationFields.push({
                            type: aRecords[i].RecordType,
                            semanticObject: aRecords[i].SemanticObject.String,
                            action: aRecords[i].Action.String,
                            label: aRecords[i].Label.String
                        });
                    }
                    if (aRecords[i].RecordType === "com.sap.vocabularies.UI.v1.DataFieldWithUrl" && !aRecords[i].Url.UrlRef) {

                        var oModel = this.getView().getModel();
                        var oMetaData = oModel.oMetaModel;
                        var oEntityBindingContext = oMetaData.createBindingContext(oEntityType.$path);
                        var sBindingString = sap.ui.model.odata.AnnotationHelper.format(oEntityBindingContext, aRecords[i].Url);
                        var oCustomData = new sap.ui.core.CustomData({key: "url", value: sBindingString});
                        oCustomData.setModel(oModel);
                        oCustomData.setBindingContext(oContext);
                        var oUrl = oCustomData.getValue();

                        aNavigationFields.push({
                            type: aRecords[i].RecordType,
                            url: oUrl,
                            value: aRecords[i].Value.String,
                            label: aRecords[i].Label.String
                        });
                    }
                }
            }
            return aNavigationFields;
        },

        getModel: function () {
            return this.getView().getModel();
        },

        getMetaModel: function () {
            return this.getModel().getMetaModel();
        },

        getCardPropertiesModel: function () {
            return this.getView().getModel("ovpCardProperties");
        },

        getEntitySet: function () {
            if (!this.entitySet) {
                var sEntitySet = this.getCardPropertiesModel().getProperty("/entitySet");
                this.entitySet = this.getMetaModel().getODataEntitySet(sEntitySet);
            }

            return this.entitySet;
        },

        getEntityType: function () {
            if (!this.entityType) {
                this.entityType = this.getMetaModel().getODataEntityType(this.getEntitySet().entityType);
            }

            return this.entityType;
        },

        getCardContentContainer: function(){
            if (!this.cardContentContainer){
                this.cardContentContainer = this.getView().byId("ovpCardContentContainer");
            }
            return this.cardContentContainer;
        },

        _saveAppState : function(sFilterDataSuiteFormat) {
            var oDeferred = jQuery.Deferred();
            var oAppState = sap.ushell.Container.getService("CrossApplicationNavigation").createEmptyAppState(this.getOwnerComponent());
            var sAppStateKey = oAppState.getKey();
            var oAppDataForSave = {
                selectionVariant: sFilterDataSuiteFormat
            };
            oAppState.setData(oAppDataForSave);
            var oSavePromise = oAppState.save();

            oSavePromise.done(function () {
                oDeferred.resolve(sAppStateKey, oAppDataForSave);
            });

            return oDeferred.promise();
        },

        /**
         * Retrieve entity parameters (if exists) and add xAppState from oComponentData.appStateKeyFunc function (if exists)
         * @param oEntity
         * @returns {*}
         * @private
         */
        _getEntityNavigationParameters: function (oEntity) {
            var oDeferred = jQuery.Deferred();
            var oUrlParameters = {};
            var oEntityType;
            var oComponentData = this.getOwnerComponent().getComponentData();
            var oGlobalFilter = oComponentData ? oComponentData.globalFilter : undefined;
            var oSaveAppStatePromise;
            var oCardFilters = sap.ovp.cards.AnnotationHelper.getCardFilters(this.getCardPropertiesModel());
            var oSelectionVariant;

            // Build result object of card parameters
            if (oEntity) {
                oEntityType = this.getEntityType();
                var key;
                for (var i = 0; oEntityType.property && i < oEntityType.property.length; i++) {
                    key = oEntityType.property[i].name;
                    if (oEntity.hasOwnProperty(key)) {
                        if (window.Array.isArray(oEntity[key]) && oEntity[key].length === 1) {
                            oUrlParameters[key] = oEntity[key][0].toString();
                        } else if (oEntity[key]) {
                            oUrlParameters[key] = oEntity[key].toString();
                        }
                    }
                }
            }

            //Build selection variant object from global filter, card filter and card parameters
            oSelectionVariant = this._buildSelectionVariant(oGlobalFilter, oCardFilters, oUrlParameters);

            //Get all filters with EQ option and add it to parameters result
            // in order for it will to be shown on the URL
            var aSelectOptionsNames = oSelectionVariant.getSelectOptionsPropertyNames();
            for (var i = 0; i < aSelectOptionsNames.length; i++) {
                var sSelectOptions = aSelectOptionsNames[i];
                var oValue = oSelectionVariant.getSelectOption(sSelectOptions);
                if ((oValue)[0] && (oValue)[0].Option === "EQ"){
                    var value = (oValue)[0].Low;
                    if (value) {
                        oUrlParameters[sSelectOptions] = value;
                    }
                }
            }

            //Save parameters and filters on app-state in case selection variant not empty
            if (!oSelectionVariant.isEmpty()) {
                oSaveAppStatePromise = this._saveAppState(oSelectionVariant.toJSONString());
                oSaveAppStatePromise.done(function(sAppStateKey, oAppDataForSave) {
                    oUrlParameters["sap-xapp-state"] = sAppStateKey;
                    oDeferred.resolve(oUrlParameters, oAppDataForSave);
                });
                oSaveAppStatePromise.fail(function () {
                    jQuery.sap.log.error("appStateKey is not saved for OVP Application");
                    oDeferred.resolve(oUrlParameters);
                });
            } else {
                oDeferred.resolve(oUrlParameters);
            }

            return oDeferred.promise();
        },

        _buildSelectionVariant: function(oGlobalFilter, oCardFilters, oUrlParameters) {
            var sGlobalFilter = oGlobalFilter ? oGlobalFilter.getFilterDataAsString() : "{}";
            var oSelectionVariant = new sap.ui.generic.app.navigation.service.SelectionVariant(sGlobalFilter);

            // Add card filters to selection variant
            for (var i = 0; i < oCardFilters.length; i++) {
                var entry = oCardFilters[i];
                //value1 might be typeof number, hence we check not typeof undefined
                if (entry.path && entry.operator && typeof entry.value1 !==  "undefined") {
                    //value2 is optional, hence we check it separately
                    var sValue2 = (typeof entry.value2 ===  "number") ? entry.value2.toString() : undefined;
                    oSelectionVariant.addSelectOption(entry.path, "I", entry.operator, entry.value1.toString(), sValue2);
                }
            }

            // Add card parameters to selection variant
            // in case key exist from filters do not add it!
            if (oUrlParameters) {
                var value;
                for (var key in oUrlParameters) {
                    value = oUrlParameters[key];
                    //Check that current parameter is not already exist on filters
                    if (!oSelectionVariant.getSelectOption(key)) {
                        oSelectionVariant.addParameter(key, value);
                    }
                }
            }

            return oSelectionVariant;
        },

        _loadParametersForm: function() {
            var oParameterModel = new sap.ui.model.json.JSONModel();
            oParameterModel.setData(this.actionData.parameterData);
            var that = this;

            // first create dialog
            var oParameterDialog = new sap.m.Dialog('ovpCardActionDialog', {
                title: this.actionData.sFunctionLabel,
                afterClose: function() {
                    oParameterDialog.destroy();
                }
            }).addStyleClass("sapUiNoContentPadding");

            // action button (e.g. BeginButton)
            var actionButton = new sap.m.Button({
                text: this.actionData.sFunctionLabel,
                press: function(oEvent) {
                    var mParameters = ActionUtils.getParameters(oEvent.getSource().getModel(), that.actionData.oFunctionImport);
                    oParameterDialog.close();
                    that._callFunction(mParameters);
                }
            });

            // cancel button (e.g. EndButton)
            var cancelButton = new sap.m.Button({
                text: "Cancel",
                press: function() {
                    oParameterDialog.close();
                }
            });
            // assign the buttons to the dialog
            oParameterDialog.setBeginButton(actionButton);
            oParameterDialog.setEndButton(cancelButton);

            // preparing a callback function which will be invoked on the Form's Fields-change
            var onFieldChangeCB = function(oEvent) {
                var missingMandatory = ActionUtils.mandatoryParamsMissing(oEvent.getSource().getModel(),that.actionData.oFunctionImport);
                actionButton.setEnabled(!missingMandatory);
            };

            // get the form assign it the Dialog and open it
            var oForm = ActionUtils.buildParametersForm(this.actionData,onFieldChangeCB);

            oParameterDialog.addContent(oForm);
            oParameterDialog.setModel(oParameterModel);
            oParameterDialog.open();
        },

        _callFunction: function(mUrlParameters) {
            var mParameters = {
                batchGroupId: "Changes",
                changeSetId: "Changes",
                urlParameters: mUrlParameters,
                forceSubmit: true,
                context: this.actionData.oContext,
                functionImport: this.actionData.oFunctionImport
            };
            var that = this;
            var oPromise = new Promise(function(resolve, reject) {
                var model = that.actionData.oContext.getModel();
                var sFunctionImport;
                sFunctionImport = "/" + mParameters.functionImport.name;
                model.callFunction(sFunctionImport, {
                    method: mParameters.functionImport.httpMethod,
                    urlParameters: mParameters.urlParameters,
                    batchGroupId: mParameters.batchGroupId,
                    changeSetId: mParameters.changeSetId,
                    headers: mParameters.headers,
                    success: function(oData, oResponse) {
                        resolve(oResponse);
                    },
                    error : function(oResponse) {
                        reject(oResponse);
                    }
                });
            });
            //Todo: call translation on message toast
            oPromise.then(function(oResponse) {
                return sap.m.MessageToast.show(sap.ui.getCore().getLibraryResourceBundle("sap.ovp").getText("Toast_Action_Success"), { duration: 1000});
            }, function(oError) {
                return sap.m.MessageToast.show(sap.ui.getCore().getLibraryResourceBundle("sap.ovp").getText("Toast_Action_Error"), { duration: 1000});
            });
        },

        /**
         * In case of error card implementation can call this method to display
         * card error state.
         * Current instance of the card will be destroied and instead loading card
         * will be presenetd with the 'Cannot load card' meassage
         */
        setErrorState: function(){
            //get the current card component
            var oCurrentCard = this.getOwnerComponent();
            //get the component container
            var oComponentContainer = oCurrentCard.oContainer;
            //prepare card configuration, i.e. category, title, description and entitySet
            //which are required for the loading card. in addition set the card state to error
            //so no loading indicator will be presented
            var oCardPropertiesModel = this.getCardPropertiesModel();
            var oComponentConfig = {
                name: "sap.ovp.cards.loading",
                componentData: {
                    model: this.getView().getModel(),
                    settings: {
                        category: oCardPropertiesModel.getProperty("/category"),
                        title: oCardPropertiesModel.getProperty("/title"),
                        description: oCardPropertiesModel.getProperty("/description"),
                        entitySet: oCardPropertiesModel.getProperty("/entitySet"),
                        state: sap.ovp.cards.loading.State.ERROR
                    }
                }
            };
            //create the loading card
            var oLoadingCard = sap.ui.component(oComponentConfig);
            //set the loading card in the container
            oComponentContainer.setComponent(oLoadingCard);
            //destroy the current card
            setTimeout(function(){
                oCurrentCard.destroy();
            }, 0);
        }


    });
})();
}; // end of sap/ovp/cards/generic/Card.controller.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.generic.Component') ) {
(function () {
    "use strict";
    /*global jQuery, sap */

    jQuery.sap.declare("sap.ovp.cards.generic.Component");
    jQuery.sap.require('sap.ui.core.UIComponent'); // unlisted dependency retained

    

    sap.ui.core.UIComponent.extend("sap.ovp.cards.generic.Component", {
        // use inline declaration instead of component.json to save 1 round trip
        metadata: {
            properties: {
                "contentFragment": {
                    "type": "string"
                },
                "headerExtensionFragment": {
                    "type": "string"
                },
                "contentPosition": {
                    "type": "string",
                    "defaultValue": "Middle"
                },
                "footerFragment": {
                    "type": "string"
                },
                "identificationAnnotationPath":{
                    "type": "string",
                    "defaultValue": "com.sap.vocabularies.UI.v1.Identification"
                },
                "selectionAnnotationPath":{
                    "type": "string"
                },
                "filters": {
                    "type": "object"
                },
                "addODataSelect": {
                    "type": "boolean",
                    "defaultValue": false
                }
            },
            version: "1.36.12",

            library: "sap.ovp",

            includes: [],

            dependencies: {
                libs: [ "sap.m" ],
                components: []
            },
            config: {}
        },

        /**
         * Default "abstract" empty function.
         * In case there is a need to enrich the default preprocessor which provided by OVP, the extended Component should provide this function and return a preprocessor object.
         * @public
         * @returns {Object} SAPUI5 preprocessor object
         */
        getCustomPreprocessor: function () {},

        getPreprocessors : function(ovplibResourceBundle) {
            var oComponentData = this.getComponentData(),
                oSettings = oComponentData.settings,
                oModel = oComponentData.model,
                oMetaModel,
                oEntityTypeContext,
                oEntitySetContext;

            //Backwards compatibility to support "description" property
            if (oSettings.description && !oSettings.subTitle) {
                oSettings.subTitle = oSettings.description;
            }
            if (oModel){
                var oMetaModel = oModel.getMetaModel();
                var oEntitySet = oMetaModel.getODataEntitySet(oSettings.entitySet);
                var sEntitySetPath = oMetaModel.getODataEntitySet(oSettings.entitySet, true);
                var oEntityType = oMetaModel.getODataEntityType(oEntitySet.entityType);

                oEntitySetContext = oMetaModel.createBindingContext(sEntitySetPath);
                oEntityTypeContext = oMetaModel.createBindingContext(oEntityType.$path);
            }

            var oCardProperties = this._getCardPropertyDefaults();

            oCardProperties = jQuery.extend(true, {metaModel: oMetaModel, entityType: oEntityType}, oCardProperties, oSettings);

            var oOvpCardPropertiesModel = new sap.ui.model.json.JSONModel(oCardProperties);
            var ovplibResourceBundle = this.getOvplibResourceBundle();

            var oDefaultPreprocessors = {
                xml: {
                    bindingContexts: {entityType: oEntityTypeContext, entitySet: oEntitySetContext},
                    models: {entityType: oMetaModel, entitySet:oMetaModel, ovpMeta: oMetaModel, ovpCardProperties: oOvpCardPropertiesModel, ovplibResourceBundle: ovplibResourceBundle},
                    ovpCardProperties: oOvpCardPropertiesModel,
                    dataModel: oModel,
                    _ovpCache: {}
                }
            };

            return jQuery.extend(true, {}, this.getCustomPreprocessor(), oDefaultPreprocessors);
        },

        _getCardPropertyDefaults: function(){
            var oCardProperties = {};
            var oPropsDef = this.getMetadata().getAllProperties();
            var oPropDef;
            for (var propName in oPropsDef){
                oPropDef = oPropsDef[propName];
                if (oPropDef.defaultValue !== undefined){
                    oCardProperties[oPropDef.name] = oPropDef.defaultValue;
                }
            }
            return oCardProperties;
        },

        getOvplibResourceBundle: function(){
            if (!this.ovplibResourceBundle){
                var oResourceBundle = sap.ui.getCore().getLibraryResourceBundle("sap.ovp");
                this.ovplibResourceBundle = oResourceBundle ? new sap.ui.model.resource.ResourceModel({bundleUrl: oResourceBundle.oUrlInfo.url}) : null;
            }
            return this.ovplibResourceBundle;
        },

        createContent: function () {
            var oComponentData = this.getComponentData && this.getComponentData();
            var oModel = oComponentData.model;
            var oPreprocessors = this.getPreprocessors();

            var oView;
            oView = sap.ui.view({
                preprocessors: oPreprocessors,
                type: sap.ui.core.mvc.ViewType.XML,
                viewName: "sap.ovp.cards.generic.Card"
            });

            oView.setModel(oModel);
            // check if i18n model is available and then add it to card view
            if (oComponentData.i18n) {
                oView.setModel(oComponentData.i18n, "@i18n");
            }
            oView.setModel(oPreprocessors.xml.ovpCardProperties, "ovpCardProperties");
            oView.setModel(this.getOvplibResourceBundle(), "ovplibResourceBundle");

            return oView;
        }
    });
})();

}; // end of sap/ovp/cards/generic/Component.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.image.Component') ) {
(function () {
    "use strict";
    /*global jQuery, sap */

    jQuery.sap.declare("sap.ovp.cards.image.Component");
    

    sap.ovp.cards.generic.Component.extend("sap.ovp.cards.image.Component", {
        // use inline declaration instead of component.json to save 1 round trip
        metadata: {
            properties: {
                "contentFragment": {
                    "type": "string",
                    "defaultValue": "sap.ovp.cards.image.Image"
                }
            },

            version: "1.36.12",

            library: "sap.ovp",

            includes: [],

            dependencies: {
                libs: [ "sap.m" ],
                components: []
            },
            config: {},
            customizing: {
                "sap.ui.controllerExtensions": {
                    "sap.ovp.cards.generic.Card": {
                        controllerName: "sap.ovp.cards.image.Image"
                    }
                }
            }
        }
    });
})();

}; // end of sap/ovp/cards/image/Component.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.list.Component') ) {
(function () {
    "use strict";
    /*global jQuery, sap */

    jQuery.sap.declare("sap.ovp.cards.list.Component");
    

    sap.ovp.cards.generic.Component.extend("sap.ovp.cards.list.Component", {
        // use inline declaration instead of component.json to save 1 round trip
        metadata: {
            properties: {
                "contentFragment": {
                    "type": "string",
                    "defaultValue": "sap.ovp.cards.list.List"
                },
                "annotationPath": {
                    "type": "string",
                    "defaultValue": "com.sap.vocabularies.UI.v1.LineItem"
                },
                "footerFragment": {
                    "type": "string",
                    "defaultValue": "sap.ovp.cards.generic.CountFooter"
                },
                "headerExtensionFragment":{
                    "type": "string",
                    "defaultValue": "sap.ovp.cards.generic.KPIHeader"
                }
            },

            version: "1.36.12",

            library: "sap.ovp",

            includes: [],

            dependencies: {
                libs: [ "sap.m" ],
                components: []
            },
            config: {},
            customizing: {
                "sap.ui.controllerExtensions": {
                    "sap.ovp.cards.generic.Card": {
                        controllerName: "sap.ovp.cards.list.List"
                    }
                }
            }
        }
    });
})();

}; // end of sap/ovp/cards/list/Component.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.loading.Component') ) {
(function () {
    "use strict";
    /*global jQuery, sap */

    jQuery.sap.declare("sap.ovp.cards.loading.Component");
    

    sap.ovp.cards.loading.State = {
        ERROR: "Error",
        LOADING: "Loading"
    };

    sap.ovp.cards.generic.Component.extend("sap.ovp.cards.loading.Component", {
        // use inline declaration instead of component.json to save 1 round trip
        metadata: {
            properties: {
                "footerFragment": {
                    "type": "string",
                    "defaultValue": "sap.ovp.cards.loading.LoadingFooter"
                },
                "state": {
                    "type": "string",
                    "defaultValue": sap.ovp.cards.loading.State.LOADING
                }
            },

            version: "1.36.12",

            library: "sap.ovp",
            customizing: {
                "sap.ui.controllerExtensions": {
                    "sap.ovp.cards.generic.Card": {
                        controllerName: "sap.ovp.cards.loading.Loading"
                    }
                }
            }

        }

    });
})();


}; // end of sap/ovp/cards/loading/Component.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.quickview.Component') ) {
(function () {
    "use strict";
    /*global jQuery, sap */

    jQuery.sap.declare("sap.ovp.cards.quickview.Component");
    

    sap.ovp.cards.generic.Component.extend("sap.ovp.cards.quickview.Component", {
        // use inline declaration instead of component.json to save 1 round trip
        metadata: {
            properties: {
                "contentFragment": {
                    "type": "string",
                    "defaultValue": "sap.ovp.cards.quickview.Quickview"
                },
                "annotationPath": {
                    "type": "string",
                    "defaultValue": "com.sap.vocabularies.UI.v1.Facets"
                },
                "footerFragment": {
                    "type": "string",
                    "defaultValue": "sap.ovp.cards.generic.ActionsFooter"
                }
            },

            version: "1.36.12",

            library: "sap.ovp",

            includes: [],

            dependencies: {
                libs: [ "sap.m" ],
                components: []
            },
            config: {},
            customizing: {
                "sap.ui.controllerExtensions": {
                    "sap.ovp.cards.generic.Card": {
                        controllerName: "sap.ovp.cards.quickview.Quickview"
                    }
                }
            }
        }
    });
})();

}; // end of sap/ovp/cards/quickview/Component.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.quickview.Quickview.controller') ) {
  jQuery.sap.declare('sap.ovp.cards.quickview.Quickview.controller');
(function () {
    "use strict";
    /*global sap, jQuery */

    
    sap.ui.controller("sap.ovp.cards.quickview.Quickview", {
        onInit: function () {
        },
        onAfterRendering: function(){
        }

    });
})();

}; // end of sap/ovp/cards/quickview/Quickview.controller.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.stack.Component') ) {
(function () {
    "use strict";
    /*global jQuery, sap */

    jQuery.sap.declare("sap.ovp.cards.stack.Component");
    

    sap.ovp.cards.generic.Component.extend("sap.ovp.cards.stack.Component", {
        // use inline declaration instead of component.json to save 1 round trip
        metadata: {
            properties: {
                "contentFragment": {
                    "type": "string",
                    "defaultValue": "sap.ovp.cards.stack.Stack"
                },
                "contentPosition": {
                    "type": "string",
                    "defaultValue": "Right"
                },
                "objectStreamCardsSettings" : {
                    "type": "object",
                    "defaultValue": {
                    }
                },
                "objectStreamCardsTemplate" : {
                    "type": "string",
                    "defaultValue": "sap.ovp.cards.quickview"
                },
                "objectStreamCardsNavigationProperty" : {
                    "type": "string"
                }
            },

            version: "1.36.12",

            library: "sap.ovp",

            includes: [],

            dependencies: {
                libs: [ "sap.m" ],
                components: []
            },
            config: {},
            customizing: {
                "sap.ui.controllerExtensions": {
                    "sap.ovp.cards.generic.Card": {
                        controllerName: "sap.ovp.cards.stack.Stack"
                    }
                }
            }
        }
    });
})();

}; // end of sap/ovp/cards/stack/Component.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.table.Component') ) {
(function () {
    "use strict";
    /*global jQuery, sap */

    jQuery.sap.declare("sap.ovp.cards.table.Component");
    

    sap.ovp.cards.generic.Component.extend("sap.ovp.cards.table.Component", {
        // use inline declaration instead of component.json to save 1 round trip
        metadata: {
            properties: {
                "contentFragment": {
                    "type": "string",
                    "defaultValue": "sap.ovp.cards.table.Table"
                },
                "annotationPath": {
                    "type": "string",
                    "defaultValue": "com.sap.vocabularies.UI.v1.LineItem"
                },
                "footerFragment": {
                    "type": "string",
                    "defaultValue": "sap.ovp.cards.generic.CountFooter"
                },
                "headerExtensionFragment":{
                    "type": "string",
                    "defaultValue": "sap.ovp.cards.generic.KPIHeader"
                }
            },

            version: "1.36.12",

            library: "sap.ovp",

            includes: [],

            dependencies: {
                libs: [ "sap.m" ],
                components: []
            },
            config: {},
            customizing: {
                "sap.ui.controllerExtensions": {
                    "sap.ovp.cards.generic.Card": {
                        controllerName: "sap.ovp.cards.table.Table"
                    }
                }
            }
        }
    });
})();


}; // end of sap/ovp/cards/table/Component.js
if ( !jQuery.sap.isDeclared('sap.ovp.library') ) {
/*!
 * Copyright (c) 2009-2014 SAP SE, All Rights Reserved
 */

/* -----------------------------------------------------------------------------------
 * Hint: This is a derived (generated) file. Changes should be done in the underlying
 * source files only (*.type, *.js) or they will be lost after the next generation.
 * ----------------------------------------------------------------------------------- */

/**
 * Initialization Code and shared classes of library sap.ovp (1.36.12)
 */
jQuery.sap.declare("sap.ovp.library");
jQuery.sap.require('sap.ui.core.Core'); // unlisted dependency retained

/**
 * SAP library: sap.ovp
 *
 * @namespace
 * @name sap.ovp
 * @public
 */


// library dependencies
jQuery.sap.require('sap.ui.core.library'); // unlisted dependency retained

jQuery.sap.require('sap.ui.layout.library'); // unlisted dependency retained

jQuery.sap.require('sap.ui.generic.app.library'); // unlisted dependency retained

jQuery.sap.require('sap.m.library'); // unlisted dependency retained

jQuery.sap.require('sap.ui.comp.library'); // unlisted dependency retained


// delegate further initialization of this library to the Core
sap.ui.getCore().initLibrary({
	name : "sap.ovp",
	dependencies : ["sap.ui.core","sap.ui.layout","sap.ui.generic.app","sap.m","sap.ui.comp"],
	types: [],
	interfaces: [],
	controls: [],
	elements: [],
	version: "1.36.12"
});


}; // end of sap/ovp/library.js
if ( !jQuery.sap.isDeclared('sap.ovp.ui.CardContentContainer') ) {
/*!
 * ${copyright}
 */

/*global sap window*/

jQuery.sap.declare('sap.ovp.ui.CardContentContainer'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ovp/ui/CardContentContainer",["jquery.sap.global", "sap/ovp/library"],
    function(jQuery) {
        "use strict";

        var CardContentContainer = sap.m.FlexBox.extend("sap.ovp.ui.CardContentContainer", {
            metadata: {
                library: "sap.ovp"
            },
            renderer: {
                render: function (oRm, oControl) {
                    oRm.write("<div");
                    oRm.writeControlData(oControl);
                    oRm.addClass("sapOvpCardContentContainer");
                    oRm.writeClasses();
                    oRm.write(">");
                    var items = oControl.getItems();
                    for (var i = 0; i < items.length; i++) {
                        oRm.renderControl(items[i]);
                    }
                    oRm.write("</div>");
                }
            }

        });


        return CardContentContainer;

    }, /* bExport= */ true);

}; // end of sap/ovp/ui/CardContentContainer.js
if ( !jQuery.sap.isDeclared('sap.ovp.ui.CustomData') ) {
/*!
 * ${copyright}
 */
jQuery.sap.declare('sap.ovp.ui.CustomData'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.CustomData'); // unlisted dependency retained
jQuery.sap.require('sap.ushell.library'); // unlisted dependency retained
sap.ui.define("sap/ovp/ui/CustomData",['jquery.sap.global', 'sap/ui/core/CustomData', 'sap/ushell/library'],
    function (jQuery, CustomData, library) {
        "use strict";

        var CustomData = CustomData.extend("sap.ovp.ui.CustomData");
           // fnOrigcheckWriteToDom = CustomData.prototype._checkWriteToDom;


        CustomData.prototype._checkWriteToDom = function (oRelated) {
            var sKey = this.getKey().toLowerCase(),
                bIsAccessibilityOn = sap.ui.getCore().getConfiguration().getAccessibility();
            if (!bIsAccessibilityOn) {
                return;
            }
            if (!this.getWriteToDom()) {
                return null;
            }
            var value = this.getValue();

            if (typeof value != "string") {
                jQuery.sap.log.error("CustomData with key " + sKey + " should be written to HTML of " + oRelated + " but the value is not a string.");
                return null;
            }

            if (!(sap.ui.core.ID.isValid(sKey)) || (sKey.indexOf(":") != -1)) {
                jQuery.sap.log.error("CustomData with key " + sKey + " should be written to HTML of " + oRelated + " but the key is not valid (must be a valid sap.ui.core.ID without any colon).");
                return null;
            }

            if (sKey == jQuery.sap._FASTNAVIGATIONKEY) {
                value = /^\s*(x|true)\s*$/i.test(value) ? "true" : "false"; // normalize values
            } else if (sKey.indexOf("sap-ui") == 0) {
                jQuery.sap.log.error("CustomData with key " + sKey + " should be written to HTML of " + oRelated + " but the key is not valid (may not start with 'sap-ui').");
                return null;
            }
            return {key: sKey, value: value};
        };

        return CustomData;

    }, /* bExport= */ true);

}; // end of sap/ovp/ui/CustomData.js
if ( !jQuery.sap.isDeclared('sap.ovp.ui.EasyScanLayout') ) {
/*!
 * ${copyright}
 */

/*global sap window*/
jQuery.sap.declare('sap.ovp.ui.EasyScanLayout'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ovp/ui/EasyScanLayout",["jquery.sap.global", "sap/ovp/library"],
    function (jQuery) {
        "use strict";
        jQuery.sap.require('sap.ovp.ui.UIActions');

        var ReplaceItems = function (settings) {
            this.init(settings);
        };

        ReplaceItems.prototype.init = function (settings) {
            settings.beforeDragCallback = this._beforeDragHandler.bind(this);
            settings.dragStartCallback = this._dragStartHandler.bind(this);
            settings.dragMoveCallback = this._dragMoveHandler.bind(this);
            settings.dragEndCallback = this._dragEndHandler.bind(this);
            settings.endCallback = this._endHandler.bind(this);

            this.layout = settings.layout;
            this.afterReplaceElements = settings.afterReplaceElements || function () {};
            this.settings = settings;
            delete settings.afterReplaceElements;
            this.destroy(); //destroy the previous instance of UIActions
            this.uiActions = new sap.ovp.ui.UIActions(this.settings).enable();
            this.aCardsOrder = null; //DOM elements array
            this.verticalMargin = null; //space vertical between items
            this.horizontalMargin = null; //horizontal space vertical between items
            this.columnCount = null; //number of layout columns
            this.top = null; //space between layout top and first card
            this.left = null; //space between layout left and first card
            this.width = null; //item width
            this.layoutOffset = null; //layout coordinates on screen, needed to normalize mouse position to layout
            this.jqLayout = null; //layout jQuery reference
            this.jqLayoutInner = null; //layout inner wrapper jQuery reference
            this.isRTLEnabled = null; //RTL flag
            this.lastCollidedEl = null; //last collided element
            this.lastCollisionTop = null; //last element collision top or bottom true/false
        };


        //search collision with elements,
        //moveX - normalized X cord.
        //moveY - normalized Y cord.
        //itemList array of elements with posDnD property {top: , left: , height:, width: }
        //returns found element or undefined
        ReplaceItems.prototype.findCollision = function (moveX, moveY, itemList) {
            var colliedItem;
            for (var i = 0; i < itemList.length; i++) {
                var item = itemList[i];
                var isHorizontalIntersection = !(item.posDnD.right < moveX || item.posDnD.left > moveX);
                var isVerticalIntersection = !(item.posDnD.bottom < moveY || item.posDnD.top > moveY);
                if (isHorizontalIntersection && isVerticalIntersection) {
                    colliedItem = item;
                    break;
                }
            }
            return colliedItem;
        };

        //returns which part of element has collision - true for top, false for bottom
        ReplaceItems.prototype.isCollisionTop = function (moveX, moveY, item) {
            var halfBottom = ((item.posDnD.bottom - item.posDnD.top) / 2) + item.posDnD.top;
            var isCollisionTop = !(halfBottom < moveY || item.posDnD.top > moveY);
            return isCollisionTop;
        };

        //callback for UIActions, every time when mouse is moved in drag mode.
        ReplaceItems.prototype._dragMoveHandler = function (actionObject) {
            //{evt : evt, clone : this.clone, element: this.element, isScrolling: isScrolling, moveX : this.moveX, moveY : this.moveY}
            var sourceElement = actionObject.element;
            var moveX = actionObject.moveX - this.layoutOffset.left;
            var moveY = actionObject.moveY - this.jqLayout.get(0).getBoundingClientRect().top + this.jqLayout.scrollTop();

            var collidedItem = this.findCollision(moveX, moveY, this.aCardsOrder);
            if (!collidedItem) {
                return; //no collided item, no need to act
            }
            var collidedItemTopCollision = this.isCollisionTop(moveX, moveY, collidedItem); //get element collision part
            if (collidedItem === sourceElement) {
                this.lastCollidedEl = collidedItem; //collided is dragged element, save it as last collided, and exit.
                return;
            }
            if (collidedItem === this.lastCollidedEl) {
                //current collided element the same as it was last time
                if (this.lastCollisionTop === collidedItemTopCollision) {
                    //mouse was not moved to another element part (from top to bottom or wise versa), so no need to act
                    return;
                }
                if (this.lastCollisionTop) {
                    this.lastCollisionTop = collidedItemTopCollision;
                    if (sourceElement.posDnD.top > collidedItem.posDnD.top) {
                        //mouse was moved from top to bottom, but sourceElement already on the bottom of collided element, no need to switch.
                        return;
                    }
                } else {
                    this.lastCollisionTop = collidedItemTopCollision;
                    if (sourceElement.posDnD.top < collidedItem.posDnD.top) {
                        //mouse was moved from bottom to top, but sourceElement already on the top of collided element, no need to switch.
                        return;
                    }
                }
            }
            if (this.lastCollidedEl && (this.lastCollidedEl !== collidedItem && this.lastCollidedEl !== sourceElement) &&
                (this.lastCollidedEl.posDnD.left === collidedItem.posDnD.left && this.lastCollidedEl.posDnD.left ===  sourceElement.posDnD.left)){
                //complicated situation, when lastCollided, currentCollided and sourceElement, it's 3 different items, and they all in the same column.
                //it means that we don't want to switch with currentCollided element, becouse it dosn't look good.
                //Instead we switch with lastCollided item, which is more logical behaviour for user.
                collidedItem = this.lastCollidedEl;
            }
            //switch elements and recalculate new layout state.
            this.dragAndDropElement(sourceElement, collidedItem);
            //we want to know under which card mouse will be after  cards change places.
            //Because cards could be very high, it's possible that after change, mouse will appear under another card.
            //So we need to prevent future collision with this card, else you could face endless loop, when two high card will change each other endlessly.
            this.lastCollidedEl = this.findCollision(moveX, moveY, this.aCardsOrder);
            if (this.lastCollidedEl) {
                this.lastCollisionTop = this.isCollisionTop(moveX, moveY, this.lastCollidedEl);
            }
        };

        //switch elements and apply new element positions
        ReplaceItems.prototype.dragAndDropElement = function (sourceElement, targetElement) {
            if (sourceElement && targetElement) {
                this.aCardsOrder = this.dragAndDropSwapElement(sourceElement, targetElement, this.aCardsOrder);
                this.drawLayout(this.aCardsOrder);
            }
        };

        //switch two elements
        ReplaceItems.prototype.dragAndDropSwapElement = function (sourceElement, targetElement, itemsList) {
            var newOrder = itemsList.slice();
            var sourceElementIndex = itemsList.indexOf(sourceElement);
            var targetElementIndex = itemsList.indexOf(targetElement);
            newOrder[targetElementIndex] = sourceElement;
            newOrder[sourceElementIndex] = targetElement;
            return newOrder;
        };


        //keyboard navigation
        ReplaceItems.prototype.dragAndDropSwapElementForKeyboardNavigation = function (sourceElement, targetElement) {
            if (sourceElement && targetElement) {
                var aLayoutCards = this.layout.getVisibleLayoutItems().map(function (item) {
                    return item.$().parent()[0];
                });

                var changes = 0;
                for (var i = 0; i < aLayoutCards.length; i++){
                    if (aLayoutCards[i] === sourceElement){
                        aLayoutCards[i] = targetElement;
                        changes++;
                        continue;
                    }
                    if (aLayoutCards[i] === targetElement){
                        aLayoutCards[i] = sourceElement;
                        changes++;
                        continue;
                    }
                }

                //callback afterSwapItems
                if (changes === 2) {
                    this.afterReplaceElements(aLayoutCards);
                }
            }
        };

        //init function called when drag start
        ReplaceItems.prototype.initCardsSettingsForDragAndDrop = function () {
            this.jqLayout = this.layout.$();
            this.jqLayoutInner = this.jqLayout.children().first();
            var layoutScroll = this.jqLayout.scrollTop();
            var layoutHeight = this.jqLayoutInner.height();
            this.isRTLEnabled = sap.ui.getCore().getConfiguration().getRTL() ? 1 : -1;
            this.aCardsOrder = [];
            this.layoutOffset = this.jqLayout.offset();

            var visibleLayoutItems = this.layout.getVisibleLayoutItems();
            if (!visibleLayoutItems) {
                return;
            }
            this.aCardsOrder = visibleLayoutItems.map(function (item) {
                var element = item.$().parent()[0];
                element.posDnD = {
                    width: element.offsetWidth,
                    height: element.offsetHeight
                };
                element.style.width = element.offsetWidth + "px";
                return element;
            });
            var jqFirstColumn = this.jqLayoutInner.children().first();
            var marginProp = (this.isRTLEnabled === 1) ? "margin-left" : "margin-right";
            this.verticalMargin = parseInt(jqFirstColumn.css(marginProp), 10);
            var firstItemEl = this.aCardsOrder[0];
            this.horizontalMargin = parseInt(jQuery(firstItemEl).css("margin-bottom"), 10);
            this.columnCount = this.layout.getColumnCount();
            this.top = firstItemEl.getBoundingClientRect().top - this.jqLayoutInner[0].getBoundingClientRect().top;
            this.left = firstItemEl.getBoundingClientRect().left - this.jqLayoutInner[0].getBoundingClientRect().left;
            this.width = firstItemEl.offsetWidth;

            jQuery(this.aCardsOrder).css("position", "absolute");
            this.drawLayout(this.aCardsOrder);

            //all elements are switched to position absolute to prevent layout from collapsing we put height on it like it was before change.
            //and fix scroll, so user will not see position changes on the screen.
            this.jqLayoutInner.height(layoutHeight);
            this.jqLayout.scrollTop(layoutScroll);

        };

        //put all elements to new position.
        ReplaceItems.prototype.drawLayout = function (aCardsLayout) {
            var oCountColumnHeight = [];
            for (var i = 0; i < this.columnCount; i++) {
                oCountColumnHeight[i] = 0;
            }
            for (var naturalIndex = 0; naturalIndex < aCardsLayout.length; naturalIndex++) {
                var currentColumn = naturalIndex % this.columnCount;
                var currentHeight = oCountColumnHeight[currentColumn]++;
                var currentLeft = this.left - this.isRTLEnabled * (currentColumn * this.verticalMargin + currentColumn * this.width);
                var currentTop = this.top;
                var domElement =  aCardsLayout[naturalIndex];

                for (var j = 0; j < currentHeight; j++) {
                    currentTop += this.horizontalMargin;
                    var parentIndex = naturalIndex - (j + 1) * this.columnCount;
                    currentTop += aCardsLayout[parentIndex].posDnD.height;
                }

                domElement.posDnD.top = currentTop;
                domElement.posDnD.bottom = currentTop + domElement.posDnD.height;
                domElement.posDnD.left = currentLeft;
                domElement.posDnD.right = currentLeft + domElement.posDnD.width;
                this.updateElementCSS(aCardsLayout[naturalIndex]);
            }
        };

        ReplaceItems.prototype.updateElementCSS = function (element) {
            jQuery(element).css({
                top: element.posDnD.top,
                left: element.posDnD.left
            });
        };

        //callback when drag starts
        ReplaceItems.prototype._dragStartHandler = function (evt, cardElement) {
            //Prevent selection of text on tiles and groups
            if (window.getSelection) {
                var selection = window.getSelection();
                selection.removeAllRanges();
            }
            this.initCardsSettingsForDragAndDrop();
        };

        //callback before clone created
        ReplaceItems.prototype._beforeDragHandler = function (evt, ui) {
            //Prevent the browser to mark any elements while dragging
            if (sap.ui.Device.system.desktop) {
                jQuery('body').addClass("sapOVPDisableUserSelect sapOVPDisableImageDrag");
            }
            //Prevent text selection menu and magnifier on mobile devices
            if (sap.ui.Device.browser.mobile) {
                this.selectableElemets = jQuery(ui).find('.sapUiSelectable');
                this.selectableElemets.removeClass('sapUiSelectable');
            }
            jQuery(this.settings.wrapper).addClass("dragAndDropMode");
        };

        //model changes, and cleanup after drag and drop finished
        ReplaceItems.prototype._dragEndHandler = function (evt, ui) {
            this.lastCollidedEl = null;
            if (this.aCardsOrder) {
                this.afterReplaceElements(this.aCardsOrder);
            }
            //Cleanup added classes and styles before drag
            if (sap.ui.Device.system.desktop) {
                jQuery('body').removeClass("sapOVPDisableUserSelect sapOVPDisableImageDrag");
            }
            jQuery(this.settings.wrapper).removeClass("dragAndDropMode");
            this.jqLayoutInner.removeAttr("style");
            jQuery(this.aCardsOrder).removeAttr("style");
        };

        ReplaceItems.prototype._endHandler = function (evt, ui) {
            //Prevent text selection menu and magnifier on mobile devices
            if (sap.ui.Device.browser.mobile && this.selectableElemets) {
                this.selectableElemets.addClass('sapUiSelectable');
            }
        };

        ReplaceItems.prototype.getSwapItemsFunction = function () {
            return this.dragAndDropSwapElementForKeyboardNavigation.bind(this);
        };

        ReplaceItems.prototype.destroy = function () {
            if (this.uiActions) {
                this.uiActions.disable();
                this.uiActions = null;
            }
        };

        var DragAndDropFactory = {
            buildReplaceItemsInstance: function (settings) {
                var defaultSettings = {
                    containerSelector: ".sapUshellEasyScanLayoutInner",
                    wrapper: ".sapUshellEasyScanLayout",
                    draggableSelector: ".easyScanLayoutItemWrapper",
                    placeHolderClass: "easyScanLayoutItemWrapper-placeHolder",
                    cloneClass: "easyScanLayoutItemWrapperClone",
                    moveTolerance: 10,
                    switchModeDelay: 800,
                    isTouch: !sap.ui.Device.system.desktop,
                    debug: false
                };

                settings = jQuery.extend(defaultSettings, settings);
                return new ReplaceItems(settings);
            }
        };

        var KeyboardNavigation = function (easyScanLayout, swapItemsFunction) {
            this.init(easyScanLayout, swapItemsFunction);
        };

        KeyboardNavigation.prototype.init = function (easyScanLayout, swapItemFunction) {
            this.easyScanLayout = easyScanLayout;
            this.swapItemsFunction = (typeof swapItemFunction === "function") ? swapItemFunction : function () {
            };
            this.keyCodes = jQuery.sap.KeyCodes;
            this.jqElement = easyScanLayout.$();
            this.jqElement.on('keydown.keyboardNavigation', this.keydownHandler.bind(this));
            this.jqElement.find(".after").on("focus.keyboardNavigation", this.afterFocusHandler.bind(this));
            this.jqElement.find(".sapUshellEasyScanLayoutInner").on("focus.keyboardNavigation", this.layoutFocusHandler.bind(this));
            this.jqElement.on("focus.keyboardNavigation", ".easyScanLayoutItemWrapper", this.layoutItemFocusHandler.bind(this));
            this._ignoreSelfFocus = false;
            this.swapSourceElement = null;
        };

        KeyboardNavigation.prototype.destroy = function () {
            if (this.jqElement) {
                this.jqElement.off(".keyboardNavigation");
                this.jqElement.find(".after").off(".keyboardNavigation");
                this.jqElement.find(".sapUshellEasyScanLayoutInner").off(".keyboardNavigation");
            }
            delete this.jqElement;
            delete this.easyScanLayout;
        };

        KeyboardNavigation.prototype.getVisibleLayoutItems = function () {
            //layout items could be hidden, so we filter them and receive only visible
            var content = this.easyScanLayout.getContent();
            var filteredItems = content.filter(function (item) {
                return item.getVisible();
            });
            return filteredItems;
        };

        KeyboardNavigation.prototype.afterFocusHandler = function () {
            //two options are possible, or focus came to us from outside, as a result of outside navigation (Shift+tab Shift+F6 etc...)
            //or we put focus as a result of Tab button inside layout, to maintain Accessibility guide:
            // If focus is on the last control inside a Item, move focus to the next control in the tab chain after the Item Container
            if (this._ignoreSelfFocus) {
                //focus was on the last control inside a Item, move focus to the next control in the tab chain after the Item Container
                //so, this function was called from tabButtonHandler,  we put focus on after element, so browser will move it outside of layout
                this._ignoreSelfFocus = false;
                return;
            }
            //focus came to us from outside, as a result of outside navigation (Shift+tab Shift+F6 etc...)
            //	On enter first time, move focus to the last control of the first Item.
            //	On enter any consecutive time, move focus to the last control of the Item which had the focus before
            var jqItem = this.jqElement.find(".easyScanLayoutItemWrapper:sapTabbable").first();
            var lastTabbable = jqItem.find(":sapTabbable").last();
            if (!lastTabbable.length) {
                lastTabbable = jqItem;
            }
            lastTabbable.focus();
        };

        KeyboardNavigation.prototype.layoutFocusHandler = function () {
            //two options are possible, or focus came to us from outside, as a result of outside navigation (tab F6 etc...)
            //or we put focus as a result of Shift+Tab button inside layout, to maintain Accessibility guide:
            // If focus is on a Item, move focus to the previous control in the tab chain before the Item Container.
            if (this._ignoreSelfFocus) {
                //focus was on the Item, move focus to the previous control in the tab chain before the Item Container
                //so  this function was called from shiftTabButtonHandler, and we put focus on layout itself, so browser will move it outside of layout
                this._ignoreSelfFocus = false;
                return;
            }
            //focus was received from outside element
            //On enter first time, move focus to the first Item (as a whole).
            //On enter any consecutive time, move focus to the Item which had the focus before.
            this.jqElement.find(".easyScanLayoutItemWrapper:sapTabbable").first().focus();
        };

        KeyboardNavigation.prototype.layoutItemFocusHandler = function () {
            var jqFocused = jQuery(document.activeElement);

            // Check that focus element exits, id this item exits it will be easyScanLayoutItemWrapper (because the jQuery definitions
            // After we have the element we want to add to his aria-labelledby attribute all the IDs of his sub elements that have aria-label and role headind
            if (jqFocused) {

                // Select all sub elements with aria-label
                var labelledElement = jqFocused.find("[aria-label]");
                var i, strIdList = "";

                //  Add every element id with aria label and roll heading inside the LayoutItemWrapper to string list
                for (i = 0; i < labelledElement.length; i++) {
                    if (labelledElement[i].getAttribute("role") == "heading") {
                        strIdList += labelledElement[i].id + " ";
                    }
                }

                // add the id string list to the focus element (warpper) aria-labelledby attribute
                if (strIdList.length) {
                    jqFocused.attr("aria-labelledby", strIdList);
                }
            }
        };

        //return array index of visible items from layout content aggregation
        KeyboardNavigation.prototype._getLayoutItemIndex = function (jqFocused) {
            if (!jqFocused.hasClass("easyScanLayoutItemWrapper")) {
                return false;
            }
            var currentItemId = jqFocused.children().attr("id");
            var itemIndex = false;
            this.getVisibleLayoutItems().forEach(function (item, index) {
                if (currentItemId == item.getId()) {
                    itemIndex = index;
                }
            });
            return itemIndex;
        };

        KeyboardNavigation.prototype._changeItemsFocus = function (jqItem) {
            //to preserve last focusable item, we need to set all other items tabindex=-1
            var jqTabbableElements = jQuery('.easyScanLayoutItemWrapper');
            jqTabbableElements.attr("tabindex", "-1");
            jqItem.attr("tabindex", 0);
            jqItem.focus();
        };

        KeyboardNavigation.prototype._swapItemsFocus = function (e, jqItemFrom, jqItemTo) {
            //to preserve last focusable item, first item received tabindex=-1, second tabindex=-1.
            e.preventDefault();
            jqItemFrom.attr("tabindex", "-1");
            jqItemTo.attr("tabindex", "0").focus();
        };


        KeyboardNavigation.prototype.tabButtonHandler = function (e) {
            //Forward navigation:
            //On enter first time, move focus to the first Item (as a whole).
            //On enter any consecutive time, move focus to the Item which had the focus before.
            //If focus is on a Item, move focus to the first control in the tab chain inside the Item.
            //If focus is on a control inside a Item, move focus to the next control in the tab chain inside the same Item.
            //If focus is on the last control inside a Item, move focus to the next control in the tab chain after the Item Container
            var jqFocusedElement = jQuery(document.activeElement);
            if (jqFocusedElement.hasClass("easyScanLayoutItemWrapper")) {
                return;
            }
            var jqItem = jqFocusedElement.closest(".easyScanLayoutItemWrapper");
            //need to check if focus is inside layout item
            if (!jqItem.length) {
                return;
            }
            //we know that focus is inside item, so now we want to check if it is last focusable.
            var jqTabbables = jqItem.find(":sapTabbable");
            //need to filter elements which have `after` in id, becouse those are dummy focusable elements and they
            // prevent us from finding real last element
            jqTabbables = jqTabbables.filter(":not([id$=after])");
            //if currently focused element is itm's last one, then we place focus outside of layout
            if (jqTabbables.eq(jqTabbables.length - 1).is(jqFocusedElement)) {
                e.stopPropagation();
                e.stopImmediatePropagation();
                var beforeScrollLocation = this.jqElement.scrollTop();
                this._ignoreSelfFocus = true;
                this.jqElement.find(".after").focus();
                this.jqElement.scrollTop(beforeScrollLocation);
            }
        };

        KeyboardNavigation.prototype.f7Handler = function (e) {
            //If focus is on a Item, move focus to the control inside the Item. Default: first control in the tab chain inside the Item.
            //If focus is on a control inside a Item, move focus to the Item.
            var jqFocusedElement = jQuery(document.activeElement);
            if (jqFocusedElement.hasClass("easyScanLayoutItemWrapper")) {
                //focus on item we place on first element inside
                jqFocusedElement.find(":sapTabbable").first().focus();
            } else {
                //focus inside item, we put it on item itself
                jqFocusedElement.closest(".easyScanLayoutItemWrapper").focus();
            }
            e.preventDefault();
        };

        KeyboardNavigation.prototype.shiftTabButtonHandler = function (e) {
            //Backward navigation:
            //On enter first time, move focus to the last control of the first Item.
            //If focus is on a control inside a Item, move focus to the previous control in the tab chain inside the same Item.
            //If focus is on the first control inside a Item, move focus to the corresponding Item (as a whole).
            //If focus is on a Item, move focus to the previous control in the tab chain before the Item Container.
            var jqFocusedElement = jQuery(document.activeElement);
            if (!jqFocusedElement.hasClass("easyScanLayoutItemWrapper")) {
                return;
            }
            //focus was on the Item, move focus to the previous control in the tab chain before the Item Container
            //we  put focus on layout itself, so browser will move it outside of layout
            this._ignoreSelfFocus = true;
            this.jqElement.find(".sapUshellEasyScanLayoutInner").focus();
        };

        KeyboardNavigation.prototype.arrowUpDownHandler = function (e, isArrowUp) {
            //UP - If focus is on a Item, move focus to the Item above. If focus is on the first Item of a column, do nothing.
            //DOWN - If focus is on a Item, move focus to the Item below. If focus is on the last Item of a column, do nothing.
            var fName = isArrowUp ? "prev" : "next";
            var jqFocused = jQuery(document.activeElement);
            var nextFocus = jQuery(jqFocused)[fName](".easyScanLayoutItemWrapper");
            if (!nextFocus.is(jqFocused)) {
                this._swapItemsFocus(e, jqFocused, nextFocus);
            }
        };

        KeyboardNavigation.prototype.arrowRightLeftHandler = function (e, isArrowRight) {
            //Left - If focus is on a Card, move focus one Card to the left.
            //      If focus is on the first Card of a row, move focus to the last Card of the previous row.
            //      If focus is on the first Card, do nothing.
            //Right - If focus is on a Card, move focus one Card to the right.
            //      If focus is on the last Card of a row, move focus to the first Card of the next row.
            //      If focus is on the last Card, do nothing.
            var indexDiff = isArrowRight ? 1 : -1;
            var jqFocused = jQuery(document.activeElement);
            var currentItemIndex = this._getLayoutItemIndex(jqFocused);
            if (currentItemIndex === false) {
                return;
            }
            var oItem = this.getVisibleLayoutItems()[currentItemIndex + indexDiff];
            if (oItem) {
                this._swapItemsFocus(e, jqFocused, oItem.$().parent());
            }
        };

        KeyboardNavigation.prototype.homeHandler = function (e) {
            //If focus is on a Card, move focus to the first Card of the same row.
            //If focus is on the first Card of a row, move focus to the first item within the Card Container.
            var jqFocused = jQuery(document.activeElement);
            var focusedElementIndex = this._getLayoutItemIndex(jqFocused);
            if (focusedElementIndex === false) {
                return;
            }
            var colCount = this.easyScanLayout.getColumnCount();
            var indexDelta = focusedElementIndex % colCount;
            var item;
            var layoutItems = this.getVisibleLayoutItems();
            if (indexDelta == 0) {
                //focus will be put to the first item in layout
                item = layoutItems[0];
            } else {
                //focus will be put to the first element in row
                item = layoutItems[focusedElementIndex - indexDelta];
            }

            this._swapItemsFocus(e, jqFocused, item.$().parent());
        };

        KeyboardNavigation.prototype.endHandler = function (e) {
            //If focus is on a Card, move focus to the last Card of the same row.
            //If focus is on the last Card of a row, move focus to the last item within the Card Container.
            var jqFocused = jQuery(document.activeElement);
            var focusedElementIndex = this._getLayoutItemIndex(jqFocused);
            if (focusedElementIndex === false) {
                return;
            }
            var colCount = this.easyScanLayout.getColumnCount();
            var indexDelta = focusedElementIndex % colCount;
            var item;
            var layoutItems = this.getVisibleLayoutItems();
            if ((indexDelta == (colCount - 1)) ||
                ((focusedElementIndex + (colCount - indexDelta)) > layoutItems.length)) {
                //focus wil be put to last layout item
                item = layoutItems[(layoutItems.length - 1)];
            } else {
                //focus will be put to last item in row
                item = layoutItems[focusedElementIndex + (colCount - indexDelta - 1)];
            }
            this._swapItemsFocus(e, jqFocused, item.$().parent());
        };

        KeyboardNavigation.prototype.ctrlHomeHandler = function (e) {
            //If focus is on a Card, move focus to the first Card of the same column.
            //If focus is on the first Card of a column, move focus to the first Card within the Card Container.
            var jqFocused = jQuery(document.activeElement);
            var focusedElementIndex = this._getLayoutItemIndex(jqFocused);
            if (focusedElementIndex === false) {
                return;
            }
            var colCount = this.easyScanLayout.getColumnCount();
            var indexDelta = focusedElementIndex % colCount;
            var visibleItems = this.getVisibleLayoutItems();
            var item = visibleItems[indexDelta];
            var nextFocus = item.$().parent();
            if (nextFocus.is(jqFocused)) {
                nextFocus = visibleItems[0].$().parent();
            }
            this._swapItemsFocus(e, jqFocused, nextFocus);
        };

        KeyboardNavigation.prototype.ctrlEndHandler = function (e) {
            //If focus is on a Card, move focus to the last Card of the same column.
            //If focus is on the last Card of a column, move focus to the last Card within the Card Container.
            var jqFocused = jQuery(document.activeElement);
            var focusedElementIndex = this._getLayoutItemIndex(jqFocused);
            if (focusedElementIndex < 0) {
                return;
            }
            var colCount = this.easyScanLayout.getColumnCount();
            var indexDelta = focusedElementIndex % colCount;
            var item;
            var visibleItems = this.getVisibleLayoutItems();
            for (var i = visibleItems.length - 1; i >= 0; i--) {
                if ((i % colCount) == indexDelta) {
                    item = visibleItems[i];
                    break;
                }
            }
            var nextFocus = item.$().parent();
            if (nextFocus.is(jqFocused)) {
                nextFocus = visibleItems[visibleItems.length - 1].$().parent();
            }
            this._swapItemsFocus(e, jqFocused, nextFocus);
        };

        KeyboardNavigation.prototype.altPageUpHandler = function (e) {
            //If focus is on a Card, move focus left by page size. Page size can be set by apps, default page size is 5 Cards.
            //If there are less Cards available than page size, move focus to the first Card of the row.
            //If focus is on the first Card of the row, do nothing.
            var jqFocused = jQuery(document.activeElement);
            var focusedElementIndex = this._getLayoutItemIndex(jqFocused);
            if (!focusedElementIndex) {
                return;
            }
            var colCount = this.easyScanLayout.getColumnCount();
            var indexDelta = focusedElementIndex % colCount;
            var item = this.getVisibleLayoutItems()[focusedElementIndex - indexDelta];
            this._swapItemsFocus(e, jqFocused, item.$().parent());
        };

        KeyboardNavigation.prototype.altPageDownHandler = function (e) {
            //If focus is on a Card, move focus right by page size. Page size can be set by apps, default page size is 5 Cards.
            //If there are less Cards available than page size, move focus to the last Card of the row.
            //If focus is on the last Card of the row, do nothing.
            var jqFocused = jQuery(document.activeElement);
            var focusedElementIndex = this._getLayoutItemIndex(jqFocused);
            if (focusedElementIndex < 0) {
                return;
            }
            var colCount = this.easyScanLayout.getColumnCount();
            var indexDelta = focusedElementIndex % colCount;
            var item;
            var layoutItems = this.getVisibleLayoutItems();
            if (indexDelta != (colCount - 1)) {
                item = layoutItems[focusedElementIndex + (colCount - indexDelta - 1)];
                if (!item) {
                    item = layoutItems[layoutItems.length - 1];
                }
                this._swapItemsFocus(e, jqFocused, item.$().parent());
            }
        };

        KeyboardNavigation.prototype.pageUpDownHandler = function (e, isPageUp) {
            //move focus Up/Down to the first not visible (outside of viewport).
            //if all items (on direction) are visible, then to first/last
            var fName = isPageUp ? "prev" : "next";

            var jqFocused = jQuery(document.activeElement);
            if (!jqFocused.hasClass("easyScanLayoutItemWrapper")) {
                return;
            }
            if (!jqFocused[fName]().length) {
                return;
            }
            var nextFocusEl = false;
            var currentEl = jqFocused;
            var windowHeight = jQuery(window).height();
            var layoutTop = this.jqElement.offset().top;
            //find first "outside of viewport" item
            while (!nextFocusEl) {
                var next = currentEl[fName]();
                if (!next.length) {
                    nextFocusEl = currentEl;
                    break;
                }
                if (!isPageUp && next.offset().top > windowHeight) {
                    nextFocusEl = next;
                    break;
                }
                if (isPageUp && (next.offset().top + next.outerHeight()) <= layoutTop) {
                    nextFocusEl = next;
                    break;
                }
                currentEl = next;
            }
            this._swapItemsFocus(e, jqFocused, nextFocusEl);
        };

        KeyboardNavigation.prototype.ctrlArrowHandler = function (e) {
            //Check that we are not in Drag mode already
            //then we need to start the DragMode if it's possible
            if (this.swapSourceElement == null) {
                this.swapSourceElement = jQuery(document.activeElement);
                if (!this.swapSourceElement.hasClass("easyScanLayoutItemWrapper")) {
                    this.endSwap();
                } else {
                    this.jqElement.on('keyup.keyboardNavigation', this.keyupHandler.bind(this));
                    //change css of the current element
                    this.jqElement.addClass('dragAndDropMode');
                    this.swapSourceElement.addClass('dragHovered');
                }
            }
        };

        KeyboardNavigation.prototype.keyupHandler = function (e) {
            //This is the case when we finished our Drag and Drop actions, and we want to swap items
            if (this.swapSourceElement != null && e.keyCode === this.keyCodes.CONTROL) {
                var jqFocused = jQuery(document.activeElement);
                if (jqFocused.hasClass("easyScanLayoutItemWrapper")) {
                    this.swapItemsFunction(this.swapSourceElement[0], jqFocused[0]);
                    this._changeItemsFocus(this.swapSourceElement);
                }
                this.endSwap();
            }
        };


        KeyboardNavigation.prototype.endSwap = function (e) {
            this.swapSourceElement.removeClass('dragHovered');
            this.jqElement.removeClass('dragAndDropMode');
            this.swapSourceElement = null;
            this.jqElement.off('keyup.keyboardNavigation');
        };

        KeyboardNavigation.prototype.checkIfSwapInterrupted = function (e) {
            //When Drag&Drop mode is enabled, any other button except arrowKey will stop Drag&Drop action
            if (this.swapSourceElement != null &&
                e.keyCode != this.keyCodes.ARROW_LEFT &&
                e.keyCode != this.keyCodes.ARROW_RIGHT &&
                e.keyCode != this.keyCodes.ARROW_UP &&
                e.keyCode != this.keyCodes.ARROW_DOWN) {
                this.endSwap();
            }
        };

        KeyboardNavigation.prototype.keydownHandler = function (e) {
            //in case swap was interrupted call end swap
            this.checkIfSwapInterrupted(e);

            switch (e.keyCode) {
                case this.keyCodes.TAB:
                    (e.shiftKey) ? this.shiftTabButtonHandler(e) : this.tabButtonHandler(e);
                    break;
                case this.keyCodes.F6:
                    if (e.shiftKey) {
                        this._ignoreSelfFocus = true;
                        this.jqElement.find(".sapUshellEasyScanLayoutInner").focus();
                        jQuery.sap.handleF6GroupNavigation(e);
                    } else {
                        this._ignoreSelfFocus = true;
                        var beforeScrollLocation = this.jqElement.scrollTop();
                        this.jqElement.find(".after").focus();
                        jQuery.sap.handleF6GroupNavigation(e);
                        this.jqElement.scrollTop(beforeScrollLocation);
                    }
                    break;
                case this.keyCodes.F7:
                    this.f7Handler(e);
                    break;
                case this.keyCodes.ARROW_UP:
                    if (e.ctrlKey == true) {
                        this.ctrlArrowHandler(e);
                    }
                    this.arrowUpDownHandler(e, true);
                    break;
                case this.keyCodes.ARROW_DOWN:
                    if (e.ctrlKey == true) {
                        this.ctrlArrowHandler(e);
                    }
                    this.arrowUpDownHandler(e, false);
                    break;
                case this.keyCodes.ARROW_RIGHT:
                    if (e.ctrlKey == true) {
                        this.ctrlArrowHandler(e);
                    }
                    this.arrowRightLeftHandler(e, true);
                    break;
                case this.keyCodes.ARROW_LEFT:
                    if (e.ctrlKey == true) {
                        this.ctrlArrowHandler(e);
                    }
                    this.arrowRightLeftHandler(e, false);
                    break;
                case this.keyCodes.HOME:
                    (e.ctrlKey == true) ? this.ctrlHomeHandler(e) : this.homeHandler(e);
                    break;
                case this.keyCodes.END:
                    (e.ctrlKey == true) ? this.ctrlEndHandler(e) : this.endHandler(e);
                    break;
                case this.keyCodes.PAGE_UP:
                    (e.altKey == true) ? this.altPageUpHandler(e) : this.pageUpDownHandler(e, true);
                    break;
                case this.keyCodes.PAGE_DOWN:
                    (e.altKey == true) ? this.altPageDownHandler(e) : this.pageUpDownHandler(e, false);
                    break;
            }
        };

        var EasyScanLayout = sap.ui.core.Control.extend("sap.ovp.ui.EasyScanLayout", {

            metadata: {
                library: "sap.ovp",
                aggregations: {
                    content: {type: "sap.ui.core.Control", multiple: true, singularName: "content"}
                },
                defaultAggregation: "content",
                events: {
                    afterRendering: {},
                    afterDragEnds: {}
                },
                properties: {
                    useMediaQueries: {group: "Misc", type: "boolean", defaultValue: false},
                    dragAndDropRootSelector: {group: "Misc", type: "string"},
                    dragAndDropEnabled: {group: "Misc", type: "boolean", defaultValue: true},
                    debounceTime: {group: "Misc", type: "sap.ui.core/int", defaultValue: 150}
                }
            },

            renderer: {
                render: function (oRm, oControl) {
                    oRm.write("<div");
                    oRm.writeControlData(oControl);
                    oRm.addClass("sapUshellEasyScanLayout");
                    oRm.writeClasses();
                    oRm.write(">");

                    oRm.write("<div class='sapUshellEasyScanLayoutInner' tabindex='0'>");

                    var columnCount = oControl.columnCount;
                    var columnList = Array.apply(null, new Array(columnCount)).map(function () {
                        return [];
                    });
                    var filteredItems = oControl.getContent().filter(function (item) {
                        return item.getVisible();
                    });
                    for (var i = 0; i < filteredItems.length; i++) {
                        columnList[i % columnCount].push(filteredItems[i]);
                    }
                    var itemCounter = 1;
                    columnList.forEach(function (column) {
                        oRm.write("<div");
                        oRm.addClass("easyScanLayoutColumn");
                        oRm.writeAccessibilityState(undefined, {role: "list"});
                        oRm.writeClasses();
                        oRm.write(">");
                        column.forEach(function (item, index) {
                            oRm.write("<div ");
                            (itemCounter === 1) ? oRm.write("tabindex='0' ") : oRm.write("tabindex='-1' ");
                            oRm.addClass("easyScanLayoutItemWrapper");
                            oRm.writeAccessibilityState(undefined, {role: "listitem"});
                            oRm.write("aria-setsize=" + filteredItems.length + " aria-posinset=" + itemCounter);
                            itemCounter++;
                            oRm.writeClasses();
                            oRm.write(">");
                            oRm.renderControl(item);
                            oRm.write("</div>");
                        });
                        oRm.write("</div>");
                    });

                    oRm.write("</div>");
                    // dummy after focusable area
                    oRm.write("<div class='after' tabindex='0'></div>");
                    oRm.write("</div>");
                }
            }

        });

        var getColumnResolutionList = function () {
            return [
                {minWidth: 0, styleClass: "columns-blank", columnCount: 1},
                {minWidth: 240, styleClass: "columns-block", columnCount: 1},
                {minWidth: 352, styleClass: "columns-narrow", columnCount: 1},
                {minWidth: 433, styleClass: "columns-wide", columnCount: 1},
                {minWidth: 704, styleClass: "columns-narrow", columnCount: 2},
                {minWidth: 864, styleClass: "columns-wide", columnCount: 2},
                {minWidth: 1024, styleClass: "columns-narrow", columnCount: 3},
                {minWidth: 1280, styleClass: "columns-wide", columnCount: 3},
                {minWidth: 1440, styleClass: "columns-narrow", columnCount: 4},
                {minWidth: 1920, styleClass: "columns-wide", columnCount: 4},
                {minWidth: 2560, styleClass: "columns-narrow", columnCount: 5},
                {minWidth: 3008, styleClass: "columns-wide", columnCount: 5},

                //This is for 8K and 4K Screens (on 3600px flp make 1rem - 32px)
                {minWidth: 3600, styleClass: "columns-narrow", columnCount: 4},
                {minWidth: 3840, styleClass: "columns-wide", columnCount: 4},
                {minWidth: 5120, styleClass: "columns-wide", columnCount: 5},
                {minWidth: 6016, styleClass: "columns-wide", columnCount: 5}
            ];
        };

        EasyScanLayout.prototype.init = function () {
            this.data("sap-ui-fastnavgroup", "true", true);
            this.columnResolutionList = getColumnResolutionList();
            this.columnCount = this.columnResolutionList[0].columnCount;
            this.columnStyle = "";
            this.updateColumnClass(this.columnResolutionList[0].styleClass);
            var matchMediaSupported = sap.ui.Device.browser.msie && sap.ui.Device.browser.version > 9;
            if (matchMediaSupported && this.getUseMediaQueries()) { //if matchMedia supported and full page --> use media queries
                this.mediaQueryList = this.initMediaListeners(this.columnResolutionList);
            } else { //if not full page --> use resize handler
                this.resizeHandlerId = this.initResizeHandler(this.columnResolutionList);
            }
        };

        var mediaListenerHandlerTimerId;

        var mediaListenersDebounce = function (columnCount, columnStyle, mq) {
            var mediaListenerHandler = function (cols, className) {
                this.updateColumnClass(className);
                this.refreshColumnCount(cols, this.getContent());
            };
            if (mq.matches) {
                window.clearTimeout(mediaListenerHandlerTimerId);
                mediaListenerHandlerTimerId = window.setTimeout(mediaListenerHandler.bind(this, columnCount, columnStyle), this.getDebounceTime());
            }
        };

        var buildQuery = function (bottomRes, topRes) {
            var min = bottomRes.minWidth;
            var max = topRes && topRes.minWidth;
            return "(min-width: " + min + "px)" + (max ? " and (max-width: " + (max - 1) + "px)" : "");
        };

        EasyScanLayout.prototype.initMediaListeners = function (colResList) {
            var mediaQueryList = [];
            for (var i = 0; i < colResList.length; i++) {
                var query = buildQuery(colResList[i], colResList[i + 1]);
                var mediaQuery = window.matchMedia(query);
                var boundedListener = mediaListenersDebounce.bind(this, colResList[i].columnCount, colResList[i].styleClass);
                mediaQuery.addListener(boundedListener);
                mediaQuery.bindedListener = boundedListener;
                boundedListener(mediaQuery);
                mediaQueryList.push(mediaQuery);
            }
            return mediaQueryList;
        };

        EasyScanLayout.prototype.initResizeHandler = function (colResList) {
            var resizeHandlerTimerId;
            var debounceTime = this.getDebounceTime();
            var resizeHandlerDebounce = function () {
                window.clearTimeout(resizeHandlerTimerId);
                resizeHandlerTimerId = window.setTimeout(this.oControl.resizeHandler.bind(this, colResList), debounceTime);
            };

            return sap.ui.core.ResizeHandler.register(this, resizeHandlerDebounce);
        };

        EasyScanLayout.prototype.resizeHandler = function (colResList) {
            var width = this.iWidth;
            var oControl = this.oControl;
            var resObject;
            for (var i = 0; i < colResList.length; i++) {
                if (!colResList[i + 1]) {
                    resObject = colResList[i];
                    break;
                }
                if (colResList[i].minWidth <= width && colResList[i + 1].minWidth > width) {
                    resObject = colResList[i];
                    break;
                }
            }

            oControl.refreshColumnCount(resObject.columnCount, oControl.getContent());
            oControl.updateColumnClass(resObject.styleClass);
        };

        EasyScanLayout.prototype.refreshColumnCount = function (columnCount, content) {
            this.columnCount = columnCount;
            var jqColumnsNew = jQuery();
            for (var i = 0; i < columnCount; i++) {
                jqColumnsNew = jqColumnsNew.add("<div class='easyScanLayoutColumn' role = 'list'/>");
            }
            var filteredItems = content.filter(function (item) {
                return item.getVisible();
            });
            for (var j = 0; j < filteredItems.length; j++) {
                jqColumnsNew.get(j % columnCount).appendChild(filteredItems[j].getDomRef().parentNode);
            }

            this.$().children(".sapUshellEasyScanLayoutInner").empty().append(jqColumnsNew);

        };

        EasyScanLayout.prototype.getColumnCount = function () {
            return this.columnCount;
        };

        EasyScanLayout.prototype.getVisibleLayoutItems = function () {
            //layout items could be hidden, so we filter them and receive only visible
            var content = this.getContent();
            var filteredItems = content.filter(function (item) {
                return item.getVisible();
            });
            return filteredItems;
        };

        EasyScanLayout.prototype.updateColumnClass = function (columnClass) {
            if (this.columnStyle === columnClass) {
                return;
            }
            this.removeStyleClass(this.columnStyle);
            this.addStyleClass(columnClass);
            this.columnStyle = columnClass;
        };


        EasyScanLayout.prototype.afterDragAndDropHandler = function (aElements) {
            var aAllControls = this.removeAllAggregation("content", true);
            var aVisibleControls = [];
            var iVizibleIndex = 0;
            //receive contols list from wrapperDOM list
            aElements.forEach(function (el) {
                var elementId = el.children[0].getAttribute("id");
                var oControl = sap.ui.getCore().byId(elementId);
                aVisibleControls.push(oControl);
            });

            // We need to keep all controls in the content aggregation, keep
            // the original order and change the order only for the visible controls
            for (var i = 0; i < aAllControls.length; i++){
                if (aAllControls[i].getVisible()){
                    this.addAggregation("content", aVisibleControls[iVizibleIndex], true);
                    iVizibleIndex++;
                } else {
                    this.addAggregation("content", aAllControls[i], true);
                }

            }

            this.fireAfterDragEnds();
            this.refreshColumnCount(this.getColumnCount(), this.getContent());
        };


        EasyScanLayout.prototype.onAfterRendering = function () {
            if (!this.getDragAndDropRootSelector()) {
                this.setDragAndDropRootSelector("#" + this.getId());
            }
            if (this.layoutDragAndDrop) {
                this.layoutDragAndDrop.destroy();
            }
            if (this.getDragAndDropEnabled()) {
                this.layoutDragAndDrop = DragAndDropFactory.buildReplaceItemsInstance({
                    afterReplaceElements: this.afterDragAndDropHandler.bind(this),
                    rootSelector: this.getDragAndDropRootSelector(),
                    layout: this
                });
            }
            if (this.keyboardNavigation) {
                this.keyboardNavigation.destroy();
            }
            var swapItemsFunc = this.layoutDragAndDrop ? this.layoutDragAndDrop.getSwapItemsFunction() : null;
            this.keyboardNavigation = new KeyboardNavigation(this, swapItemsFunc);
            this.fireAfterRendering();
        };

        EasyScanLayout.prototype.exit = function () {
            if (this.mediaQueryList) {
                this.mediaQueryList.forEach(function (mediaQuery) {
                    mediaQuery.removeListener(mediaQuery.bindedListener);
                });
                delete this.mediaQueryList;
            }
            if (this.resizeHandlerId) {
                sap.ui.core.ResizeHandler.deregister(this.resizeHandlerId);
            }
            if (this.layoutDragAndDrop) {
                this.layoutDragAndDrop.destroy();
                delete this.layoutDragAndDrop;
            }
        };

        return EasyScanLayout;

    }, /* bExport= */ true);

}; // end of sap/ovp/ui/EasyScanLayout.js
if ( !jQuery.sap.isDeclared('sap.ovp.ui.ObjectStream') ) {
/**
 * Created by i060586 on 11/25/14.
 */
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5/OpenUI5)
 * (c) Copyright 2009-2014 SAP SE or an SAP affiliate company.
 * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
 */
jQuery.sap.require('sap.ui.core.delegate.ScrollEnablement'); // unlisted dependency retained


jQuery.sap.declare('sap.ovp.ui.ObjectStream'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ovp/ui/ObjectStream",['jquery.sap.global'],
    function(jQuery) {
        "use strict";

        var KeyboardNavigation = function (objectStream) {
            this.init(objectStream);
        };

        KeyboardNavigation.prototype.init = function(objectStream) {
            this.objectStream = objectStream;
            this.keyCodes = jQuery.sap.KeyCodes;
            this.jqElement = objectStream.$();
            this.jqElement.on('keydown.keyboardNavigation', this.keydownHandler.bind(this));
            this.jqElement.on("focus.keyboardNavigation",".sapOvpObjectStreamItem", this.ObjectStreamFocusAccessabilityHandler.bind(this));
        };

        KeyboardNavigation.prototype.destroy = function () {
            if (this.jqElement) {
                this.jqElement.off(".keyboardNavigation");
            }
            delete this.jqElement;
            delete this.objectStream;
        };

        KeyboardNavigation.prototype._swapItemsFocus = function (e, jqItemFrom, jqItemTo) {
            //to preserve last focusable item, first item received tabindex=-1, second tabindex=-1.
            e.preventDefault();
            jqItemFrom.attr("tabindex", "-1");
            jqItemTo.attr("tabindex", "0").focus();
        };

        //Handle focus on object stream item
        KeyboardNavigation.prototype.ObjectStreamFocusAccessabilityHandler = function () {
            var focusedDomElement = document.activeElement;
            focusedDomElement = jQuery(focusedDomElement);
            //Check that we got a focused item, after that will add to aria-labelledby every id
            // of items inside the object stream item that have role=heading and aria-label
            if (focusedDomElement){
                // get all elements inside that have aria-label
                var labelledElement = focusedDomElement.find("[aria-label]");
                var i, strIdList = "";
                // add every item that also have role heading to id list string
                for (i = 0; i < labelledElement.length; i++ ){
                    if (labelledElement[i].getAttribute("role") == "heading"){
                        strIdList += labelledElement[i].id + " ";
                    }
                }
                //add the object stream item the aria-labelledby attribute with list of relevants IDs
                if (strIdList.length) {
                    focusedDomElement.attr("aria-labelledby", strIdList);
                }
            }
        };

        KeyboardNavigation.prototype.tabButtonHandler = function (e) {
            //Forward navigation:
            //On enter first time, move focus to the first Item (as a whole).
            //If focus is on a Item, move focus to the first control in the tab chain inside the Item.
            //If focus is on a control inside a Item, move focus to the next control in the tab chain inside the same Item.
            //If focus is on the last control inside a Item, move focus to the next control in the tab chain after the Object Stream, usually it's Close button
            var jqFocused = jQuery(document.activeElement);
            if (jqFocused.hasClass("sapOvpObjectStreamItem")) {
                return;
            }
            if (jqFocused.hasClass("sapOvpObjectStreamClose")) {
                //focus on the close button, move focus to last focused item.
                e.preventDefault();
                this.jqElement.find(".sapOvpObjectStreamItem:sapTabbable").focus();
                return;
            }
            var jqCard = jqFocused.closest(".sapOvpObjectStreamItem");
            if (!jqCard.length) {
                return;
            }
            var jqTabbables = jqCard.find(":sapTabbable");
            //If focus is on the last control inside a Item, move focus to the next control in the tab chain after the Object Stream, usually it's Close button
            if (jqTabbables.eq(jqTabbables.length - 1).is(jqFocused)) {
                e.preventDefault();
                this.jqElement.find(".sapOvpObjectStreamClose").focus();
            }
        };

        KeyboardNavigation.prototype.shiftTabButtonHandler = function (e) {
            //Backward navigation:
            //On enter first time, move focus to the last control of the first Card.
            //On enter any consecutive time, move focus to the last control of the Card which had the focus before.
            //If focus is on a control inside a Card, move focus to the previous control in the tab chain inside the same Card. usually it's Close button
            var jqFocused = jQuery(document.activeElement);
            if (jqFocused.hasClass("sapOvpObjectStreamItem")) {
                e.preventDefault();
                this.jqElement.find(".sapOvpObjectStreamClose").focus();
            }
            if (jqFocused.hasClass("sapOvpObjectStreamClose")) {
                e.preventDefault();
                this.jqElement.find(".sapOvpObjectStreamItem:sapTabbable *:sapTabbable").last().focus();
                return;
            }
        };


        KeyboardNavigation.prototype.enterHandler = function (e) {
            var jqFocused = jQuery(document.activeElement);
            //if Space/Enter was on Close button, close dialog
            if (jqFocused.hasClass("sapOvpObjectStreamClose")) {
                e.preventDefault();
                this.objectStream.getParent().close();
                return;
            }

            //if Space/Enter was last item (it is a Placeholder), trigger click
            if (jqFocused.hasClass("sapOvpObjectStreamItem") && !jqFocused.next().length) {
                jqFocused.children().click();
                return;
            }
        };

        KeyboardNavigation.prototype.f6Handler = function (e) {
            //No matter where the focus resides inside the Object Stream, move it to the first element in the tab chain of the next F6-group. (It's Close button)
            var jqFocused = jQuery(document.activeElement);
            if (jqFocused.hasClass("sapOvpObjectStreamClose")) {
                this.jqElement.find('.sapOvpObjectStreamItem').attr("tabindex", "-1").first().attr("tabindex", "0").focus();
            } else {
                this.jqElement.find('.sapOvpObjectStreamClose').focus();
            }
        };

        KeyboardNavigation.prototype.f7Handler = function (e) {
            //If focus is on a Card, move focus to the control inside the Default: first control in the tab chain inside the Card.
            //If focus is on a control inside a Card, move focus to the Card.
            var jqFocused = jQuery(document.activeElement);
            if (jqFocused.hasClass("sapOvpObjectStreamItem")) {
                jqFocused.find(':sapTabbable').first().focus();
            } else {
                jqFocused.closest('.sapOvpObjectStreamItem').focus();
            }
            e.preventDefault();
        };

        KeyboardNavigation.prototype.leftRightHandler = function (e, isRight) {
            //Left - If focus is on a Card, move focus to the previous Card. If focus is on the first Card, do nothing.
            //Right - If focus is on a Card, move focus to the next Card. If focus is on the last Card, do nothing.

                var fName = isRight ? "next" : "prev";
            var jqFocused = jQuery(document.activeElement);
            if (!jqFocused.hasClass("sapOvpObjectStreamItem")) {
                return false;
            }
            var nextFocus = jqFocused[fName]();
            if (!nextFocus.length) {
                return;
            }
            this._swapItemsFocus(e, jqFocused, nextFocus);
        };

        KeyboardNavigation.prototype.homeEndHandler = function (e, isHome) {
            //Home - If focus is on a Card, move focus to the first Card.
            //End - If focus is on a Card, move focus to the last Card. This is usually the Placeholder Card.
            var fName = isHome ? "first" : "last";
            var jqFocused = jQuery(document.activeElement);
            if (!jqFocused.hasClass("sapOvpObjectStreamItem")) {
                return false;
            }
            e.preventDefault();
            var nextFocus = this.jqElement.find(".sapOvpObjectStreamItem")[fName]();
            this._swapItemsFocus(e, jqFocused, nextFocus);
        };

        KeyboardNavigation.prototype.pageUpDownHandler = function (e, isPageUp) {
            //move focus Left/Right to the first not visible (outside of viewport) item.
            //if all items (on direction) are visible, then to first/last
            var fName = isPageUp ? "prev" : "next";

            var jqFocused = jQuery(document.activeElement);
            if (!jqFocused.hasClass("sapOvpObjectStreamItem")) {
                return;
            }
            if (!jqFocused[fName]().length) {
                return;
            }
            var nextFocusEl = false;
            var currentEl = jqFocused;
            var windowWidth = jQuery(window).width();

            while (!nextFocusEl) {
                var next = currentEl[fName]();
                if (!next.length) {
                    nextFocusEl = currentEl;
                    break;
                }
                if (!isPageUp && next.offset().left > windowWidth) {
                    nextFocusEl = next;
                    break;
                }
                if (isPageUp && (next.offset().left + next.outerHeight()) <= 0) {
                    nextFocusEl = next;
                    break;
                }
                currentEl = next;
            }
            this._swapItemsFocus(e, jqFocused, nextFocusEl);
        };

        KeyboardNavigation.prototype.keydownHandler = function(e) {
            switch (e.keyCode) {
                case this.keyCodes.TAB:
                    (e.shiftKey) ? this.shiftTabButtonHandler(e) : this.tabButtonHandler(e);
                    break;
                case this.keyCodes.ENTER:
                case this.keyCodes.SPACE:
                    this.enterHandler(e);
                    break;
                case this.keyCodes.F6:
                    this.f6Handler(e);
                    break;
                case this.keyCodes.F7:
                    this.f7Handler(e);
                    break;
                case this.keyCodes.ARROW_UP:
                case this.keyCodes.ARROW_LEFT:
                    this.leftRightHandler(e, false);
                    break;
                case this.keyCodes.ARROW_DOWN:
                case this.keyCodes.ARROW_RIGHT:
                    this.leftRightHandler(e, true);
                    break;
                case this.keyCodes.HOME:
                    this.homeEndHandler(e, true);
                    break;
                case this.keyCodes.END:
                    this.homeEndHandler(e, false);
                    break;
                case this.keyCodes.PAGE_UP:
                    this.pageUpDownHandler(e, true);
                    break;
                case this.keyCodes.PAGE_DOWN:
                    this.pageUpDownHandler(e, false);
                    break;
            }
        };


        var ObjectStream = sap.ui.core.Control.extend("sap.ovp.ui.ObjectStream", { metadata : {
            library : "sap.ovp",
            properties : {
                title: {type : "string", defaultValue: ""}
            },
            aggregations : {
                content: {type: "sap.ui.core.Control", multiple: true},
                placeHolder: {type: "sap.ui.core.Control", multiple: false}
            }
        }});


        ObjectStream.prototype.init = function() {
            var that = this;
            this._closeIcon = new sap.ui.core.Icon({
                src: "sap-icon://decline",
                tooltip: "close"
            });
            this._closeIcon.addEventDelegate({
                onclick: function () {
                    that.getParent().close();
                }
            });
        };

        ObjectStream.prototype._startScroll = function(direction) {
            this._direction = direction;
            var scrollDiff = this.wrapper.scrollWidth - this.wrapper.offsetWidth - Math.abs(this.wrapper.scrollLeft);
            var leftToScroll;
            if (direction == "left" ) {
                leftToScroll = (this.rtl && !this.scrollReverse) ? scrollDiff :  this.wrapper.scrollLeft;
                if (leftToScroll <= 0) {
                    return;
                }
                this.jqRightEdge.css("opacity", 1);
            } else {
                leftToScroll = (this.rtl && !this.scrollReverse) ? Math.abs(this.wrapper.scrollLeft) : scrollDiff;
                if (leftToScroll <= 0) {
                    return;
                }
                this.jqLeftEdge.css("opacity", 1);
            }
            var scrollTime = leftToScroll * 3;
            var translateX = (direction == "left") ? leftToScroll : ~leftToScroll + 1;
            jQuery(this.container).one("transitionend", function () {
                this._mouseLeave({data: this});
            }.bind(this));
            this.container.style.transition = 'transform ' + scrollTime + 'ms linear';
            this.container.style.transform = 'translate(' + translateX + 'px, 0px) scale(1) translateZ(0px) ';
        };

        ObjectStream.prototype._mouseLeave = function (e) {
            var containerTransform = window.getComputedStyle(e.data.container).transform;
            e.data.container.style.transform = containerTransform;
            e.data.container.style.transition = '';

            var transformX;
            var transformParamsArr = containerTransform.split(",");
            if (containerTransform.substr(0, 8) == "matrix3d") {
                transformX = parseInt(transformParamsArr[12], 10);
            } else if (containerTransform.substr(0, 6) == "matrix") {
                transformX = parseInt(transformParamsArr[4], 10);
            }
            if (isNaN(transformX)) {
                return;
            }
            e.data.container.style.transform = "none";
            e.data.wrapper.scrollLeft += ~transformX + (e.data._direction == "left" ? -5 : 5);
            e.data._checkEdgesVisibility();
        };

        var scrollHandlerTimerId;
        ObjectStream.prototype.debounceScrollHandler = function () {
            window.clearTimeout(scrollHandlerTimerId);
            scrollHandlerTimerId = window.setTimeout(this._checkEdgesVisibility.bind(this), 150);
        };

        ObjectStream.prototype._initScrollVariables = function () {
            var jqObjectStream = this.$();
            this.container =  jqObjectStream.find(".sapOvpObjectStreamScroll").get(0);
            this.rtl = sap.ui.getCore().getConfiguration().getRTL();
            this.wrapper = jqObjectStream.find(".sapOvpObjectStreamCont").get(0);
            this.scrollReverse = this.scrollReverse || this.wrapper.scrollLeft > 0;
            this.shouldShowScrollButton = (!sap.ui.Device.system.phone && !sap.ui.Device.system.tablet) || sap.ui.Device.system.combi; //should be shown only in desktop (and combi)
            this.jqRightEdge = jqObjectStream.find(".sapOvpOSEdgeRight");
            this.jqLeftEdge = jqObjectStream.find(".sapOvpOSEdgeLeft");
            if (this.shouldShowScrollButton) {
                this.jqRightEdge.add(this.jqLeftEdge).on("mouseenter.objectStream", this, this._mouseEnter).
                    on("mouseleave.objectStream", this, this._mouseLeave);
                jQuery(this.wrapper).on("scroll.objectStream", this.debounceScrollHandler.bind(this));
            }else {
                this.jqLeftEdge.css("display", "none");
                this.jqRightEdge.css("display", "none");
            }

            this._checkEdgesVisibility();
        };

        ObjectStream.prototype._afterOpen = function () {
            if (sap.ui.Device.os.ios && this.$().length) {
                //prevent sap.m.Dialog from stop scroll by cancelling "touchmove" on iOS
                this.$().on("touchmove.scrollFix", function (e) {e.stopPropagation(); });
            }
            this.$().find('.sapOvpObjectStreamItem').first().focus();
            if (this.keyboardNavigation) {
                this.keyboardNavigation.destroy();
            }
            this.keyboardNavigation = new KeyboardNavigation(this);
            this._initScrollVariables();
            this.jqBackground = jQuery("<div id='objectStreamBackgroundId' class='objectStreamNoBackground'></div>");
            jQuery.sap.byId("sap-ui-static").prepend(this.jqBackground);
            this.jqBackground.on('click.closePopup', function () {
                this._oPopup.close();
            }.bind(this));
            jQuery(".sapUshellEasyScanLayout").addClass("bluredLayout");
        };

        ObjectStream.prototype._beforeClose = function () {
            if (sap.ui.Device.os.ios && this.$().length) {
                this.$().off(".scrollFix");
            }
            this.keyboardNavigation.destroy();
            this.jqBackground.remove();
            this.jqLeftEdge.add(this.jqRightEdge).add(this.wrapper).off(".objectStream");
            jQuery(".sapUshellEasyScanLayout").removeClass("bluredLayout");
        };

        ObjectStream.prototype._mouseEnter = function (evt) {
            var scrollDirection = 'right';
            if ((evt.target == evt.data.jqRightEdge.get(0)) ||
                (evt.currentTarget == evt.data.jqRightEdge.get(0))){
                scrollDirection = sap.ui.getCore().getConfiguration().getRTL() ? 'left' : 'right';
            }
            if ((evt.target == evt.data.jqLeftEdge.get(0)) ||
                (evt.currentTarget == evt.data.jqLeftEdge.get(0))){
                scrollDirection = sap.ui.getCore().getConfiguration().getRTL() ? 'right' : 'left';
            }
            evt.data._startScroll(scrollDirection);
        };

        ObjectStream.prototype._checkEdgesVisibility = function () {
            var scrollPosition = this.wrapper.scrollLeft;
            var leftToScroll = this.wrapper.scrollWidth - this.wrapper.offsetWidth - this.wrapper.scrollLeft;
            var leftEdgeOpacity = (scrollPosition == 0) ? 0 : 1;
            var rightEdgeOpacity = (leftToScroll == 0) ? 0 : 1;
            if (sap.ui.getCore().getConfiguration().getRTL() && this.scrollReverse) {
                this.jqLeftEdge.css("opacity", rightEdgeOpacity);
                this.jqRightEdge.css("opacity", leftEdgeOpacity);
            } else {
                this.jqLeftEdge.css("opacity", leftEdgeOpacity);
                this.jqRightEdge.css("opacity", rightEdgeOpacity);
            }
        };

        ObjectStream.prototype._createPopup = function () {
            this._oPopup = new sap.m.Dialog({
                showHeader: false,
                afterOpen: this._afterOpen.bind(this),
                beforeClose: this._beforeClose.bind(this),
                content: [this],
                stretch: sap.ui.Device.system.phone
            }).removeStyleClass("sapUiPopupWithPadding").addStyleClass("sapOvpStackedCardPopup");
            this._oPopup.oPopup.setModal(false);
        };

        ObjectStream.prototype.open = function (cardWidth) {
            if (!this._oPopup) {
                this._createPopup();
            }
            //save card width for after rendering
            this._cardWidth = cardWidth;

            //set height and width of each card on object stream
            this.setCardsSize(this._cardWidth);

            this._oPopup.open();
        };

        ObjectStream.prototype.onBeforeRendering = function() {
        };

        ObjectStream.prototype.onAfterRendering = function() {

            if (!this._oPopup || !this._oPopup.isOpen() || !this.getContent().length ) {
                return;
            }

            //set height and width of each card on object stream
            this.setCardsSize(this._cardWidth);
            setTimeout(function () {
                this._initScrollVariables();
            }.bind(this));
        };


        ObjectStream.prototype.exit = function() {
            if (this._oPopup){
                this._oPopup.destroy();
            }
            this._closeIcon.destroy();
            if (this._oScroller) {
                this._oScroller.destroy();
                this._oScroller = null;
            }
        };

        ObjectStream.prototype.setCardsSize = function(cardWidth) {
            var remSize = parseInt(window.getComputedStyle(document.documentElement).fontSize, 10);
            var cardHeight = sap.ui.Device.system.phone ? document.body.clientHeight / remSize - 4.5 : 28.75;
            var cardList = this.getContent();
            cardList.map(function (oCard) {
                oCard.setWidth(cardWidth + "px");
                oCard.setHeight(cardHeight + "rem");
            });

            var oPlaceHolder = this.getPlaceHolder();
            if (oPlaceHolder) {
                oPlaceHolder.setWidth(cardWidth + "px");
                oPlaceHolder.setHeight(cardHeight + "rem");
            }
        };

        ObjectStream.prototype.updateContent = function(reason){
            /* We are updaing the content only data was change and not by refresh
             * This is done due to the fact that UI5 is calling the updateContent
             * twice, one with reason = 'refresh' with no data in the model and second
             * with reason = 'change' with the data.
             * In order to be able to have rendering optimization we are updating only when
             * we have the data in the model and therefore we can reuse most of the items
             * Ticket was open on this # 1570807520
             */
            // in any case we need to call the oBinding.getContexts().
            // it seams that this will trigger the second call with the change reason
            var oBindingInfo = this.mBindingInfos["content"],
                oBinding = oBindingInfo.binding,
                aBindingContexts = oBinding.getContexts(oBindingInfo.startIndex, oBindingInfo.length);
            if (reason === "change"){
                var fnFactory = oBindingInfo.factory,
                    i = 0,
                    aItems = this.getContent(),
                    addNewItem = jQuery.proxy(function (oContext) {
                        var sId = this.getId() + "-" + jQuery.sap.uid(),
                            oClone = fnFactory(sId, oContext);
                        oClone.setBindingContext(oContext, oBindingInfo.model);
                        this.addContent(oClone);
                    }, this);


                // Bind as many context as possible to existing elements. Create new ones if necessary.
                for (i = 0; i < aBindingContexts.length; ++i) {
                    if (i < aItems.length) {
                        aItems[i].setBindingContext(aBindingContexts[i], oBindingInfo.model);
                    } else {
                        addNewItem(aBindingContexts[i]);
                    }
                }

                if (aItems.length > aBindingContexts.length){
                    // Delete unused elements.
                    for (; i < aItems.length; ++i) {
                        aItems[i].destroy();
                    }
                    // Update the array length.
                    aItems.length = aBindingContexts.length;
                }
            }
        };

        return ObjectStream;

    }, /* bExport= */ true);

}; // end of sap/ovp/ui/ObjectStream.js
if ( !jQuery.sap.isDeclared('sap.ovp.ui.ObjectStreamRenderer') ) {
/**
 * Created by i060586 on 11/25/14.
 */

jQuery.sap.declare('sap.ovp.ui.ObjectStreamRenderer'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ovp/ui/ObjectStreamRenderer",['jquery.sap.global'],

    function(jQuery) {
        "use strict";

        /**
         * Button renderer.
         * @namespace
         */
        var ObjectStreamRenderer = {
        };

        /**
         * Renders the HTML for the given control, using the provided
         * {@link sap.ui.core.RenderManager}.
         *
         * @param {sap.ui.core.RenderManager} oRm
         *            the RenderManager that can be used for writing to
         *            the Render-Output-Buffer
         * @param {sap.ui.core.Control} oButton
         *            the button to be rendered
         */
        ObjectStreamRenderer.render = function(oRm, oControl) {

            if (!oControl.getVisible()) {
                return;
            }

            oRm.write("<div");
            oRm.writeControlData(oControl);
            oRm.writeAccessibilityState(undefined, {role: "dialog"});
            oRm.writeAccessibilityState(oControl, {label: oControl.getTitle()});
            oRm.addClass("sapOvpObjectStream");
            oRm.writeClasses();
            oRm.write(">");

            /*header*/
            oRm.write("<div");
            oRm.addClass("sapOvpObjectStreamHeader");
            oRm.writeAccessibilityState(undefined, {role: "heading"});
            oRm.writeClasses();
            oRm.write(">" + oControl.getTitle() + "</div>");
            oRm.write('<div tabindex="0" ');
            oRm.addClass("sapOvpObjectStreamClose");
            oRm.writeAccessibilityState(undefined, {role: "button"});
            oRm.writeAccessibilityState(oControl, {label: "close"});
            oRm.writeClasses();
            oRm.write(">");
            oRm.renderControl(oControl._closeIcon);
            oRm.write("</div>");
            /*header*/

            oRm.write('<div id="' + oControl.getId() + '-cont" class="sapOvpObjectStreamCont"');
            oRm.write(">");
            oRm.write('<div id="' + oControl.getId() + '-scroll"');
            oRm.writeAccessibilityState(undefined, {role: "list"});
            oRm.addClass("sapOvpObjectStreamScroll");

            oRm.writeClasses();
            oRm.write(">");


            var aContent = oControl.getContent();

            aContent.forEach(function(control, i) {
                oRm.write("<div class='sapOvpObjectStreamItem' ");
                if (i == 0) {
                    oRm.write("tabindex='0' ");
                } else {
                    oRm.write("tabindex='-1' ");
                }
                oRm.writeAccessibilityState(undefined, {role: "listitem"});
                oRm.write("aria-setsize = " + (aContent.length + 1) + " aria-posinset = " + (i + 1));
                oRm.write(">");
                oRm.renderControl(control);
                oRm.write("</div>");
            });

            var placeHolder = oControl.getPlaceHolder();
            if (placeHolder){
                oRm.write("<div class='sapOvpObjectStreamItem' ");
                if (!aContent.length) {
                    oRm.write("tabindex='0'");
                } else {
                    oRm.write("tabindex='-1'");
                }
                oRm.writeAccessibilityState(undefined, {role: "listitem"});
                oRm.write("aria-setsize = " + (aContent.length + 1) + " aria-posinset = " + (aContent.length + 1));
                oRm.write(">");
                oRm.renderControl(placeHolder);
                oRm.write("</div>");
            }

            oRm.write("</div>"); // scroll

            oRm.write('<div id="' + oControl.getId() + '-leftedge" class="sapOvpOSEdgeLeft">');
            oRm.renderControl(new sap.ui.core.Icon({src: "sap-icon://slim-arrow-left", useIconTooltip:false}));
            oRm.write('</div>');
            oRm.write('<div id="' + oControl.getId() + '-rightedge" class="sapOvpOSEdgeRight">');
            oRm.renderControl(new sap.ui.core.Icon({src: "sap-icon://slim-arrow-right", useIconTooltip:false}));
            oRm.write('</div>');

            oRm.write("</div>"); // cont
            oRm.write("</div>"); // root

        };

        ObjectStreamRenderer.renderFooterContent = function(oRm, oControl) {

            // overrides this function
        };

        return ObjectStreamRenderer;

    }, /* bExport= */ true);

}; // end of sap/ovp/ui/ObjectStreamRenderer.js
if ( !jQuery.sap.isDeclared('sap.ovp.ui.SmartphoneHeaderToggle') ) {
(function () {
    "use strict";
    /*global jQuery, sap */

    jQuery.sap.declare("sap.ovp.ui.SmartphoneHeaderToggle");

    sap.ovp.ui.SmartphoneHeaderToggle = {
        threshold : 10,
        headerVisible : true,
        startY : undefined,
        app : undefined,
        jqView : undefined,

        startHandler : function(e) {
            if (this.app.getGlobalFilter().getVisible()) {
                return;
            }
            this.startY = e.touches[0].pageY;
        },

        resizeHandler : function() {
            if (!this.headerVisible) {
                this.animateHeader.call(this, this.headerVisible);
            }
        },

        animateHeader : function(setVisible) {
            var jqHeaderVbox = this.jqView.find('.ovpApplication > .sapUiFixFlexFixed > .sapMVBox');
            var jqFlexContainerParent = this.jqView.find('.ovpApplication > .sapUiFixFlexFlexible');
            var jqFlexContainer = jqFlexContainerParent.children();
            var translate;

            if (setVisible) {
                translate = "translateY(0px)";
                jqHeaderVbox.add(jqFlexContainerParent).css({"transform": translate, "-webkit-transform": translate});
                jqFlexContainerParent.one('transitionend', function(e) {
                    if (this.headerVisible) {
                        jqFlexContainer.css({bottom: "0px"});
                    }
                }.bind(this));
            } else {
                var headerHeight = this.view.byId('ovpPageHeader').$().height();
                jqFlexContainer.css({bottom: "-" + headerHeight + "px"});
                translate = "translateY(-" + headerHeight + "px)";
                jqFlexContainerParent.add(jqHeaderVbox).css({"transform": translate, "-webkit-transform": translate});
            }
        },

        moveHandler : function(e) {
            var moveY = e.touches[0].pageY;
            if (typeof this.startY == "undefined") {
                if (this.app.getGlobalFilter().getVisible()) {
                    return;
                }
                this.startY = moveY;
            }
            if (Math.abs(this.startY - moveY) < this.threshold) {
                return;
            }
            if (this.startY > moveY && this.headerVisible) {
                this.headerVisible = false;
                this.startY = moveY;
                this.animateHeader.call(this, this.headerVisible);
            }
            if (this.startY < moveY && !this.headerVisible) {
                this.headerVisible = true;
                this.startY = moveY;
                this.animateHeader.call(this, this.headerVisible);
            }
        },

        endHandler : function() {
            this.startY = undefined;
            return;
        },

        enable : function(app) {
            this.app = app;
            this.view = this.app.getView();
            this.jqView = this.view.$();

            this.jqView.on('touchstart.headerHiding', this.startHandler.bind(this));
            this.jqView.on('touchmove.headerHiding', this.moveHandler.bind(this));
            this.jqView.on('touchend.headerHiding touchcancel.headerHiding touchleave.headerHiding', this.endHandler.bind(this));
            jQuery(window).on("resize.headerHiding", this.resizeHandler.bind(this));
        },

        disable : function() {
            this.jqView.off('touchstart.headerHiding touchmove.headerHiding touchend.headerHiding touchcancel.headerHiding touchleave.headerHiding');
            jQuery(window).off("resize.headerHiding");
        }
    };

}());

}; // end of sap/ovp/ui/SmartphoneHeaderToggle.js
if ( !jQuery.sap.isDeclared('sap.ovp.ui.UIActions') ) {
/*global jQuery, sap, clearTimeout, console, window */
(function () {
    "use strict";

    jQuery.sap.declare("sap.ovp.ui.UIActions");

    sap.ovp.ui.UIActions = function(cfg) {

        if (!cfg || !cfg.rootSelector || !cfg.containerSelector || !cfg.draggableSelector) {
            throw new Error("No configuration object to initialize User Interaction module.");
        }

        /* PRIVATE MEMBERS */
        this.captureStart = null;              // {Function} capture start event X and Y position
        this.captureMove = null;               // {Function} capture move event X and Y position
        this.captureEnd = null;                // {Function} capture end event X and Y position
        this.clickCallback = null;             // {Function} Callback function execute after capture `click` event
        this.clickEvent = null;                // {String} `click` event
        this.clickHandler = null;              // {Function} capture click event and prevent the default behaviour on IOS
        this.clone = null;                     // {Element} cloned draggable element
        this.cloneClass = null;                // {String} clone CSS Class
        this.container = null;                 // {Element} content container to be scrolled
        this.contextMenuEvent = null;          // {String} `contextmenu` event for Windows 8 Chrome
        this.debug = false;                    // {Boolean} for debug mode
        this.dragMoveCallback = null;          // {Function} Callback function executes while drag mode is active
        this.dragAndScrollDuration = null;     // {Number} Scroll timer duration in ms
        this.dragAndScrollTimer = null;        // {Number} timer ID. Used in drag & scroll animation
        this.draggable = null;                 // {Array<Element>|NodeList<Element>} list of draggable elements
        this.placeHolderClass = null;          // {String} placeholder CSS Class
        this.draggableSelector = null;         // {String} CSS Selector String which specifies the draggable elements
        this.doubleTapCallback = null;         // {Function} Callback function execute when double tap
        this.doubleTapDelay = null;            // {Number} number of milliseconds to recognize double tap
        this.element = null;                   // {Element} draggable element
        this.swapTargetElement = null;         // {Element} draggable element to swap the current element with
        this.endX = null;                      // {Number} X coordinate of end event
        this.endY = null;                      // {Number} Y coordinate of end event
        this.isTouch = null;                   // {Boolean} does browser supports touch events
        this.lastElement = null;               // {Element} last tapped element
        this.lastTapTime = null;               // {Number} number of milliseconds elapsed since last touchstart or mousedown
        this.lockMode = null;                  // {Boolean} if the value is true, preventing change element mode
        this.log = null;                       // {Function} logs to console in debug mode
        this.mode = null;                      // {String} current feature mode `normal`, `scroll`, `drag`, `move`
        this.mouseDownEvent = null;            // {String} 'mousedown'
        this.mouseMoveEvent = null;            // {String} 'mousemove'
        this.mouseUpEvent = null;              // {String} 'mouseup'
        this.moveTolerance = null;             // {Number} tolerance in pixels between touchStart/mousedwon and touchMove/mousemove
        this.moveX = null;                     // {Number} X coordinate of move event
        this.moveY = null;                     // {Number} Y coordinate of move event
        this.noop = null;                      // {Function} empty function
        this.preventClickFlag;                 // {Boolean} flag indicates if prevent default click behaviour
        this.preventClickTimeoutId;            // {Number}  timer ID. Used to clear click preventing
        this.scrollContainer = null;           // {Element} the element we would like to transition while drag and scroll
        this.scrollContainerSelector = null;   // {String} CSS Selector String which specifies the element we would like to transition while drag and scroll
        this.scrollEvent = null;               // {String} `scroll` event
        this.scrollTimer = null;               // {Number} number of milliseconds elapsed since the last scroll event
        this.startX = null;                    // {Number} X coordinate of start event
        this.startY = null;                    // {Number} Y coordinate of start event
        this.switchModeDelay = null;           // {Number} switch mode delay in ms
        this.tapsNumber = null;                // {Number} the number of taps. could be 0 / 1 / 2
        this.timer = null;                     // {Number} timer ID. Used to decide mode
        this.scrollHandler = null;             // {Function} scroll event handler
        this.touchCancelEvent = null;          // {String} `touchcancel` event
        this.dragStartCallback = null;         // {Function} Callback function execute when drag mode is active
        this.dragEndCallback = null;           // {Function} Callback function execute after capture `touchend` or `mouseup` event and mode is 'drag' or 'drag-and-scroll'
        this.endCallback = null;               // {Function} Callback function execute after capture `touchend` or `mouseup` event
        this.touchEndEvent = null;             // {String} `touchend`
        this.touchMoveEvent = null;            // {String} `touchmove`
        this.beforeDragCallback = null;        // {Function} Callback function execute after capture `touchstart` or `mousedown` event
        this.touchStartEvent = null;           // {String} `touchstart`
        this.wrapper = null;                   // {Element} content container parent
        this.wrapperRect = null;               // {Object} wrapper Bounding Rect
        this.scrollEdge = 100;                 // {Number} edge in pixels top and bottom when scroll is starting

        /**
         * Initialize state using configuration
         *
         * @private
         */
        this.init = function (cfg) {
            this.startX = -1;
            this.startY = -1;
            this.moveX = -1;
            this.moveY = -1;
            this.endX = -1;
            this.endY = -1;

            this.noop = function() {};
            this.isTouch = cfg.isTouch  ? !!cfg.isTouch : false;
            this.container = document.querySelector(cfg.containerSelector);
            this.scrollContainerSelector = cfg.scrollContainerSelector || cfg.containerSelector;
            this.switchModeDelay = cfg.switchModeDelay || 1500;
            this.dragAndScrollDuration = cfg.dragAndScrollDuration || 230;
            this.moveTolerance = cfg.moveTolerance === 0 ? 0 : cfg.moveTolerance || 10;
            this.draggableSelector = cfg.draggableSelector;
            this.mode = 'normal';
            this.debug = cfg.debug || false;
            this.root = document.querySelector(cfg.rootSelector);
            this.tapsNumber = 0;
            this.lastTapTime = 0;
            this.log = this.debug ? this.logToConsole : this.noop;
            this.lockMode = false;
            this.placeHolderClass = cfg.placeHolderClass || "";
            this.cloneClass = cfg.cloneClass || "";
            this.wrapper = cfg.wrapperSelector ? document.querySelector(cfg.wrapperSelector) : this.container.parentNode;
            this.clickCallback = typeof cfg.clickCallback === 'function' ? cfg.clickCallback : this.noop;
            this.beforeDragCallback = typeof cfg.beforeDragCallback === 'function' ? cfg.beforeDragCallback : this.noop;
            this.doubleTapCallback = typeof cfg.doubleTapCallback === 'function' ? cfg.doubleTapCallback : this.noop;
            this.dragEndCallback = typeof cfg.dragEndCallback === 'function' ? cfg.dragEndCallback : this.noop;
            this.endCallback = typeof cfg.endCallback === 'function' ? cfg.endCallback : this.noop;
            this.dragStartCallback = typeof cfg.dragStartCallback === 'function' ? cfg.dragStartCallback : this.noop;
            this.dragMoveCallback = typeof cfg.dragMoveCallback === 'function' ? cfg.dragMoveCallback : this.noop;
            this.doubleTapDelay = cfg.doubleTapDelay || 500;
            this.wrapperRect = this.wrapper.getBoundingClientRect();
            this.scrollEvent = 'scroll';
            this.touchStartEvent = 'touchstart';
            this.touchMoveEvent = 'touchmove';
            this.touchEndEvent = 'touchend';
            this.mouseDownEvent = 'mousedown';
            this.mouseMoveEvent = 'mousemove';
            this.mouseUpEvent = 'mouseup';
            this.contextMenuEvent = 'contextmenu';
            this.touchCancelEvent = 'touchcancel';
            this.clickEvent = 'click';

            if (this.wrapper) {
                jQuery(this.wrapper).css({"position": "absolute",
                "top": 0,
                "left": 0,
                "right": 0,
                "bottom": 0,
                "-webkit-transform": "translateZ(0)",
                "transform": "translateZ(0)"});
            }
        };

        /* PRIVATE METHODS */

        /**
         * Iterates over array-like object and calls callback function
         * for each item
         *
         * @param {Array|NodeList|Arguments} scope - array-like object
         * @param {Function} callback - function to be called for each element in scope
         * @returns {Array|NodeList|Arguments} scope
         */
        this.forEach = function (scope, callback) {
            /*
             * NodeList and Arguments don't have forEach,
             * therefore borrow it from Array.prototype
             */
            return Array.prototype.forEach.call(scope, callback);
        };

        /**
         * Returns index of item in array-like object
         *
         * @param {Array|NodeList|Arguments} scope - array-like object
         * @param {*} item - item which index to be found
         * @returns {Number} index of item in the array-like object
         */
        this.indexOf = function (scope, item) {
            /*
             * NodeList and Arguments don't have indexOf,
             * therefore borrow it from Array.prototype
             */
            return Array.prototype.indexOf.call(scope, item);
        };

        /**
         * Cuts item from array-like object and pastes before reference item
         *
         * @param {Array|NodeList|Arguments} scope
         * @param {*} item
         * @param {*} referenceItem
         */
        this.insertBefore = function (scope, item, referenceItem) {
            var itemIndex,
                referenceItemIndex,
                splice;

            splice = Array.prototype.splice;
            itemIndex = this.indexOf(scope, item);
            referenceItemIndex = this.indexOf(scope, referenceItem);

            splice.call(
                scope,
                referenceItemIndex - (itemIndex < referenceItemIndex ? 1 : 0),
                0,
                splice.call(scope, itemIndex, 1)[0]
            );
        };

        /**
         * Log to console
         *
         * @private
         */
        this.logToConsole = function () {
            window.console.log.apply(console, arguments);
        };


        this.getDraggableElement = function (currentElement) {
            var element;

            this.draggable = jQuery(this.draggableSelector, this.container);
            //Since we are listening on the root element,
            //we would like to identify when a draggable element is being touched.
            //The target element of the event is the lowest element in the DOM hierarchy
            //where the user touched the screen.
            //We need to climb in the DOM tree from the target element until we identify the draggable element,
            //or getting out of container scope.
            while (typeof element === 'undefined' && currentElement !== this.root) {
                //Only draggable tiles
                if (this.indexOf(this.draggable, currentElement) >= 0) {
                    element = currentElement;
                }
                currentElement = currentElement.parentNode;
            }

            return element;
        };

        /**
         * Capture X and Y coordinates of touchstart or mousedown event
         *
         * @param {Event} evt - touchstart or mousedowm event
         * @private
         */
        this.captureStart = function (evt) {
            var eventObj;

            if (evt.type === 'touchstart' && evt.touches.length === 1) {
                eventObj = evt.touches[0];
            } else if (evt.type === 'mousedown') {
                eventObj = evt;
                if (evt.which != 1) {//Only LEFT click operation is enabled. Otherwise do nothing.
                    return;
                }
            }

            if (eventObj) {
                this.element = this.getDraggableElement(eventObj.target);
                this.startX = eventObj.pageX;
                this.startY = eventObj.pageY;
                this.lastMoveX = 0;
                this.lastMoveY = 0;
                //Check if it is a doubletap flow or single tap
                if (this.lastTapTime && this.lastElement && this.element && (this.lastElement === this.element)
                    && Math.abs(Date.now() - this.lastTapTime) < this.doubleTapDelay) {
                    this.lastTapTime = 0;
                    this.tapsNumber = 2;
                } else {
                    this.lastTapTime = Date.now();
                    this.tapsNumber = 1;
                    this.lastElement = this.element;
                }

                this.log('captureStart(' + this.startX + ', ' + this.startY + ')');
            }
        };

        /**
         * Handler for `mousedown` or `touchstart`
         *
         * @private
         */
        this.startHandler = function (evt) {
            this.log('startHandler');
            clearTimeout(this.timer);
            delete this.timer;
            this.captureStart(evt);
            if (this.element) {
                this.beforeDragCallback(evt, this.element);
                if (this.lockMode === false) {
                    if (this.tapsNumber === 2) {
                        this.mode = 'double-tap';
                        return;
                    }
                    if (this.isTouch) {
                        this.timer = setTimeout(function () {
                            this.log('mode switched to drag');
                            this.mode = 'drag';
                            this.createClone();
                            this.dragStartCallback(evt, this.element);
                        }.bind(this), this.switchModeDelay);
                    }
                }
            }
        }.bind(this);

        /**
         * Capture X and Y coordinates of touchmove or mousemove event
         *
         * @param {Event} evt - touchmove or mousemove event
         * @private
         */
        this.captureMove = function (evt) {
            var eventObj;

            if (evt.type === 'touchmove' && evt.touches.length === 1) {
                eventObj = evt.touches[0];
            } else if (evt.type === 'mousemove') {
                eventObj = evt;
            }
            if (eventObj) {
                this.moveX = eventObj.pageX;
                this.moveY = eventObj.pageY;

                this.log('captureMove(' + this.moveX + ', ' + this.moveY + ')');
            }
        };

        /**
         * Handler for `mousemove` or `touchmove`
         *
         * @private
         */
        this.moveHandler = function(evt) {
            var isScrolling;
            this.log('moveHandler');
            this.captureMove(evt);
            switch (this.mode) {
            case 'normal':
                if ((Math.abs(this.startX - this.moveX) > this.moveTolerance || Math.abs(this.startY - this.moveY) > this.moveTolerance)) {
                    if (this.isTouch) {
                        this.log('-> normal');
                        clearTimeout(this.timer);
                        delete this.timer;
                    } else if (this.element) { //In desktop start dragging immediately
                            this.log('mode switched to drag');
                            this.mode = 'drag';
                            this.createClone();
                    }
                }
                break;
            case 'drag':
                evt.preventDefault();
                this.log('-> drag');
                this.mode = 'drag-and-scroll';
                window.addEventListener(this.mouseUpEvent, this.endHandler, true);
                this.translateClone();
                this.scrollContainer = document.querySelector(this.scrollContainerSelector);
                this.dragAndScroll();

                if (!this.isTouch) {
                    this.dragStartCallback(evt, this.element);
                }
                break;
            case 'drag-and-scroll':
                evt.stopPropagation();
                evt.preventDefault();
                this.log('-> drag-and-scroll');
                isScrolling = this.dragAndScroll();
                this.translateClone();
                this.dragMoveCallback({evt : evt, clone : this.clone, element: this.element, draggable: this.draggable, isScrolling: isScrolling, moveX : this.moveX, moveY : this.moveY});
                break;
            default:
                break;
            }
        }.bind(this);

        /**
         * Capture X and Y coordinates of touchend or mouseup event
         *
         * @param {Event} evt - touchmove or mouseup event
         * @private
         */
        this.captureEnd = function (evt) {
            var eventObj;

            if ((evt.type === 'touchend' || evt.type ===  'touchcancel') && (evt.changedTouches.length === 1)) {
                eventObj = evt.changedTouches[0];
            } else if (evt.type === 'mouseup') {
                eventObj = evt;
            }
            if (eventObj) {
                this.endX = eventObj.pageX;
                this.endY = eventObj.pageY;

                this.log('captureEnd(' + this.endX + ', ' + this.endY + ')');
            }
        };

        /**
         * Handler for `contextmenu` event. Disable right click on Chrome
         *
         * @private
         */
        this.contextMenuHandler = function (evt) {
            if (this.isTouch) {
                evt.preventDefault();
            }

        }.bind(this);

        /**
         *
         * @param event
         */
        this.clickHandler = function (event) {

            if (this.preventClickFlag) {
                this.preventClickFlag = false;
                event.preventDefault();
                event.stopPropagation();
                event.stopImmediatePropagation();
                clearTimeout(this.preventClickTimeoutId);
            }
            this.clickCallback();

        }.bind(this);

        /**
         * This function solves a bug which causes the tile to be launched after D&D.
         */
        this.preventClick = function () {
            this.preventClickFlag = true;
            this.preventClickTimeoutId = setTimeout(function () {
                this.preventClickFlag = false;
            }.bind(this), 100);
        };

        /**
         * Handler for `mouseup` or `touchend`
         *
         * @private
         */
        this.endHandler = function (evt) {
            this.log('endHandler');
            this.captureEnd(evt);
            switch (this.mode) {
            case 'normal':
                this.log('-> normal');
                break;
            case 'drag':
                this.log('-> drag');
                this.removeClone();
                this.dragEndCallback(evt, this.element);
                this.preventClick();
                break;
            case 'drag-and-scroll':
                this.log('-> drag-and-scroll');
                window.removeEventListener(this.mouseUpEvent, this.endHandler, true);
                this.removeClone();
                this.dragEndCallback(evt, this.element);
                this.preventClick();
                evt.stopPropagation();
                evt.preventDefault();
                break;
            case 'double-tap':
                this.log('-> double-tap');
                this.doubleTapCallback(evt, this.element);
                break;
            default:
                break;
            }
            if (this.element) {
                this.endCallback(evt, this.element);
            }
            clearTimeout(this.timer);
            delete this.timer;
            this.lastMoveX = 0;
            this.lastMoveY = 0;
            this.swapTargetElement = null;
            this.element = null;
            this.mode = 'normal';
        }.bind(this);

        this.defaultDragStartHandler = function (evt) {
            //prevent the Native Drag behavior of the browser
            evt.preventDefault();
        };

        this.scrollHandler = function() {
            clearTimeout(this.scrollTimer);
            this.lockMode = true;
            //release the scroll lock after 100 ms
            this.scrollTimer = setTimeout(function(){
                this.lockMode = false;
            }.bind(this), 500);
        }.bind(this);

        /**
         * Create clone of draggable element
         *
         * @private
         */
        this.createClone = function () {
            var style,
                rect;

            rect = this.element.getBoundingClientRect();
            this.clone = this.element.cloneNode(true);
            this.clone.className += (' ' + this.cloneClass);
            this.element.className += (' ' + this.placeHolderClass);
            style = this.clone.style;
            style.position = 'absolute';
            style.display = 'block';
            style.top = ( rect.top - this.root.getBoundingClientRect().top ) + 'px';
            style.left = ( rect.left - this.root.getBoundingClientRect().left ) + 'px';
            style.width = rect.width + 'px';
            style.zIndex = '100';
            style.webkitTransition = '-webkit-transform 0ms cubic-bezier(0.33, 0.66, 0.66, 1)';
            style.mozTransition = '-moz-transform 0ms cubic-bezier(0.33, 0.66, 0.66, 1)';
            style.msTransition = '-ms-transform 0ms cubic-bezier(0.33, 0.66, 0.66, 1)';
            style.transition = 'transform 0ms cubic-bezier(0.33, 0.66, 0.66, 1)';
            style.webkitTransform = 'translate3d(0px, 0px, 0px) ';
            style.mozTransform = 'translate3d(0px, 0px, 0px) ';
            style.msTransform = 'translate3d(0px, 0px, 0px) ';
            style.transform = 'translate3d(0px, 0px, 0px) ';
            this.root.appendChild(this.clone);
            this.log('createClone');
        };

        /**
         * Remove clone of draggable element
         *
         * @private
         */
        this.removeClone = function () {
            this.element.className = this.element.className.split(' ' + this.placeHolderClass).join('');
            this.clone.parentElement.removeChild(this.clone);
            // unset reference to DOM element of the clone, otherwise it will remain DOM fragment
            this.clone = null;
            this.log('removeClone');
        };

        /**
         * Translate clone of draggable element
         *
         * @private
         */
        this.translateClone = function () {
            var deltaX,
                deltaY;

            deltaX = this.moveX - this.startX;
            deltaY = this.moveY - this.startY;
            this.clone.style.webkitTransform = 'translate3d(' + deltaX + 'px, ' + deltaY + 'px, 0px)';
            this.clone.style.mozTransform = 'translate3d(' + deltaX + 'px, ' + deltaY + 'px, 0px)';
            //IE9 contains only 2-D transform
            this.clone.style.msTransform = 'translate(' + deltaX + 'px, ' + deltaY + 'px)';
            this.clone.style.transform = 'translate3d(' + deltaX + 'px, ' + deltaY + 'px, 0px)';

            this.log('translateClone (' + deltaX + ', ' + deltaY + ')');
        };

        /**
         * Scroll while dragging if needed
         *
         * @private
         */
        this.dragAndScroll = function () {


            var
            /*
             * Duration of scrolling animation in milliseconds.
             * Greater value makes scroll faster, lower values - smoother
             */
                duration = this.dragAndScrollDuration,
                style,
                that = this;

            function startAnimation(transitionY) {

                style.webkitTransition = '-webkit-transform ' + duration + 'ms linear';
                style.transition = 'transform ' + duration + 'ms linear';
                style.mozTransition = '-moz-transform ' + duration + 'ms linear';
                style.msTransition = '-ms-transform ' + duration + 'ms linear';
                style.webkitTransform = 'translate(0px, ' + transitionY + 'px) scale(1) translateZ(0px)';
                style.mozTransform = 'translate(0px, ' + transitionY + 'px) scale(1) translateZ(0px)';
                style.msTransform = 'translate(0px, ' + transitionY + 'px) scale(1) translateZ(0px)';
                style.transform = 'translate(0px, ' + transitionY + 'px) scale(1) translateZ(0px)';
            }

            function clearAnimation(transitionY) {
                style.webkitTransition = '';
                style.mozTransition = '';
                style.msTransition = '';
                style.transition = '';
                style.webkitTransform = '';
                style.mozTransform = '';
                style.msTransform = '';
                style.transform = '';
                that.wrapper.scrollTop -= transitionY;
            }

            /*
             * Indicates how much pixels of draggable element are overflowing in a vertical axis.
             * When deltaY is negative - content should be scrolled down,
             * when deltaY is positive - content should be scrolled up,
             * when deltaY is zero - content should not be scrolled
             */
            function getDeltaY() {
                var wrapperRect = that.wrapper.getBoundingClientRect();
                //Up
                var topDiff = that.moveY - wrapperRect.top - that.scrollEdge;
                if (topDiff < 0) {
                    return Math.abs(topDiff);
                }

                //Down
                var bottomDiff = wrapperRect.bottom - that.moveY - that.scrollEdge;
                if (bottomDiff < 0) {
                    return bottomDiff;
                }

                return 0;
            }

            function getNextTransitionY(deltaY) {
                var possibleScroll;
                var nextTransitionY = deltaY * 2;
                if (deltaY < 0) {
                    //Down
                    possibleScroll = (that.wrapper.offsetHeight + that.wrapper.scrollTop) - that.wrapper.scrollHeight;
                    return nextTransitionY < possibleScroll ? possibleScroll : nextTransitionY;
                } else if (deltaY > 0) {
                    //Up
                    possibleScroll = that.wrapper.scrollTop;
                    return nextTransitionY < possibleScroll ? nextTransitionY : possibleScroll;
                }
                return 0;
            }

            function start(transitionY) {
                startAnimation(transitionY);
                that.dragAndScrollTimer = setTimeout(function(oldTransitionY) {
                    clearAnimation(oldTransitionY);
                    that.dragAndScrollTimer = undefined;
                    var nextTransitionY = getNextTransitionY(getDeltaY());
                    if (nextTransitionY) {
                        start(nextTransitionY);
                    }
                }.bind(that, transitionY), duration);
            }

            var nextTransitionY = getNextTransitionY(getDeltaY());
            if (nextTransitionY && !this.dragAndScrollTimer) {
                //in IE when reaching the drag and scroll we lose the ref to this.scrollContainer
                this.scrollContainer = this.scrollContainer || document.querySelector(this.scrollContainerSelector);
                style = this.scrollContainer.style;
                start(nextTransitionY);
            }

            this.log('dragAndScroll (' + nextTransitionY + ')');
            
            return !!nextTransitionY;
        };

        /* PUBLIC METHODS */

        /**
         * Enable feature
         *
         * @public
         */
        this.enable = function () {
            this.log('enable');
            //Touch Events
            this.root.addEventListener(this.touchStartEvent, this.startHandler, false);
            this.root.addEventListener(this.touchMoveEvent, this.moveHandler, true);
            this.root.addEventListener(this.touchEndEvent, this.endHandler, false);
            this.root.addEventListener(this.touchCancelEvent, this.endHandler, false);
            //Mouse Events
            this.root.addEventListener(this.mouseMoveEvent, this.moveHandler, true);
            this.root.addEventListener(this.mouseDownEvent, this.startHandler, false);
            this.root.addEventListener(this.mouseUpEvent, this.endHandler, false);
            //Additional Events
            this.root.addEventListener(this.contextMenuEvent, this.contextMenuHandler, false);
            this.root.addEventListener(this.clickEvent, this.clickHandler, true);
            this.wrapper.addEventListener(this.scrollEvent, this.scrollHandler, false);

            return this;
        };

        /**
         * Disable feature
         *
         * @public
         */
        this.disable = function () {
            this.log('disable');
            this.root.removeEventListener(this.touchStartEvent, this.startHandler, false);
            this.root.removeEventListener(this.touchMoveEvent, this.moveHandler, true);
            this.root.removeEventListener(this.touchEndEvent, this.endHandler, false);
            this.root.removeEventListener(this.mouseDownEvent, this.startHandler, false);
            this.root.removeEventListener(this.mouseMoveEvent, this.moveHandler, true);
            this.root.removeEventListener(this.mouseUpEvent, this.endHandler, false);
            this.root.removeEventListener(this.contextMenuEvent, this.contextMenuHandler, false);
            this.root.removeEventListener(this.clickEvent, this.clickHandler, true);
            this.root.removeEventListener(this.touchCancelEvent, this.endHandler, false);
            this.wrapper.removeEventListener(this.scrollEvent, this.scrollHandler, false);

            return this;
        };

        /*
         * Initialize dynamic feature state
         * and behaviour using configuration
         */
        this.init(cfg);

        /**
         * @public
         * @returns {{x: moveX, y: moveY}}
         */
        this.getMove = function () {
            return {x: this.moveX, y: this.moveY};
        };
    };
})();

}; // end of sap/ovp/ui/UIActions.js
if ( !jQuery.sap.isDeclared('sap.ovp.app.Main.controller') ) {
  jQuery.sap.declare('sap.ovp.app.Main.controller');
(function () {
    "use strict";
    /*global sap, jQuery */

    jQuery.sap.require('sap.ui.model.odata.ODataUtils'); // unlisted dependency retained

    
    jQuery.sap.require('sap.ui.generic.app.navigation.service.NavigationHandler'); // unlisted dependency retained


    sap.ui.controller("sap.ovp.app.Main", {

        onInit: function () {
            this.oCardsModels = {};
            this.oLoadedComponents = {};
            jQuery.sap.measure.start("ovp:GlobalFilter", "Main Controller init -> Global Filter loaded", "ovp");
            jQuery.sap.measure.start("ovp:Personalization", "Main Controller init -> Personalization loaded", "ovp");
            this.isInitialLoading = true;
            this._initSmartVariantManagement();
            this.getLayout().addStyleClass("ovpLayoutElement");
            /* Appstate*/
			this.oState = {};
			this.oState.oSmartFilterbar = this.byId("ovpGlobalFilter");
			/* Appstate */
            this._initGlobalFilter();
        },

        //clarify with UI5 Core: why can view models not be accessed in onInit?
        onBeforeRendering: function () {
        },

        onAfterRendering: function() {
            //make sure we will not initialize more then ones
            if (this.initialized){
                return;
            }
            this.initialized = true;

            this.oPersistencyVariantPromise.then(function(oVariant) {
                jQuery.sap.measure.end("ovp:Personalization");
                this.persistencyVariantLoaded = true;
                var oCard;
                this.aManifestOrderedCards = this._getCardArrayAsVariantFormat(this.getLayout().getContent());
                this.aOrderedCards = this._mergeCards(this.aManifestOrderedCards, oVariant);
                this._updateLayoutWithOrderedCards();
                if (this.isDragAndDropEnabled()) {
                    this._initShowHideCardsButton();
                }

                jQuery.sap.measure.start("ovp:CreateLoadingCards", "Create Loading cards", "ovp");
                //First create the loading card
                for (var i = 0; i < this.aOrderedCards.length; i++) {
                    if (this.aOrderedCards[i].visibility) {
                        oCard = this._getCardFromManifest(this.aOrderedCards[i].id);
                        if (oCard) {
                            this.createLoadingCard(oCard);
                        }
                    }
                }
                jQuery.sap.measure.end("ovp:CreateLoadingCards");

                //In order to add the below css class after second layout rendering which caused by this._updateLayoutWithOrderedCards()
                setTimeout(function () {
                    this.getLayout().addStyleClass("ovpLayoutElementShow");
                }.bind(this), 0);

                //Second load each card component and create the card
                //We would like to wait for the loading cards invocation
                setTimeout(function () {
                    jQuery.sap.measure.start("ovp:CreateCards", "Create cards loop", "ovp");
                    for (var i = 0; i < this.aOrderedCards.length; i++) {
                        if (this.aOrderedCards[i].visibility) {
                            oCard = this._getCardFromManifest(this.aOrderedCards[i].id);
                            if (oCard) {
                                oCard.settings.baseUrl = this._getBaseUrl();
                                this._initCardModel(oCard.model);
                                this._loadCardComponent(oCard.template);
                                this.createCard(oCard);
                            }
                        }
                    }
                    jQuery.sap.measure.end("ovp:CreateCards");
                }.bind(this), 10);

                if (this.busyDialog) {
                    this.busyDialog.close();
                }
            }.bind(this), function(err) {
                jQuery.sap.log.error("Could not load information from LREP Persistency");
                jQuery.sap.log.error(err);
            });
            if (sap.ui.Device.system.phone) {
                jQuery.sap.require("sap.ovp.ui.SmartphoneHeaderToggle");
                sap.ovp.ui.SmartphoneHeaderToggle.enable(this);
            }

            setTimeout(function () {
                if (!this.persistencyVariantLoaded) {
                    this.busyDialog = new sap.m.BusyDialog({text: this._getLibraryResourceBundle().getText("loading_dialog_text")});
                    this.busyDialog.open();
                    this.busyDialog.addStyleClass('sapOVPBusyDialog');
                }
            }.bind(this), 500);
        },

        _getLibraryResourceBundle : function () {
            if (!this.oLibraryResourceBundle) {
                this.oLibraryResourceBundle = sap.ui.getCore().getLibraryResourceBundle("sap.ovp");
            }
            return this.oLibraryResourceBundle;
        },

        _getCardsModel : function() {
            var oUIModel = this.getView().getModel("ui");
            if (!this.oCards) {
                this.oCards = oUIModel.getProperty("/cards");
            }
            return this.oCards;
        },

        _getBaseUrl : function() {
            var oUIModel = this.getView().getModel("ui");
            if (!this.sBaseUrl) {
                this.sBaseUrl = oUIModel.getProperty("/baseUrl");
            }
            return this.sBaseUrl;
        },

        _getCardFromManifest : function (sCardId) {
            var aCards = this._getCardsModel();
            for (var i = 0; i < aCards.length; i++) {
                if (aCards[i].id === sCardId) {
                    return aCards[i];
                }
            }

            return null;
        },

        _getCardArrayAsVariantFormat: function(aComponentContainerArray) {
            var aCards = [];

            for (var i = 0; i < aComponentContainerArray.length; i++) {
                aCards.push({id: this._getCardId(aComponentContainerArray[i].getId()) , visibility: aComponentContainerArray[i].getVisible()});
            }
            return aCards;
        },

        _mergeCards: function (aLayoutCardsArray, oVariant) {
            var variantCardsArray = (oVariant && oVariant.cards) ? oVariant.cards : [];
            var oResult = [];
            var sCardId;
            var bCardVisibility;
            var aLayoutCardsArr = (aLayoutCardsArray && aLayoutCardsArray.length) ? aLayoutCardsArray : [];

            //First, we insert into the oResult the cards from the variant which exist in the oLayoutCard:
            for (var i = 0; i < variantCardsArray.length; i++) {
                bCardVisibility = variantCardsArray[i].visibility;
                for (var j = 0; j < aLayoutCardsArr.length; j++) {
                    sCardId = aLayoutCardsArr[j].id;
                    if (variantCardsArray[i].id === sCardId) {
                        oResult.push({id: sCardId, visibility: bCardVisibility});
                        break;
                    }
                }
            }

            //Second, we add additional cards from the current layout (fragment + manifest) into the end of the oResult
            for (var j = 0; j < aLayoutCardsArr.length; j++) {
                var isFound = false;
                sCardId = aLayoutCardsArr[j].id;
                bCardVisibility = aLayoutCardsArr[j].visibility;
                for (var i = 0; !isFound && i < oResult.length; i++) {
                    if (oResult[i].id === sCardId) {
                        isFound = true;
                    }
                }

                if (!isFound) {
                    oResult.push({id: sCardId, visibility: bCardVisibility});
                }
            }

            return oResult;
        },

        _updateLayoutWithOrderedCards: function() {
            var oLayout = this.getLayout();
            var aOrderedCards = this.aOrderedCards;
            oLayout.removeAllContent();
            for (var i = 0; i < aOrderedCards.length; i++) {
                var oComponentContainer = this.getView().byId(aOrderedCards[i].id);
                oComponentContainer.setVisible(aOrderedCards[i].visibility);
                oLayout.addContent(oComponentContainer);
            }
        },

        verifyGlobalFilterLoaded: function(){
            if (this.getGlobalFilter().search()) {
                return true;
            }
            //else make sure filter is open so user will see the required field
            return false;
        },

        /**
         * Register to the filterChange event of the filter bar in order to mark that
         * one or more of the filters were changed
         */
        onGlobalFilterChange: function(){
            this.filterChanged = true;
        },

        /**
         * Register to the search event of the filter bar in order to refresh all models
         * with the changes in the filter bar (if there are changes) when "go" is clicked
         */
        onGlobalFilterSearch: function(){
            if (this.filterChanged){
                var sBatchGroupId = "ovp-" + new Date().getTime();
                for (var modelKey in this.oCardsModels){
                    if (this.oCardsModels.hasOwnProperty(modelKey)){
                        this.oCardsModels[modelKey].refresh(false, false, sBatchGroupId);
                    }
                }
                this.filterChanged = false;
            }
        },

        _initGlobalFilter: function(){
            var oGlobalFilter = this.getGlobalFilter();
            if (!oGlobalFilter){
                jQuery.sap.measure.end("ovp:GlobalFilter");
                return;
            }

            this.oGlobalFilterLodedPromise = new Promise(function (resolve, reject){
                oGlobalFilter.attachAfterVariantLoad(function(){
                    this.oParseNavigationPromise.done(function (oAppData, oURLParameters, sNavType) {
                        this._setNavigationVariantToGlobalFilter(oAppData, oURLParameters, sNavType);
                    }.bind(this));
                    this.oParseNavigationPromise.fail(function () {
                        jQuery.sap.log.error("Could not parse navigation variant from URL");
                    });
                    this.oParseNavigationPromise.always(function () {
                        if (this.verifyGlobalFilterLoaded()){
                            resolve();
                        }
                    }.bind(this));
                }, this);

                oGlobalFilter.attachInitialise(function(){
                    //Parse navigation variant from the URL (if exists)
                    this._parseNavigationVariant();
                    // in case no variant is selected by user then the attachAfterVariantLoad
                    //event is not fired, therefore we check if there is no variant we
                    //call the verification here
                    if (!oGlobalFilter.getCurrentVariantId()) {
                        if (this.verifyGlobalFilterLoaded()){
                            resolve();
                        }
                    }
                }, this);
                oGlobalFilter.attachSearch(function(){
                    //If user pressed GO, it means that the required field varification
                    //was allredy done by the globalFilter, therefore we can resolve the promise.
                    //This is needed in case some required field was empty and therefore the promise
                    //object was not resolved in the initial flow, we have to do it now after user
                    //set the filter
                    resolve();

                    this.onGlobalFilterSearch();
                }, this);
                oGlobalFilter.attachFilterChange(this.onGlobalFilterChange, this);
            }.bind(this));

            this.oGlobalFilterLodedPromise.then(function(oVariant) {
                jQuery.sap.measure.end("ovp:GlobalFilter");
            });
        },

        _loadCardComponent: function(sComponentName){
            if (!this.oLoadedComponents[sComponentName]) {
                jQuery.sap.measure.start("ovp:CardComponentLoad:" + sComponentName, "Card Component load", "ovp");
                this.oLoadedComponents[sComponentName] = sap.ui.component.load({
                    name: sComponentName,
                    url: jQuery.sap.getModulePath(sComponentName),
                    async: true
                });
                this.oLoadedComponents[sComponentName].then(function(){
                    jQuery.sap.measure.end("ovp:CardComponentLoad:" + sComponentName);
                });
            }
        },

        _initCardModel: function(sCardModel){
            if (this.oCardsModels[sCardModel]){
                return;
            }
            this.oCardsModels[sCardModel] = this.getView().getModel(sCardModel);
            this.oCardsModels[sCardModel].setUseBatch(true);
            if (this.getGlobalFilter()){
                this._overrideCardModelRead(this.oCardsModels[sCardModel]);
            }
        },



        toggleFilterBar: function toggleFilterBar() {
            var oGlobalFilter = this.getGlobalFilter();
            function toOpenState(jqGlobalFilter, jqGlobalFilterWrapper, height) {
                jqGlobalFilterWrapper.height(height);
                jqGlobalFilter.css('top', 0);
            }
            function toCloseState(jqGlobalFilter, jqGlobalFilterWrapper, height) {
                jqGlobalFilterWrapper.height(0);
                jqGlobalFilter.css("top", "-" + height + "px");
            }

            var isVisible = oGlobalFilter.getVisible();

            if ((sap.ui.Device.system.phone) || (sap.ui.Device.system.tablet)) {
                oGlobalFilter.setVisible(!isVisible);
                return;
            }
            if (toggleFilterBar.animationInProcess) {
                return;
            }
            toggleFilterBar.animationInProcess = true;

            if (isVisible) {
                var jqGlobalFilter = jQuery(oGlobalFilter.getDomRef());
                var jqGlobalFilterWrapper = jQuery(this.getView().byId("ovpGlobalFilterWrapper").getDomRef());
                var height = jqGlobalFilterWrapper.height();
                toOpenState(jqGlobalFilter, jqGlobalFilterWrapper, height);
                jqGlobalFilterWrapper.height(); //make browser render css change
                jqGlobalFilterWrapper.one('transitionend', function(e) {
                    oGlobalFilter.setVisible(false); //set filterbar invisible in case shell wants to reRender it
                    toggleFilterBar.animationInProcess = false;
                });
                toCloseState(jqGlobalFilter, jqGlobalFilterWrapper, height);
            } else {
                oGlobalFilter.setVisible(true);
                setTimeout(function () { //we need this to wait for globalFilter renderer
                    var jqGlobalFilter = jQuery(oGlobalFilter.getDomRef());
                    var jqGlobalFilterWrapper = jQuery(this.getView().byId("ovpGlobalFilterWrapper").getDomRef());
                    var height = jqGlobalFilter.outerHeight();
                    toCloseState(jqGlobalFilter, jqGlobalFilterWrapper, height);
                    jqGlobalFilterWrapper.height(); //make browser render css change
                    jqGlobalFilterWrapper.one('transitionend', function(e) {
                        jqGlobalFilterWrapper.css("height", "auto");
                        toggleFilterBar.animationInProcess = false;
                    });
                    toOpenState(jqGlobalFilter, jqGlobalFilterWrapper, height);
                }.bind(this));
            }
        },

        /**
         * This function is overriding the read function of the oDataModel with a function that will
         * first find the relevant filters from the filter bar and then will call the original
         * read function with the relevant filters as parameters.
         * @param oModel
         * @private
         */
        _overrideCardModelRead: function(oModel){
            var fOrigRead = oModel.read;
            var that = this;
            oModel.read = function(){
                var aFilters = that.getGlobalFilter().getFilters();
                var oParameters = arguments[1];
                if (!oParameters) {
                    oParameters = {};
                    Array.prototype.push.call(arguments, oParameters);
                }
                var oEntityType = that._getEntityTypeFromPath(oModel, arguments[0], oParameters.context);
                if (oEntityType){
                    var aRelevantFIlters = that._getEntityRelevantFilters(oEntityType, aFilters);
                    if (aRelevantFIlters.length > 0){
                        var foundIndex = -1;
                        var aUrlParams = oParameters.urlParameters;
                        if (aUrlParams){
                            for (var index = 0; index < aUrlParams.length; index++){
                                // We use here lastIndexOf instead of startsWith because it doesn't work on safari (ios devices)
                                if ((aUrlParams[index]).lastIndexOf("$filter=", 0) === 0){
                                    foundIndex = index;
                                    break;
                                }
                            }
                        }
                        if (foundIndex >= 0) {
                            aUrlParams[foundIndex] =
                                aUrlParams[foundIndex] + "%20and%20" +
                                sap.ui.model.odata.ODataUtils.createFilterParams(aRelevantFIlters, oModel.oMetadata, oEntityType).substr(8);
                        } else {
                            oParameters.filters = aRelevantFIlters;
                        }

                    }
                }

                fOrigRead.apply(oModel, arguments);
            };
        },

        /**
         * This is a temporary function used to retrieve the EntityType from a given path to an entity.
         * This function is required due to fact that the function _getEntityTypeByPath of the ODataMetadata is not public.
         * @param oModel
         * @param sPath
         * @param oContext
         * @returns {object}
         * @private
         */
        _getEntityTypeFromPath: function(oModel, sPath, oContext){
            //TODO need to request UI5 to have this a public API!!!!
            var sNormPath = sap.ui.model.odata.v2.ODataModel.prototype._normalizePath.apply(oModel, [sPath, oContext]);
            var oEntityType = sap.ui.model.odata.ODataMetadata.prototype._getEntityTypeByPath.apply(oModel.oMetadata, [sNormPath]);
            return oEntityType;
        },

        /**
         * This function goes over the provided list of filters and checks which filter appears as a field
         * in the EntityType provided. The fields that appears in both lists  (filters and EntityType fields)
         * will be returned in an array.
         * @param oEntityType
         * @param aFilters
         * @returns {array}
         * @private
         */
        _getEntityRelevantFilters: function(oEntityType, aFilters){
            var aRelevantFiltes = [];
            if (aFilters.length) {
                var allFilters = aFilters[0].aFilters;
                var entityProperties = oEntityType.property;
                for (var i = 0; i < allFilters.length; i++) {
                    var currentFilterName;
                    if (allFilters[i].aFilters) {
                        currentFilterName = allFilters[i].aFilters[0].sPath;
                    } else {
                        currentFilterName = allFilters[i].sPath;
                    }
                    for (var j = 0; j < entityProperties.length; j++) {
                        if (entityProperties[j].name ===  currentFilterName) {
                            aRelevantFiltes.push(allFilters[i]);
                            break;
                        }
                    }
                }
            }
            // Retaining the default OR/AND operation
            if (aRelevantFiltes.length != 0) {
                var aRelevantFilWrap = [];
                aRelevantFilWrap.push(new sap.ui.model.Filter(aRelevantFiltes, aFilters[0].bAnd));
                return aRelevantFilWrap;
            }

            return aRelevantFiltes;
        },

        /*
         Check derived Card Component is implemented with respect to the below restrictions:

         Custom card must be instance of sap.ovp.cards.generic.Component. In other words, custom card must extend sap.ovp.cards.generic.Component.
         If sap.ovp.cards.generic.Card view is replaced by another custom View it means the custom card is not valid.
         [If the extended Component has customization (under the component metadata) and the sap.ovp.cards.generic.Card is replaced by another view (using sap.ui.viewReplacements)]
         If the extended Component overrides the createContent function of the base sap.ovp.cards.generic.Component class, the custom card is not valid.
         If the extended Component overrides the getPreprocessors function of the base sap.ovp.cards.generic.Component class, the custom card is not valid.

         */
        _checkIsCardValid: function (sCardTemplate) {
            var sComponentClassName = sCardTemplate + ".Component";
            var oComponentMetadata, oCustomizations;

            jQuery.sap.require(sComponentClassName);

            var oComponentClass = jQuery.sap.getObject(sComponentClassName);

            if (!oComponentClass) {
                return false;
            }

            if ((oComponentClass !== sap.ovp.cards.generic.Component) && !(oComponentClass.prototype instanceof sap.ovp.cards.generic.Component)) {
                return false;
            }

            if ((oComponentMetadata = oComponentClass.getMetadata()) && (oCustomizations = oComponentMetadata.getCustomizing())) {
                //if OVP Card view was replaced
                if (oCustomizations["sap.ui.viewReplacements"] && oCustomizations["sap.ui.viewReplacements"]["sap.ovp.cards.generic.Card"]) {
                    return false;
                }
            }

            if (oComponentClass.prototype.createContent != sap.ovp.cards.generic.Component.prototype.createContent) {
                return false;
            }

            if (oComponentClass.prototype.getPreprocessors != sap.ovp.cards.generic.Component.prototype.getPreprocessors) {
                return false;
            }

            return true;
        },

        _createCardComponent: function (oView, oModel, card) {
            var sId = "ovp:CreateCard-" + card.template + ":" + card.id;
            jQuery.sap.measure.start(sId, "Create Card", "ovp");
            var oi18nModel = this.getView().getModel("@i18n");
            if (card.template && this._checkIsCardValid(card.template)) {
                var oComponentConfig = {
                    name: card.template,
                    componentData: {
                        model: oModel,
                        i18n: oi18nModel,
                        settings: card.settings,
                        appComponent: this.getOwnerComponent()
                    }
                };
                var oGlobalFilter = this.getGlobalFilter();

                if (oGlobalFilter) {
                    oComponentConfig.componentData.globalFilter = {
                        getFilterDataAsString : oGlobalFilter.getDataSuiteFormat.bind(oGlobalFilter)
                    };
                }
                var oComponent = sap.ui.component(oComponentConfig);
                var oComponentContainer = oView.byId(card.id);

                var oOldCard = oComponentContainer.getComponentInstance();
                oComponentContainer.setComponent(oComponent);
                if (oOldCard){
                    //currently the old component is not destroyed when setting a different component
                    //so we need to do that in timeout to make sure that it will not be destoroyed
                    //too early, before real card will be rendered on the screen.
                    setTimeout(function(){
                        oOldCard.destroy();
                    }, 0);
                }
            } else {
                // TODO: define the proper behavior indicating a card loading failure
                jQuery.sap.log.error("Could not create Card from '" + card.template + "' template. Card is not valid.");
            }
            jQuery.sap.measure.end(sId);
        },

        createLoadingCard: function(card, opacityDelay){
            /*
             * we have to make sure metadata and filter are loaded before we create the card
             * so we first create loading card and once all promises will be resulved
             * we will create the real card and replace the loading card
             */
            var loadingCard = jQuery.extend(true, {}, card, {template: "sap.ovp.cards.loading", settings: {opacityDelay: opacityDelay}});
            this._createCardComponent(this.getView(), undefined, loadingCard);
        },

        createCard: function(card){
            var oView = this.getView();
            var oModel = oView.getModel(card.model);

            ///*
            // * we have to make sure metadata and filter are loaded before we create the card
            // * so we first create loading card and once all promises will be resulved
            // * we will create the real card and replace the loading card
            // */

            Promise.all([
                    oModel.getMetaModel().loaded(),
                    this.oGlobalFilterLodedPromise,
                    this.oLoadedComponents[card.template]]
            ).then(
                function() {
                    this._createCardComponent(oView, oModel, card);
                }.bind(this),
                function(reason) {
                    jQuery.sap.log.error("Can't load card with id:'" + card.id + "' and type:'" + card.template + "', reason:" + reason);
                }
            );
        },

        /**
         * The function gets an UI5 generated id and returns the element original Id
         *
         * @param {string} generatedId - the UI5 generated id
         * @param {string} elementId - the element original  id
         */
        _getCardId: function(generatedId) {
            var appIdString = this.getView().getId() + "--";
            if (generatedId.indexOf(appIdString) != -1) {
                var start = generatedId.indexOf(appIdString) + appIdString.length;
                return generatedId.substr(start);
            }
            return generatedId;
        },

        _initSmartVariantManagement: function () {
            var oPersistencyControl = this._createPersistencyControlForSmartVariantManagement();
            var oOVPVariantInfo = new sap.ui.comp.smartvariants.PersonalizableInfo({
                type: "OVPVariant",
                keyName: "persistencyKey",
                control: oPersistencyControl
            });

            this.oPersistencyVariantPromise = new Promise(function(resolve, reject) {
                this.smartVariandManagement = new sap.ui.comp.smartvariants.SmartVariantManagement({
                    personalizableControls: oOVPVariantInfo,
                    initialise: function(oEvent) {
                        var aKeys = oEvent.getParameters().variantKeys;
                        if (aKeys.length) { //the user has already a variant
                            resolve(this.smartVariandManagement.getVariantContent(oPersistencyControl, aKeys[0]));
                        } else { //the user do not have have any variant
                            resolve(null);
                        }
                    }.bind(this)
                });
                this.smartVariandManagement.initialise();
            }.bind(this));

        },

        layoutChanged: function() {
            var aContent = this.getLayout().getContent();
            this.aOrderedCards = this._getCardArrayAsVariantFormat(aContent);
            this.saveVariant();
        },

        saveVariant: function(oEvent) {
            var that = this;
            this.smartVariandManagement.getVariantsInfo(function(aVariants) {
                var oPersonalisationVariantKey = null;
                if (aVariants && aVariants.length > 0) {
                    oPersonalisationVariantKey = aVariants[0].key;
                }
                var bOverwrite = oPersonalisationVariantKey !== null;

                var oParams = {
                    name: "Personalisation",
                    global: false,
                    overwrite: bOverwrite,
                    key: oPersonalisationVariantKey,
                    def: true
                };
                that.smartVariandManagement.fireSave(oParams);
            });

        },

        getLayout: function() {
            return this.getView().byId("ovpLayout");
        },

        _createPersistencyControlForSmartVariantManagement: function() {
            var that = this;
            sap.ui.core.Control.extend("sap.ovp.app.PersistencyControl", {
                metadata: {
                    properties: {
                        persistencyKey : {type : "string", group : "Misc", defaultValue : null}
                    }
                }
            });
            var oPersistencyControl = new sap.ovp.app.PersistencyControl({persistencyKey:"ovpVariant"});

            /**
             * Interface function for SmartVariantManagment control, returns the current used variant data
             *
             * @public
             * @returns {json} The currently set variant
             */
            oPersistencyControl.fetchVariant = function () {
                //in the initial loading the variant is not saved
                if (that.isInitialLoading) {
                    that.isInitialLoading = false;
                    return {};
                }
                var oLayout = this.getLayout();
                if (!oLayout) {
                    jQuery.sap.log.error("Could not save persistency variant - 'ovpLayout' does not exists");
                    return;
                }
                var aLayoutContent = oLayout.getContent();
                var aContentForSave = this._getCardArrayAsVariantFormat(aLayoutContent);
                this.oOrderedCards = aContentForSave;
                return {cards: aContentForSave};
            }.bind(this);

            return oPersistencyControl;

        },

        _initShowHideCardsButton: function() {
            var srvc, oCardMenuButton;

            var srvc = sap.ushell.services.AppConfiguration;
            var oCardMenuButton = new sap.m.Button().addStyleClass("ovpManageCardsBtn");
            oCardMenuButton.setIcon('sap-icon://dimension');
            oCardMenuButton.setTooltip(this._getLibraryResourceBundle().getText("hideCardsBtn_tooltip"));
            oCardMenuButton.setText(this._getLibraryResourceBundle().getText("hideCardsBtn_title"));
            oCardMenuButton.attachPress((this._onCardMenuButtonPress).bind(this));
            srvc.addApplicationSettingsButtons([oCardMenuButton]);
        },

        _onCardMenuButtonPress : function() {
            var oModel;

            function getCardIndexInArray(aCardsArr, cardId) {
                for (var i = 0; i < aCardsArr.length; i++) {
                    if (aCardsArr[i].id == cardId) {
                        return i;
                    }
                }
                return -1;
            }

            function createOrDestroyCards(aOldContent, aNewContent) {
                var oldIndex = -1;
                for (var i = 0; i < aNewContent.length ; i++) {
                    //In case the card position has been changed, we need to get the card index in the old array.
                    //Otherwise, the new and the old position are the same
                    if (aOldContent[i].id == aNewContent[i].id) {
                        oldIndex = i;
                    } else {
                        oldIndex = getCardIndexInArray(aOldContent, aNewContent[i].id);
                    }

                    if (aNewContent[i].visibility != aOldContent[oldIndex].visibility) {
                        if (aNewContent[i].visibility === true) {
                            var oCard = this._getCardFromManifest(aNewContent[i].id);
                            if (oCard) {
                                this.createLoadingCard(oCard);
                                oCard.settings.baseUrl = this._getBaseUrl();
                                this._initCardModel(oCard.model);
                                this._loadCardComponent(oCard.template);
                                this.createCard(oCard);
                            }
                        } else {
                            var oOldComponentContainer = this.getView().byId(aNewContent[i].id);
                            var oOldCard = oOldComponentContainer.getComponentInstance();
                            if (oOldCard) {
                                oOldCard.destroy();
                            }
                        }
                    }
                }
            }

            function cardTitleFormatter(id) {
                var oCard = this._getCardFromManifest(id);
                var cardSettings = oCard.settings;
                if (cardSettings.title) {
                    return cardSettings.title;
                } else if (cardSettings.category) {
                    return (cardSettings.category);
                } else if (cardSettings.description) {
                    return cardSettings.description;
                }
                return id;
            }

            var oCardsTableTemplate = new sap.m.ColumnListItem({
                cells: [
                    new sap.m.Text({text: {path: "id", formatter: cardTitleFormatter.bind(this) }}),
                    new sap.m.Switch({
                        state: "{visibility}",
                        customTextOff: " ",
                        customTextOn: " ",
                        change: function (event) {
                            var parent = event.oSource.getParent();
                            parent.toggleStyleClass('sapOVPHideCardsTableItem');
                            parent.getCells()[0].toggleStyleClass('sapOVPHideCardsDisabledCell');
                        },
                        tooltip: this._getLibraryResourceBundle().getText("hideCards_switchTooltip")
                    })
                ]
            });

            var oCardsTable = new sap.m.Table("sapOVPHideCardsTable", {
                backgroundDesign: sap.m.BackgroundDesign.Transparent,
                showSeparators: sap.m.ListSeparators.Inner,
                columns: [
                    new sap.m.Column({
                        vAlign: "Middle"
                    }),
                    new sap.m.Column({
                        hAlign: sap.ui.core.TextAlign.Right,
                        vAlign: "Middle",
                        width: "4.94rem"
                    })
                ]
            });
            oCardsTable.addStyleClass('sapOVPHideCardsTable');
            oCardsTable.bindItems({
                path: "/cards",
                template: oCardsTableTemplate
            });


            var oOrigOnAfterRendering = oCardsTable.onAfterRendering;
            oCardsTable.onAfterRendering = function (event) {
                oOrigOnAfterRendering.apply(oCardsTable, arguments);

                var items = event.srcControl.mAggregations.items;
                if (items) {
                    for (var i = 0; i < items.length; i++) {
                        if (!items[i].getCells()[1].getState()) {
                            items[i].addStyleClass('sapOVPHideCardsTableItem');
                            items[i].getCells()[0].addStyleClass('sapOVPHideCardsDisabledCell');
                        }
                    }
                }
                setTimeout(function () {
                    jQuery('.sapMListTblRow').first().focus();
                }, 200);
            };

            var oSaveButton = new sap.m.Button("manageCardsokBtn", {
                text: this._getLibraryResourceBundle().getText("okBtn"),
                press: function () {
                    var aDialogCards = this.oDialog.getModel().getProperty('/cards');
                    createOrDestroyCards.apply(this, [this.aOrderedCards, aDialogCards]);
                    this.aOrderedCards = aDialogCards;
                    this._updateLayoutWithOrderedCards();
                    this.saveVariant();
                    this.oDialog.close();
                }.bind(this)
            });

            var oCancelButton = new sap.m.Button("manageCardsCancelBtn", {
                text: this._getLibraryResourceBundle().getText("cancelBtn"),
                press: function () {
                    this.oDialog.close();
                }.bind(this)
            });

            var oResetButton = new sap.m.Button("manageCardsResetBtn", {
                text: this._getLibraryResourceBundle().getText("resetBtn"),
                press: function () {
                    sap.m.MessageBox.show(this._getLibraryResourceBundle().getText("reset_cards_confirmation_msg"), {
                        id: "resetCardsConfirmation",
                        icon: sap.m.MessageBox.Icon.QUESTION,
                        title: this._getLibraryResourceBundle().getText("reset_cards_confirmation_title"),
                        actions: [sap.m.MessageBox.Action.OK, sap.m.MessageBox.Action.CANCEL],
                        onClose : function (oAction) {
                            if (oAction === sap.m.MessageBox.Action.OK) {
                                this.smartVariandManagement.getVariantsInfo(function(aVariants) {
                                    var oPersonalisationVariantKeys = null;
                                    if (aVariants && aVariants.length > 0) {
                                        oPersonalisationVariantKeys = aVariants[0].key;
                                        this.smartVariandManagement.fireManage({
                                            deleted: [oPersonalisationVariantKeys]
                                        });
                                    }
                                    createOrDestroyCards.apply(this,[this.aOrderedCards,this.aManifestOrderedCards]);
                                    this.aOrderedCards = this.aManifestOrderedCards;
                                    this._updateLayoutWithOrderedCards();
                                    this.oDialog.close();
                                }.bind(this));
                            }
                        }.bind(this)
                    });
                }.bind(this)
            });

            this.oDialog = new sap.m.Dialog({
                title: this._getLibraryResourceBundle().getText("hideCardsBtn_title"),
                contentWidth : "29.6rem",
                contentHeight : "50%",
                stretch: sap.ui.Device.system.phone,
                content : oCardsTable,
                buttons: [oResetButton, oSaveButton,oCancelButton],
                afterClose: function () {
                    this.oDialog.destroy();
                }.bind(this)
            }).addStyleClass("sapOVPCardsVisibilityDialog");

            var oDialogCardsModel = jQuery.extend(true, [], this.aOrderedCards);
            oModel = new sap.ui.model.json.JSONModel({cards : oDialogCardsModel});
            this.oDialog.setModel(oModel);

            this.oDialog.open();
        },

        isDragAndDropEnabled : function () {
            return !sap.ui.Device.system.phone;
        },

        getGlobalFilter : function () {
            if (!this.oGlobalFilter) {
                this.oGlobalFilter = this.getView().byId("ovpGlobalFilter");
            }
            return this.oGlobalFilter;
        },

        _parseNavigationVariant : function () {
            var oGlobalFilter = this.getGlobalFilter();
            if (oGlobalFilter) {
                this.oNavigationHandler = this.oNavigationHandler || new sap.ui.generic.app.navigation.service.NavigationHandler(this);
                this.oParseNavigationPromise = this.oNavigationHandler.parseNavigation();
                jQuery.sap.require("sap.ovp.cards.CommonUtils");
                sap.ovp.cards.CommonUtils.enable(this,this.oNavigationHandler);
            } else {
                // still initialize the global nav handler
                jQuery.sap.require("sap.ovp.cards.CommonUtils");
                this.oNavigationHandler = this.oNavigationHandler || new sap.ui.generic.app.navigation.service.NavigationHandler(this);
                sap.ovp.cards.CommonUtils.enable(this,this.oNavigationHandler);
            }
        },

        _setNavigationVariantToGlobalFilter: function (oAppData, oURLParameters, sNavType) {
            if (sNavType !== sap.ui.generic.app.navigation.service.NavType.initial) {
                var oGlobalFilter = this.getGlobalFilter();
                var bHasOnlyDefaults = oAppData && oAppData.bNavSelVarHasDefaultsOnly;
                var oSelectionVariant = new sap.ui.generic.app.navigation.service.SelectionVariant(oAppData.selectionVariant);
                var aSelectionVariantProperties = oSelectionVariant.getParameterNames().concat(oSelectionVariant.getSelectOptionsPropertyNames());
                for (var i = 0; i < aSelectionVariantProperties.length; i++) {
                    oGlobalFilter.addFieldToAdvancedArea(aSelectionVariantProperties[i]);
                }
                if (!bHasOnlyDefaults || oGlobalFilter.getCurrentVariantId() === "") {
                    // A default variant could be loaded. We have to clear the variant and we have to clear all the selections
                    // in the Smart Filter Bar.
                    oGlobalFilter.clearVariantSelection();
                    oGlobalFilter.clear();
                    oGlobalFilter.setDataSuiteFormat(oAppData.selectionVariant, true);
                }
            }
        }
        
        /* Appstate *//*
        getCurrentAppState: function() {
            var oSelectionVariant = new sap.ui.generic.app.navigation.service.SelectionVariant(this.oState.oSmartFilterbar.getDataSuiteFormat());
            return {
                selectionVariant: oSelectionVariant.toJSONString()
            };
        },

        storeCurrentAppStateAndAdjustURL: function(oCurrentAppState) {
            // oCurrentAppState is optional
            // - nothing, if NavigationHandler not available
            // - adjusts URL immediately
            // - stores appState for this URL (asynchronously)
            oCurrentAppState = oCurrentAppState || this.getCurrentAppState();
            try {
                var oNavigationHandler = new sap.ui.generic.app.navigation.service.NavigationHandler(this);
                oNavigationHandler.storeInnerAppState(oCurrentAppState);
            } catch (err) {
                jQuery.sap.log.error("OVP.storeCurrentAppStateAndAdjustURL: " + err);
            }
        },

        onSearchButtonPressed: function() {
            //store navigation context
            this.storeCurrentAppStateAndAdjustURL();
        }
		*//* Appstate */
    });
}());
}; // end of sap/ovp/app/Main.controller.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.charts.generic.Component') ) {
(function () {
	"use strict";
	/*global jQuery, sap */

	jQuery.sap.declare("sap.ovp.cards.charts.generic.Component");
	
	
	sap.ovp.cards.generic.Component.extend("sap.ovp.cards.charts.generic.Component", {
		// use inline declaration instead of component.json to save 1 round trip
		metadata: {
			properties: {
				"headerExtensionFragment":{
					"type": "string",
					"defaultValue": "sap.ovp.cards.generic.KPIHeader"
				},
				"selectionAnnotationPath":{
					"type": "string",
					"defaultValue": "com.sap.vocabularies.UI.v1.SelectionVariant"
				},
				"chartAnnotationPath":{
					"type": "string",
					"defaultValue": "com.sap.vocabularies.UI.v1.Chart"
				},
				"presentationAnnotationPath":{
					"type": "string",
					"defaultValue": "com.sap.vocabularies.UI.v1.PresentationVariant"
				},
				"identificationAnnotationPath":{
					"type": "string",
					"defaultValue": "com.sap.vocabularies.UI.v1.Identification"
				},
				"dataPointAnnotationPath":{
					"type": "string",
					"defaultValue": "com.sap.vocabularies.UI.v1.DataPoint"
				}
			},

			version: "1.36.12",

			library: "sap.ovp",

			includes: [],

			dependencies: {
				libs: [ "sap.m" ],
				components: []
			},
			config: {}
		},

		addTabindex: function() {
			jQuery(".tabindex0").attr("tabindex", 0);
		},

		onAfterRendering: function() {
			this.addTabindex();
		}
	});
})();

}; // end of sap/ovp/cards/charts/generic/Component.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.charts.line.Component') ) {
(function () {
	"use strict";
	/*global jQuery, sap */

	jQuery.sap.declare("sap.ovp.cards.charts.line.Component");
	
	sap.ovp.cards.charts.generic.Component.extend("sap.ovp.cards.charts.line.Component", {
		// use inline declaration instead of component.json to save 1 round trip
		metadata: {
			properties: {
				"contentFragment": {
					"type": "string",
					"defaultValue": "sap.ovp.cards.charts.line.LineChart"
				}
			},

			version: "1.36.12",

			library: "sap.ovp",

			includes: [],

			dependencies: {
				libs: [ "sap.m","sap.viz" ],
				components: []
			},
			config: {},
			customizing: {
				"sap.ui.controllerExtensions": {
					"sap.ovp.cards.generic.Card": {
						controllerName: "sap.ovp.cards.charts.line.LineChart"
					}
				}
			}
		}
	});
})();

}; // end of sap/ovp/cards/charts/line/Component.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.stack.Stack.controller') ) {
  jQuery.sap.declare('sap.ovp.cards.stack.Stack.controller');
(function () {
    "use strict";
    /*global sap, jQuery */
    
    

    sap.ui.controller("sap.ovp.cards.stack.Stack", {
        onInit: function () {
            var oVbox = this.getView().byId("stackContent");
            oVbox.addEventDelegate({
                onclick: this.openStack.bind(this),
                //when space or enter is pressed on stack card, we open ObjectStream
                onkeydown: function (oEvent) {
                    if (!oEvent.shiftKey && (oEvent.keyCode == 13 || oEvent.keyCode == 32)) {
                        oEvent.preventDefault();
                        this.openStack();
                    }
                }.bind(this)
            });
        },
        onExit: function() {
            if (this.oObjectStream) {
                this.oObjectStream.destroy();
            }
        },

        onAfterRendering: function () {
            var oView = this.getView();
            var oModel = oView.getModel();
            var oCardPropsModel = oView.getModel("ovpCardProperties");
            var sEntitySet = oCardPropsModel.getProperty("/entitySet");
            var oObjectStreamCardsSettings = oCardPropsModel.getProperty("/objectStreamCardsSettings");
            var oMetaModel = oModel.getMetaModel();
            var oEntitySet = oMetaModel.getODataEntitySet(sEntitySet);
            var oEntityType = oMetaModel.getODataEntityType(oEntitySet.entityType);

            //in order to support auto expand, the annotationPath property contains a "hint" to the
            //annotaionPath of the stack card content. There might be more then 1 annotationPath value due to support of Facets
            var sAnnotationPath = oCardPropsModel.getProperty("/annotationPath");
            var aAnotationPath = (sAnnotationPath) ? sAnnotationPath.split(",") : [];

            function getSetting(sKey){
                if (sKey === "ovpCardProperties"){
                    return oCardPropsModel;
                } else if (sKey === "dataModel"){
                    return oModel;
                } else if (sKey === "_ovpCache"){
                    return {};
                }
            }
            var aFormatItemsArguments = [{getSetting: getSetting}, oEntitySet].concat(aAnotationPath);
            var sBindingInfo = sap.ovp.cards.AnnotationHelper.formatItems.apply(this,aFormatItemsArguments);
            var oBindingInfo = sap.ui.base.BindingParser.complexParser(sBindingInfo);

            var sObjectStreamCardsNavigationProperty = oCardPropsModel.getProperty("/objectStreamCardsNavigationProperty");
            var bStackFlavorAssociation = sObjectStreamCardsNavigationProperty ? true : false;
            var oStackFilterMapping;
            var sObjectStreamCardsTemplate = oCardPropsModel.getProperty("/objectStreamCardsTemplate");


            // if we are in the association-flavor scenario we need to determine bot filter AND entity set for the object stream cards
            if (bStackFlavorAssociation) {
                if (sObjectStreamCardsTemplate === "sap.ovp.cards.quickview"){
                    jQuery.sap.log.error("objectStreamCardsTemplate cannot be 'sap.ovp.cards.quickview' when objectStreamCardsNavigationProperty is provided");
                    this.setErrorState();
                    return;
                }

                oStackFilterMapping =  this._determineFilterPropertyId(oModel, oEntitySet, oEntityType, sObjectStreamCardsNavigationProperty);
                oObjectStreamCardsSettings.entitySet = oModel.getMetaModel().getODataAssociationSetEnd(oEntityType, sObjectStreamCardsNavigationProperty).entitySet;
            } else {
                if (sObjectStreamCardsTemplate !== "sap.ovp.cards.quickview"){
                    jQuery.sap.log.error("objectStreamCardsTemplate must be 'sap.ovp.cards.quickview' when objectStreamCardsNavigationProperty is not provided");
                    this.setErrorState();
                    return;
                }
                // we are in the regular scenario (QuickView cards for collection entities)
                if (!oObjectStreamCardsSettings.category){
                    if (oEntityType["com.sap.vocabularies.UI.v1.HeaderInfo"] &&
                        oEntityType["com.sap.vocabularies.UI.v1.HeaderInfo"].TypeName &&
                        oEntityType["com.sap.vocabularies.UI.v1.HeaderInfo"].TypeName.String ) {
                        oObjectStreamCardsSettings.category = oEntityType["com.sap.vocabularies.UI.v1.HeaderInfo"].TypeName.String;
                    } else {
                        oObjectStreamCardsSettings.category = oEntityType.name;
                    }
                }
                oObjectStreamCardsSettings.entitySet = sEntitySet;
            }



            oBindingInfo.factory = function (sId, oContext) {
                var oSettings = oObjectStreamCardsSettings, oFilters;

                if (bStackFlavorAssociation) {

                    oFilters = {
                        filters : [{
                                path : oStackFilterMapping.foreignKey,
                                operator: "EQ",
                                value1: oContext.getProperty(oStackFilterMapping.key)
                    }]};

                    oSettings = jQuery.extend(oFilters, oObjectStreamCardsSettings);
                }


                var oComponent = sap.ui.component({
                    name: oCardPropsModel.getProperty("/objectStreamCardsTemplate"),
                    componentData: {
                        model: oModel,
                        settings: oSettings
                    }
                });

                var oCardComp = new sap.ui.core.ComponentContainer({component: oComponent});
                /* we need to override the setBindingContext method as from some reason
                 * when calling it on the container its not set on the inner component
                 */
                oCardComp.setBindingContext = function(oContext){
                    oComponent.setBindingContext(oContext);
                };
                return oCardComp;
            };


            this.oObjectStream = new sap.ovp.ui.ObjectStream({
                title: oCardPropsModel.getObject("/category"),
                content: oBindingInfo
            });
            this.oObjectStream.setModel(oModel);

            // place holder card is relevant only for the regular Stack-Card flavor (not the AssociationSet flavor)
            if (!bStackFlavorAssociation) {
                //Check if we have navigate target, if there is create placeHolder card and set it
                var aNavigationFields = this.getEntityNavigationEntries();
                if (aNavigationFields.length > 0) {
                    var sAppName = aNavigationFields[0].label;
                    var oPlaceHolder = this._createPlaceHolder(sAppName);
                    var that = this;

                    oPlaceHolder.addEventDelegate({
                        onclick: function () {
                            that.doNavigation(null);
                        }
                    });

                    this.oObjectStream.setPlaceHolder(oPlaceHolder);
                }
            }


            var oListBinding = this.oObjectStream.getBinding("content");
            oListBinding.attachDataReceived(function () {
                var nCardCount = oListBinding.getCurrentContexts().length;
                oView.byId("stackSize").setText(nCardCount);
                var stackContentDomRef = this.getView().byId("stackContent").getDomRef();
                jQuery(stackContentDomRef).attr("aria-label", sap.ui.getCore().getLibraryResourceBundle("sap.ovp").getText("stackCardContent", [nCardCount]));
                var stackSizeDomRef = this.getView().byId("stackSize").getDomRef();
                jQuery(stackSizeDomRef).attr("aria-label", sap.ui.getCore().getLibraryResourceBundle("sap.ovp").getText("stackCard", [nCardCount]));
            }, this);
        },

        _determineFilterPropertyId : function(oModel, oEntitySet, oEntityType, sNavigationProperty) {
            var oNavigationProperty, ns = oEntityType.namespace, sRelationshipName, oAssociation;

            // find the relevant navigation property on the entity type
            for (var i = 0; i < oEntityType.navigationProperty.length; i++) {
                if (oEntityType.navigationProperty[i].name === sNavigationProperty) {
                    oNavigationProperty = oEntityType.navigationProperty[i];
                    break;
                }
            }

            // find the Association ID / object which is the navigation property relationship member
            sRelationshipName = oNavigationProperty.relationship;
            oAssociation = sap.ovp.cards.AnnotationHelper.getAssociationObject(oModel, sRelationshipName, ns);

            // find the filter value for stack card - by looking at the Association Object
            var oRefs = oAssociation.referentialConstraint, filterMapping = {};
            if (oRefs) {
                filterMapping.foreignKey = oRefs.dependent.propertyRef[0].name;
                filterMapping.key = oRefs.principal.propertyRef[0].name;
                return filterMapping;
            }
        },

        _createPlaceHolder: function (sAppName) {

            var iIcon = new sap.ui.core.Icon({
                src: "sap-icon://offsite-work",
                useIconTooltip: false,
                layoutData: new sap.m.FlexItemData({growFactor : 1, alignSelf: sap.m.FlexAlignSelf.Center})
            });

            iIcon.addStyleClass("sapOvpStackPlaceHolderIcon");

            var lbAppName = new sap.m.Label({text: sAppName});
            var strText = sap.ui.getCore().getLibraryResourceBundle("sap.ovp").getText("ForMoreContentAppName", [sAppName]);
            var txtText = new sap.m.Text({text: strText});
            txtText.addCustomData(new sap.ovp.ui.CustomData({
                key: "role",
                value: "heading",
                writeToDom: true
            }));
            txtText.addCustomData(new sap.ovp.ui.CustomData({
                key: "aria-label",
                value: strText,
                writeToDom: true
            }));

            lbAppName.addStyleClass("sapOvpStackPlaceHolderAppName");
            txtText.addStyleClass("sapOvpStackPlaceHolderTextLine");

            var oDivVbox = new sap.m.VBox({items: [lbAppName, txtText]});
            oDivVbox.addStyleClass("sapOvpStackPlaceHolderLabelsContainer");
            oDivVbox.addCustomData(new sap.ovp.ui.CustomData({
                key: "tabindex",
                value: "0",
                writeToDom: true
            }));
            oDivVbox.addCustomData(new sap.ovp.ui.CustomData({
                key: "role",
                value: "button",
                writeToDom: true
            }));

            var oVbox = new sap.m.VBox({items: [iIcon, oDivVbox]});
            oVbox.addStyleClass("sapOvpStackPlaceHolder");
            oVbox.addEventDelegate({
                //when space or enter is pressed on Placeholder, we trigger click
                onkeydown: function (oEvent) {
                    if (!oEvent.shiftKey && (oEvent.keyCode == 13 || oEvent.keyCode == 32)) {
                        oEvent.preventDefault();
                        oEvent.srcControl.$().click();
                    }
                }
            });
            return oVbox;
        },

        openStack: function () {
            if (this.oObjectStream){
                var oListBinding = this.oObjectStream.getBinding("content");
                if (oListBinding.getCurrentContexts().length > 0){
                    var cardWidth = this.getView().$().width();
                    this.oObjectStream.open(cardWidth);
                }
            }
        }
    });
})();

}; // end of sap/ovp/cards/stack/Stack.controller.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.charts.bubble.Component') ) {
(function () {
	"use strict";
	/*global jQuery, sap */

	jQuery.sap.declare("sap.ovp.cards.charts.bubble.Component");
	
	sap.ovp.cards.charts.generic.Component.extend("sap.ovp.cards.charts.bubble.Component", {
		// use inline declaration instead of component.json to save 1 round trip
		metadata: {
			properties: {
				"contentFragment": {
					"type": "string",
					"defaultValue": "sap.ovp.cards.charts.bubble.BubbleChart"
				}
			},

			version: "1.36.12",

			library: "sap.ovp",

			includes: [],

			dependencies: {
				libs: [ "sap.m","sap.viz" ],
				components: []
			},
			config: {},
			customizing: {
				"sap.ui.controllerExtensions": {
					"sap.ovp.cards.generic.Card": {
						controllerName: "sap.ovp.cards.charts.bubble.BubbleChart"
					}
				}
			}
		}
	});
})();

}; // end of sap/ovp/cards/charts/bubble/Component.js
if ( !jQuery.sap.isDeclared('sap.ovp.cards.charts.donut.Component') ) {
(function () {
	"use strict";
	/*global jQuery, sap */

	jQuery.sap.declare("sap.ovp.cards.charts.donut.Component");
	
	sap.ovp.cards.charts.generic.Component.extend("sap.ovp.cards.charts.donut.Component", {
		// use inline declaration instead of component.json to save 1 round trip
		metadata: {
			properties: {
				"contentFragment": {
					"type": "string",
					"defaultValue": "sap.ovp.cards.charts.donut.DonutChart"
				}
			},

			version: "1.36.12",

			library: "sap.ovp",

			includes: [],

			dependencies: {
				libs: [ "sap.m","sap.viz" ],
				components: []
			},
			config: {},
			customizing: {
				"sap.ui.controllerExtensions": {
					"sap.ovp.cards.generic.Card": {
						controllerName: "sap.ovp.cards.charts.donut.DonutChart"
					}
				}
			}
		}
	});
})();

}; // end of sap/ovp/cards/charts/donut/Component.js
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2015 SAP SE. All rights reserved
	
 */

sap.ui.define(['sap/ui/core/theming/Parameters'], function (Parameters) {
	"use strict";

	/**
	 * Gantt Chart with table renderer.
	 *
	 * @namespace
	 */
	var GanttChartWithTable = {};

	GanttChartWithTable.render = function (oRenderManager, oGanttChartWithTable) {
		oRenderManager.write("<div");
		oRenderManager.writeControlData(oGanttChartWithTable);
		oRenderManager.addClass("sapUiTableHScr");  //force horizontal scroll bar to show
		oRenderManager.addClass("sapGanttChartWithTable");
		oRenderManager.writeClasses();
		oRenderManager.addStyle("width", oGanttChartWithTable.getWidth());
		oRenderManager.addStyle("height", oGanttChartWithTable.getHeight());
		oRenderManager.writeStyles();
		oRenderManager.write(">");

		if (oGanttChartWithTable._oToolbar.getAllToolbarItems().length == 0) {
			oGanttChartWithTable._oTT.addStyleClass("sapGanttChartColumnHeight");
		} else if (oGanttChartWithTable._oTT.hasStyleClass("sapGanttChartColumnHeight")){
			oGanttChartWithTable._oTT.removeStyleClass("sapGanttChartColumnHeight");
		}

		oRenderManager.renderControl(oGanttChartWithTable._oSplitter);

		oRenderManager.write("</div>");

	};

	return GanttChartWithTable;
}, /* bExport= */ true);
<file_sep>/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */
sap.ui.define(['jquery.sap.global','sap/ui/fl/changeHandler/Base'],function(q,B){"use strict";var R=function(){};R.prototype=q.sap.newObject(B.prototype);R.prototype.applyChange=function(c,g){var i=null;if(g.getParent){i=g.getParent();if(i){if(i.removeFormContainer){i.removeFormContainer(g);}}}else{throw new Error("no Group control provided for removing the group");}};R.prototype.completeChangeContent=function(c,s){var C=c.getDefinition();if(!C.content){C.content={};}};return R;},true);
<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
jQuery.sap.declare("sap.apf.modeler.core.messageDefinition");

sap.apf.modeler.core.messageDefinition = [ {
	code : "11005",
	severity : "technError",
	text : "Bad HTTP request returned status code {0} with status text {1}."
}, {
	code : "11006",
	severity : "technError",
	text : "Unknown identifier: {0}"
}, {
	code : "11007",
	severity : "technError",
	text : "Cannot export unsaved configuration. Configuration ID: {0}"
}, {
	code : "11008",
	severity : "error",
	description : "Format information is missing at least for text element {0} - please edit the exported text property file manually",
	key : "11008"
}, {
	code : "11009",
	severity : "error",
	description : "Application id {0} cannot be used as translation uuid in text property file - please edit the exported text property file manually",
	key : "11009"
}, {
	code : "11010",
	severity : "error",
	description : "Imported text property file does not contain the APF application id - expected an entry like #ApfApplicationId=543EC63F05550175E10000000A445B6D.",
	key : "11010"
}, {
	code : "11011",
	severity : "error",
	description : "Expected a valid text entry <key>=<value> in line {0}, but could not find - key must be in valid guid format.",
	key : 11011
}, {
	code : "11012",
	severity : "error",
	description : "No valid text entry <key>=<value> in line {0}, key is not in valid guid format like 543EC63F05550175E10000000A445B6D.",
	key : 11012
}, {
	code : "11013",
	severity : "technError",
	text : "Metadata request {3} to server failed with http status code {0}, http error message {1}, and server response {2}",
	key : "11013"
}, {
	code : "11014",
	severity : "error",
	description : "ApfApplicationId in line {0} has invalid format - a valid application id looks like 543EC63F05550175E10000000A445B6D.",
	key : "11014"
}, {
	code : "11015",
	severity : "error",
	description : "Date in line {0} has invalid format.",
	key : "11015"
}, {
	code : "11016",
	severity : "error",
	description : "Sorting options must be supplied when setting top n",
	key : "11016"
},{
	code : "11020",
	severity : "error",
	description : "Text property has invalid format and cannot be imported - see previous messages for details",
	key : "11020"
}, {
	code : "11021",
	severity : "error",
	description : "ApfApplicationId {0} referenced in the text property is not yet existing - please load one configuration of the application before importing the texts.",
	key : "11021"
},
{
	code : "11030",
	severity : "error",
	description : "Label {0} is not valid",
	key : "11030"
},
{
	code : "11031",
	severity : "error",
	description : "Category {0} is not valid",
	key : "11031"
},
{
	code : "11032",
	severity : "error",
	description : "Request {0} is not valid",
	key : "11032"
},
{
	code : "11033",
	severity : "error",
	description : "Binding {0} is not valid",
	key : "11033"
},
{
	code : "11034",
	severity : "error",
	description : "Facet filter {0} is not valid",
	key : "11034"
},
{
	code : "11035",
	severity : "error",
	description : "Step {0} is not valid",
	key : "11035"
},
{
	code : "11036",
	severity : "error",
	description : "Configuration is not valid",
	key : "11036"
},
{
	code : "11037",
	severity : "error",
	description : "Invalid application guid {0}",
	key : "11037"
},
{
	code : "11038",
	severity : "error",
	description : "Invalid configuration guid {0}",
	key : "11038"
},
{
	code : "11039",
	severity : "error",
	description : "Invalid text guid {0}",
	key : "11039"
},
{
	code : "11040",
	severity : "error",
	description : "Navigation target {0} is not valid",
	key : "11040"
},{
	code : "11041",
	severity : "technError",
	text : "Network service for retrieving semantic objects failed - see console."
},{
	code : "11042",
	severity : "technError",
	text : "Error occurred when retrieving actions for semantic object - see console."
},{
	code : "11500",
	severity : "error",
	description : "An error occurred while attempting to save the application.",
	key : "11500"
},{
	code : "11501",
	severity : "error",
	description : "An error occurred while attempting to delete the application.",
	key : "11501"
},{
	code : "11502",
	severity : "error",
	description : "An error occurred while importing the configuration.",
	key : "11502"
},{
	code : "11503",
	severity : "error",
	description : "An error occurred while importing the text properties file.",
	key : "11503"
},{
	code : "11504",
	severity : "error",
	description : "An error occurred while retrieving the semantic objects available.",
	key : "11504"
},{
	code : "11505",
	severity : "error",
	description : "An error occurred while retrieving the actions for the given semantic object.",
	key : "11505"
}
];<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */
sap.ui.define(['jquery.sap.global'],
	function(jQuery) {
	"use strict";


	/**
	 * @class FieldListNode renderer.
	 * @static
	 */
	var FieldListNodeRenderer = {};
	
	/**
	 * Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
	 * 
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control that should be rendered
	 */
	FieldListNodeRenderer.render = function(oRm, oControl) {

		// write the HTML into the render manager
		oRm.write("<div");
		oRm.writeControlData(oControl);
		oRm.addClass("sapUiCompFieldListNode");
		if (!oControl.getIsVisible()) {
			oRm.addClass("sapUiCompFieldListNodeIsHidden");
		} else {
			oRm.addClass("sapUiCompFieldListNodeIsVisible");
		}
		if (oControl.getIsSelected()) {
			oRm.addClass("sapUiCompFieldListNodeIsSelected");
		}
		oRm.writeClasses();
		oRm.write(">"); // span element
	
		FieldListNodeRenderer.renderLayout(oRm, oControl);
		FieldListNodeRenderer.renderChildren(oRm, oControl);
	
		oRm.write("</div>");
	};
	
	/**
	 * Renders the layout control
	 * 
	 * @param {sap.ui.core.RenderManager} oRm RenderManager
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oControl field list node
	 * @private
	 */
	FieldListNodeRenderer.renderLayout = function(oRm, oControl) {

		oRm.renderControl(oControl._oLayout);
	};
	
	/**
	 * Renders the child nodes
	 * 
	 * @param {sap.ui.core.RenderManager} oRm RenderManager
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oControl field list node
	 * @private
	 */
	FieldListNodeRenderer.renderChildren = function(oRm, oControl) {

		var length, i, aChildren;
		aChildren = oControl.getNodes();
		length = aChildren.length;
		oRm.write('<div class="sapUiCompFieldListNodeBorder">');
		for (i = 0; i < length; i++) {
			oRm.renderControl(aChildren[i]);
		}
		oRm.write("</div>");
	};
	

	return FieldListNodeRenderer;

}, /* bExport= */ true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */
sap.ui.define([],function(){"use strict";return{aggregations:{customToolbar:{ignore:true},semanticObjectController:{ignore:true},noData:{ignore:true}}};},false);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// This file defines behavior for the control.
sap.ui.define(['jquery.sap.global', './library', 'sap/ui/core/Control'],
	function(jQuery, library, Control) {
	"use strict";

	/**
	 * The configuration of the graphic element on the chart.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Displays parts of a whole as highlighted sectors in a pie chart.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.HarveyBallMicroChart
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var HarveyBallMicroChart = Control.extend("sap.suite.ui.microchart.HarveyBallMicroChart", /** @lends sap.suite.ui.microchart.HarveyBallMicroChart.prototype */ {
		metadata : {
			library: "sap.suite.ui.microchart",
			properties: {

				/**
				 * The total value. This is taken as 360 degrees value on the chart.
				 */
				total: {group:"Misc", type:"float", defaultValue: null},

				/**
				 * The total label. If specified, it is displayed instead of the total value.
				 */
				totalLabel: {group:"Misc", type:"string"},

				/**
				The scaling factor that is displayed next to the total value.
				*/
				totalScale: {group:"Misc", type:"string"},

				/**
				If set to true, the totalLabel parameter is considered as the combination of the total value and its scaling factor. The default value is false. It means that the total value and the scaling factor are defined separately by the total and the totalScale properties accordingly.
				*/
				formattedLabel: {group:"Misc", type:"boolean", defaultValue:false},

				/**
				If it is set to true, the total value is displayed next to the chart. The default setting is true.
				*/
				showTotal: {group:"Misc", type:"boolean", defaultValue:true},

				/**
				If it is set to true, the fraction values are displayed next to the chart. The default setting is true.
				*/
				showFractions: {group:"Misc", type:"boolean", defaultValue:true},

				/**
				The size of the chart. If it is not set, the default size is applied based on the device type.
				*/
				size: {group:"Misc", type:"sap.m.Size", defaultValue:"Auto"},

				/**
				The color palette for the chart. If this property is set, semantic colors defined in HarveyBallMicroChart are ignored. Colors from the palette are assigned to each slice consequentially. When all the palette colors are used, assignment of the colors begins from the first palette color.
				*/
				colorPalette: {type: "string[]", group : "Appearance", defaultValue : [] },

				/**
				The width of the chart. If it is not set, the size of the control is defined by the size property.
				*/
				width: {group:"Misc", type:"sap.ui.core.CSSSize"}
			},
			events: {
				/**
				 * The event is fired when the user chooses the control.
				 */
				press: {}
			},
			aggregations: {

				/**
				 * The set of points for this graphic element.
				 */
				"items": { multiple: true, type: "sap.suite.ui.microchart.HarveyBallMicroChartItem" }
			}
		}
	});

	///**
	// * This file defines behavior for the control,
	// */


	HarveyBallMicroChart.prototype.getAltText = function() {
		var sAltText = "";
		var bIsFirst = true;

		var aItems = this.getItems();
		for (var i = 0; i < aItems.length; i++) {
			var oItem = aItems[i];
			var sColor = (this.getColorPalette().length === 0) ? this._rb.getText(("SEMANTIC_COLOR_" + oItem.getColor()).toUpperCase()) : "";
			var sLabel = oItem.getFractionLabel();
			var sScale = oItem.getFractionScale();
			if (!sLabel && sScale) {
				sLabel = oItem.getFormattedLabel() ? oItem.getFraction() : oItem.getFraction() + oItem.getFractionScale().substring(0,3);
			} else if (!oItem.getFormattedLabel() && oItem.getFractionLabel()) {
				sLabel += oItem.getFractionScale().substring(0,3);
			}

			sAltText += (bIsFirst ? "" : "\n") + sLabel + " " + sColor;
			bIsFirst = false;
		}

		if (this.getTotal()) {
			var sTLabel = this.getTotalLabel();
			if (!sTLabel) {
				sTLabel = this.getFormattedLabel() ? this.getTotal() : this.getTotal() + this.getTotalScale().substring(0,3);
			} else if (!this.getFormattedLabel()) {
				sTLabel += this.getTotalScale().substring(0,3);
			}

			sAltText += (bIsFirst ? "" : "\n") + this._rb.getText("HARVEYBALLMICROCHART_TOTAL_TOOLTIP") + " " + sTLabel;
		}
		return sAltText;
	};

	HarveyBallMicroChart.prototype.getTooltip_AsString = function() {
		var oTooltip = this.getTooltip();
		var sTooltip = this.getAltText();

		if (typeof oTooltip === "string" || oTooltip instanceof String) {
			sTooltip = oTooltip.split("{AltText}").join(sTooltip).split("((AltText))").join(sTooltip);
			return sTooltip;
		}
		return oTooltip ? oTooltip : "";
	};

	HarveyBallMicroChart.prototype.init = function() {
		this._rb = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.microchart");
		this.setTooltip("{AltText}");
		sap.ui.Device.media.attachHandler(this.rerender, this, sap.ui.Device.media.RANGESETS.SAP_STANDARD);
	};

	HarveyBallMicroChart.prototype._calculatePath = function() {
		var oSize = this.getSize();

		var fTot = this.getTotal();
		var fFrac = 0;

		if (this.getItems().length) {
			fFrac = this.getItems()[0].getFraction();
		}

		var bIsPhone = false;

		if (oSize == "Auto") {
			bIsPhone = jQuery("html").hasClass("sapUiMedia-Std-Phone");
		}

		if (oSize == "S" || oSize == "XS") {
			bIsPhone = true;
		}

		var iMeadiaSize = bIsPhone ? 56 : 72;
		var iCenter = iMeadiaSize / 2;
		// var iBorder = bIsPhone? 3 : 4;
		var iBorder = 4;
		this._oPath = {
			initial : {
				x : iCenter,
				y : iCenter,
				x1 : iCenter,
				y1 : iCenter
			},
			lineTo : {
				x : iCenter,
				y : iBorder
			},
			arc : {
				x1 : iCenter - iBorder,
				y1 : iCenter - iBorder,
				xArc : 0,
				largeArc : 0,
				sweep : 1,
				x2 : "",
				y2 : ""
			},
			size : iMeadiaSize,
			border : iBorder,
			center : iCenter
		};

		var fAngle = fFrac / fTot * 360;
		if (fAngle < 10) {
			this._oPath.initial.x -= 1.5;
			this._oPath.initial.x1 += 1.5;
			this._oPath.arc.x2 = this._oPath.initial.x1;
			this._oPath.arc.y2 = this._oPath.lineTo.y;
		} else if (fAngle > 350 && fAngle < 360) {
			this._oPath.initial.x += 1.5;
			this._oPath.initial.x1 -= 1.5;
			this._oPath.arc.x2 = this._oPath.initial.x1;
			this._oPath.arc.y2 = this._oPath.lineTo.y;
		} else {
			var fRad = Math.PI / 180.0;
			var fRadius = this._oPath.center - this._oPath.border;

			var ix = fRadius * Math.cos((fAngle - 90) * fRad) + this._oPath.center;
			var iy = this._oPath.size - (fRadius * Math.sin((fAngle + 90) * fRad) + this._oPath.center);

			this._oPath.arc.x2 = ix.toFixed(2);
			this._oPath.arc.y2 = iy.toFixed(2);
		}

		var iLargeArc = fTot / fFrac < 2 ? 1 : 0;

		this._oPath.arc.largeArc = iLargeArc;
	};

	HarveyBallMicroChart.prototype.onBeforeRendering = function() {
		this._calculatePath();
	};

	HarveyBallMicroChart.prototype.serializePieChart = function() {
		var p = this._oPath;

		return ["M", p.initial.x, ",", p.initial.y, " L", p.initial.x, ",", p.lineTo.y, " A", p.arc.x1, ",", p.arc.y1,
				" ", p.arc.xArc, " ", p.arc.largeArc, ",", p.arc.sweep, " ", p.arc.x2, ",", p.arc.y2, " L", p.initial.x1,
				",", p.initial.y1, " z"].join("");
	};

	HarveyBallMicroChart.prototype._parseFormattedValue = function(
			sValue) {
		return {
			scale: sValue.replace(/.*?([^+-.,\d]*)$/g, "$1").trim(),
			value: sValue.replace(/(.*?)[^+-.,\d]*$/g, "$1").trim()
		};
	};

	HarveyBallMicroChart.prototype.ontap = function(oEvent) {
		if (sap.ui.Device.browser.internet_explorer) {
			this.$().focus();
		}
		this.firePress();
	};

	HarveyBallMicroChart.prototype.onkeydown = function(oEvent) {
		if (oEvent.which == jQuery.sap.KeyCodes.SPACE) {
			oEvent.preventDefault();
		}
	};

	HarveyBallMicroChart.prototype.onkeyup = function(oEvent) {
		if (oEvent.which == jQuery.sap.KeyCodes.ENTER
				|| oEvent.which == jQuery.sap.KeyCodes.SPACE) {
			this.firePress();
			oEvent.preventDefault();
		}
	};

	HarveyBallMicroChart.prototype.attachEvent = function(
			sEventId, oData, fnFunction, oListener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, sEventId, oData,
				fnFunction, oListener);
		if (this.hasListeners("press")) {
			this.$().attr("tabindex", 0).addClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	HarveyBallMicroChart.prototype.detachEvent = function(
			sEventId, fnFunction, oListener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, sEventId, fnFunction,
				oListener);
		if (!this.hasListeners("press")) {
			this.$().removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	HarveyBallMicroChart.prototype.exit = function(oEvent) {
		sap.ui.Device.media.detachHandler(this.rerender, this, sap.ui.Device.media.RANGESETS.SAP_STANDARD);
	};

	return HarveyBallMicroChart;

});
<file_sep>// This file has been generated by the SAPUI5 'AllInOne' Builder
jQuery.sap.declare('sap.ui.fl.library-all');
if ( !jQuery.sap.isDeclared('sap.ui.fl.Utils') ) {
/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.Utils'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Component'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/Utils",[
	"jquery.sap.global", "sap/ui/core/Component"
], function(jQuery, Component) {
	"use strict";

	/**
	 * Provides utility functions for the flexibility library
	 *
	 * @namespace
	 * @alias sap.ui.fl.Utils
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.25.0
	 */
	var Utils = {

		/**
		 * log object exposes available log functions
		 *
		 * @name sap.ui.fl.Utils.log
		 * @public
		 */
		log: {
			error: function(sMessage, sDetails, sComponent) {
				jQuery.sap.log.error(sMessage, sDetails, sComponent);
			},
			warning: function(sMessage, sDetails, sComponent) {
				jQuery.sap.log.warning(sMessage, sDetails, sComponent);
			}
		},

		/**
		 * Tries to retrieve the xsrf token from the controls OData Model. Returns empty string if retrieval failed.
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {String} XSRF Token
		 * @public
		 * @function
		 * @name sap.ui.fl.Utils.getXSRFTokenFromControl
		 */
		getXSRFTokenFromControl: function(oControl) {
			var oModel;
			if (!oControl) {
				return "";
			}

			// Get Model
			if (oControl && typeof oControl.getModel === "function") {
				oModel = oControl.getModel();
				return Utils._getXSRFTokenFromModel(oModel);
			}
			return "";
		},

		/**
		 * Returns XSRF Token from the Odata Model. Returns empty string if retrieval failed
		 *
		 * @param {sap.ui.model.odata.ODataModel} oModel - OData Model
		 * @returns {String} XSRF Token
		 * @private
		 */
		_getXSRFTokenFromModel: function(oModel) {
			var mHeaders;
			if (!oModel) {
				return "";
			}
			if (typeof oModel.getHeaders === "function") {
				mHeaders = oModel.getHeaders();
				if (mHeaders) {
					return mHeaders["x-csrf-token"];
				}
			}
			return "";
		},

		/**
		 * Returns the class name of the component the given control belongs to.
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {String} The component class name, ending with ".Component"
		 * @see sap.ui.base.Component.getOwnerIdFor
		 * @public
		 * @function
		 * @name sap.ui.fl.Utils.getComponentClassName
		 */
		getComponentClassName: function(oControl) {
			var oComponent = null, sVariantId = null;

			// determine UI5 component out of given control
			if (oControl) {
				oComponent = this._getAppComponentForControl(oControl);

				// check if the component is an application variant and assigned an application descriptor then use this as reference
				if (oComponent) {
					sVariantId = this._getComponentStartUpParameter(oComponent, "sap-app-id");
					if (sVariantId) {
						return sVariantId;
					}
				}
			}

			return Utils._getComponentName(oComponent);
		},

		/**
		 * Returns the appDescriptor of the component for the given control
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {object} that represent the appDescriptor
		 * @public
		 * @function
		 * @name sap.ui.fl.Utils.getAppDescriptor
		 */
		getAppDescriptor: function(oControl) {
			var oManifest = null, oComponent = null, oComponentMetaData = null;

			// determine UI5 component out of given control
			if (oControl) {
				oComponent = this._getAppComponentForControl(oControl);

				// determine manifest out of found component
				if (oComponent && oComponent.getMetadata) {
					oComponentMetaData = oComponent.getMetadata();
					if (oComponentMetaData && oComponentMetaData.getManifest) {
						oManifest = oComponentMetaData.getManifest();
					}
				}
			}

			return oManifest;
		},

		/**
		 * Returns the siteId of a component
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {string} siteId - that represent the found sietId
		 * @public
		 * @function
		 * @name sap.ui.fl.Utils.getSiteId
		 */
		getSiteId: function(oControl) {
			var sSiteId = null, oComponent = null;

			// determine UI5 component out of given control
			if (oControl) {
				oComponent = this._getAppComponentForControl(oControl);

				// determine siteId from ComponentData
				if (oComponent) {

					//Workaround for backend check: isApplicationPermitted
					//As long as FLP does not know about appDescriptorId we have to pass siteID and applicationID.
					//With startUpParameter hcpApplicationId we will get a concatenation of “siteId:applicationId”

					//sSiteId = this._getComponentStartUpParameter(oComponent, "scopeId");
					sSiteId = this._getComponentStartUpParameter(oComponent, "hcpApplicationId");

				}
			}

			return sSiteId;
		},

		/**
		 * Indicates if the current application is a variant of an existing one and the VENDOR layer is selected
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {boolean} true if application is a variant and the VENDOR layer selected
		 * @public
		 * @function
		 * @name sap.ui.fl.Utils.isAppVariantMode
		 */
		isAppVariantMode: function(oControl) {
			return (Utils.isVendorLayer() && Utils.isApplicationVariant(oControl));
		},

		/**
		 * Indicates if the VENDOR is selected
		 *
		 * @returns {boolean} true if it's an application variant
		 * @public
		 * @function
		 * @name sap.ui.fl.Utils.isVendorLayer
		 */
		isVendorLayer: function() {
			// variant mode only supported for vendor other types are not allowed to change standard control variants
			if (Utils.getCurrentLayer(false) === "VENDOR") {
				return true;
			}

			return false;
		},

		/**
		 * Indicates if the current application is a variant of an existing one
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {boolean} true if it's an application variant
		 * @public
		 * @function
		 * @name sap.ui.fl.Utils.isApplicationVariant
		 */
		isApplicationVariant: function(oControl) {
			var bIsApplicationVariant = false, oComponent = null, sVariantId = null;

			if (oControl) {
				oComponent = this._getAppComponentForControl(oControl);

				// check if the component is an application variant and assigned an application descriptor then use this as reference
				if (oComponent) {
					sVariantId = this._getComponentStartUpParameter(oComponent, "sap-app-id");
					if (sVariantId) {
						bIsApplicationVariant = true;
					}
				}
			}

			return bIsApplicationVariant;
		},

		/**
		 * Determines the content for a given startUpParameter name
		 *
		 * @param {sap.ui.core.Component} oComponent - component instance
		 * @param {String} sParameterName - startUpParameterName that shall be determined
		 * @returns {String} content of found startUpParameter
		 * @private
		 */
		_getComponentStartUpParameter: function(oComponent, sParameterName) {
			var startUpParameterContent = null, oComponentData = null;

			if (sParameterName) {
				if (oComponent && oComponent.getComponentData) {
					oComponentData = oComponent.getComponentData();
					if (oComponentData && oComponentData.startupParameters) {
						if (jQuery.isArray(oComponentData.startupParameters[sParameterName])) {
							startUpParameterContent = oComponentData.startupParameters[sParameterName][0];
						}
					}
				}
			}

			return startUpParameterContent;
		},

		/**
		 * Gets the component name for a component instance.
		 *
		 * @param {sap.ui.core.Component} oComponent component instance
		 * @returns {String} component name
		 * @private
		 */
		_getComponentName: function(oComponent) {
			var sComponentName = "";
			if (oComponent) {
				sComponentName = oComponent.getMetadata().getName();
			}
			if (sComponentName.length > 0 && sComponentName.indexOf(".Component") < 0) {
				sComponentName += ".Component";
			}
			return sComponentName;
		},

		/**
		 * Gets the component instance for a component ID.
		 *
		 * @param {String} sComponentId component ID
		 * @returns {sap.ui.core.Component} component for the component ID
		 * @private
		 */
		_getComponent: function(sComponentId) {
			var oComponent;
			if (sComponentId) {
				oComponent = sap.ui.getCore().getComponent(sComponentId);
			}
			return oComponent;
		},

		/**
		 * Returns ComponentId of the control. If the control has no component, it walks up the control tree in order to find a control having one
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {String} The component id
		 * @see sap.ui.base.Component.getOwnerIdFor
		 * @private
		 */
		_getComponentIdForControl: function(oControl) {
			var sComponentId = "", i = 0;
			do {
				i++;
				sComponentId = Utils._getOwnerIdForControl(oControl);
				if (sComponentId) {
					return sComponentId;
				}
				if (oControl && typeof oControl.getParent === "function") { // Walk up control tree
					oControl = oControl.getParent();
				} else {
					return "";
				}
			} while (oControl && i < 100);
			return "";
		},
		
		/**
		 * Returns the Component that belongs to given control. If the control has no component, it walks up the control tree in order to find a
		 * control having one.
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {sap.ui.base.Component} found component
		 * @public
		 */
		getComponentForControl: function(oControl) {
			return Utils._getComponentForControl(oControl);
		},
		
		/**
		 * Returns the Component that belongs to given control whose type is "application". If the control has no component, it walks up the control tree in order to find a
		 * control having one.
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {sap.ui.base.Component} found component
		 * @private
		 */
		_getAppComponentForControl: function(oControl) {
			var oComponent = null;
			var oSapApp = null;
			
			oComponent = this._getComponentForControl(oControl);
			
			// special case for SmartTemplating to reach the real appComponent
			if (oComponent && oComponent.getAppComponent) {
				return oComponent.getAppComponent();
			}

			if (oComponent && oComponent.getManifestEntry) {
				oSapApp = oComponent.getManifestEntry("sap.app");
			} else {
				return oComponent;
			}
			
			if (oSapApp && oSapApp.type && oSapApp.type !== "application") {
				return this._getAppComponentForControl(oComponent);
			}
			
			return oComponent;
		},

		/**
		 * Returns the Component that belongs to given control. If the control has no component, it walks up the control tree in order to find a
		 * control having one.
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {sap.ui.base.Component} found component
		 * @private
		 */
		_getComponentForControl: function(oControl) {
			var oComponent = null;
			var sComponentId = null;

			// determine UI5 component out of given control
			if (oControl) {
				sComponentId = Utils._getComponentIdForControl(oControl);
				if (sComponentId) {
					oComponent = Utils._getComponent(sComponentId);
					
				}
			}

			return oComponent;
		},

		/**
		 * Returns the parent view of the control. If there are nested views, only the one closest to the control will be returned. If no view can be
		 * found, undefiend will be returned.
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {sap.ui.core.mvc.View} The view
		 * @see sap.ui.base.Component.getOwnerIdFor
		 * @public
		 */
		getViewForControl: function(oControl) {
			return Utils.getFirstAncestorOfControlWithControlType(oControl, sap.ui.core.mvc.View);

		},

		getFirstAncestorOfControlWithControlType: function(oControl, controlType) {
			if (oControl instanceof controlType) {
				return oControl;
			}

			if (oControl && typeof oControl.getParent === "function") {
				oControl = oControl.getParent();
				return Utils.getFirstAncestorOfControlWithControlType(oControl, controlType);
			}
		},

		hasControlAncestorWithId: function(sControlId, sAncestorControlId) {
			var oControl;

			if (sControlId === sAncestorControlId) {
				return true;
			}

			oControl = sap.ui.getCore().byId(sControlId);
			while (oControl) {

				if (oControl.getId() === sAncestorControlId) {
					return true;
				}

				if (typeof oControl.getParent === "function") {
					oControl = oControl.getParent();
				} else {
					return false;
				}
			}

			return false;
		},

		/**
		 * Checks whether the provided control is a view
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {Boolean} Flag
		 * @see sap.ui.base.Component.getOwnerIdFor
		 * @private
		 */
		_isView: function(oControl) {
			return oControl instanceof sap.ui.core.mvc.View;
		},

		/**
		 * Returns OwnerId of the control
		 *
		 * @param {sap.ui.core.Control} oControl - SAPUI5 control
		 * @returns {String} The owner id
		 * @see sap.ui.base.Component.getOwnerIdFor
		 * @private
		 */
		_getOwnerIdForControl: function(oControl) {
			return Component.getOwnerIdFor(oControl);
		},

		/**
		 * Returns the current layer as defined by the url parameter. If the end user flag is set, it always returns "USER".
		 *
		 * @param {boolean} bIsEndUser - the end user flag
		 * @returns {string} the current layer
		 * @public
		 * @function
		 * @name sap.ui.fl.Utils.getCurrentLayer
		 */
		getCurrentLayer: function(bIsEndUser) {
			var oUriParams, layer;
			if (bIsEndUser) {
				return "USER";
			}

			oUriParams = this._getUriParameters();
			layer = oUriParams.mParams["sap-ui-layer"];
			if (layer && layer.length > 0) {
				return layer[0];
			}
			return "CUSTOMER";

		},

		/**
		 * Checks if a shared newly created variant requires an ABAP package
		 *
		 * @returns {boolean} - Indicates whether a new variant needs an ABAP package
		 * @public
		 * @function
		 * @name sap.ui.fl.Utils.doesSharedVariantRequirePackage
		 */
		doesSharedVariantRequirePackage: function() {
			var sCurrentLayer;
			sCurrentLayer = Utils.getCurrentLayer(false);
			if ((sCurrentLayer === "VENDOR") || (sCurrentLayer === "PARTNER")) {
				return true;
			}
			if (sCurrentLayer === "USER") {
				return false;
			}
			if (sCurrentLayer === "CUSTOMER") {
				return false; // Variants in CUSTOMER layer might either be transported or stored as local objects ($TMP) as they are client
				// dependent content. A variant which will be transported must not be assigned to a package.
			}

			return false;
		},

		/**
		 * Returns the tenant number for the communication with the ABAP backend.
		 *
		 * @public
		 * @function
		 * @returns {string} the current client
		 * @name sap.ui.fl.Utils.getClient
		 */
		getClient: function() {
			var oUriParams, client;
			oUriParams = this._getUriParameters();
			client = oUriParams.mParams["sap-client"];
			if (client && client.length > 0) {
				return client[0];
			}
			return undefined;
		},

		_getUriParameters: function() {
			return jQuery.sap.getUriParameters();
		},
		/**
		 * Returns whether the hot fix mode is active (url parameter hotfix=true)
		 *
		 * @public
		 * @returns {bool} is hotfix mode active, or not
		 */
		isHotfixMode: function() {
			var oUriParams, aIsHotfixMode, sIsHotfixMode;
			oUriParams = this._getUriParameters();
			aIsHotfixMode = oUriParams.mParams["hotfix"];
			if (aIsHotfixMode && aIsHotfixMode.length > 0) {
				sIsHotfixMode = aIsHotfixMode[0];
			}
			return (sIsHotfixMode === "true");
		},

		/**
		 * Converts the browser language into a 2-character ISO 639-1 language. If the browser language is in format RFC4646, the first part will be
		 * used: For example en-us will be converted to EN. If the browser language already is in ISO 639-1, it will be returned after an upper case
		 * conversion: For example de will be converted to DE.
		 *
		 * @param {String} sBrowserLanguage - Language in RFC4646
		 * @returns {String} Language in ISO 639-1. Empty string if conversion was not successful
		 * @public
		 * @function
		 * @name sap.ui.fl.Utils.convertBrowserLanguageToISO639_1
		 */
		convertBrowserLanguageToISO639_1: function(sBrowserLanguage) {
			if (!sBrowserLanguage || typeof sBrowserLanguage !== "string") {
				return "";
			}

			var nIndex = sBrowserLanguage.indexOf("-");
			if ((nIndex < 0) && (sBrowserLanguage.length <= 2)) {
				return sBrowserLanguage.toUpperCase();
			}
			if (nIndex > 0 && nIndex <= 2) {
				return sBrowserLanguage.substring(0, nIndex).toUpperCase();
			}

			return "";
		},

		/**
		 * Returns the current language in ISO 639-1 format.
		 *
		 * @returns {String} Language in ISO 639-1. Empty string if language cannot be determined
		 * @public
		 */
		getCurrentLanguage: function() {
			var sLanguage = sap.ui.getCore().getConfiguration().getLanguage();
			return Utils.convertBrowserLanguageToISO639_1(sLanguage);
		},

		/**
		 * Retrieves the controlType of the control
		 *
		 * @param {sap.ui.core.Control} oControl Control instance
		 * @returns {string} control type of the control - undefined if controlType cannot be determined
		 * @private
		 */
		getControlType: function(oControl) {
			var oMetadata;
			if (oControl && typeof oControl.getMetadata === "function") {
				oMetadata = oControl.getMetadata();
				if (oMetadata && typeof oMetadata.getElementName === "function") {
					return oMetadata.getElementName();
				}
			}
		},

		/**
		 * Converts ASCII coding into a string. Required for restoring stored code extinsions
		 *
		 * @param {String} ascii string containing ascii code valid numbers seperated by ','
		 * @returns {String} parsedString parsed string
		 */
		asciiToString: function (ascii) {
			var asciiArray = ascii.split(",");
			var parsedString = "";

			jQuery.each(asciiArray, function (index, asciiChar) {
				parsedString += String.fromCharCode(asciiChar);
			});

			return parsedString;

		},

		/**
		 * Converts ASCII coding into a string. Required for restoring stored code extinsions
		 *
		 * @param {String} string string which has to be encoded
		 * @returns {String} ascii imput parsed to ascii numbers seperated by ','
		 */
		stringToAscii: function (string) {
			var ascii = "";

			for ( var i = 0; i < string.length; i++ ) {
				ascii += string.charCodeAt(i) + ",";
			}

			// remove last ","
			ascii = ascii.substring( 0 , ascii.length - 1 );

			return ascii;
		},

		/**
		 * Check if the control id is generated or maintained by the application
		 *
		 * @param {sap.ui.core.Control} oControl Control instance
		 * @returns {boolean} Returns true if the id is maintained by the application
		 */
		checkControlId: function(oControl) {
			var bIsGenerated = sap.ui.base.ManagedObjectMetadata.isGeneratedId(oControl.getId());
			// get the information if the control id was generated or not
			if (bIsGenerated === true) {
				jQuery.sap.log.error("Generated id attribute found", "to offer flexibility a stable control id is needed to assign the changes to, but for this control the id was generated by SAPUI5", oControl.getId());
			}
			return !bIsGenerated;
		},



		/**
		 * Returns the a string containing all url parameters of the current window.location
		 *
		 * @returns {string} Substring of url containing the url query parameters
		 * @private
		 */
		_getAllUrlParameters: function() {
			return window.location.search.substring(1);
		},

		/**
		 * Returns the value of the specified url parameter of the current url
		 *
		 * @param {String} sParameterName - Name of the url parameter
		 * @returns {string} url parameter
		 * @private
		 */
		getUrlParameter: function(sParameterName) {
			return jQuery.sap.getUriParameters().get(sParameterName);
		}

	};
	return Utils;
}, true);

}; // end of sap/ui/fl/Utils.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.changeHandler.Base') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.changeHandler.Base'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/changeHandler/Base",[
	"sap/ui/fl/Utils", "jquery.sap.global"
], function(Utils, $) {
	"use strict";

	/**
	 * Base class for all change handler subclasses which provides some reuse methods
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.Base
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 *
	 */
	var Base = function() {
	};

	/**
	 * @param {sap.ui.core.Control} oControl - the control for which the properties shall be returned
	 * @param {String} sName - name of property
	 * @returns {Object} property object
	 * @private
	 */
	Base.prototype._getProperty = function(oControl, sName) {
		if (oControl) {
			if (oControl.getMetadata) {
				var oMetadata = oControl.getMetadata();
				var oProperties = oMetadata.getProperties();
				if (oProperties) {
					var oProperty = oProperties[sName];
					if (oProperty) {
						return oProperty;
					}
				}
			}
		}
	};

	/**
	 * Changes a property of the control 
	 *
	 * @param {sap.ui.core.Control} oControl - the control for which the changes should be fetched
	 * @param {string} sName - property name
	 * @param {object} oValue - new value of the property
	 *
	 * @public
	 */
	Base.prototype.changeProperty = function(oControl, sName, oValue) {
		var oProperty = this._getProperty(oControl, sName);
		if (oProperty) {
			oControl.setProperty(sName, oValue);
		}
	};

	/**
	 * Sets a property of the control back to its default value
	 *
	 * @param {sap.ui.core.Control} oControl - the control for which the changes should be fetched
	 * @param {string} sName - property name
	 *
	 * @public
	 */
	Base.prototype.clearProperty = function(oControl, sName) {
		var oProperty = this._getProperty(oControl, sName);
		if (oProperty) {
			oControl.setProperty(sName, oProperty.defaultValue);
		}
	};

	/**
	 * Adds an additional item of the aggregation or changes it in case it is not a multiple one
	 *
	 * @param {sap.ui.core.Control} oControl - the control for which the changes should be fetched
	 * @param {string} sName - aggregation name
	 * @param {string} oObject - aggregated object to be set
	 * @param {integer} iIndex <optional> - index to which it should be added/inserted
	 *
	 * @public
	 */
	Base.prototype.addAggregation = function(oControl, sName, oObject, iIndex) {
		if (oControl) {
			if (oControl.getMetadata) {
				var oMetadata = oControl.getMetadata();
				var oAggregations = oMetadata.getAllAggregations();
				if (oAggregations) {
					var oAggregation = oAggregations[sName];
					if (oAggregation) {
						//						if(oAggregation.multiple === false) {
						//							oControl.destroyAggregation(sName);
						//						}
						if (oAggregation.multiple) {
							var iInsertIndex = iIndex || oAggregations.length || 0;
							oControl[oAggregation._sInsertMutator](oObject, iInsertIndex);
						} else {
							oControl[oAggregation._sMutator](oObject);
						}
					}
				}
			}
		}
	};
	
	Base.prototype.removeAggregation = function(oControl, sName, oObject) {
		if (oControl) {
			if (oControl.getMetadata) {
				var oMetadata = oControl.getMetadata();
				var oAggregations = oMetadata.getAllAggregations();
				if (oAggregations) {
					var oAggregation = oAggregations[sName];
					if (oAggregation) {
						oControl[oAggregation._sRemoveMutator](oObject);
					}
				}
			}
		}
	};
	/**
	 * Sets a text in a change.
	 *
	 * @param {object} oChange - change object
	 * @param {string} sKey - text key
	 * @param {string} sText - text value
	 * @param {string} sType - translation text type e.g. XBUT, XTIT, XTOL, XFLD
	 *
	 * @public
	 */
	Base.prototype.setTextInChange = function(oChange, sKey, sText, sType) {
		if (!oChange.texts) {
			oChange.texts = {};
		}
		if (!oChange.texts[sKey]) {
			oChange.texts[sKey] = {};
		}
		oChange.texts[sKey].value = sText;
		oChange.texts[sKey].type = sType;
	};

	return Base;
}, /* bExport= */true);

}; // end of sap/ui/fl/changeHandler/Base.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.changeHandler.HideControl') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.changeHandler.HideControl'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/changeHandler/HideControl",[
	'jquery.sap.global', './Base'
], function(jQuery, Base) {
	"use strict";

	/**
	 * Change handler for hiding of a control.
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.HideControl
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 */
	var HideControl = function() {
	};
	HideControl.prototype = jQuery.sap.newObject(Base.prototype);

	/**
	 * Hides a control.
	 *
	 * @param {sap.ui.fl.Change} oChange change object with instructions to be applied on the control map
	 * @param {sap.ui.core.Control} oControl control that matches the change selector for applying the change
	 * @public
	 */
	HideControl.prototype.applyChange = function(oChange, oControl) {

		if (oControl.setVisible) {
			oControl.setVisible(false);
		} else {
			throw new Error("Provided control instance has no setVisible method");
		}
	};

	/**
	 * Completes the change by adding change handler specific content
	 *
	 * @param {sap.ui.fl.Change} oChange change object to be completed
	 * @param {object} oSpecificChangeInfo as an empty object since no additional attributes are required for this operation
	 * @public
	 */
	HideControl.prototype.completeChangeContent = function(oChange, oSpecificChangeInfo) {

		var oChangeJson = oChange.getDefinition();

		if (!oChangeJson.content) {
			oChangeJson.content = {};
		}

	};

	return HideControl;
},
/* bExport= */true);

}; // end of sap/ui/fl/changeHandler/HideControl.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.changeHandler.MoveElements') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.changeHandler.MoveElements'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/changeHandler/MoveElements",['jquery.sap.global', './Base'], function(jQuery, Base) {
	"use strict";

	/**
	 * Change handler for moving of a elements.
	 * 
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.MoveElements
	 * @author <NAME>
	 * @version 1.36.12
	 * @experimental Since 1.34.0
	 */
	var MoveElements = function() {
	};
	MoveElements.prototype = jQuery.sap.newObject(Base.prototype);

	MoveElements.CHANGE_TYPE = "moveElements";

	/**
	 * Moves an element from one aggregation to another.
	 * 
	 * @param {sap.ui.fl.Change}
	 *          oChange change object with instructions to be applied on the control map
	 * @param {sap.ui.core.Control}
	 *          oSourceParent control that matches the change selector for applying the change, which is the source of the
	 *          move
	 * @public
	 */
	MoveElements.prototype.applyChange = function(oChange, oSourceParent) {
		var that = this;
		var mContent = oChange.getContent();

		if (oSourceParent.getId() !== oChange.getSelector().id) {
			throw new Error("Source parent id (selector) doesn't match the control on which to apply the change");
		}
		var sSourceAggregation = oChange.getSelector().aggregation;
		if (!sSourceAggregation) {
			throw new Error("No source aggregation supplied via selector for move");
		}

		if (!mContent.target || !mContent.target.selector) {
			throw new Error("No target supplied for move");
		}
		var oTargetParent = this._byId(mContent.target.selector.id);
		if (!oTargetParent) {
			throw new Error("Move target parent not found");
		}
		var sTargetAggregation = mContent.target.selector.aggregation;
		if (!sTargetAggregation) {
			throw new Error("No target aggregation supplied for move");
		}
		if (!mContent.movedElements) {
			throw new Error("No moveElements supplied");
		}

		mContent.movedElements.forEach(function(mMovedElement) {
			var oMovedElement = that._byId(mMovedElement.selector.id);
			if (!oMovedElement) {
				throw new Error("Unkown element with id '" + mMovedElement.selector.id + "' in moveElements supplied");
			}
			if ( typeof mMovedElement.targetIndex !== "number") {
				throw new Error("Missing targetIndex for element with id '" + mMovedElement.selector.id
						+ "' in moveElements supplied");
			}
			that.removeAggregation(oSourceParent, sSourceAggregation, oMovedElement);
			that.addAggregation(oTargetParent, sTargetAggregation, oMovedElement, mMovedElement.targetIndex);
		});

	};

	/**
	 * Completes the change by adding change handler specific content
	 * 
	 * @param {sap.ui.fl.Change}
	 *          oChange change object to be completed
	 * @param {object}
	 *          mSpecificChangeInfo as an empty object since no additional attributes are required for this operation
	 * @public
	 */
	MoveElements.prototype.completeChangeContent = function(oChange, mSpecificChangeInfo) {
		var that = this;

		var mSpecificInfo = this.getSpecificChangeInfo(mSpecificChangeInfo);

		var mChangeData = oChange.getDefinition();

		mChangeData.changeType = MoveElements.CHANGE_TYPE;

		mChangeData.selector = mSpecificInfo.source;

		mChangeData.content = {
			movedElements : [],
			target : {
				selector : mSpecificInfo.target
			}
		};
		mSpecificInfo.movedElements.forEach(function(mElement) {
			var oElement = mElement.element || that._byId(mElement.id);

			mChangeData.content.movedElements.push({
				selector : {
					id : oElement.getId(),
					type : that._getType(oElement)
				},
				sourceIndex : mElement.sourceIndex,
				targetIndex : mElement.targetIndex
			});
		});
	};

	/**
	 * Enrich the incoming change info with the change info from the setter, to get the complete data in one format
	 */
	MoveElements.prototype.getSpecificChangeInfo = function(mSpecificChangeInfo) {
		var oSourceParent = this._getParentElement(this._mSource || mSpecificChangeInfo.source);
		var oTargetParent = this._getParentElement(this._mTarget || mSpecificChangeInfo.target);

		var sSourceAggregation = this._mSource && this._mSource.aggregation || mSpecificChangeInfo.source.aggregation;
		var sTargetAggregation = this._mTarget && this._mTarget.aggregation || mSpecificChangeInfo.target.aggregation;

		var mSpecificInfo = {
			source : {
				id : oSourceParent.getId(),
				aggregation : sSourceAggregation,
				type : this._getType(oSourceParent)
			},
			target : {
				id : oTargetParent.getId(),
				aggregation : sTargetAggregation,
				type : this._getType(oTargetParent)
			},
			movedElements : this._aMovedElements || mSpecificChangeInfo.movedElements
		};

		return mSpecificInfo;
	};

	/**
	 * @param {array}
	 *          aElements
	 * @param {string}
	 *          aElements.elementId id of the moved element, can be omitted if element is passed
	 * @param {sap.ui.core.Element}
	 *          aElements.element moved element, optional fallback for elementId
	 * @param {number}
	 *          aElements.sourceIndex index of the moved elements in the source aggregation
	 * @param {number}
	 *          aElements.targetIndex index of the moved elements in the target aggregation
	 */
	MoveElements.prototype.setMovedElements = function(aElements) {
		this._aMovedElements = aElements;
	};

	/**
	 * @param {object}
	 *          mSource
	 * @param {string}
	 *          mSource.id id of the source parent, can be omitted if element is passed
	 * @param {sap.ui.core.Element}
	 *          mSource.parent optional fallback for id
	 * @param {string}
	 *          mSource.aggregation original aggregation of the moved elements
	 */
	MoveElements.prototype.setSource = function(mSource) {
		this._mSource = mSource;
	};

	/**
	 * @param {object}
	 *          mTarget
	 * @param {string}
	 *          mTarget.id id of the target parent
	 * @param {sap.ui.core.Element}
	 *          mTarget.parent optional fallback for id, can be omitted if parent is passed
	 * @param {string}
	 *          mTarget.aggregation target aggregation of the moved elements in the target element
	 */
	MoveElements.prototype.setTarget = function(mTarget) {
		this._mTarget = mTarget;
	};

	MoveElements.prototype._byId = function(sId) {
		return sap.ui.getCore().byId(sId);
	};

	MoveElements.prototype._getType = function(oElement) {
		return oElement.getMetadata().getName();
	};

	MoveElements.prototype._getParentElement = function(mData) {
		var oElement = mData.parent;
		if (!oElement) {
			oElement = this._byId(mData.id);
		}
		return oElement;
	};

	return MoveElements;
},
/* bExport= */true);

}; // end of sap/ui/fl/changeHandler/MoveElements.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.changeHandler.PropertyChange') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

/*global sap */

jQuery.sap.declare('sap.ui.fl.changeHandler.PropertyChange'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/changeHandler/PropertyChange",["jquery.sap.global", "sap/ui/fl/changeHandler/Base", "sap/ui/fl/Utils"], function(jQuery, Base, FlexUtils) {
	"use strict";

	/**
	 * Change handler for setting properties on controls
	 *
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.PropertyChange
	 * @author SAP SE
	 * @version 1.36.12
	 * @since 1.36
	 * @private
	 * @experimental Since 1.36. This class is experimental and provides only limited functionality. Also the API might be changed in future.
	 */
	var PropertyChange = function() {
	};

	PropertyChange.prototype = jQuery.sap.newObject(Base.prototype);

	/**
	 * Changes the properties on the given control
	 *
	 * @param {object} oChange - change object with instructions to be applied on the control
	 * @param {object} oControl - the control which has been determined by the selector id
	 * @public
	 * @name sap.ui.fl.changeHandler.PropertyChange#applyChange
	 */
	PropertyChange.prototype.applyChange = function(oChange, oControl) {

		try {
			var oDef = oChange.getDefinition();

			var propertyName = oDef.content.property;
			var propertyMetadata = oControl.getMetadata().getAllProperties()[propertyName];
			var propertySetter = propertyMetadata._sMutator;

			oControl[propertySetter](oDef.content.newValue);
		} catch (ex) {
			throw new Error("Applying property changes failed: " +  ex);
		}

	};

	/**
	 * Completes the change by adding change handler specific content
	 *
	 * @param {object} oChange change object to be completed
	 * @param {object} oSpecificChangeInfo with attribute property which contains an array which holds objects which have attributes
	 * 				   id and index - id is the id of the field to property and index the new position of the field in the smart form group
	 * @public
	 * @name sap.ui.fl.changeHandler.PropertyChange#completeChangeContent
	 */
	PropertyChange.prototype.completeChangeContent = function(oChange, oSpecificChangeInfo) {

		var oChangeJson = oChange.getDefinition();

		if (oSpecificChangeInfo.content) {

			oChangeJson.content = oSpecificChangeInfo.content;

		} else {

			throw new Error("oSpecificChangeInfo attribute required");

		}

	};

	return PropertyChange;
}, /* bExport= */true);

}; // end of sap/ui/fl/changeHandler/PropertyChange.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.changeHandler.UnhideControl') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.changeHandler.UnhideControl'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/changeHandler/UnhideControl",[
	'jquery.sap.global', './Base'
], function(jQuery, Base) {
	"use strict";

	/**
	 * Change handler for unhiding of a control.
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.UnhideControl
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 */
	var UnhideControl = function() {
	};
	UnhideControl.prototype = jQuery.sap.newObject(Base.prototype);

	/**
	 * Unhides a control.
	 *
	 * @param {sap.ui.fl.Change} oChange change object with instructions to be applied on the control map
	 * @param {sap.ui.core.Control} oControl control that matches the change selector for applying the change
	 * @public
	 */
	UnhideControl.prototype.applyChange = function(oChange, oControl) {

		if (oControl.setVisible) {
			oControl.setVisible(true);
		} else {
			throw new Error("Provided control instance has no setVisible method");
		}
	};

	/**
	 * Completes the change by adding change handler specific content
	 *
	 * @param {sap.ui.fl.Change} oChange change object to be completed
	 * @param {object} oSpecificChangeInfo as an empty object since no additional attributes are required for this operation
	 * @public
	 */
	UnhideControl.prototype.completeChangeContent = function(oChange, oSpecificChangeInfo) {

		var oChangeJson = oChange.getDefinition();

		if (!oChangeJson.content) {
			oChangeJson.content = {};
		}

	};

	return UnhideControl;
},
/* bExport= */true);

}; // end of sap/ui/fl/changeHandler/UnhideControl.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.core.FlexVisualizer') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.core.FlexVisualizer'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/core/FlexVisualizer",[
	"jquery.sap.global"
], function(jQuery) {
	"use strict";

	/**
	 * 
	 * @constructor 
	 * @alias sap.ui.fl.core.FlexVisualizer
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 *
	 */
	var FlexVisualizer = function() {

	};

	/**
	 * Show a dialog providing detailed options to do a change
	 * @param {Object} oAffectedRegistryItems Relevant registry items required by the dialog to display itself correctly
	 * @param {Boolean} bIsKeyUser Is the current user in key user mode
	 *
	 * @public	 
	 */
	FlexVisualizer.showDialog = function(oAffectedRegistryItems, bIsKeyUser) {

	};

	/**
	 * Close an open dialog explicitly
	 *
	 * @public	 
	 */
	FlexVisualizer.closeDialog = function() {

	};

	return FlexVisualizer;

}, true);

}; // end of sap/ui/fl/core/FlexVisualizer.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.fieldExt.Access') ) {
/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
/* global Promise */
jQuery.sap.declare('sap.ui.fl.fieldExt.Access'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
sap.ui.define("sap/ui/fl/fieldExt/Access",[], function() {
	"use strict";

	/**
	 * @namespace
	 * @alias sap.ui.fl.fieldExt.Access
	 * @experimental Since 1.25.0
	 * @author <NAME>
	 * @version 1.36.12
	 */
	var Access = {};

	/**
	 * Returns all Business Contexts for given service and EntityTypeName/EntitySetName. Not that only EntityTypeName or EntitySetName can be
	 * supplied. Providing both results in an exception
	 * 
	 * @param {string} sServiceUri
	 * @param {string} sEntityTypeName
	 * @param {string} sEntitySetName
	 * @returns {array} aBusinessContexts
	 * @public
	 */
	Access.getBusinessContexts = function(sServiceUri, sEntityTypeName, sEntitySetName) {
		// Determine ServiceName and ServiceVersion from Service URI
		var sServiceName = this._parseServiceName(sServiceUri);
		var sServiceVersion = this._parseServiceVersion(sServiceUri, sServiceName);

		// Build URL for BusinessContextRetrievalService based on ServiceName, ServiceVersion, EntityName
		var sBusinessContextRetrievalUri = this._buildBusinessContextRetrievalUri(sServiceName, sServiceVersion, sEntityTypeName, sEntitySetName);

		// Execute Ajax call
		var mAjaxSettings = this._getAjaxSettings();
		var promise = this._executeAjaxCall(sBusinessContextRetrievalUri, mAjaxSettings, sServiceName, sServiceVersion, sEntityTypeName, sEntitySetName);

		return promise;
	};

	/**
	 * Extracts ServiceName out of Service URI
	 * 
	 * @private
	 * @param {string} sServiceUri
	 * @returns {string} sVersionName
	 */
	Access._parseServiceName = function(sServiceUri) {
		var sServiceName, sServiceNameWithVersion;
		var sODataPath = "sap/opu/odata";

		var iIndexOfODataPath = sServiceUri.indexOf(sODataPath);
		if (iIndexOfODataPath !== -1) {
			// Remove service path prefix
			var iEndOfsODataPath = iIndexOfODataPath + sODataPath.length;
			sServiceNameWithVersion = sServiceUri.substring(iEndOfsODataPath);

            var sSapPrefix = "/SAP";
            var bHasSapPrefix = jQuery.sap.startsWith(sServiceNameWithVersion, sSapPrefix);
            if (bHasSapPrefix) {
				// case of sap specific namespace for the service
                sServiceNameWithVersion = sServiceNameWithVersion.substring(sSapPrefix.length);
            }
        } else {
			// Remove all stuff before and including the first slash
			var iStartPositionOfServiceName = sServiceUri.lastIndexOf("/") + 1;
			sServiceNameWithVersion = sServiceUri.substring(iStartPositionOfServiceName);
		}

		if (sServiceNameWithVersion.indexOf(";v=") != -1) {
			// Cut away all URI stuff that comes before the serviceName
			sServiceName = sServiceNameWithVersion.substring(0, sServiceNameWithVersion.indexOf(";v="));
		} else {
			sServiceName = sServiceNameWithVersion;
		}
		return sServiceName;
	};

	/**
	 * Extracts ServiceVersion out of Service URI
	 * 
	 * @private
	 * @param {string} sServiceUri
	 * @param {string} sServiceName
	 * @returns {string} sVersionNumber
	 */
	Access._parseServiceVersion = function(sServiceUri, sServiceName) {
		if (sServiceUri.indexOf(sServiceName + ";v=") != -1) {
			// Cut away all URI stuff that comes before the serviceName
			var iPositionOfServiceWithVersionFragment = sServiceUri.indexOf(sServiceName + ";v=");
			var sRemainingUri = sServiceUri.substring(iPositionOfServiceWithVersionFragment);

			// Get String from ";v=" up to the next "/" --> this is the version
			// number
			var iPositionAfterVersionPrefix = sServiceName.length + 3;
			var sVersionNumber = sRemainingUri.slice(iPositionAfterVersionPrefix, sRemainingUri.indexOf("/"));

			return sVersionNumber;
		} else {// In this case there is no version information and so it is
			// version 1
			return "0001";
		}
	};

	/**
	 * Builds URI for BusinessContext Retrieval
	 * 
	 * @private
	 * @param {string} sServiceUri
	 * @param {string} sServiceName
	 * @param {string} sEntityName
	 * @param {string} sEntitySetName
	 * @returns {string} sBusinessContextRetrievalUri
	 */
	Access._buildBusinessContextRetrievalUri = function(sServiceName, sServiceVersion, sEntityName, sEntitySetName) {
		if (sEntityName == null) {
			sEntityName = '';
		}
		if (sEntitySetName == null) {
			sEntitySetName = '';
		}

		if (((sEntitySetName.length == 0) && (sEntityName.length == 0)) || (!(sEntitySetName.length == 0) && !(sEntityName.length == 0))) {
			throw new Error("sap.ui.fl.fieldExt.Access._buildBusinessContextRetrievalUri()" + "Inconsistent input parameters EntityName: " + sEntityName + " EntitySet: " + sEntitySetName);
		}

		// Example call:
		// sap/opu/odata/SAP/APS_CUSTOM_FIELD_MAINTENANCE_SRV/GetBusinessContextsByEntityType?EntitySetName=''&EntityTypeName='BusinessPartner'&ServiceName='CFD_TSM_BUPA_MAINT_SRV'&ServiceVersion='0001'&$format=json
		var sBusinessContextRetrievalUri = "/sap/opu/odata/SAP/APS_CUSTOM_FIELD_MAINTENANCE_SRV/GetBusinessContextsByEntityType?" + "EntitySetName=\'" + sEntitySetName + "\'" + "&EntityTypeName=\'" + sEntityName + "\'" + "&ServiceName=\'" + sServiceName + "\'" + "&ServiceVersion=\'" + sServiceVersion + "\'" + "&$format=json";
		return sBusinessContextRetrievalUri;
	};

	/**
	 * Executes Ajax Call for BusinessContext Retrieval
	 * 
	 * @private
	 * @param {string} sBusinessContextRetrievalUri
	 * @param {map} mRequestSettings
	 * @param {string} sServiceName
	 * @param {string} sServiceVersion
	 * @param {string} sEntityName
	 * @returns {Object} oPromise
	 */
	Access._executeAjaxCall = function(sBusinessContextRetrievalUri, mRequestSettings, sServiceName, sServiceVersion, sEntityType, sEntitySetName) {
		var that = this;
		var oDeferred = jQuery.Deferred();

		jQuery.ajax(sBusinessContextRetrievalUri, mRequestSettings).done(function(data, textStatus, jqXHR) {
			var aBusinessContexts = [];
			if (data) {
				var aBusinessContexts = that._extractBusinessContexts(data);
			}

			var oResult = {
				BusinessContexts: aBusinessContexts,
				ServiceName: sServiceName,
				ServiceVersion: sServiceVersion
			};
			oDeferred.resolve(oResult);

		}).fail(function(jqXHR, textStatus, errorThrown) {
			var aErrorMessages = that._getMessagesFromXHR(jqXHR);
			var oError = {
				errorOccured: true,
				errorMessages: aErrorMessages,
				serviceName: sServiceName,
				serviceVersion: sServiceVersion,
				entityType: sEntityType,
				entitySet: sEntitySetName
			};
			oDeferred.reject(oError);
		});

		return oDeferred.promise();
	};

	/**
	 * @private
	 * @returns {map} mSettings
	 */
	Access._getAjaxSettings = function() {
		var mSettings = {
			type: "GET",
			async: true,
			dataType: 'json'
		};
		return mSettings;
	};

	/**
	 * Extracts BusinessContext out of Request response data
	 * 
	 * @private
	 * @param {object} oData
	 * @returns {array} BusinessContexts
	 */
	Access._extractBusinessContexts = function(data) {
		var aResults = null;
		var aBusinessContexts = [];
		if (data && data.d) {
			aResults = data.d.results;
		}

		if (aResults !== null && aResults.length > 0) {
			for (var i = 0; i < aResults.length; i++) {
				if (aResults[i].BusinessContext !== null) {
					aBusinessContexts.push(aResults[i].BusinessContext);
				}
			}
		}

		return aBusinessContexts;
	};

	/**
	 * Extracts error messages from request failure response
	 * 
	 * @private
	 * @param {object} oXHR
	 * @returns {array} errorMessages
	 */
	Access._getMessagesFromXHR = function(oXHR) {
		var aMessages = [];
		try {
			var oErrorResponse = JSON.parse(oXHR.responseText);
			if (oErrorResponse && oErrorResponse.error && oErrorResponse.error.message && oErrorResponse.error.message.value && oErrorResponse.error.message.value !== '') {
				aMessages.push({
					severity: "error",
					text: oErrorResponse.error.message.value
				});
			} else {
				aMessages.push({
					severity: "error",
					text: oXHR.responseText
				});
			}

		} catch (e) {
			// ignore
		}
		return aMessages;
	};

	return Access;
}, /* bExport= */true);

}; // end of sap/ui/fl/fieldExt/Access.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.registry.ChangeRegistryItem') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.registry.ChangeRegistryItem'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/registry/ChangeRegistryItem",[
	"sap/ui/fl/Utils", "jquery.sap.global"
], function(Utils, jQuery) {
	"use strict";

	/**
	 * Object to define a change on a specific control type with it's permissions
	 * @constructor	 
	 * @param {Object} mParam Parameter description below
	 * @param {sap.ui.fl.registry.ChangeTypeMetadata} mParam.changeTypeMetadata Change type metadata this registry item is describing 
	 * @param {String} mParam.controlType Control type this registry item is assigned to
	 * @param {Object} [mParam.permittedRoles] Permissions who is allowed to use this kind of change type on the assigned control	 
	 * @alias sap.ui.fl.registry.ChangeRegistryItem
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 *
	 */
	var ChangeRegistryItem = function(mParam) {
		if (!mParam.changeTypeMetadata) {
			Utils.log.error("sap.ui.fl.registry.ChangeRegistryItem: ChangeTypeMetadata required");
		}
		if (!mParam.controlType) {
			Utils.log.error("sap.ui.fl.registry.ChangeRegistryItem: ControlType required");
		}

		this._changeTypeMetadata = mParam.changeTypeMetadata;
		this._controlType = mParam.controlType;

		if (mParam.permittedRoles) {
			this._permittedRoles = mParam.permittedRoles;
		}

		if (mParam.dragTargets) {
			this._dragTargets = mParam.dragTargets;
		}
	};

	ChangeRegistryItem.prototype._changeTypeMetadata = undefined;
	ChangeRegistryItem.prototype._controlType = undefined;
	ChangeRegistryItem.prototype._permittedRoles = {};
	ChangeRegistryItem.prototype._dragTargets = [];

	/**
	 * Get the metadata for a change type
	 * 
	 * @returns {sap.ui.fl.registry.ChangeTypeMetadata} Returns the change type metadata of the item
	 *
	 * @public	 
	 */
	ChangeRegistryItem.prototype.getChangeTypeMetadata = function() {
		return this._changeTypeMetadata;
	};

	/**
	 * Get the name of a change type
	 * 
	 * @returns {String} Returns the name of the change type of the item
	 *
	 * @public	 
	 */
	ChangeRegistryItem.prototype.getChangeTypeName = function() {
		return this._changeTypeMetadata.getName();
	};

	/**
	 * Get the control type
	 * 
	 * @returns {String} Returns the control type the item is assigned to
	 *
	 * @public	 
	 */
	ChangeRegistryItem.prototype.getControlType = function() {
		return this._controlType;
	};

	/**
	 * Get the roles the change type for the control is permitted to
	 * 
	 * @returns {String} Returns a list of permitted roles
	 *
	 * @public	 
	 */
	ChangeRegistryItem.prototype.getPermittedRoles = function() {
		return this._permittedRoles;
	};

	/**
	 * Get the targets the control type can be dragged on
	 * 
	 * @returns {String} Returns a list of possible drag targets
	 *
	 * @public	 
	 */
	ChangeRegistryItem.prototype.getDragTargets = function() {
		return this._dragTargets;
	};

	return ChangeRegistryItem;
}, true);

}; // end of sap/ui/fl/registry/ChangeRegistryItem.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.registry.ChangeTypeMetadata') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.registry.ChangeTypeMetadata'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/registry/ChangeTypeMetadata",[
	"sap/ui/fl/Utils", "jquery.sap.global"
], function(Utils, jQuery) {
	"use strict";

	/**
	 * Object to define a change type with it's handlers and visual appearance options
	 * @constructor	 
	 * @param {Object} mParam Parameter description below
	 * @param {String} mParam.name Semantic name to identify the change type
	 * @param {String} mParam.changeHandler Full qualified name of the function which is executed when a change for this change type is merged or applied
	 * @param {String} [mParam.labelKey] Key of the translatable label
	 * @param {String} [mParam.tooltipKey] Key of the translatable tooltip
	 * @param {String} [mParam.iconKey] Key of the icon which should be displayed
	 * @param {Object} [mParam.sortIndex] Index to sort the change type on the visualization. (0 = default, lowest priority)
	 * @alias sap.ui.fl.registry.ChangeTypeMetadata
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 *
	 */
	var ChangeTypeMetadata = function(mParam) {
		if (!mParam.name) {
			Utils.log.error("sap.ui.fl.registry.ChangeType: Name required");
		}
		if (!mParam.changeHandler) {
			Utils.log.error("sap.ui.fl.registry.ChangeType: ChangeHandler required");
		}

		this._name = mParam.name;
		this._changeHandler = mParam.changeHandler;

		if (mParam.labelKey) {
			this._labelKey = mParam.labelKey;
		}
		if (mParam.tooltipKey) {
			this._tooltipKey = mParam.tooltipKey;
		}
		if (mParam.iconKey) {
			this._iconKey = mParam.iconKey;
		}
		if (mParam.sortIndex) {
			this._sortIndex = mParam.sortIndex;
		}
	};

	ChangeTypeMetadata.prototype._name = "";
	ChangeTypeMetadata.prototype._changeHandler = "";
	ChangeTypeMetadata.prototype._sortIndex = 0;
	ChangeTypeMetadata.prototype._labelKey = "";
	ChangeTypeMetadata.prototype._tooltipKey = "";
	ChangeTypeMetadata.prototype._iconKey = "";

	/**
	 * Get the semantical name of the change type
	 * @returns {String} Returns the semantical name of the change type
	 * @public
	 */
	ChangeTypeMetadata.prototype.getName = function() {
		return this._name;
	};

	/**
	 * Get the full qualified name of the change handler function
	 * @returns {String} Returns the full qualified name of the change handler function
	 * @public
	 */
	ChangeTypeMetadata.prototype.getChangeHandler = function() {
		return this._changeHandler;
	};

	/**
	 * Get the translated label text for this type of change
	 * @returns {String} Returns the translated label text for this type of change
	 * @public
	 */
	ChangeTypeMetadata.prototype.getLabel = function() {
		return this._labelKey; //TODO: Add call with translation
	};

	/**
	 * Get the translated tooltip text for this type of change
	 * @returns {String} Returns the translated tooltip text for this type of change
	 * @public
	 */
	ChangeTypeMetadata.prototype.getTooltip = function() {
		//TODO: Add call with translation
		return this._tooltipKey;
	};

	/**
	 * Get the path to the icon which should be displayed for this type of change
	 * @returns {String} Returns the path to the icon which should be displayed for this type of change
	 * @public
	 */
	ChangeTypeMetadata.prototype.getIcon = function() {
		return this._iconKey; //TODO: Add call to get icon path
	};

	/**
	 * Get the sort index of this type of change
	 * @returns {String} Returns the sort index of this type of change
	 * @public
	 */
	ChangeTypeMetadata.prototype.getSortIndex = function() {
		return this._sortIndex;
	};

	return ChangeTypeMetadata;
}, true);

}; // end of sap/ui/fl/registry/ChangeTypeMetadata.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.registry.SimpleChanges') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.registry.SimpleChanges'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/registry/SimpleChanges",[
	"jquery.sap.global", "sap/ui/fl/changeHandler/HideControl", "sap/ui/fl/changeHandler/UnhideControl", "sap/ui/fl/changeHandler/MoveElements", "sap/ui/fl/changeHandler/PropertyChange"
], function(jQuery, HideControl, UnhideControl, MoveElements, PropertyChange) {
	"use strict";

	/**
	 * Object containing standard changes like labelChange. Structure is like this: <code> { "labelChange":{"changeType":"labelChange", "changeHandler":sap.ui.fl.changeHandler.LabelChange}} </code>
	 * @constructor	 	  
	 * @alias sap.ui.fl.registry.SimpleChanges
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 *
	 */
	var SimpleChanges = {
		hideControl: {
			changeType: "hideControl",
			changeHandler: HideControl
		},
		unhideControl: {
			changeType: "unhideControl",
			changeHandler: UnhideControl
		},
		moveElements: {
			changeType: "moveElements",
			changeHandler: MoveElements
		},
		propertyChange : {
			changeType: "propertyChange",
			changeHandler: PropertyChange 
		}
	};

	return SimpleChanges;

}, true);

}; // end of sap/ui/fl/registry/SimpleChanges.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.Cache') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.Cache'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
sap.ui.define("sap/ui/fl/Cache",["sap/ui/fl/Utils"], function(Utils) {
	"use strict";

	/**
	 * Helper object to access a change from the backend.
	 * Access helper object for each change (and variant) which was fetched from the backend
	 *
	 * @namespace
	 * @alias sap.ui.fl.Cache
	 * @experimental Since 1.25.0
	 * @author SAP SE
	 * @version 1.36.12
	 */
	var Cache = function() {
	};

	Cache._isOn = true;

	Cache._entries = {};

	/**
	 * Indicates if the cache is active or not (for testing)
	 * 
	 * @returns {boolean} Is Cache currently active or not
	 *
	 * @public
	 */
	Cache.isActive = function() {
		return Cache._isOn;
	};

	/**
	 * Sets the active state
	 * 
	 * @param {boolean} bActive - cache active or not
	 *
	 * @public
	 */
	Cache.setActive = function(bActive) {
		Cache._isOn = bActive;
	};

	/**
	 * This method retrieves the changes for a given
	 * component. It answers all subsequent calls with the same promise, which
	 * will resolve with the same result. In the success case, it will keep the
	 * promise to resolve all calls in future event loop execution paths with 
	 * the same result. In case of an error, it will delete the initial promise
	 * to give calls from future execution paths the chance to re-request the 
	 * changes from the backend.
	 *
	 * If the cache is not active, the method just delegates the call to the
	 * loadChanges method of the given LrepConnector.
	 * 
	 * @param {sap.ui.fl.LrepConnector} oLrepConnector - LrepConnector instance to retrieve the changes with
	 * @param {string} sComponentName - the component name to retrieve the changes for
	 * @param {map} mPropertyBag - (optional) contains additional data that are needed for reading of changes
	 * - appDescriptor that belongs to actual component
	 * - siteId that belongs to actual component
	 * @returns {Promise} resolves with the change file for the given component, either from cache or backend
	 *
	 * @public
	 */
	Cache.getChangesFillingCache = function(oLrepConnector, sComponentName, mPropertyBag) {
		if (!this.isActive()) {
			return oLrepConnector.loadChanges(sComponentName, mPropertyBag);
		}

		var oCacheEntry = Cache._entries[sComponentName];

		if (!oCacheEntry) {
			oCacheEntry = Cache._entries[sComponentName] = {};
		}

		if (oCacheEntry.promise) {
			return oCacheEntry.promise;
		}

		var currentLoadChanges = oLrepConnector.loadChanges(sComponentName, mPropertyBag).then(function(mChanges) {
			if (oCacheEntry.file) {
				Utils.log.error('sap.ui.fl.Cache: Cached changes for component ' + sComponentName + ' overwritten.');
			}

			oCacheEntry.file = mChanges;
			return oCacheEntry.file;
		}, function(err) {
			delete oCacheEntry.promise;
			throw err;
		});

		oCacheEntry.promise = currentLoadChanges;

		return currentLoadChanges;
	};

	/**
	 * @private
	 *
	 * @param {string} sComponentName - name of the SAPUI5 component
	 * @returns {array} Array of changes
	 */
	Cache._getChangeArray = function(sComponentName) {
		var oEntry = Cache._entries[sComponentName];
		if (oEntry) {
			if (oEntry.file) {
				return oEntry.file.changes.changes;
			}
		}
	};

	/**
	 * Add a change for the given component to the cached changes.
	 *
	 * @param {string} sComponentName Name of the component
	 * @param {object} oChange The change in JSON format
	 * @public
	 */
	Cache.addChange = function(sComponentName, oChange) {
		var aChanges = Cache._getChangeArray(sComponentName);

		if (!aChanges) {
			return;
		}

		aChanges.push(oChange);
	};

	/**
	 * Updates a change for the given component in the cached changes.
	 *
	 * @param {string} sComponentName Name of the component
	 * @param {object} oChange The change in JSON format
	 * @public
	 */
	Cache.updateChange = function(sComponentName, oChange) {
		var aChanges = Cache._getChangeArray(sComponentName);

		if (!aChanges) {
			return;
		}

		for ( var i = 0; i < aChanges.length; i++) {
			if (aChanges[i].fileName === oChange.fileName) {
				aChanges.splice(i, 1, oChange);
				break;
			}
		}
	};

	/**
	 * Delete a change for the given component from the cached changes.
	 *
	 * @param {string} sComponentName Name of the SAPUI5 component
	 * @param {object} oChangeDefinition The change in JSON format
	 * @public
	 */
	Cache.deleteChange = function(sComponentName, oChangeDefinition) {
		var aChanges = Cache._getChangeArray(sComponentName);

		if (!aChanges) {
			return;
		}

		for ( var i = 0; i < aChanges.length; i++) {
			if (aChanges[i].fileName === oChangeDefinition.fileName) {
				aChanges.splice(i, 1);
				break;
			}
		}
	};

	return Cache;
}, /* bExport= */true);

}; // end of sap/ui/fl/Cache.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.LrepConnector') ) {
/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
/* global Promise */

jQuery.sap.declare('sap.ui.fl.LrepConnector'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.thirdparty.URI'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/LrepConnector",[
	"jquery.sap.global", "sap/ui/thirdparty/URI", "sap/ui/fl/Utils"
], function(jQuery, uri, FlexUtils) {
	"use strict";

	/**
	 * Provides the connectivity to the ABAP based LRep REST-service
	 * 
	 * @param {object} [mParameters] - map of parameters, see below
	 * @param {String} [mParameters.XsrfToken] - XSRF Token which can be reused for the backend connectivity. If no XSRF token is passed, a new one
	 *        will be fetched from backend.
	 * @constructor
	 * @alias sap.ui.fl.LrepConnector
	 * @experimental Since 1.25.0
	 * @author SAP SE
	 * @version 1.36.12
	 */
	var Connector = function(mParameters) {
		this._initClientParam();
		this._initLanguageParam();
		if (mParameters) {
			this._sXsrfToken = mParameters.XsrfToken;
		}

	};

	Connector.createConnector = function(mParameters) {
		return new Connector(mParameters);
	};

	Connector.prototype.DEFAULT_CONTENT_TYPE = "application/json";
	Connector.prototype._sClient = undefined;
	Connector.prototype._sLanguage = undefined;
	Connector.prototype._aSentRequestListeners = [];

	/**
	 * Registers a callback for a sent request to the backend. The callback is called for each change done one time! Each call is done with an object
	 * similar to the resolve of the promises containing a <code>status</code> of the response from the backend i.e. <code>success</code>, a
	 * <code>response</code> containing the change processed in this request
	 * 
	 * @param {function} fCallback function called after all related promises are resolved
	 * @public
	 */
	Connector.attachSentRequest = function(fCallback) {
		if (typeof fCallback === "function" && Connector.prototype._aSentRequestListeners.indexOf(fCallback) === -1) {
			Connector.prototype._aSentRequestListeners.push(fCallback);
		}
	};

	/**
	 * Deregisters a callback for a sent request to the backend if the callback was registered
	 * 
	 * @param {function} fCallback function called after all related promises are resolved
	 * @public
	 */
	Connector.detachSentRequest = function(fCallback) {
		var iIndex = Connector.prototype._aSentRequestListeners.indexOf(fCallback);
		if (iIndex !== -1) {
			Connector.prototype._aSentRequestListeners.splice(iIndex, 1);
		}
	};

	/**
	 * Extract client from current running instance
	 * 
	 * @private
	 */
	Connector.prototype._initClientParam = function() {
		var client = FlexUtils.getClient();
		if (client) {
			this._sClient = client;
		}
	};

	/**
	 * Extract the sap-language url parameter from current url
	 * 
	 * @private
	 */
	Connector.prototype._initLanguageParam = function() {
		var sLanguage;
		sLanguage = this._getUrlParameter('sap-language') || this._getUrlParameter('sap-ui-language');
		if (sLanguage) {
			this._sLanguage = sLanguage;
		}
	};

	/**
	 * Returns the a string containing all url parameters of the current window.location
	 * 
	 * @returns {string} Substring of url containing the url query parameters
	 * @private
	 */
	Connector.prototype._getAllUrlParameters = function() {
		return window.location.search.substring(1);
	};

	/**
	 * Returns the value of the specified url parameter of the current url
	 * 
	 * @param {String} sParameterName - Name of the url parameter
	 * @returns {string} url parameter
	 * @private
	 */
	Connector.prototype._getUrlParameter = function(sParameterName) {
		var aURLVariables, sUrlParams, i, aCurrentParameter;
		sUrlParams = this._getAllUrlParameters();
		aURLVariables = sUrlParams.split('&');
		for (i = 0; i < aURLVariables.length; i++) {
			aCurrentParameter = aURLVariables[i].split('=');
			if (aCurrentParameter[0] === sParameterName) {
				return aCurrentParameter[1];
			}
		}
	};

	/**
	 * Resolve the complete url of a request by taking the backendUrl and the relative url from the request
	 * 
	 * @param {String} sRelativeUrl - relative url of the current request
	 * @returns {sap.ui.core.URI} returns the complete uri for this request
	 * @private
	 */
	Connector.prototype._resolveUrl = function(sRelativeUrl) {
		if (!jQuery.sap.startsWith(sRelativeUrl, "/")) {
			sRelativeUrl = "/" + sRelativeUrl;
		}
		var oUri = uri(sRelativeUrl).absoluteTo("");
		return oUri.toString();
	};

	/**
	 * Get the default header for a request
	 * 
	 * @returns {Object} Returns an object containing all headers for each request
	 * @private
	 */
	Connector.prototype._getDefaultHeader = function() {
		var mHeaders = {
			headers: {
				"X-CSRF-Token": this._sXsrfToken || "fetch"
			}
		};
		return mHeaders;
	};

	/**
	 * Get the default options, required for the jQuery.ajax request
	 * 
	 * @param {String} sMethod - HTTP-method (PUT, POST, GET (default)...) used for this request
	 * @param {String} sContentType - Set the content-type manually and overwrite the default (application/json)
	 * @param {Object} oData - Payload of the request
	 * @returns {Object} Returns an object containing the options and the default header for a jQuery.ajax request
	 * @private
	 */
	Connector.prototype._getDefaultOptions = function(sMethod, sContentType, oData) {
		var mOptions;
		if (!sContentType) {
			sContentType = this.DEFAULT_CONTENT_TYPE;
		}

		mOptions = jQuery.extend(true, this._getDefaultHeader(), {
			type: sMethod,
			async: true,
			contentType: sContentType,
			processData: false,
			//xhrFields: {
			//	withCredentials: true
			//},
			headers: {
				"Content-Type": sContentType
			}
		});

		if (oData && mOptions.contentType === 'application/json') {
			mOptions.dataType = 'json';
			if (typeof oData === 'object') {
				mOptions.data = JSON.stringify(oData);
			} else {
				mOptions.data = oData;
			}
		} else if (oData) {
			mOptions.data = oData;
		}

		if (sMethod === 'DELETE') {
			delete mOptions.data;
			delete mOptions.contentType;
		}

		return mOptions;
	};

	/**
	 * Send a request to the backend
	 * 
	 * @param {String} sUri Relative url for this request
	 * @param {String} sMethod HTTP-method to be used by this request (default GET)
	 * @param {Object} oData Payload of the request
	 * @param {Object} mOptions Additional options which should be used in the request
	 * @returns {Promise} Returns a promise to the result of the request
	 * @public
	 */
	Connector.prototype.send = function(sUri, sMethod, oData, mOptions) {
		sMethod = sMethod || "GET";
		sMethod = sMethod.toUpperCase();
		mOptions = mOptions || {};
		sUri = this._resolveUrl(sUri);

		if (mOptions.success || mOptions.error) {
			var sErrorMessage = "Success and error handler are not allowed in mOptions";
			throw new Error(sErrorMessage);
		}

		var sContentType = mOptions.contentType || this.DEFAULT_CONTENT_TYPE;

		mOptions = jQuery.extend(true, this._getDefaultOptions(sMethod, sContentType, oData), mOptions);

		return this._sendAjaxRequest(sUri, mOptions);
	};

	/**
	 * Extracts the messages from the backend reponse
	 * 
	 * @param {Object} oXHR - ajax request object
	 * @returns {Array} Array of messages, for example <code>[ { "severity": "Error", "text": "content id must be non-initial" } ] </code>
	 * @private
	 */
	Connector.prototype._getMessagesFromXHR = function(oXHR) {
		var errorResponse, aMessages, length, i;
		aMessages = [];
		try {
			errorResponse = JSON.parse(oXHR.responseText);
			if (errorResponse && errorResponse.messages && errorResponse.messages.length > 0) {
				length = errorResponse.messages.length;
				for (i = 0; i < length; i++) {
					aMessages.push({
						severity: errorResponse.messages[i].severity,
						text: errorResponse.messages[i].text
					});
				}
			}
		} catch (e) {
			// ignore
		}

		return aMessages;
	};

	/**
	 * @param {String} sUri - Complete request url
	 * @param {Object} mOptions - Options to be used by the request
	 * @returns {Promise} Returns a Promise with the status and response and messages
	 * @private
	 */
	Connector.prototype._sendAjaxRequest = function(sUri, mOptions) {
		var that = this;
		var sFetchXsrfTokenUrl = "/sap/bc/lrep/actions/getcsrftoken/";
		var mFetchXsrfTokenOptions = {
			headers: {
				'X-CSRF-Token': 'fetch'
			},
			type: "HEAD"
		};

		if (this._sClient) {
			mFetchXsrfTokenOptions.headers['sap-client'] = this._sClient;
		}

		return new Promise(function(resolve, reject) {
			function handleValidRequest(oResponse, sStatus, oXhr) {

				var sNewCsrfToken = oXhr.getResponseHeader("X-CSRF-Token");
				that._sXsrfToken = sNewCsrfToken || that._sXsrfToken;

				var oResult = {
					status: sStatus,
					response: oResponse
				};

				resolve(oResult);

				jQuery.each(that._aSentRequestListeners, function(iIndex, fCallback) {
					fCallback(oResult);
				});
			}

			function fetchTokenAndHandleRequest(oResponse, sStatus, oXhr) {
				that._sXsrfToken = oXhr.getResponseHeader("X-CSRF-Token");
				mOptions.headers = mOptions.headers || {};
				mOptions.headers["X-CSRF-Token"] = that._sXsrfToken;

				// Re-send request after fetching token
				jQuery.ajax(sUri, mOptions).done(handleValidRequest).fail(function(oXhr, sStatus, sErrorThrown) {
					var oError = new Error(sErrorThrown);
					oError.status = "error";
					oError.code = oXhr.statusCode().status;
					oError.messages = that._getMessagesFromXHR(oXhr);
					reject(oError);
				});
			}

			function refetchTokenAndRequestAgainOrHandleInvalidRequest(oXhr, sStatus, sErrorThrown) {
				if (oXhr.status === 403) {
					// Token seems to be invalid, refetch and then resend
					jQuery.ajax(sFetchXsrfTokenUrl, mFetchXsrfTokenOptions).done(fetchTokenAndHandleRequest).fail(function(oXhr, sStatus, sErrorThrown) {
						// Fetching XSRF Token failed
						reject({
							status: "error"
						});
					});
				} else {
					if (mOptions && mOptions.type === "DELETE" && oXhr.status === 404) {
						// Do not reject, if a file was not found during deletion
						// (can be the case if another user already triggered a restore meanwhile)
						resolve();
					} else {
						var result;
						result = {
							status: "error"
						};
						result.code = oXhr.statusCode().status;
						result.messages = that._getMessagesFromXHR(oXhr);
						reject(result);
					}
				}
			}

			//Check, whether CSRF token has to be requested
			var bRequestCSRFToken = true;
			if (mOptions && mOptions.type) {
				if (mOptions.type === 'GET' || mOptions.type === 'HEAD') {
					bRequestCSRFToken = false;
				}
			} else {
				if (that._sXsrfToken && that._sXsrfToken !== "fetch") {
					bRequestCSRFToken = false;
				}
			}
			
			if (bRequestCSRFToken) {
				// Fetch XSRF Token
				jQuery.ajax(sFetchXsrfTokenUrl, mFetchXsrfTokenOptions).done(fetchTokenAndHandleRequest).fail(function(oXhr, sStatus, sErrorThrown) {
					// Fetching XSRF Token failed
					reject({
						status: "error"
					});
				});
			} else {
				// Send normal request
				jQuery.ajax(sUri, mOptions).done(handleValidRequest).fail(refetchTokenAndRequestAgainOrHandleInvalidRequest);
			}
		});
	};

	/**
	 * Loads the changes for the given component class name.
	 * 
	 * @see sap.ui.core.Component
	 * @param {String} sComponentClassName - Component class name
	 * @param {map} mPropertyBag - (optional) contains additional data that are needed for reading of changes - appDescriptor that belongs to actual
	 *        component - siteId that belongs to actual component
	 * @returns {Promise} Returns a Promise with the changes and componentClassName
	 * @public
	 */
	Connector.prototype.loadChanges = function(sComponentClassName, mPropertyBag) {
		var sUri, oPromise, mOptions;
		var that = this;

		if (!sComponentClassName) {
			return Promise.reject(new Error('Component name not specified'));
		}

		sUri = '/sap/bc/lrep/flex/data/';
		if (sComponentClassName) {
			sUri += sComponentClassName;
		}
		if (this._sClient) {
			sUri += '&sap-client=' + this._sClient;
		}
		// Replace first & with ?
		sUri = sUri.replace('&', '?');

		// fill header attribute: appDescriptor.id
		if (mPropertyBag) {
			if (mPropertyBag.appDescriptor) {
				if (mPropertyBag.appDescriptor["sap.app"]) {
					if (!mOptions) {
						mOptions = {};
					}

					if (!mOptions.headers) {
						mOptions.headers = {};
					}

					mOptions.headers = {
						"X-LRep-AppDescriptor-Id": mPropertyBag.appDescriptor["sap.app"].id
					};
				}
			}

			// fill header attribute: siteId
			if (mPropertyBag.siteId) {
				if (!mOptions) {
					mOptions = {};
				}

				if (!mOptions.headers) {
					mOptions.headers = {};
				}

				mOptions.headers = {
					"X-LRep-Site-Id": mPropertyBag.siteId
				};
			}
		}

		oPromise = this.send(sUri, undefined, undefined, mOptions);
		return oPromise.then(function(oResponse) {
			if (oResponse.response) {
				return {
					changes: oResponse.response,
					messagebundle: oResponse.response.messagebundle,
					componentClassName: sComponentClassName
				};
			} else {
				return Promise.reject('response is empty');
			}
		}, function(oError) {
			if (oError.code === 404 || oError.code === 405) {
				// load changes based old route, because new route is not implemented
				return that._loadChangesBasedOnOldRoute(sComponentClassName);
			} else {
				throw (oError);
			}
		});
	};

	Connector.prototype._loadChangesBasedOnOldRoute = function(sComponentClassName) {
		var resourceName, params;

		try {
			resourceName = jQuery.sap.getResourceName(sComponentClassName, "-changes.json");
		} catch (e) {
			return Promise.reject(e);
		}

		params = {
			async: true,
			dataType: "json",
			failOnError: true,
			headers: {
				"X-UI5-Component": sComponentClassName
			}
		};

		if (this._sClient) {
			params.headers["sap-client"] = this._sClient;
		}

		return jQuery.sap.loadResource(resourceName, params).then(function(oResponse) {
			return {
				changes: oResponse,
				componentClassName: sComponentClassName
			};
		});
	};

	/**
	 * @param {Array} aParams Array of parameter objects in format {name:<name>, value:<value>}
	 * @returns {String} Returns a String with all parameters concatenated
	 * @private
	 */
	Connector.prototype._buildParams = function(aParams) {
		if (!aParams) {
			aParams = [];
		}
		if (this._sClient) {
			// Add mandatory 'sap-client' parameter
			aParams.push({
				name: "sap-client",
				value: this._sClient
			});
		}

		if (this._sLanguage) {
			// Add mandatory 'sap-language' url parameter.
			// sap-language shall be used only if there is a sap-language parameter in the original url.
			// If sap-language is not added, the browser language might be used as backend login language instead of sap-language.
			aParams.push({
				name: "sap-language",
				value: this._sLanguage
			});
		}

		var result = "";
		var len = aParams.length;
		for (var i = 0; i < len; i++) {
			if (i === 0) {
				result += "?";
			} else if (i > 0 && i < len) {
				result += "&";
			}
			result += aParams[i].name + "=" + aParams[i].value;
		}
		return result;
	};

	/**
	 * The URL prefix of the REST API for example /sap/bc/lrep/changes/.
	 * 
	 * @param {Boolean} bIsVariant Flag whether the change is of type variant
	 * @returns {String} url prefix
	 * @private
	 */
	Connector.prototype._getUrlPrefix = function(bIsVariant) {
		if (bIsVariant) {
			return "/sap/bc/lrep/variants/";
		}
		return "/sap/bc/lrep/changes/";
	};

	/**
	 * Creates a change or variant via REST call.
	 * 
	 * @param {Object} oPayload The content which is send to the server
	 * @param {String} [sChangelist] The transport ID.
	 * @param {Boolean} bIsVariant - is variant?
	 * @returns {Object} Returns the result from the request
	 * @public
	 */
	Connector.prototype.create = function(oPayload, sChangelist, bIsVariant) {
		var sRequestPath = this._getUrlPrefix(bIsVariant);

		var aParams = [];
		if (sChangelist) {
			aParams.push({
				name: "changelist",
				value: sChangelist
			});
		}

		sRequestPath += this._buildParams(aParams);

		return this.send(sRequestPath, "POST", oPayload, null);
	};

	/**
	 * Update a change or variant via REST call.
	 * 
	 * @param {Object} oPayload The content which is send to the server
	 * @param {String} sChangeName Name of the change
	 * @param {String} sChangelist (optional) The transport ID.
	 * @param {Boolean} bIsVariant - is variant?
	 * @returns {Object} Returns the result from the request
	 * @public
	 */
	Connector.prototype.update = function(oPayload, sChangeName, sChangelist, bIsVariant) {
		var sRequestPath = this._getUrlPrefix(bIsVariant);
		sRequestPath += sChangeName;

		var aParams = [];
		if (sChangelist) {
			aParams.push({
				name: "changelist",
				value: sChangelist
			});
		}

		sRequestPath += this._buildParams(aParams);

		return this.send(sRequestPath, "PUT", oPayload, null);
	};

	/**
	 * Delete a change or variant via REST call.
	 * 
	 * @param {String} mParameters property bag
	 * @param {String} mParameters.sChangeName - name of the change
	 * @param {String} [mParameters.sLayer='USER'] - other possible layers: VENDOR,PARTNER,CUSTOMER
	 * @param {String} mParameters.sNamespace - the namespace of the change file
	 * @param {String} mParameters.sChangelist - The transport ID.
	 * @param {Boolean} bIsVariant - is it a variant?
	 * @returns {Object} Returns the result from the request
	 * @public
	 */
	Connector.prototype.deleteChange = function(mParameters, bIsVariant) {
		// REVISE rename to deleteFile
		var sRequestPath = this._getUrlPrefix(bIsVariant);
		sRequestPath += mParameters.sChangeName;

		var aParams = [];
		if (mParameters.sLayer) {
			aParams.push({
				name: "layer",
				value: mParameters.sLayer
			});
		}
		if (mParameters.sNamespace) {
			aParams.push({
				name: "namespace",
				value: mParameters.sNamespace
			});
		}
		if (mParameters.sChangelist) {
			aParams.push({
				name: "changelist",
				value: mParameters.sChangelist
			});
		}

		sRequestPath += this._buildParams(aParams);

		return this.send(sRequestPath, "DELETE", {}, null);
	};

	/**
	 * Authenticated access to a resource in the Lrep
	 * 
	 * @param {String} sNamespace The abap package goes here. It is needed to identify the change. Default LREP namespace is "localchange".
	 * @param {String} sName Name of the change
	 * @param {String} sType File type extension
	 * @param {Boolean} bIsRuntime The stored file content is handed over to the lrep provider that can dynamically adjust the content to the runtime
	 *        context (e.g. do text replacement to the users' logon language) before
	 * @returns {Object} Returns the result from the request
	 * @public
	 */
	Connector.prototype.getStaticResource = function(sNamespace, sName, sType, bIsRuntime) {
		var sApiPath = "/sap/bc/lrep/content/";
		var sRequestPath = sApiPath;
		sRequestPath += sNamespace + "/" + sName + "." + sType;

		var aParams = [];
		if (!bIsRuntime) {
			aParams.push({
				name: "dt",
				value: "true"
			});
		}

		sRequestPath += this._buildParams(aParams);

		return this.send(sRequestPath, "GET", {}, null);
	};

	/**
	 * Retrieves the file attributes for a given resource in the LREP.
	 * 
	 * @param {String} sNamespace The abap package goes here. It is needed to identify the change. Default LREP namespace is "localchange".
	 * @param {String} sName Name of the change
	 * @param {String} sType File type extension
	 * @param {String} sLayer File layer
	 * @returns {Object} Returns the result from the request
	 * @public
	 */
	Connector.prototype.getFileAttributes = function(sNamespace, sName, sType, sLayer) {
		var sApiPath = "/sap/bc/lrep/content/";
		var sRequestPath = sApiPath;
		sRequestPath += sNamespace + "/" + sName + "." + sType;

		var aParams = [];
		aParams.push({
			name: "metadata",
			value: "true"
		});

		if (sLayer) {
			aParams.push({
				name: "layer",
				value: sLayer
			});
		}

		sRequestPath += this._buildParams(aParams);

		return this.send(sRequestPath, "GET", {}, null);
	};

	/**
	 * Upserts a given change or variant via REST call.
	 * 
	 * @param {String} sNamespace The abap package goes here. It is needed to identify the change.
	 * @param {String} sName Name of the change
	 * @param {String} sType File type extension
	 * @param {String} sLayer File layer
	 * @param {String} sContent File content to be saved as string
	 * @param {String} sContentType Content type (e.g. application/json, text/plain, ...), default: application/json
	 * @param {String} sChangelist The transport ID, optional
	 * @returns {Object} Returns the result from the request
	 * @public
	 */
	Connector.prototype.upsert = function(sNamespace, sName, sType, sLayer, sContent, sContentType, sChangelist) {
		var that = this;
		return Promise.resolve(that._fileAction("PUT", sNamespace, sName, sType, sLayer, sContent, sContentType, sChangelist));
	};

	/**
	 * Delete a file via REST call.
	 * 
	 * @param {String} sNamespace The abap package goes here. It is needed to identify the change.
	 * @param {String} sName Name of the change
	 * @param {String} sType File type extension
	 * @param {String} sLayer File layer
	 * @param {String} sChangelist The transport ID, optional
	 * @returns {Object} Returns the result from the request
	 * @public
	 */
	Connector.prototype.deleteFile = function(sNamespace, sName, sType, sLayer, sChangelist) {
		return this._fileAction("DELETE", sNamespace, sName, sType, sLayer, null, null, sChangelist);
	};

	Connector.prototype._fileAction = function(sMethod, sNamespace, sName, sType, sLayer, sContent, sContentType, sChangelist) {
		var sApiPath = "/sap/bc/lrep/content/";
		var sRequestPath = sApiPath;
		sRequestPath += sNamespace + "/" + sName + "." + sType;

		var aParams = [];
		aParams.push({
			name: "layer",
			value: sLayer
		});

		if (sChangelist) {
			aParams.push({
				name: "changelist",
				value: sChangelist
			});
		}

		sRequestPath += this._buildParams(aParams);

		var mOptions = {
			contentType: sContentType || this.DEFAULT_CONTENT_TYPE
		};

		return this.send(sRequestPath, sMethod.toUpperCase(), sContent, mOptions);
	};

	/**
	 * @param {String} sOriginNamespace The abap package goes here. It is needed to identify the change. Default LREP namespace is "localchange".
	 * @param {String} sName Name of the change
	 * @param {String} sType File type extension
	 * @param {String} sOriginLayer File layer
	 * @param {String} sTargetLayer File where the new Target-Layer
	 * @param {String} sTargetNamespace target namespace
	 * @param {String} sChangelist The changelist where the file will be written to
	 * @returns {Object} Returns the result from the request
	 * @private Private for now, as is not in use.
	 */
	Connector.prototype.publish = function(sOriginNamespace, sName, sType, sOriginLayer, sTargetLayer, sTargetNamespace, sChangelist) {
		var sApiPath = "/sap/bc/lrep/actions/publish/";
		var sRequestPath = sApiPath;
		sRequestPath += sOriginNamespace + "/" + sName + "." + sType;

		var aParams = [];
		if (sOriginLayer) {
			aParams.push({
				name: "layer",
				value: sOriginLayer
			});
		}
		if (sTargetLayer) {
			aParams.push({
				name: "target-layer",
				value: sTargetLayer
			});
		}
		if (sTargetNamespace) {
			aParams.push({
				name: "target-namespace",
				value: sTargetNamespace
			});
		}
		if (sChangelist) {
			aParams.push({
				name: "changelist",
				value: sChangelist
			});
		}

		sRequestPath += this._buildParams(aParams);

		return this.send(sRequestPath, "POST", {}, null);
	};

	/**
	 * Retrieves the content for a given namespace and layer via REST call.
	 * 
	 * @param {String} sNamespace - The file namespace goes here. It is needed to identify the change.
	 * @param {String} sLayer - File layer
	 * @returns {Object} Returns the result from the request
	 * @public
	 */
	Connector.prototype.listContent = function(sNamespace, sLayer) {
		var sRequestPath = "/sap/bc/lrep/content/";
		sRequestPath += sNamespace;

		var aParams = [];
		if (sLayer) {
			aParams.push({
				name: "layer",
				value: sLayer
			});
		}

		sRequestPath += this._buildParams(aParams);

		return this.send(sRequestPath, "GET", {}, null);
	};

	return Connector;
}, true);

}; // end of sap/ui/fl/LrepConnector.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.Transports') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
/*global Promise */

jQuery.sap.declare('sap.ui.fl.Transports'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
sap.ui.define("sap/ui/fl/Transports",[
	"sap/ui/fl/LrepConnector", "sap/ui/fl/Utils"
], function(LrepConnector, FlexUtils) {
	"use strict";

	/**
	 * Entity that handles ABAP transport related information.
	 * @constructor
	 * @alias sap.ui.fl.Transports
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.25.0
	 */
	var Transports = function() {
	};

	/**
	 * Reads the transports of the current user from the backend.
	 * The "locked" attribute indicates that the provided file (package/name/type) is already locked on this transport.
	 *
	 * @param {object} mParameters map of parameters, see below
	 * @param {string} mParameters.package - abap package; only relevant for VENDOR layer
	 * @param {string} mParameters.name - name of the lrep document
	 * @param {string} mParameters.namespace - namespace of the lrep document
	 * @param {string} mParameters.type - file extension of the lrep document
	 * @returns {Promise} with parameter <code>oResult</code>
	 * 					which is an object that has the attributes "transports", "localonly" and "errorCode". 
	 * 					"localonly" tells the consumer if only local development is valid and no transport selection should take place.
	 * 					"transports" is an array of objects with attributes "transportId", "owner", "description", "locked"(true/false).
	 * 					"errorCode" can have the values "INVALID_PACKAGE" or "NO_TRANSPORTS" or is an empty string if there is no error.
	 * @public
	 */
	Transports.prototype.getTransports = function(mParameters) {
		var sUri, sClient, oLrepConnector, oPromise;
		sUri = '/sap/bc/lrep/actions/gettransports/';
		if (mParameters['package']) {
			sUri += '&package=' + mParameters['package'];
		}
		if (mParameters.name) {
			sUri += '&name=' + mParameters.name;
		}
		if (mParameters.namespace) {
			sUri += '&namespace=' + mParameters.namespace;
		}
		if (mParameters.type) {
			sUri += '&type=' + mParameters.type;
		}
		sClient = FlexUtils.getClient();
		if (sClient) {
			sUri += '&sap-client=' + sClient;
		}
		//Replace first & with ?
		sUri = sUri.replace('&', '?');

		oLrepConnector = LrepConnector.createConnector();
		oPromise = oLrepConnector.send(sUri);
		return oPromise.then(function(oResponse) {
			if (oResponse.response) {
				if (!oResponse.response.localonly) {
					oResponse.response.localonly = false;
				}
				if (!oResponse.response.errorCode) {
					oResponse.response.errorCode = "";
				}
				return Promise.resolve(oResponse.response);
			} else {
				return Promise.reject('response is empty');
			}
		});
	};

	/**
	 * Reads the transports of the current user from the backend.
	 * The "locked" attribute indicates that the provided file (package/name/type) is already locked on this transport.
	 *
	 * @param {object} mParameters map of parameters, see below
	 * @param {string} mParameters.transportId - ABAP transport ID
	 * @param {string} mParameters.changeIds - array of change ID objects with attributes "namespace", "fileName", "fileType"
	 * @returns {Promise} without parameters
	 * @public
	 */
	Transports.prototype.makeChangesTransportable = function(mParameters) {
		var sUri, sClient, oLrepConnector;
		sUri = '/sap/bc/lrep/actions/make_changes_transportable/';
		sClient = FlexUtils.getClient();
		if (sClient) {
			sUri += '?sap-client=' + sClient;
		}
		if (!mParameters.transportId) {
			return Promise.reject(new Error("no transportId provided as attribute of mParameters"));
		}
		if (!mParameters.changeIds) {
			return Promise.reject(new Error("no changeIds provided as attribute of mParameters"));
		}
		oLrepConnector = LrepConnector.createConnector();
		return oLrepConnector.send(sUri,'POST',mParameters);
	};
	
	return Transports;
}, /* bExport= */true);

}; // end of sap/ui/fl/Transports.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.registry.Settings') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
/*global Error */

jQuery.sap.declare('sap.ui.fl.registry.Settings'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.base.EventProvider'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/registry/Settings",[
	"jquery.sap.global", "sap/ui/fl/LrepConnector", "sap/ui/fl/Cache", "sap/ui/fl/Utils", "sap/ui/base/EventProvider"
], function(jQuery, LrepConnector, Cache, Utils, EventProvider) {
	"use strict";

	/**
	 * FlexSettings access
	 *
	 * @param {object} oSettings settings as JSON object
	 * @constructor
	 * @alias sap.ui.fl.registry.Settings
	 * @author SAP SE
	 * @experimental Since 1.27.0
	 * @private
	 */
	var Settings = function(oSettings) {
		EventProvider.apply(this);
		if (!oSettings) {
			throw new Error("no flex settings provided");
		}
		if (!oSettings.features) {
			// hardcoded list of flex features (change types) and their valid "writable layer"
			oSettings.features = {
				"addField": [
					"CUSTOMER", "VENDOR"
				],
				"addGroup": [
					"CUSTOMER", "VENDOR"
				],
				"removeField": [
					"CUSTOMER", "VENDOR"
				],
				"removeGroup": [
					"CUSTOMER", "VENDOR"
				],
				"hideControl": [
					"CUSTOMER", "VENDOR"
				],
				"unhideControl": [
					"CUSTOMER", "VENDOR"
				],
				"renameField": [
					"CUSTOMER", "VENDOR"
				],
				"renameGroup": [
					"CUSTOMER", "VENDOR"
				],
				"moveFields": [
					"CUSTOMER", "VENDOR"
				],
				"moveGroups": [
					"CUSTOMER", "VENDOR"
				],
				"moveElements": [
					"CUSTOMER", "VENDOR"
				],
				"propertyChange": [
					"VENDOR"
				]
			};
		}
		this._oSettings = oSettings;
		this._hasMergeErrorOccured = false;
	};

	Settings.prototype = jQuery.sap.newObject(EventProvider.prototype);

	Settings.events = {
		flexibilityAdaptationButtonAllowedChanged: "flexibilityAdaptationButtonAllowedChanged",
		changeModeUpdated: "changeModeUpdated"
	};

	Settings._instances = {};
	Settings._bFlexChangeMode = true;
	Settings._bFlexibilityAdaptationButtonAllowed = false;
	Settings._oEventProvider = new EventProvider();

	/**
	 * fires the passed event via its event provider
	 *
	 * @param {string} sEventId name of the event
	 * @param {object} mParameters
	 *
	 * @public
	 */
	Settings.fireEvent = function(sEventId, mParameters) {
		Settings._oEventProvider.fireEvent(sEventId, mParameters);
	};

	/**
	 * attaches an callback to an event on the event provider of Settings
	 *
	 * @param {string} sEventId name of the event
	 * @param {function} oCallback
	 *
	 * @public
	 */
	Settings.attachEvent = function(sEventId, oCallback) {
		Settings._oEventProvider.attachEvent(sEventId, oCallback);
	};

	/**
	 * detaches an callback to an event on the event provider of Settings
	 *
	 * @param {string} sEventId name of the event
	 * @param {function} oCallback
	 *
	 * @public
	 */
	Settings.detachEvent = function(sEventId, oCallback) {
		Settings._oEventProvider.detachEvent(sEventId, oCallback);
	};

	/**
	 * Returns a settings instance after reading the settings from the backend if not already done. There is only one instance of settings during a
	 * session.
	 *
	 * @param {string} sComponentName current UI5 component name
	 * @param {map} mPropertyBag - (optional) contains additional data that are needed for reading of changes
	 * - appDescriptor that belongs to actual component
	 * - siteId that belongs to actual component
	 * @returns {Promise} with parameter <code>oInstance</code> of type {sap.ui.fl.registry.Settings}
	 * @public
	 */
	Settings.getInstance = function(sComponentName, mPropertyBag) {
		return Cache.getChangesFillingCache(LrepConnector.createConnector(), sComponentName, mPropertyBag).then(function(oFileContent) {
			var oSettings;
			if (Settings._instances[sComponentName]) {
				// if instance exists the backend settings are coming from the cache as well and can be ignored
				oSettings = Settings._instances[sComponentName];
			} else if (oFileContent.changes && oFileContent.changes.settings) {
				oSettings = new Settings(oFileContent.changes.settings);
				Settings._instances[sComponentName] = oSettings;
			} else {
				oSettings = new Settings({});
				Settings._instances[sComponentName] = oSettings;
			}
			return oSettings;
		});
	};

	/**
	 * Returns a settings instance from the local instance cache. There is only one instance of settings during a session. If no instance has been
	 * created before, undefined will be returned.
	 *
	 * @param {string} sComponentName current UI5 component name
	 * @returns {sap.ui.fl.registry.Settings} instance or undefined if no instance has been created so far.
	 * @public
	 */
	Settings.getInstanceOrUndef = function(sComponentName) {
		var oSettings;
		if (Settings._instances[sComponentName]) {
			oSettings = Settings._instances[sComponentName];
		}
		return oSettings;
	};

	/**
	 * Checks if the flexibility change mode is enabled.
	 *
	 * @returns {boolean} true if the flexibility change mode is enabled
	 * @public
	 */
	Settings.isFlexChangeMode = function() {
		var bFlexChangeModeUrl = this._isFlexChangeModeFromUrl();
		if (bFlexChangeModeUrl !== undefined) {
			return bFlexChangeModeUrl;
		}

		return Settings._bFlexChangeMode;
	};

	/**
	 * Checks if the flexibility change mode is enabled via URL query parameter
	 *
	 * @returns {boolean} bFlexChangeMode true if the flexibility change mode is enabled, false if not enabled, undefined if not set via url.
	 * @public
	 */
	Settings._isFlexChangeModeFromUrl = function() {
		var bFlexChangeMode;
		var oUriParams = jQuery.sap.getUriParameters();
		if (oUriParams && oUriParams.mParams && oUriParams.mParams['sap-ui-fl-changeMode'] && oUriParams.mParams['sap-ui-fl-changeMode'][0]) {
			if (oUriParams.mParams['sap-ui-fl-changeMode'][0] === 'true') {
				bFlexChangeMode = true;
			} else if (oUriParams.mParams['sap-ui-fl-changeMode'][0] === 'false') {
				bFlexChangeMode = false;
			}
		}
		return bFlexChangeMode;
	};

	/**
	 * Activates the flexibility change mode.
	 *
	 * @public
	 */
	Settings.activateFlexChangeMode = function() {
		var bFlexChangeModeOn = true;
		Settings._setFlexChangeMode(bFlexChangeModeOn);
	};

	/**
	 * Deactivates / leaves the flexibility change mode.
	 *
	 * @public
	 */
	Settings.leaveFlexChangeMode = function() {
		var bFlexChangeModeOff = false;
		Settings._setFlexChangeMode(bFlexChangeModeOff);
	};


	/**
	 * sets the flexChangeMode flag
	 * fires an event if the flag has been toggled
	 *
	 * @private
	 */
	Settings._setFlexChangeMode = function (bFlexChangeModeOn) {
		if (Settings._bFlexChangeMode === bFlexChangeModeOn) {
			return; // no change
		}

		Settings._bFlexChangeMode = bFlexChangeModeOn;
		var mParameter = {
			bFlexChangeMode: bFlexChangeModeOn
		};
		Settings.fireEvent(Settings.events.changeModeUpdated, mParameter);
	};

	/**
	 * Method to check for adaptation button allowance
	 *
	 * @returns {boolean} Settings._bFlexibilityAdaptationButtonAllowed
	 * @public
	 */
	Settings.isFlexibilityAdaptationButtonAllowed = function () {
		return Settings._bFlexibilityAdaptationButtonAllowed;
	};

	/**
	 * Method to allow the adaptation button
	 *
	 * @public
	 */
	Settings.allowFlexibilityAdaptationButton = function () {
		var bFlexibilityAdaptationButtonAllowed = true;
		Settings.setFlexibilityAdaptationButtonAllowed(bFlexibilityAdaptationButtonAllowed);
	};

	/**
	 * Method to disallow the adaptation button
	 *
	 * @public
	 */
	Settings.disallowFlexibilityAdaptationButton = function () {
		var bFlexibilityAdaptationButtonDisallowed = false;
		Settings.setFlexibilityAdaptationButtonAllowed(bFlexibilityAdaptationButtonDisallowed);
	};

	/**
	 * Method to set the adaptation button allowance flag on or off depending on the passed parameter
	 * fires an event if the flag has been toggled
	 *
	 * @param {boolean} bFlexibilityAdaptationButtonAllowed
	 *
	 * @public
	 */
	Settings.setFlexibilityAdaptationButtonAllowed = function (bFlexibilityAdaptationButtonAllowed) {
		if (Settings._bFlexibilityAdaptationButtonAllowed === bFlexibilityAdaptationButtonAllowed) {
			return; // no change
		}

		Settings._bFlexibilityAdaptationButtonAllowed = bFlexibilityAdaptationButtonAllowed;

		var mParameter = {
			bFlexibilityAdaptationButtonAllowed: bFlexibilityAdaptationButtonAllowed
		};
		Settings.fireEvent(Settings.events.flexibilityAdaptationButtonAllowedChanged, mParameter);

	};

	/**
	 * Returns the key user status of the current user.
	 *
	 * @returns {boolean} true if the user is a flexibility key user, false if not supported.
	 * @public
	 */
	Settings.prototype.isKeyUser = function() {
		var bIsKeyUser = false;
		if (this._oSettings.isKeyUser) {
			bIsKeyUser = this._oSettings.isKeyUser;
		}
		return bIsKeyUser;
	};

	/**
	 * Returns true if backend is ModelS backend.
	 *
	 * @returns {boolean} true if ATO coding exists in backend.
	 * @public
	 */
	Settings.prototype.isModelS = function() {
		var bIsModelS = false;
		if (this._oSettings.isAtoAvailable) {
			bIsModelS = this._oSettings.isAtoAvailable;
		}
		return bIsModelS;
	};

	/**
	 * Returns true if ATO is enabled in the backend.
	 *
	 * @returns {boolean} true if ATO is enabled.
	 * @public
	 */
	Settings.prototype.isAtoEnabled = function() {
		var bIsAtoEnabled = false;
		if (this._oSettings.isAtoEnabled) {
			bIsAtoEnabled = this._oSettings.isAtoEnabled;
		}
		return bIsAtoEnabled;
	};

	/**
	 * Checks if a change type is enabled for the current writable layer
	 *
	 * @param {string} sChangeType change type to be checked
	 * @param {string} sActiveLayer active layer name; if not provided "USER" is the default.
	 * @returns {boolean} true if the change type is enabled, false if not supported.
	 * @public
	 */
	Settings.prototype.isChangeTypeEnabled = function(sChangeType, sActiveLayer) {
		if (!sActiveLayer) {
			sActiveLayer = 'USER';
		}
		var bIsEnabled = false;
		if (!this._oSettings.features[sChangeType]) {
			// if the change type is not in the feature list, the change type is not check relevant and therefore always enabled.
			// if a change type should be disabled for all layers, an entry in the feature map has to exist with an empty array.
			bIsEnabled = true;
		} else {
			var iArrayPos = jQuery.inArray(sActiveLayer, this._oSettings.features[sChangeType]);
			if (iArrayPos < 0) {
				bIsEnabled = false;
			} else {
				bIsEnabled = true;
			}
		}
		return bIsEnabled;
	};

	/**
	 * Is current back end system defined as productive system which can also transport changes
	 *
	 * @public
	 * @returns {boolean} true if system is productive system
	 */
	Settings.prototype.isProductiveSystem = function() {
		var bIsProductiveSystem = false;
		if (this._oSettings.isProductiveSystem) {
			bIsProductiveSystem = this._oSettings.isProductiveSystem;
		}
		return bIsProductiveSystem;
	};

	Settings.prototype.setMergeErrorOccured = function(bErrorOccured) {
		this._hasMergeErrorOccoured = bErrorOccured;
	};
	/**
	 * Checks if an merge error occured during merging changes into the view on startup
	 */
	Settings.prototype.hasMergeErrorOccured = function() {
		return this._hasMergeErrorOccured;
	};

	return Settings;
}, /* bExport= */true);

}; // end of sap/ui/fl/registry/Settings.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.Change') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
jQuery.sap.declare('sap.ui.fl.Change'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('sap.ui.base.EventProvider'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/Change",[
	"sap/ui/base/EventProvider", "sap/ui/fl/Utils", "sap/ui/fl/registry/Settings"
], function(EventProvider, Utils, Settings) {

	"use strict";

	/**
	 * A change object based on the json data with dirty handling.
	 * @constructor
	 * @alias sap.ui.fl.Change
	 * @param {object} oFile - file content and admin data
	 * @experimental Since 1.25.0
	 * @author SAP SE
	 * @version 1.36.12
	 */
	var Change = function(oFile) {
		EventProvider.apply(this);
		if (typeof (oFile) !== "object") {
			Utils.log.error("Constructor : sap.ui.fl.Change : oFile is not defined");
		}

		this._oDefinition = oFile;
		this._oOriginDefinition = JSON.parse(JSON.stringify(oFile));
		this._sRequest = '';
		this._bIsDeleted = false;
		this._bUserDependent = (oFile.layer === "USER");
	};

	Change.events = {
		markForDeletion: "markForDeletion"
	};

	Change.prototype = jQuery.sap.newObject(EventProvider.prototype);

	/**
	 * Returns if the change protocol is valid
	 * @returns {boolean} Change is valid (mandatory fields are filled, etc)
	 *
	 * @public
	 */
	Change.prototype.isValid = function() {
		var bIsValid = true;

		if (typeof (this._oDefinition) !== "object") {
			bIsValid = false;
		}
		if (!this._oDefinition.fileType) {
			bIsValid = false;
		}
		if (!this._oDefinition.fileName) {
			bIsValid = false;
		}
		if (!this._oDefinition.changeType) {
			bIsValid = false;
		}
		if (!this._oDefinition.layer) {
			bIsValid = false;
		}
		if (!this._oDefinition.originalLanguage) {
			bIsValid = false;
		}

		return bIsValid;
	};

	/**
	 * Returns if the change is of type variant
	 * @returns {boolean} fileType of the change document is a variant
	 *
	 * @public
	 */
	Change.prototype.isVariant = function() {
		return this._oDefinition.fileType === "variant";
	};

	/**
	 * Returns the change type
	 *
	 * @returns {String} Changetype of the file, for example LabelChange
	 * @public
	 */
	Change.prototype.getChangeType = function() {
		if (this._oDefinition) {
			return this._oDefinition.changeType;
		}
	};

	/**
	 * Returns the the original language in ISO 639-1 format
	 *
	 * @returns {String} Original language
	 *
	 * @public
	 */
	Change.prototype.getOriginalLanguage = function() {
		if (this._oDefinition && this._oDefinition.originalLanguage) {
			return this._oDefinition.originalLanguage;
		}
		return "";
	};

	/**
	 * Returns the abap package name
	 * @returns {string} ABAP package where the change is assigned to
	 *
	 * @public
	 */
	Change.prototype.getPackage = function() {
		return this._oDefinition.packageName;
	};

	/**
	 * Returns the namespace. The changes' namespace is
	 * also the namespace of the change file in the repository.
	 *
	 * @returns {String} Namespace of the change document
	 *
	 * @public
	 */
	Change.prototype.getNamespace = function() {
		return this._oDefinition.namespace;
	};

	/**
	 * Returns the id of the change
	 * @returns {string} Id of the change document
	 *
	 * @public
	 */
	Change.prototype.getId = function() {
		return this._oDefinition.fileName;
	};

	/**
	 * Returns the content section of the change
	 * @returns {string} Content of the change document. The content structure can be any JSON.
	 *
	 * @public
	 */
	Change.prototype.getContent = function() {
		return this._oDefinition.content;
	};

	/**
	 * Sets the object of the content attribute
	 * 
	 * @param {object} oContent The content of the change document. Can be any JSON object.
	 *
	 * @public
	 */
	Change.prototype.setContent = function(oContent) {
		this._oDefinition.content = oContent;
	};

	/**
	 * Returns the selector from the file content
	 * @returns {object} selector in format selectorPropertyName:selectorPropertyValue
	 *
	 * @public
	 */
	Change.prototype.getSelector = function() {
		return this._oDefinition.selector;
	};

	/**
	 * Returns the text in the current language for a given id
	 *
	 * @param {string} sTextId
	 * 				text id which was used as part of the <code>oTexts</code> object
	 * @returns {string} The text for the given text id
	 *
	 * @function
	 */
	Change.prototype.getText = function(sTextId) {
		if (typeof (sTextId) !== "string") {
			Utils.log.error("sap.ui.fl.Change.getTexts : sTextId is not defined");
		}
		if (this._oDefinition.texts) {
			if (this._oDefinition.texts[sTextId]) {
				return this._oDefinition.texts[sTextId].value;
			}
		}
		return "";
	};

	/**
	 * Sets the new text for the given text id
	 *
	 * @param {string} sTextId
	 * 				text id which was used as part of the <code>oTexts</code> object
	 * @param {string} sNewText the new text for the given text id
	 *
	 * @public
	 */
	Change.prototype.setText = function(sTextId, sNewText) {
		if (typeof (sTextId) !== "string") {
			Utils.log.error("sap.ui.fl.Change.setTexts : sTextId is not defined");
			return;
		}
		if (this._oDefinition.texts) {
			if (this._oDefinition.texts[sTextId]) {
				this._oDefinition.texts[sTextId].value = sNewText;
			}
		}
	};

	/**
	 * Returns true if the current layer is the same as the layer
	 * in which the change was created or the change is from the
	 * end-user layer and for this user created.
	 * @returns {boolean} is the change document read only
	 *
	 * @public
	 */
	Change.prototype.isReadOnly = function() {
		var bIsReadOnly = this._isReadOnlyDueToLayer();
		if ( !bIsReadOnly ){
			bIsReadOnly = this._isReadOnlyWhenNotKeyUser();
		}
		return bIsReadOnly;
	};
	
	/**
	 * Checks if the change is read-only 
	 * because the current user is not a key user and the change is "shared"
	 * @returns {boolean} Flag whether change is read only
	 *
	 * @private
	 */
	Change.prototype._isReadOnlyWhenNotKeyUser = function() {
		var bIsReadOnly = false;
		if ( !this.isUserDependent() ){
			var sReference = this.getDefinition().reference;
			if ( sReference ){
				var oSettings = Settings.getInstanceOrUndef(sReference);
				if ( oSettings ){
					var bIsKeyUser = oSettings.isKeyUser();
					if ( bIsKeyUser === false ){
						bIsReadOnly = true;
					}
				}
			}
		}
		return bIsReadOnly;
	};

	/**
	 * Returns true if the label is read only. The label might be read only because of the current layer or because the logon language differs from the original language of the change document.
	 *
	 * @returns {boolean} is the label read only
	 *
	 * @public
	 */
	Change.prototype.isLabelReadOnly = function() {
		if (this._isReadOnlyDueToLayer()) {
			return true;
		}
		return this._isReadOnlyDueToOriginalLanguage();
	};

	/**
	 * Checks if the layer allows modifying the file
	 * @returns {boolean} Flag whether change is read only
	 *
	 * @private
	 */
	Change.prototype._isReadOnlyDueToLayer = function() {
		var sCurrentLayer;
		sCurrentLayer = Utils.getCurrentLayer(this._bUserDependent);
		return (this._oDefinition.layer !== sCurrentLayer);
	};

	/**
	 * A change can only be modified if the current language equals the original language.
	 * Returns false if the current language does not equal the original language of the change file.
	 * Returns false if the original language is initial.
	 *
	 * @returns {boolean} flag whether the current logon language differs from the original language of the change document
	 *
	 * @private
	 */
	Change.prototype._isReadOnlyDueToOriginalLanguage = function() {
		var sCurrentLanguage, sOriginalLanguage;

		sOriginalLanguage = this.getOriginalLanguage();
		if (!sOriginalLanguage) {
			return false;
		}

		sCurrentLanguage = Utils.getCurrentLanguage();
		return (sCurrentLanguage !== sOriginalLanguage);
	};

	/**
	 * Mark the current change to be deleted persistently
	 *
	 * @public
	 */
	Change.prototype.markForDeletion = function() {
		this._bIsDeleted = true;
	};

	/**
	 * Determines if the Change has to be updated to the backend
	 * @returns {boolean} content of the change document has changed (change is in dirty state)
	 * @private
	 */
	Change.prototype._isDirty = function() {
		var sCurrentDefinition = JSON.stringify(this._oDefinition);
		var sOriginDefinition = JSON.stringify(this._oOriginDefinition);

		return (sCurrentDefinition !== sOriginDefinition);
	};

	/**
	 * Sets the transport request
	 *
	 * @param {string} sRequest Transport request
	 *
	 * @public
	 */
	Change.prototype.setRequest = function(sRequest) {
		if (typeof (sRequest) !== "string") {
			Utils.log.error("sap.ui.fl.Change.setRequest : sRequest is not defined");
		}
		this._sRequest = sRequest;
	};

	/**
	 * Gets the transport request
	 * @returns {string} Transport request
	 *
	 * @public
	 */
	Change.prototype.getRequest = function() {
		return this._sRequest;
	};

	/**
	 * Gets the layer type for the change
	 * @returns {string} The layer of the change document
	 *
	 * @public
	 */
	Change.prototype.getLayer = function() {
		return this._oDefinition.layer;
	};

	/**
	 * Gets the component for the change
	 * @returns {string} The SAPUI5 component this change is assigned to
	 *
	 * @public
	 */
	Change.prototype.getComponent = function() {
		return this._oDefinition.reference;
	};

	/**
	 * Gets the creation timestamp
	 *
	 * @returns {String} creation timestamp
	 *
	 * @public
	 */
	Change.prototype.getCreation = function() {
		return this._oDefinition.creation;
	};

	/**
	 * Returns true if the change is user dependent
	 * @returns {boolean} Change is only relevant for the current user
	 *
	 * @public
	 */
	Change.prototype.isUserDependent = function() {
		return (this._bUserDependent);
	};

	/**
	 * Returns the pending action on the change item
	 * @returns {string} contains one of these values: DELETE/NEW/UPDATE/NONE
	 *
	 * @public
	 */
	Change.prototype.getPendingAction = function() {
		if (this._bIsDeleted) {
			return "DELETE";
		} else if (!this._oDefinition.creation) {
			return "NEW";
		} else if (this._isDirty() === true) {
			return "UPDATE";
		}
		return "NONE";
	};

	/**
	 * Gets the JSON definition of the change
	 * @returns {object} the content of the change document
	 *
	 * @public
	 */
	Change.prototype.getDefinition = function() {
		return this._oDefinition;
	};

	/**
	 * Set the response from the backend after saving the change
	 * @param {object} oResponse the content of the change document
	 *
	 * @public
	 */
	Change.prototype.setResponse = function(oResponse) {
		var sResponse = JSON.stringify(oResponse);
		if (sResponse) {
			this._oDefinition = JSON.parse(sResponse);
			this._oOriginDefinition = JSON.parse(sResponse);
		}
	};

	/**
	 * Creates and returns a instance of change instance
	 *
	 * @param {Object}  [oPropertyBag] property bag
	 * @param {String}  [oPropertyBag.service] name of the OData service
	 * @param {String}  [oPropertyBag.componentName] name of the component
	 * @param {String}  [oPropertyBag.changeType] type of the change
	 * @param {Object}  [oPropertyBag.texts] map object with all referenced texts within the file
	 *                                      these texts will be connected to the translation process
	 * @param {Object}  [oPropertyBag.content] content of the new change
	 * @param {Boolean} [oPropertyBag.isVariant] variant?
	 * @param {String}  [oPropertyBag.namespace] namespace
	 * @param {String}  [oPropertyBag.packageName] ABAP package name
	 * @param {Object}  [oPropertyBag.selector] name value pair of the attribute and value
	 * @param {String}  [oPropertyBag.id] name/id of the file. if not set implicitly created
	 * @param {Boolean} [oPropertyBag.isVariant] name of the component
	 * @param {Boolean} [oPropertyBag.isUserDependent] true for enduser changes
	 *
	 * @returns {Object} The content of the change file
	 *
	 * @public
	 */
	Change.createInitialFileContent = function(oPropertyBag) {
		function createDefaultFileName(){
			var sFileName = jQuery.sap.uid().replace(/-/g, "_");
			if ( oPropertyBag.changeType ){
				sFileName += '_' + oPropertyBag.changeType;
			}
			return sFileName;
		}
		function createNamespace(){
			var sComponentName;
			var sReferenceName = oPropertyBag.reference.replace('.Component','');
			if ( oPropertyBag.componentName && oPropertyBag.componentName.indexOf('{project.artifactId}') >= 0 ){
				//special case when change is created within webIDE; will not work in case of application variants once we start supporting them
				sComponentName = sReferenceName;
			}else {
				sComponentName = oPropertyBag.componentName;
			}
			var sNamespace = 'apps/' + sComponentName + '/changes/';
			if ( sComponentName !== sReferenceName ){
				//add the application variant id
				sNamespace += sReferenceName + '/';
			}
			return sNamespace;
		}	
		if (!oPropertyBag) {
			oPropertyBag = {};
		}
		var oNewFile = {
			fileName: oPropertyBag.id || createDefaultFileName(),
			fileType: (oPropertyBag.isVariant) ? "variant" : "change",
			changeType: oPropertyBag.changeType || "",
			reference: oPropertyBag.reference || "",
			packageName: oPropertyBag.packageName || "",
			content: oPropertyBag.content || {},
			selector: oPropertyBag.selector || {},
			layer: Utils.getCurrentLayer(oPropertyBag.isUserDependent),
			texts: oPropertyBag.texts || {},
			namespace: createNamespace(),
			creation: "",
			originalLanguage: Utils.getCurrentLanguage(),
			conditions: {},
			support: {
				generator: "Change.createInitialFileContent",
				service: oPropertyBag.service || "",
				user: ""
			}
		};

		return oNewFile;
	};

	return Change;
}, true);

}; // end of sap/ui/fl/Change.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.ChangePersistence') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
/*global Promise */

jQuery.sap.declare('sap.ui.fl.ChangePersistence'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/ChangePersistence",[
	"sap/ui/fl/Change", "sap/ui/fl/Utils", "jquery.sap.global", "sap/ui/fl/LrepConnector", "sap/ui/fl/Cache"
], function(Change, Utils, $, LRepConnector, Cache) {
	"use strict";

	/**
	 * Helper object to access a change from the backend. Access helper object for each change (and variant) which was fetched from the backend
	 *
	 * @constructor
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.25.0
	 * @param {string} sComponentName - the name of the component this instance is responsible for
	 * @param {sap.ui.fl.LrepConnector} [oLrepConnector] the LREP connector
	 */
	var ChangePersistence = function(sComponentName, oLrepConnector) {
		this._sComponentName = sComponentName;

		if (!this._sComponentName) {
			Utils.log.error("The Control does not belong to a SAPUI5 component. Personalization and changes for this control might not work as expected.");
			throw new Error("Missing component name.");
		}

		this._oConnector = oLrepConnector || this._createLrepConnector();
		this._aDirtyChanges = [];
	};

	/**
	 * Return the name of the SAPUI5 component. All changes are assigned to 1 SAPUI5 component. The SAPUI5 component also serves as authorization
	 * object.
	 *
	 * @returns {String} component name
	 * @public
	 */
	ChangePersistence.prototype.getComponentName = function() {
		return this._sComponentName;
	};

	/**
	 * Creates a new instance of the LRepConnector
	 *
	 * @returns {sap.ui.fl.LrepConnector} LRep connector instance
	 * @private
	 */
	ChangePersistence.prototype._createLrepConnector = function() {
		return LRepConnector.createConnector();
	};

	/**
	 * Calls the backend asynchronously and fetches all changes for the component. If there are any new changes (dirty state) whoch are not yet saved to the backend, these changes will not be returned
	 * @param {map} mPropertyBag - (optional) contains additional data that are needed for reading of changes
	 * - appDescriptor that belongs to actual component
	 * - siteId that belongs to actual component
	 * @see sap.ui.fl.Change
	 * @returns {Promise} resolving with an array of changes
	 * @public
	 */
	ChangePersistence.prototype.getChangesForComponent = function(mPropertyBag) {
		return Cache.getChangesFillingCache(this._oConnector, this._sComponentName, mPropertyBag).then(function(oWrappedChangeFileContent) {
			this._bHasLoadedChangesFromBackend = true;

			if (!oWrappedChangeFileContent.changes || !oWrappedChangeFileContent.changes.changes) {
				return [];
			}

			var aChanges = oWrappedChangeFileContent.changes.changes;

			return aChanges.filter(preconditionsFulfilled).map(createChange);
		}.bind(this));

		function createChange(oChangeContent) {
			return new Change(oChangeContent);
		}

		function preconditionsFulfilled(oChangeContent) {
			if (oChangeContent.fileType !== 'change') {
				return false;
			}

			if (oChangeContent.changeType === 'defaultVariant') {
				return false;
			}

			//noinspection RedundantIfStatementJS
			if (!oChangeContent.selector || !oChangeContent.selector.id) {
				return false;
			}

			return true;
		}
	};

	/**
	 * Gets the changes for the given view id. The complete view prefix has to match.
	 *
	 * Example:
	 * Change has selector id:
	 * view1--view2--controlId
	 *
	 * Will match for view:
	 * view1--view2
	 *
	 * Will not match for view:
	 * view1
	 * view1--view2--view3
	 *
	 * @param {string} sViewId - the id of the view, changes should be retrieved for
	 * @param {map} mPropertyBag - (optional) contains additional data that are needed for reading of changes
	 * - appDescriptor that belongs to actual component
	 * - siteId that belongs to actual component
	 * @returns {Promise} resolving with an array of changes
	 * @public
	 */
	ChangePersistence.prototype.getChangesForView = function(sViewId, mPropertyBag) {
		return this.getChangesForComponent(mPropertyBag).then(function(aChanges) {
			return aChanges.filter(changesHavingCorrectViewPrefix);
		});

		function changesHavingCorrectViewPrefix(oChange) {
			var sSelectorId = oChange.getSelector().id;
			var sSelectorIdViewPrefix = sSelectorId.slice(0, sSelectorId.lastIndexOf('--'));

			return sSelectorIdViewPrefix === sViewId;
		}
	};

	/**
	 * Adds a new change (could be variant as well) and returns the id of the new change.
	 *
	 * @param {object} vChange - The complete and finalized JSON object representation the file content of the change or a Change instance
	 * @returns {sap.ui.fl.Change} the newly created change object
	 * @public
	 */
	ChangePersistence.prototype.addChange = function(vChange) {
		var oNewChange;
		if (vChange instanceof Change){
			oNewChange = vChange;
		}else {
			oNewChange = new Change(vChange);
		}
		this._aDirtyChanges.push(oNewChange);

		return oNewChange;
	};

	/**
	 * Saves all dirty changes by calling the appropriate backend method
	 * (create for new changes, deleteChange for deleted changes). The methods
	 * are called sequentially to ensure order. After a change has been saved
	 * successfully, the cache is updated and the changes is removed from the dirty
	 * changes.
	 *
	 * @returns {Promise} resolving after all changes have been saved
	 */
	ChangePersistence.prototype.saveDirtyChanges = function() {
		var aDirtyChangesClone = this._aDirtyChanges.slice(0);
		var aDirtyChanges = this._aDirtyChanges;
		var aRequests = this._getRequests(aDirtyChangesClone);
		var aPendingActions = this._getPendingActions(aDirtyChangesClone);

		if (aPendingActions.length === 1 && aRequests.length === 1 && aPendingActions[0] === 'NEW') {
			var sRequest = aRequests[0];
			var aPreparedDirtyChangesBulk = this._prepareDirtyChanges(aDirtyChanges);
			return this._oConnector.create(aPreparedDirtyChangesBulk, sRequest).then(this._massUpdateCacheAndDirtyState(aDirtyChanges, aDirtyChangesClone));
		} else {
			return aDirtyChangesClone.reduce(function (sequence, oDirtyChange) {
				var saveAction = sequence.then(this._performSingleSaveAction(oDirtyChange).bind(this));
				saveAction.then(this._updateCacheAndDirtyState(aDirtyChanges, oDirtyChange));

				return saveAction;
			}.bind(this), Promise.resolve());
		}
	};

	 ChangePersistence.prototype._performSingleSaveAction = function (oDirtyChange) {
		return function() {
			if (oDirtyChange.getPendingAction() === 'NEW') {
				return this._oConnector.create(oDirtyChange.getDefinition(), oDirtyChange.getRequest());
			}

			if (oDirtyChange.getPendingAction() === 'DELETE') {
				return this._oConnector.deleteChange({
					sChangeName: oDirtyChange.getId(),
					sLayer: oDirtyChange.getLayer(),
					sNamespace: oDirtyChange.getNamespace(),
					sChangelist: oDirtyChange.getRequest()
				});
			}
		};
	};

	ChangePersistence.prototype._updateCacheAndDirtyState = function (aDirtyChanges, oDirtyChange) {
		var that = this;

		return function() {
			if (oDirtyChange.getPendingAction() === 'NEW') {
				Cache.addChange(that._sComponentName, oDirtyChange.getDefinition());
			}

			if (oDirtyChange.getPendingAction() === 'DELETE') {
				Cache.deleteChange(that._sComponentName, oDirtyChange.getDefinition());
			}

			var iIndex = aDirtyChanges.indexOf(oDirtyChange);
			if (iIndex > -1) {
				aDirtyChanges.splice(iIndex, 1);
			}
		};
	};

	ChangePersistence.prototype._massUpdateCacheAndDirtyState = function (aDirtyChanges, aDirtyChangesClone) {
		var that = this;

		jQuery.each(aDirtyChangesClone, function (index, oDirtyChange) {
			that._updateCacheAndDirtyState(aDirtyChanges, oDirtyChange)();
		});
	};

	ChangePersistence.prototype._getRequests = function (aDirtyChanges) {
		var aRequests = [];

		jQuery.each(aDirtyChanges, function (index, oChange) {
			var sRequest = oChange.getRequest();
			if (aRequests.indexOf(sRequest) === -1) {
				aRequests.push(sRequest);
			}
		});

		return aRequests;
	};

	ChangePersistence.prototype._getPendingActions = function (aDirtyChanges) {
		var aPendingActions = [];

		jQuery.each(aDirtyChanges, function (index, oChange) {
			var sPendingAction = oChange.getPendingAction();
			if (aPendingActions.indexOf(sPendingAction) === -1) {
				aPendingActions.push(sPendingAction);
			}
		});

		return aPendingActions;
	};

	ChangePersistence.prototype._prepareDirtyChanges = function (aDirtyChanges) {
		var aChanges = [];

		jQuery.each(aDirtyChanges, function (index, oChange) {
			aChanges.push(oChange.getDefinition());
		});

		return aChanges;
	};

	ChangePersistence.prototype.getDirtyChanges = function() {
		return this._aDirtyChanges;
	};

	/**
	 * Prepares a change to be deleted with the next call to
	 * @see {ChangePersistence#saveDirtyChanges}.
	 *
	 * If the given change is already in the dirty changes and
	 * has pending action 'NEW' it will be removed, assuming,
	 * it has just been created in the current session.
	 *
	 * Otherwise it will be marked for deletion.
	 *
	 * @param {sap.ui.fl.Change} oChange - the change to be deleted
	 */
	ChangePersistence.prototype.deleteChange = function(oChange) {
		var index = this._aDirtyChanges.indexOf(oChange);

		if (index > -1) {
			if (oChange.getPendingAction() === 'DELETE'){
				return;
			}
			this._aDirtyChanges.splice(index, 1);
			return;
		}

		oChange.markForDeletion();
		this._aDirtyChanges.push(oChange);
	};

	return ChangePersistence;
}, true);

}; // end of sap/ui/fl/ChangePersistence.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.ChangePersistenceFactory') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.ChangePersistenceFactory'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/ChangePersistenceFactory",[
	"jquery.sap.global", "sap/ui/fl/ChangePersistence", "sap/ui/fl/Utils"
], function(jQuery, ChangePersistence, Utils) {
	"use strict";

	/**
	 * Factory to get or create a new instances of {sap.ui.fl.ChangePersistence}
	 * @constructor
	 * @alias sap.ui.fl.ChangePersistenceFactory
	 * @experimental Since 1.27.0
	 * @author SAP SE
	 * @version 1.36.12
	 */
	var ChangePersistenceFactory = {};

	ChangePersistenceFactory._instanceCache = {};

	/**
	 * Creates or returns an instance of the ChangePersistence
	 * @param {String} sComponentName The name of the component
	 * @returns {sap.ui.fl.ChangePersistence} instance
	 *
	 * @public
	 */
	ChangePersistenceFactory.getChangePersistenceForComponent = function(sComponentName) {
		var oChangePersistence;

		if (!ChangePersistenceFactory._instanceCache[sComponentName]) {
			oChangePersistence = new ChangePersistence(sComponentName);
			ChangePersistenceFactory._instanceCache[sComponentName] = oChangePersistence;
		}

		return ChangePersistenceFactory._instanceCache[sComponentName];
	};

	/**
	 * Creates or returns an instance of the ChangePersistence for the component of the specified control.
	 * The control needs to be embedded into a component.
	 * @param {sap.ui.core.Control} oControl The control for example a SmartField, SmartGroup or View
	 * @returns {sap.ui.fl.ChangePersistence} instance
	 *
	 * @public
	 */
	ChangePersistenceFactory.getChangePersistenceForControl = function(oControl) {
		var sComponentId;
		sComponentId = this._getComponentClassNameForControl(oControl);
		return ChangePersistenceFactory.getChangePersistenceForComponent(sComponentId);
	};

	/**
	 * Returns the name of the component of the control
	 * @param {sap.ui.core.Control} oControl Control
	 * @returns {String} The name of the component. Undefined if no component was found
	 *
	 * @private
	 */
	ChangePersistenceFactory._getComponentClassNameForControl = function(oControl) {
		return Utils.getComponentClassName(oControl);
	};

	return ChangePersistenceFactory;
}, true);

}; // end of sap/ui/fl/ChangePersistenceFactory.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.DefaultVariant') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.DefaultVariant'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/DefaultVariant",[
	"jquery.sap.global", "sap/ui/fl/Change"
], function($, Change) {
	"use strict";

	/**
	 * DefaultVariant handles default variant changes without keeping control specific state.
	 *        It knows how to create a default variant change, how to retrieve the default variant id from a given list of changes, etc.
	 * @constructor
	 * @alias sap.ui.fl.DefaultVariant
	 * @author SAP SE
	 *
	 * @version 1.36.12
	 *
	 * @experimental Since 1.25.0
	 */
	var DefaultVariant = function() {

	};

	/**
	 * Returns the id of the default variant. Returns an empty string if there is no default variant.
	 *
	 * @param {object} mChanges Map containing multiple change files.
	 *
	 * @returns {String} default variant id
	 *
	 * @public
	 */
	DefaultVariant.prototype.getDefaultVariantId = function(mChanges) {
		var defaultVariantChange = this.getNewestDefaultVariantChangeDeleteTheRest(mChanges);

		if (defaultVariantChange) {
			return defaultVariantChange.getContent().defaultVariantName;
		}

		return "";
	};

	/**
	 * Returns the newest default variant change and marks the rest for deletion.
	 * A change with an empty string as creation is considered newer
	 * than a change with an iso date string. If multiple changes
	 * have an empty string, order is not guaranteed. That is a case
	 * that should not happen.
	 *
	 * @param {object} mChanges map containing multiple change files.
	 *
	 * @returns {array} default variant changes
	 *
	 * @public
	 */
	DefaultVariant.prototype.getNewestDefaultVariantChangeDeleteTheRest = function(mChanges) {
		var aChanges = this.getDefaultVariantChanges(mChanges).sort(function(a, b) {
			var aDate = new Date(a.getCreation());
			var bDate = new Date(b.getCreation());

			if (isNaN(aDate.getDate())) {
				return -1;
			}

			if (isNaN(bDate.getDate())) {
				return 1;
			}

			return bDate - aDate;
		});

		var oNewestChange = aChanges.shift();

		aChanges.forEach(function(oChange) {
			oChange.markForDeletion();
		});

		return oNewestChange;
	};

	/**
	 * Returns all default variant changes within the given map of changes
	 *
	 * @param {object} mChanges - map containing multiple change files.
	 *
	 * @returns {array} default variant changes
	 *
	 * @public
	 */
	DefaultVariant.prototype.getDefaultVariantChanges = function(mChanges) {
		if (!mChanges || typeof mChanges !== 'object') {
			return [];
		}

		return Object.keys(mChanges).map(changeIdsToChanges).filter(defaultVariantChanges);

		function changeIdsToChanges(sChangeId) {
			return mChanges[sChangeId];
		}

		function defaultVariantChanges(oChange) {
			return oChange.getChangeType() === 'defaultVariant';
		}

	};

	/**
	 * Updates the default variant id, if the given list of changes contains a default variant change.
	 * Only the newest is updated, the rest is marked for deletion.
	 *
	 * @param {object} mChanges map of changes
	 * @param {string} sNewDefaultVariantId the new default variant id
	 * @returns {object} the updated change, undefined if non was found
	 *
	 * @public
	 */
	DefaultVariant.prototype.updateDefaultVariantId = function(mChanges, sNewDefaultVariantId) {
		var oNewsetChange = this.getNewestDefaultVariantChangeDeleteTheRest(mChanges);

		if (oNewsetChange) {
			oNewsetChange.getContent().defaultVariantName = sNewDefaultVariantId;
		}

		return oNewsetChange;
	};

	/**
	 * Creates the JSON content of a new change file, specifying the new default variant
	 *
	 * @param {object} mParameters map of parameters, see below
	 * @param {String} mParameters.defaultVariantName - id of the new default variant
	 * @param {String} mParameters.component - name of the UI5 component
	 * @param {object} mParameters.selector - stable propertyName:propertyValue
	 *
	 * @returns {Object} default variant change
	 *
	 * @private
	 */
	DefaultVariant.prototype._createChangeFile = function(mParameters) {
		var oFileData;

		mParameters.namespace = mParameters.component + '/changes/default';
		mParameters.componentName = mParameters.component;
		mParameters.changeType = 'defaultVariant';

		oFileData = Change.createInitialFileContent(mParameters);

		oFileData.content.defaultVariantName = mParameters.defaultVariantId;
		oFileData.layer = 'USER';

		return oFileData;
	};

	/**
	 * Creates an instance of {sap.ui.fl.Change}, specifying the new default variant
	 *
	 * @param {object} mParameters - map of parameters, see below
	 * @param {String} mParameters.defaultVariantName - id of the new default variant
	 * @param {String} mParameters.component - name of the UI5 component
	 * @param {object} mParameters.selector - stable propertyName:propertyValue
	 * @returns {sap.ui.fl.Change} Change
	 *
	 * @public
	 */
	DefaultVariant.prototype.createChangeObject = function(mParameters) {
		var oFileContent, oChange;

		oFileContent = this._createChangeFile(mParameters);
		oChange = new Change(oFileContent);

		return oChange;
	};

	return new DefaultVariant();
}, /* bExport= */true);

}; // end of sap/ui/fl/DefaultVariant.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.FakeLrepConnector') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
/*global Promise */

jQuery.sap.declare('sap.ui.fl.FakeLrepConnector'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.thirdparty.URI'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/FakeLrepConnector",[
	"jquery.sap.global", "sap/ui/thirdparty/URI", "sap/ui/fl/Utils", "sap/ui/fl/LrepConnector", "sap/ui/fl/Cache"
], function(jQuery, uri, FlexUtils, LrepConnector, Cache) {
	"use strict";
	var lrepConnector = Object.create(LrepConnector.prototype);
	var instance;

	/**
	 * Please use the @link {FakeLrepConnector#enableFakeConnector} function
	 * to enable the FakeLrepConnector.
	 *
	 * Provides a fake implementation for the sap.ui.fl.LrepConnector
	 * @param {String} sInitialComponentJsonPath - the relative path to a test-component-changes.json file
	 *
	 * @constructor
	 * @alias sap.ui.fl.FakeLrepConnector
	 * @experimental Since 1.27.0
	 * @author SAP SE
	 * @version 1.36.12
	 */
	function FakeLrepConnector(sInitialComponentJsonPath){
		this.sInitialComponentJsonPath = sInitialComponentJsonPath;
	}

	for (var prop in lrepConnector){
		if (typeof lrepConnector[prop] === 'function'){
			/*eslint-disable noinspection, no-loop-func */
			FakeLrepConnector.prototype[prop] = (function(prop){
				return function() {
					throw new Error('Method ' + prop + '() is not implemented in FakeLrepConnector.');
				};
			}(prop));
			/*eslint-enable noinspection, no-loop-func */
		}
	}

	FakeLrepConnector.prototype.loadChanges = function(sComponentClassName){
		var initialComponentJsonPath = this.sInitialComponentJsonPath;

		return new Promise(function(resolve, reject){
			jQuery.getJSON(initialComponentJsonPath).done(function(oResponse){
				var result = {
					changes: oResponse,
					componentClassName: sComponentClassName
				};

				resolve(result);
			}).fail(function(error){
				reject(error);
			});
		});
	};

	FakeLrepConnector.prototype.create = function(payload, changeList, isVariant){
		// REVISE ensure old behavior for now, but check again for changes
		if (!isVariant){
			return Promise.resolve();
		}

		if (!payload.creation){
			payload.creation = new Date().toISOString();
		}

		return Promise.resolve({
			response: payload,
			status: 'success'
		});
	};

	FakeLrepConnector.prototype.update = function(payload, changeName, changelist, isVariant) {
		// REVISE ensure old behavior for now, but check again for changes
		if (!isVariant){
			return Promise.resolve();
		}

		return Promise.resolve({
			response: payload,
			status: 'success'
		});
	};

	FakeLrepConnector.prototype.deleteChange = function(params, isVariant){
		// REVISE ensure old behavior for now, but check again for changes
		if (!isVariant){
			return Promise.resolve();
		}

		return Promise.resolve({
			response: undefined,
			status: 'nocontent'
		});
	};

	FakeLrepConnector.prototype.send = function(sUri, sMethod, oData, mOptions){
		return new Promise(function(resolve, reject){
			handleGetTransports(sUri, sMethod, oData, mOptions, resolve, reject);
			handleMakeChangesTransportable(sUri, sMethod, oData, mOptions, resolve, reject);
		});
	};

	function handleMakeChangesTransportable(sUri, sMethod, oData, mOptions, resolve){
		if (sUri.match(/^\/sap\/bc\/lrep\/actions\/make_changes_transportable\//) && sMethod === 'POST'){
			resolve();
		}
	}

	//REVISE Make response configurable
	function handleGetTransports(sUri, sMethod, oData, mOptions, resolve, reject){
		if (sUri.match(/^\/sap\/bc\/lrep\/actions\/gettransports\//)){
			resolve({
				response: {
					"transports": [
						{
							"transportId": "U31K008488",
							"description": "The Ultimate Transport",
							"owner": "Fantasy Owner",
							"locked": false
						}
					],
					"localonly": false,
					"errorCode": ""
				}
			});
		}
	}

	/**
	 * Hooks into the @link {sap.ui.fl.LrepConnector.createConnector} factory
	 * function to enable the fake lrep connector.
	 *
	 * @param sInitialComponentJsonPath - the relative path to a test-component-changes.json file
	 */
	FakeLrepConnector.enableFakeConnector = function(sInitialComponentJsonPath){
		Cache._entries = {};

		if (FakeLrepConnector.enableFakeConnector.original){
			return;
		}

		FakeLrepConnector.enableFakeConnector.original = LrepConnector.createConnector;

		LrepConnector.createConnector = function(){
			if (!instance) {
				instance = new FakeLrepConnector(sInitialComponentJsonPath);
			}

			return instance;
		};
	};

	/**
	 * Restore the original @link {sap.ui.fl.LrepConnector.createConnector} factory
	 * function.
	 */
	FakeLrepConnector.disableFakeConnector = function(){
		if (FakeLrepConnector.enableFakeConnector.original){
			LrepConnector.createConnector = FakeLrepConnector.enableFakeConnector.original;
		}
	};

	return FakeLrepConnector;

}, true);

}; // end of sap/ui/fl/FakeLrepConnector.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.Persistence') ) {
/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
/* global Promise */

jQuery.sap.declare('sap.ui.fl.Persistence'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/Persistence",[
	"sap/ui/fl/Change", "sap/ui/fl/DefaultVariant", "sap/ui/fl/Utils", "jquery.sap.global", "sap/ui/fl/LrepConnector", "sap/ui/fl/Cache"
], function(Change, defaultVariant, Utils, $, LRepConnector, Cache) {

	"use strict";
	/**
	 * Helper object to access a change from the backend. Access helper object for each change (and variant) which was fetched from the backend
	 * 
	 * @constructor
	 * @param {sap.ui.core.Control} oControl - the control for which the changes should be fetched
	 * @param {string} [sStableIdPropertyName='id'] the stable id
	 * @alias sap.ui.fl.Persistence
	 * @author <NAME>
	 * @version 1.36.12
	 * @experimental Since 1.25.0
	 */
	var Persistence = function(oControl, sStableIdPropertyName) {
		this._oControl = oControl;
		this._bHasLoadedChangesFromBackend = false;

		this._sStableIdPropertyName = sStableIdPropertyName || 'id';
		this._sStableId = this._getStableId();

		this._sComponentName = Utils.getComponentClassName(oControl);
		if (!this._sComponentName) {
			Utils.log.error("The Control does not belong to a SAPUI5 component. Variants and Changes for this control might not work as expected.");
		}
		this._oAppDescriptor = Utils.getAppDescriptor(oControl);
		this._sSiteId = Utils.getSiteId(oControl);

		this._oChanges = {};
		this._oMessagebundle = {};

		this._oConnector = this._createLrepConnector();
	};

	/**
	 * Return the name of the SAPUI5 component. All changes are assigned to 1 SAPUI5 component. The SAPUI5 component also serves as authorization
	 * object.
	 * 
	 * @returns {String} component name
	 * @public
	 */
	Persistence.prototype.getComponentName = function() {
		return this._sComponentName;
	};

	/**
	 * Return the name of the SAPUI5 component. All changes are assigned to 1 SAPUI5 component. The SAPUI5 component also serves as authorization
	 * object.
	 * 
	 * @param {string} sComponentName The name of the component
	 * @public
	 */
	Persistence.prototype.setComponentName = function(sComponentName) {
		this._sComponentName = sComponentName;
	};

	/**
	 * Creates a new instance of the LRepConnector
	 * 
	 * @returns {sap.ui.fl.LrepConnector} LRep connector instance
	 * @private
	 */
	Persistence.prototype._createLrepConnector = function() {
		var sXsrfToken, mParams;
		sXsrfToken = Utils.getXSRFTokenFromControl(this._oControl);
		mParams = {
			XsrfToken: sXsrfToken
		};
		return LRepConnector.createConnector(mParams);
	};

	/**
	 * Determines the value of the stable id property of the control
	 * 
	 * @returns {String} Stable Id. Empty string if stable id determination failed
	 * @private
	 */
	Persistence.prototype._getStableId = function() {
		if (!this._oControl) {
			return undefined;
		}

		if ((this._sStableIdPropertyName) && (this._sStableIdPropertyName !== 'id')) {
			var sStableId;
			try {
				sStableId = this._oControl.getProperty(this._sStableIdPropertyName);
			} catch (exception) {
				sStableId = "";
			}
			return sStableId;
		}

		if (typeof this._oControl.getId !== 'function') {
			return undefined;
		}

		return this._oControl.getId();
	};

	/**
	 * Checks for the existance of a variant within the vendor layer
	 * 
	 * @returns {boolean} bExistChangeInVendorLayer
	 * @private
	 */
	Persistence.prototype._existVendorLayerChange = function() {
		var bExistChangeInVendorLayer = false;

		jQuery.each(this._oChanges, function(sChangeKey, oChange) {
			var oOriginDefinition = oChange._oOriginDefinition;
			if (oOriginDefinition.layer === "VENDOR") {
				bExistChangeInVendorLayer = true;
				return false; // break foreach;
			}
		});

		return bExistChangeInVendorLayer;
	};

	/**
	 * Searches for the ower (sap.ui.Component) of passed control
	 * 
	 * @param {object} oControl a ui5Control
	 * @returns {sap.ui.Component} oOwnerComponent
	 * @private
	 */
	Persistence.prototype._getOwnerComponentOfControl = function(oControl) {
		if (!oControl) {
			return undefined;
		}

		var sOwnerId = sap.ui.core.Component.getOwnerIdFor(oControl);
		if (sOwnerId) {
			var oOwnerComponent = sap.ui.component(sOwnerId);
			return oOwnerComponent;
		}

		return this._getOwnerComponentOfControl(oControl.getParent());
	};

	/**
	 * Binds a json model to the component the first time a variant within the vendor layer was detected
	 * 
	 * @private
	 */
	Persistence.prototype._checkForMessagebundleBinding = function() {
		if (this._existVendorLayerChange()) {
			var oOwner = this._getOwnerComponentOfControl(this._oControl);

			if (oOwner && !oOwner.getModel("i18nFlexVendor")) {
				var oModel = new sap.ui.model.json.JSONModel(this._oMessagebundle);
				oOwner.setModel(oModel, "i18nFlexVendor");
			}
		}
	};

	/**
	 * Calls the backend asynchronously and fetches all changes and variants which point to this control in the same component.
	 * 
	 * @see sap.ui.fl.Change
	 * @returns {Promise} with parameter <code>aResults</code> which is a map with key changeId and value instance of sap.ui.fl.Change
	 * @public
	 */
	Persistence.prototype.getChanges = function() {
		var that = this;
		var sComponentName = this._sComponentName;
		var mPropertyBag = {
			appDescriptor: this._oAppDescriptor,
			siteId: this._sSiteId
		};

		if (this._bHasLoadedChangesFromBackend === true) {
			if (this._oMessagebundle) {
				this._checkForMessagebundleBinding();
			}
			return Promise.resolve(this._oChanges);
		}
		return Cache.getChangesFillingCache(this._oConnector, sComponentName, mPropertyBag).then(that._resolveFillingCacheWithChanges.bind(that));
	};

	/**
	 * Intern method of 'getChanges' to handle the resolution of the deferred returned from 'Cache.getChangesFillingCache'.
	 * 
	 * @returns {object} this._oChanges relevant changes filled by internal processing
	 * @private
	 */
	Persistence.prototype._resolveFillingCacheWithChanges = function(oFile) {
		this._fillRelevantChanges(oFile);
		if (oFile && oFile.changes && oFile.changes.messagebundle) {
			this._oMessagebundle = oFile.changes.messagebundle;
			this._checkForMessagebundleBinding();
		}
		this._bHasLoadedChangesFromBackend = true;
		return this._oChanges;
	};

	/**
	 * Calls the backend asynchronously and fetches all changes and variants of the current component.
	 * 
	 * @see sap.ui.fl.Change
	 * @returns {Promise} with parameter <code>aResults</code> which is a map with key changeId and value instance of sap.ui.fl.Change
	 * @public
	 */
	Persistence.prototype.getComponentChanges = function() {
		var that = this;
		var mPropertyBag = {
			appDescriptor: this._oAppDescriptor,
			siteId: this._sSiteId
		};
		return Cache.getChangesFillingCache(this._oConnector, this._sComponentName, mPropertyBag).then(function(oFile) {
			var bNoFilter = true;
			that._fillRelevantChanges(oFile, bNoFilter);
			return that._oChanges;
		});
	};

	/**
	 * Fill the map of <code>sap.ui.fl.Change</code> with all relevant changes
	 * 
	 * @param {object} oFile content of Component-changes.json file
	 * @param {boolean} bNoFilter do not filter on stable ID
	 * @see sap.ui.fl.Change
	 * @private
	 */
	Persistence.prototype._fillRelevantChanges = function(oFile, bNoFilter) {
		var aChangeList, len, oChangeContent, oSelector, oChange, j, sChangeId;
		var that = this;

		var fLogError = function(key, text) {
			Utils.log.error("key : " + key + " and text : " + text.value);
		};

		var fAppendValidChanges = function(id, value) {
			// when filtering set to inactive: add all changes but still filter variants
			if (bNoFilter === true && oChangeContent.fileType === 'change' || that._sStableId === value) {
				oChange = new Change(oChangeContent);
				oChange.attachEvent(Change.events.markForDeletion, that._onDeleteChange.bind(that));
				sChangeId = oChange.getId();
				if (oChange.isValid()) {
					if (that._oChanges[sChangeId] && oChange.isVariant()) {
						Utils.log.error("Id collision - two or more variant files having the same id detected: " + sChangeId);
						jQuery.each(oChange.getDefinition().texts, fLogError);
						Utils.log.error("already exists in variant : ");
						jQuery.each(that._oChanges[sChangeId].getDefinition().texts, fLogError);
					}

					that._oChanges[sChangeId] = oChange;
				}
				return false;
			}
		};

		if (oFile && oFile.changes && oFile.changes.changes) {
			aChangeList = oFile.changes.changes;
			len = aChangeList.length;
			for (j = 0; j < len; j++) {
				oChangeContent = aChangeList[j];
				oSelector = oChangeContent.selector;
				if (oSelector) {
					// filter out only controls of the current
					jQuery.each(oSelector, fAppendValidChanges);
				}
			}
		}
	};

	/**
	 * Returns the change for the provided id.
	 * 
	 * @see sap.ui.fl.Change
	 * @param {string} sChangeId - the id of the change to get
	 * @returns {sap.ui.fl.Change} the found change
	 * @public
	 */
	Persistence.prototype.getChange = function(sChangeId) {
		if (!sChangeId) {
			Utils.log.error("sap.ui.fl.Persistence.getChange : sChangeId is not defined");
			return undefined;
		}

		return this._oChanges[sChangeId];
	};

	/**
	 * Adds a new change (could be variant as well) and returns the id of the new change.
	 * 
	 * @param {object} mParameters map of parameters, see below
	 * @param {string} mParameters.type - type <filterVariant, tableVariant, etc>
	 * @param {string} mParameters.ODataService - name of the OData service --> can be null
	 * @param {object} mParameters.texts - map object with all referenced texts within the file these texts will be connected to the translation
	 *        process
	 * @param {object} mParameters.content - content of the new change
	 * @param {boolean} mParameters.isVariant - indicates if the change is a variant
	 * @param {string} mParameters.packageName - <optional> package name for the new entity <default> is $tmp
	 * @param {boolean} mParameters.isUserDependent - indicates if a change is only valid for the current user
	 * @param {boolean} [mParameters.id] - id of the change. The id has to be globally unique and should only be set in exceptional cases for example
	 *        downport of variants
	 * @returns {string} the ID of the newly created change
	 * @public
	 */
	Persistence.prototype.addChange = function(mParameters) {
		var oFile, oInfo, mInternalTexts, oChange;

		if (!mParameters) {
			return undefined;
		}
		if (!mParameters.type) {
			Utils.log.error("sap.ui.fl.Persistence.addChange : type is not defined");
		}
		if (!mParameters.ODataService) {
			Utils.log.error("sap.ui.fl.Persistence.addChange : ODataService is not defined");
		}
		var sContentType = jQuery.type(mParameters.content);
		if (sContentType !== 'object' && sContentType !== 'array') {
			Utils.log.error("mParameters.content is not of expected type object or array, but is: " + sContentType, "sap.ui.fl.Persistence#addChange");
		}
		// convert the text object to the internal structure
		mInternalTexts = {};
		if (typeof (mParameters.texts) === "object") {
			jQuery.each(mParameters.texts, function(id, text) {
				mInternalTexts[id] = {
					value: text,
					type: "XFLD"
				};
			});
		}

		var oAppDescr = Utils.getAppDescriptor(this._oControl);
		var sComponentName = this._sComponentName; //only used in case ui core provides no app descriptor e.g. during unit tests
		if ( oAppDescr && oAppDescr["sap.app"] ){
			sComponentName = oAppDescr["sap.app"].componentName || oAppDescr["sap.app"].id;
		}
		oInfo = {
			changeType: mParameters.type,
			service: mParameters.ODataService,
			texts: mInternalTexts,
			content: mParameters.content,
			reference: this._sComponentName, //in this case the component name can also be the value of sap-app-id
			componentName: sComponentName,
			isVariant: mParameters.isVariant,
			packageName: mParameters.packageName,
			isUserDependent: mParameters.isUserDependent
		};

		oInfo.selector = this._getSelector();
		oFile = Change.createInitialFileContent(oInfo);

		// If id is provided, overwrite generated id
		if (mParameters.id) {
			oFile.fileName = mParameters.id;
		}

		oChange = this.addChangeFile(oFile);
		return oChange.getId();
	};

	/**
	 * Adds a new change (could be variant as well) and returns the id of the new change.
	 * 
	 * @param {object} oChangeFile The complete and finalized JSON object representation the file content of the change
	 * @returns {sap.ui.fl.Change} the newly created change object
	 * @public
	 */
	Persistence.prototype.addChangeFile = function(oChangeFile) {
		var oChange, sChangeId;

		oChange = new Change(oChangeFile);
		oChange.attachEvent(Change.events.markForDeletion, this._onDeleteChange.bind(this));

		sChangeId = oChange.getId();
		this._oChanges[sChangeId] = oChange;
		return oChange;
	};

	Persistence.prototype.removeChangeFromPersistence = function(oChange) {
		if (oChange.getPendingAction() !== 'NEW') {
			return;
		}

		var sChangeToRemoveId = oChange.getId();
		delete this._oChanges[sChangeToRemoveId];
	};

	/**
	 * Puts an existing change into the persistence.
	 * 
	 * @param {sap.ui.fl.Change} oChange object
	 * @public
	 */
	Persistence.prototype.putChange = function(oChange) {
		oChange.attachEvent(Change.events.markForDeletion, this._onDeleteChange.bind(this));
		var sChangeId = oChange.getId();
		this._oChanges[sChangeId] = oChange;
	};

	/**
	 * Returns a selector filled with the stableIdPropertyName and its value.
	 * 
	 * @returns {Object} selector
	 * @private
	 */
	Persistence.prototype._getSelector = function() {
		var mSelector;
		mSelector = {};
		if (this._sStableIdPropertyName) {
			mSelector[this._sStableIdPropertyName] = this._sStableId;
		}
		return mSelector;
	};

	/**
	 * Retrieves the default variant for the current control
	 * 
	 * @returns {String} id of the default variant
	 * @public
	 */
	Persistence.prototype.getDefaultVariantId = function() {
		return this.getChanges().then(function(oChanges) {
			return defaultVariant.getDefaultVariantId(oChanges);
		});
	};

	/**
	 * Retrieves the default variant for the current control synchronously. WARNING: It is the responsibility of the consumer to make sure, that the
	 * changes have already been retrieved with getChanges. It's recommended to use the async API getDefaultVariantId which works regardless of any
	 * preconditions.
	 * 
	 * @returns {String} id of the default variant
	 * @public
	 */
	Persistence.prototype.getDefaultVariantIdSync = function() {
		return defaultVariant.getDefaultVariantId(this._oChanges);
	};

	/**
	 * Sets the default variant for the current control. A new change object is created or an existing is updated. This change object is kept in
	 * memory and can be flushed using saveAll. WARNING: It is the responsibility of the consumer to make sure, that the changes have already been
	 * retrieved with getChanges. It's recommended to use the async API setDefaultVariantIdId which works regardless of any preconditions.
	 * 
	 * @param {string} sDefaultVariantId - the ID of the new default variant
	 * @returns {Object} the default variant change
	 * @public
	 */
	Persistence.prototype.setDefaultVariantIdSync = function(sDefaultVariantId) {
		var mParameters, oChange;

		var selector = {};
		selector[this._sStableIdPropertyName] = this._sStableId;

		mParameters = {
			defaultVariantId: sDefaultVariantId,
			reference: this._sComponentName,
			selector: selector
		};

		oChange = defaultVariant.updateDefaultVariantId(this._oChanges, sDefaultVariantId);

		if (oChange) {
			return oChange;
		}

		oChange = defaultVariant.createChangeObject(mParameters);
		oChange.attachEvent(Change.events.markForDeletion, this._onDeleteChange.bind(this));
		var sChangeId = oChange.getId();
		this._oChanges[sChangeId] = oChange;
		return oChange;
	};

	/**
	 * Sets the default variant for the current control. A new change object is created or an existing is updated. This change object is kept in
	 * memory and can be flushed using saveAll.
	 * 
	 * @param {string} sDefaultVariantId - the ID of the new default variant
	 * @returns {Promise} the default variant change
	 * @public
	 */
	Persistence.prototype.setDefaultVariantId = function(sDefaultVariantId) {
		var mParameters, oChange;
		var that = this;

		return this.getChanges().then(function(oChanges) {
			var selector = {};
			selector[that._sStableIdPropertyName] = that._sStableId;

			mParameters = {
				defaultVariantId: sDefaultVariantId,
				reference: that._sComponentName,
				selector: selector
			};

			oChange = defaultVariant.updateDefaultVariantId(oChanges, sDefaultVariantId);

			if (oChange) {
				return oChange;
			}

			oChange = defaultVariant.createChangeObject(mParameters);
			oChange.attachEvent(Change.events.markForDeletion, that._onDeleteChange.bind(that));
			oChanges[oChange.getId()] = oChange;
			return oChange;
		});
	};

	/**
	 * Saves/flushes all current changes to the backend.
	 * 
	 * @returns {Promise} resolving with an array of responses or rejecting with the first error
	 * @public
	 */
	Persistence.prototype.saveAll = function() {
		var aPromises = [];
		var that = this;
		jQuery.each(this._oChanges, function(id, oChange) {
			switch (oChange.getPendingAction()) {
				case "NEW":
					aPromises.push(that._oConnector.create(oChange.getDefinition(), oChange.getRequest(), oChange.isVariant()).then(function(result) {
						oChange.setResponse(result.response);
						if (Cache.isActive()) {
							Cache.addChange(oChange.getComponent(), result.response);
						}
						return result;
					}));
					break;
				case "UPDATE":
					aPromises.push(that._oConnector.update(oChange.getDefinition(), oChange.getId(), oChange.getRequest(), oChange.isVariant()).then(function(result) {
						oChange.setResponse(result.response);
						if (Cache.isActive()) {
							Cache.updateChange(oChange.getComponent(), result.response);
						}
						return result;
					}));
					break;
				case "DELETE":
					aPromises.push(that._oConnector.deleteChange({
						sChangeName: oChange.getId(),
						sLayer: oChange.getLayer(),
						sNamespace: oChange.getNamespace(),
						sChangelist: oChange.getRequest()
					}, oChange.isVariant()).then(function(result) {
						var sChangeId = oChange.getId();
						// remove change from all referring Persistence instances
						var mParameter = {
							id: sChangeId
						};
						oChange.fireEvent(Change.events.markForDeletion, mParameter);
						if (Cache.isActive()) {
							Cache.deleteChange(oChange.getComponent(), oChange.getDefinition());
						}
						return result;
					}));
					break;
				default:
					break;
			}
		});

		// TODO Consider not rejecting with first error, but wait for all promises and collect the results
		return Promise.all(aPromises);
	};

	/**
	 * Event Handler for deletion event of sap.ui.fl.Change. Removes the change from the internal changes map
	 * 
	 * @param {object} oEvent - the event with parameters
	 * @private
	 */
	Persistence.prototype._onDeleteChange = function(oEvent) {
		var sChangeId;
		sChangeId = oEvent.getParameter("id");

		var oChange = this.getChange(sChangeId);
		if (oChange.getPendingAction() === "DELETE") {
			delete this._oChanges[sChangeId];
		}
	};

	/**
	 * Returns a flag whether the variant downport scenario is enabled or not. This scenario is only enabled if the current layer is the vendor layer
	 * and the url paramater hotfix is set to true.
	 * 
	 * @returns {boolean} Flag whether the variant downport scenario is enabled
	 * @public
	 */
	Persistence.prototype.isVariantDownport = function() {
		var sLayer, bIsHotfix;
		sLayer = Utils.getCurrentLayer();
		bIsHotfix = Utils.isHotfixMode();

		return ((sLayer === 'VENDOR') && (bIsHotfix));
	};

	return Persistence;
}, true);

}; // end of sap/ui/fl/Persistence.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.registry.ChangeRegistry') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.registry.ChangeRegistry'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/registry/ChangeRegistry",[
	"sap/ui/fl/Utils", "jquery.sap.global", "sap/ui/fl/registry/ChangeRegistryItem", "sap/ui/fl/registry/SimpleChanges", "sap/ui/fl/registry/ChangeTypeMetadata", "sap/ui/fl/registry/Settings"
], function(Utils, jQuery, ChangeRegistryItem, SimpleChanges, ChangeTypeMetadata, Settings) {
	"use strict";

	/**
	 * Central registration for available change types on controls
	 * @constructor	 	  
	 * @alias sap.ui.fl.registry.ChangeRegistry
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 *
	 */
	var ChangeRegistry = function() {
		this._registeredItems = {};
		this.simpleChanges = SimpleChanges;
		this.initSettings();
	};

	ChangeRegistry._instance = undefined;

	ChangeRegistry.getInstance = function() {
		if (!ChangeRegistry._instance) {
			ChangeRegistry._instance = new ChangeRegistry();
		}
		return ChangeRegistry._instance;
	};

	ChangeRegistry.prototype.registerControlsForChanges = function(mControlChanges) {
		var that = this;
		Object.keys(mControlChanges).forEach(function(sControlType){
			mControlChanges[sControlType].forEach(function(oChangeType){
				that.registerControlForSimpleChange(sControlType, oChangeType);
			});
		});
	};

	/**
	 * Adds registration for a control and a simple change
	 * @param {String} sControlType - Name of the control, for example "sap.ui.comp.smartfilterbar.SmartFilterBar"
	 * @param {sap.ui.fl.registry.SimpleChange.member} oSimpleChange - One of the simple changes
	 *
	 * @public
	 */
	ChangeRegistry.prototype.registerControlForSimpleChange = function(sControlType, oSimpleChange) {
		var oChangeRegistryItem;
		if (!sControlType) {
			return;
		}
		if (!oSimpleChange || !oSimpleChange.changeType || !oSimpleChange.changeHandler) {
			return;
		}

		oChangeRegistryItem = this._createChangeRegistryItemForSimpleChange(sControlType, oSimpleChange);

		if (oChangeRegistryItem) {
			this.addRegistryItem(oChangeRegistryItem);
		}
	};

	/**
	 * Adds registration for a control and a simple change
	 * @param {String} sControlType - Name of the control, for example "sap.ui.comp.smartfilterbar.SmartFilterBar"
	 * @param {sap.ui.fl.registry.SimpleChange.member} oSimpleChange - One of the simple changes
	 * @returns {sap.ui.fl.registry.ChangeRegistryItem} the registry item
	 *
	 * @public
	 */
	ChangeRegistry.prototype._createChangeRegistryItemForSimpleChange = function(sControlType, oSimpleChange) {
		var mParam, oChangeTypeMetadata, oChangeRegistryItem;

		//Create change type metadata
		mParam = {
			name: oSimpleChange.changeType,
			changeHandler: oSimpleChange.changeHandler
		};
		oChangeTypeMetadata = new ChangeTypeMetadata(mParam);

		//Create change registry item
		mParam = {
			changeTypeMetadata: oChangeTypeMetadata,
			controlType: sControlType
		};
		oChangeRegistryItem = new ChangeRegistryItem(mParam);

		return oChangeRegistryItem;
	};

	/**
	 * Add a registry item for the controlType and changeType. If the item already exists, it will be overwritten
	 * @param {sap.ui.fl.registry.ChangeRegistryItem} oRegistryItem the registry item
	 * @public
	 */
	ChangeRegistry.prototype.addRegistryItem = function(oRegistryItem) {
		var sChangeType, sControlType;
		if (!oRegistryItem) {
			return;
		}

		sChangeType = oRegistryItem.getChangeTypeName();
		sControlType = oRegistryItem.getControlType();

		this._registeredItems[sControlType] = this._registeredItems[sControlType] || {};
		this._registeredItems[sControlType][sChangeType] = oRegistryItem;
	};

	/**
	 * Remove a registration for:
	 *  - A single change type (only changeTypeName parameter set)
	 *  - The complete registration on a certain control (only controlType parameter set)
	 *  - Or all registrations of a change type on any control (both changeTypeName AND controlType set)
	 * @param {Object} mParam Description see below
	 * @param {String} [mParam.changeTypeName] Change type name which should be removed
	 * @param {String} [mParam.controlType] Control type which should be removed.
	 *
	 * @public	 
	 */
	ChangeRegistry.prototype.removeRegistryItem = function(mParam) {
		if (!mParam.changeTypeName && !mParam.controlType) {
			Utils.log.error("sap.ui.fl.registry.ChangeRegistry: ChangeType and/or ControlType required");
			return;
		}
		//Either remove a specific changeType from a specific control type
		if (mParam.controlType && mParam.changeTypeName) {
			if (this._registeredItems[mParam.controlType]) {
				if (Object.keys(this._registeredItems[mParam.controlType]).length === 1) { //only one changeType...
					delete this._registeredItems[mParam.controlType];
				} else {
					delete this._registeredItems[mParam.controlType][mParam.changeTypeName];
				}
			}
		//or remove by control type
		} else if (mParam.controlType) {
			if (this._registeredItems[mParam.controlType]) {
				delete this._registeredItems[mParam.controlType];
			}
		//or via changeType on all control types
		} else if (mParam.changeTypeName) {
			for ( var controlTypeKey in this._registeredItems) {
				var controlItem = this._registeredItems[controlTypeKey];
				delete controlItem[mParam.changeTypeName];
			}
		}
	};

	/**
	 * Get a registration for:
	 *  - All registration items with specific change type name on all controls (only changeTypeName parameter set)
	 *  - The complete registration(s) on a certain control (only controlType parameter set)
	 *  - Or all registrations of a change type name on any control (both changeTypeName AND controlType set)
	 * @param {Object} mParam Description see below
	 * @param {String} [mParam.changeTypeName] Change type to find registration(s) for this changeType
	 * @param {String} [mParam.controlType] Control type to find registration(s) for this controlType
	 * @param {String} [mParam.layer] Layer where changes are currently applied. If not provided no filtering for valid layers is done.
	 * @returns {Object} Returns an object in the format 
	 * @example {
	 * 				"sap.ui.core.SampleControl":{
	 * 					"labelChange":{<type of @see sap.ui.fl.registry.ChangeRegistryItem>},
	 * 					"visibility":{<type of @see sap.ui.fl.registry.ChangeRegistryItem>}
	 * 				},
	 * 				"sap.ui.core.TestControl":{
	 * 					"visibility":{<type of @see sap.ui.fl.registry.ChangeRegistryItem>}
	 * 				}
	 * 			}
	 * @public	 
	 */
	ChangeRegistry.prototype.getRegistryItems = function(mParam) {
		if (!mParam.changeTypeName && !mParam.controlType) {
			Utils.log.error("sap.ui.fl.registry.ChangeRegistry: Change Type Name and/or Control Type required");
		}

		var result = null;
		if (mParam.controlType && mParam.changeTypeName) {
			var controlRegistrations = this._registeredItems[mParam.controlType];
			if (controlRegistrations) {
				if (controlRegistrations[mParam.changeTypeName]) {
					result = {};
					result[mParam.controlType] = {};
					result[mParam.controlType][mParam.changeTypeName] = controlRegistrations[mParam.changeTypeName];
				}
			}
		} else if (mParam.controlType) {
			if (this._registeredItems[mParam.controlType]) {
				result = {};
				//keep the actual registry items but clone the control-changetype object structure to not modify the registry during filtering
				result[mParam.controlType] = {};
				jQuery.each(this._registeredItems[mParam.controlType], function(sChangeTypeName, oRegistryItem) {
					result[mParam.controlType][sChangeTypeName] = oRegistryItem;
				});
			}
		} else if (mParam.changeTypeName) {
			result = {};
			for ( var controlTypeKey in this._registeredItems) {
				if (this._registeredItems[controlTypeKey][mParam.changeTypeName]) {
					result[controlTypeKey] = {};
					result[controlTypeKey][mParam.changeTypeName] = this._registeredItems[controlTypeKey][mParam.changeTypeName];
				}
			}
		}
		//filter out disabled change types
		this._filterChangeTypes(result, mParam.layer);
		return result;
	};

	/**
	 * Retrieves the Flex Settings for a UI5 component.
	 * 
	 * @param {string} sComponentName the UI5 component name for which settings are requested;
	 * 				   if not provided, hardcoded settings will be used.
	 * 
	 * @private
	 */
	ChangeRegistry.prototype.initSettings = function(sComponentName) {
		this._oSettings = Settings.getInstanceOrUndef(sComponentName);
		if (!this._oSettings) {
			this._oSettings = new Settings({});
		}
	};

	/**
	 * Removes registry items that are not enabled for the current writable layer.
	 * @param {object} oRegistryItems see example
	 * @param {string} sLayer persistency layer, if not provided no filtering is done.
	 * @example {
	 * 				"sap.ui.core.SampleControl":{
	 * 					"labelChange":{<type of @see sap.ui.fl.registry.ChangeRegistryItem>},
	 * 					"visibility":{<type of @see sap.ui.fl.registry.ChangeRegistryItem>}
	 * 				},
	 * 				"sap.ui.core.TestControl":{
	 * 					"visibility":{<type of @see sap.ui.fl.registry.ChangeRegistryItem>}
	 * 				}
	 * 			}
	 * @private
	 */
	ChangeRegistry.prototype._filterChangeTypes = function(oRegistryItems, sLayer) {
		if (this._oSettings && sLayer && oRegistryItems) {
			var that = this;
			jQuery.each(oRegistryItems, function(sControlType, oControlReg) {
				jQuery.each(oControlReg, function(sChangeType, oRegistryItem) {
					var bIsChangeTypeEnabled = that._oSettings.isChangeTypeEnabled(sChangeType, sLayer);
					if (!bIsChangeTypeEnabled) {
						delete oControlReg[sChangeType];
					}
				});
			});
		}
	};

	ChangeRegistry.prototype.getDragInfo = function(sControlType) {
		var controlTypeItems = this._registeredItems[sControlType];
		if (controlTypeItems) {
			return controlTypeItems.getDragInfo();
		}
		return null;
	};

	return ChangeRegistry;
}, true);

}; // end of sap/ui/fl/registry/ChangeRegistry.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.FlexController') ) {
/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
/* global Promise */

jQuery.sap.declare('sap.ui.fl.FlexController'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.mvc.View'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/FlexController",[
	"jquery.sap.global", "sap/ui/fl/Persistence", "sap/ui/fl/registry/ChangeRegistry", "sap/ui/fl/Utils", "sap/ui/fl/Change", "sap/ui/fl/registry/Settings", "sap/ui/fl/ChangePersistenceFactory", "sap/ui/core/mvc/View"
], function(jQuery, Persistence, ChangeRegistry, Utils, Change, FlexSettings, ChangePersistenceFactory, View) {
	"use strict";

	/**
	 * Retrieves changes (LabelChange, etc.) for a sap.ui.core.mvc.View and applies these changes
	 *
	 * @params {string} sComponentName -the component name the flex controler is responsible for
	 * @constructor
	 * @class
	 * @alias sap.ui.fl.FlexController
	 * @experimental Since 1.27.0
	 * @author SAP SE
	 * @version 1.36.12
	 */
	var FlexController = function(sComponentName) {
		this._oChangePersistence = undefined;
		this._sComponentName = sComponentName || "";
		if (this._sComponentName) {
			this._createChangePersistence();
		}
	};

	/**
	 * Sets the component name of the FlexController
	 *
	 * @param {String} sComponentName The name of the component
	 * @public
	 */
	FlexController.prototype.setComponentName = function(sComponentName) {
		this._sComponentName = sComponentName;
		this._createChangePersistence();
	};

	/**
	 * Returns the component name of the FlexController
	 *
	 * @returns {String} the name of the component
	 * @public
	 */
	FlexController.prototype.getComponentName = function() {
		return this._sComponentName;
	};
	/**
	 * Create a change
	 *
	 * @param {object} oChangeSpecificData property bag (nvp) holding the change information (see sap.ui.fl.Change#createInitialFileContent
	 *        oPropertyBag). The property "packageName" is set to $TMP and internally since flex changes are always local when they are created.
	 * @param {sap.ui.core.Control} oControl control for which the change will be added
	 * @returns {sap.ui.fl.Change} the created change
	 * @public
	 */
	FlexController.prototype.createChange = function(oChangeSpecificData, oControl) {

		var oChangeFileContent, oChange, ChangeHandler, oChangeHandler;
		var oAppDescr = Utils.getAppDescriptor(oControl);
		var sComponentName = this.getComponentName();
		oChangeSpecificData.reference = sComponentName; //in this case the component name can also be the value of sap-app-id
		if ( oAppDescr && oAppDescr["sap.app"] ){
			oChangeSpecificData.componentName = oAppDescr["sap.app"].componentName || oAppDescr["sap.app"].id;
		}else {
			//fallback in case no appdescriptor is available (e.g. during unit testing)
			oChangeSpecificData.componentName = sComponentName;
		}
		oChangeSpecificData.packageName = '$TMP'; // first a flex change is always local, until all changes of a component are made transportable

		oChangeFileContent = Change.createInitialFileContent(oChangeSpecificData);
		oChange = new Change(oChangeFileContent);
		// for getting the change handler the control type and the change type are needed
		ChangeHandler = this._getChangeHandler(oChange, oControl);
		if (ChangeHandler) {
			oChangeHandler = new ChangeHandler();
			oChangeHandler.completeChangeContent(oChange, oChangeSpecificData);
		} else {
			throw new Error('Change handler could not be retrieved for change ' + JSON.stringify(oChangeSpecificData));
		}
// first a flex change is always local, until all changes of a component are made transportable
// if ( oChangeSpecificData.transport ){
// oChange.setRequest(oChangeSpecificData.transport);
// }
		return oChange;
	};
	/**
	 * Adds a change to the flex persistence (not yet saved). Will be saved with #saveAll.
	 *
	 * @param {object} oChangeSpecificData property bag (nvp) holding the change information (see sap.ui.fl.Change#createInitialFileContent
	 *        oPropertyBag). The property "packageName" is set to $TMP and internally since flex changes are always local when they are created.
	 * @param {sap.ui.core.Control} oControl control for which the change will be added
	 * @returns {sap.ui.fl.Change} the created change
	 * @public
	 */
	FlexController.prototype.addChange = function(oChangeSpecificData, oControl) {
		var oChange = this.createChange(oChangeSpecificData, oControl);

		this._oChangePersistence.addChange(oChange);

		return oChange;
	};

	/**
	 * Creates a new change and applies it immediately
	 *
	 * @param {object} oChangeSpecificData The data specific to the change, e.g. the new label for a RenameField change
	 * @param {sap.ui.core.Control} oControl The control where the change will be applied to
	 * @public
	 */
	FlexController.prototype.createAndApplyChange = function(oChangeSpecificData, oControl) {
		var oChange = this.addChange(oChangeSpecificData, oControl);
		try {
			this.applyChange(oChange, oControl);
		} catch (ex) {
			this._oChangePersistence.deleteChange(oChange);
			throw ex;
		}
	};

	/**
	 * Saves all changes of a persistence instance.
	 *
	 * @returns {Promise} resolving with an array of responses or rejecting with the first error
	 * @public
	 */
	FlexController.prototype.saveAll = function() {
		return this._oChangePersistence.saveDirtyChanges();
	};

	/**
	 * Loads and applies all changes for the specified view
	 *
	 * @params {object} oView - the view to process
	 * @returns {Promise} without parameters. Promise resolves once all changes of the view have been applied
	 * @public
	 */
	FlexController.prototype.processView = function(oView) {
		var that = this;
		var mPropertyBag = {
			appDescriptor: Utils.getAppDescriptor(oView),
			siteId: Utils.getSiteId(oView)
		};

		var bIsFlexEnabled = this._isFlexEnabled(oView);
		if (!bIsFlexEnabled) {
			return Promise.resolve("No control found, which enable flexibility features. Processing skipped.");
		}

		// do an async fetch of the flex settings
		// to work with that settings during the session
		return FlexSettings.getInstance(this.getComponentName(), mPropertyBag).then(function(oSettings) {
			return that._getChangesForView(oView, mPropertyBag);
		}).then(that._resolveGetChangesForView.bind(that))['catch'](function(error) {
			Utils.log.error('Error processing view ' + error);
		});
	};

	FlexController.prototype._resolveGetChangesForView = function(aChanges) {
		var that = this;
		var fChangeHandler, oChangeHandler;
		
		aChanges.forEach(function(oChange) {
			var oControl = that._getControlByChange(oChange);
			if (oControl) {
				fChangeHandler = that._getChangeHandler(oChange, oControl);
				if (fChangeHandler) {
					oChangeHandler = new fChangeHandler();
				} else {
					Utils.log.error("A change handler of type '" + oChange.getDefinition().changeType + "' does not exist");
				}
				if (oChangeHandler && oChangeHandler.getControlIdFromChangeContent) {
					// check to avoid duplicate IDs
					var sControlId = oChangeHandler.getControlIdFromChangeContent(oChange);
					var bIsControlAlreadyInDOM = !!sap.ui.getCore().byId(sControlId);
					if (!bIsControlAlreadyInDOM) {
						that.applyChangeAndCatchExceptions(oChange, oControl);
					} else {
						var sId = oChange.getSelector().id;
						Utils.log.error("A change of type '" + oChange.getDefinition().changeType + "' tries to add a object with an already existing ID ('" + sId + "')");
					}
				} else {
					that.applyChangeAndCatchExceptions(oChange, oControl);
				}
			} else {
				var oDefinition = oChange.getDefinition();
				var sChangeType = oDefinition.changeType;
				var sTargetControlId = oDefinition.selector.id;
				var fullQualifiedName = oDefinition.namespace  + "/" + oDefinition.fileName + "." + oDefinition.fileType;
				Utils.log.error("A flexibility change tries to change a non existing control.",
						"\n   type of change: '" + sChangeType + "'" +
						"\n   LRep location of the change: " + fullQualifiedName +
						"\n   id of targeted control: '" + sTargetControlId + "'");
			}
		});
	};

	/**
	 * Triggers applyChange and catches exceptions, if some were thrown (logs changes that could not be applied)
	 *
	 * @param {sap.ui.fl.Change} oChange Change instance
	 * @param {sap.ui.core.Control} oControl Control instance
	 * @public
	 */
	FlexController.prototype.applyChangeAndCatchExceptions = function(oChange, oControl) {
		var oChangeDefinition = oChange.getDefinition();
		var sChangeNameSpace = oChangeDefinition.namespace;

		try {
			this.applyChange(oChange, oControl);
		} catch (ex) {
			Utils.log.error("Change could not be applied: [" + oChangeDefinition.layer + "]" + sChangeNameSpace + "/" + oChangeDefinition.fileName + "." + oChangeDefinition.fileType + ": " + ex);
		}
	};

	/**
	 * Retrieves the corresponding change handler for the change and applies the change to the control
	 *
	 * @param {sap.ui.fl.Change} oChange Change instance
	 * @param {sap.ui.core.Control} oControl Control instance
	 * @public
	 */
	FlexController.prototype.applyChange = function(oChange, oControl) {
		var ChangeHandler, oChangeHandler;
		ChangeHandler = this._getChangeHandler(oChange, oControl);
		if (!ChangeHandler) {
			if (oChange && oControl) {
				Utils.log.warning("Change handler implementation for change not found - Change ignored");
			}
			return;
		}

		try {
			oChangeHandler = new ChangeHandler();
			if (oChangeHandler && typeof oChangeHandler.applyChange === 'function') {
				oChangeHandler.applyChange(oChange, oControl);
			}
		} catch (ex) {
			this._setMergeError(true);
			Utils.log.error("Change could not be applied. Merge error detected.");
			throw ex;
		}
	};

	/**
	 * Retrieves the <code>sap.ui.fl.registry.ChangeRegistryItem</code> for the given change and control
	 *
	 * @param {sap.ui.fl.Change} oChange - Change instance
	 * @param {sap.ui.core.Control} oControl Control instance
	 * @returns {sap.ui.fl.changeHandler.Base} the change handler. Undefined if not found.
	 * @private
	 */
	FlexController.prototype._getChangeHandler = function(oChange, oControl) {
		var oChangeTypeMetadata, fChangeHandler;

		oChangeTypeMetadata = this._getChangeTypeMetadata(oChange, oControl);
		if (!oChangeTypeMetadata) {
			return undefined;
		}

		fChangeHandler = oChangeTypeMetadata.getChangeHandler();
		return fChangeHandler;
	};

	/**
	 * Retrieves the <code>sap.ui.fl.registry.ChangeRegistryItem</code> for the given change and control
	 *
	 * @param {sap.ui.fl.Change} oChange Change instance
	 * @param {sap.ui.core.Control} oControl Control instance
	 * @returns {sap.ui.fl.registry.ChangeTypeMetadata} the registry item containing the change handler. Undefined if not found.
	 * @private
	 */
	FlexController.prototype._getChangeTypeMetadata = function(oChange, oControl) {
		var oChangeRegistryItem, oChangeTypeMetadata;

		oChangeRegistryItem = this._getChangeRegistryItem(oChange, oControl);
		if (!oChangeRegistryItem || !oChangeRegistryItem.getChangeTypeMetadata) {
			return undefined;
		}

		oChangeTypeMetadata = oChangeRegistryItem.getChangeTypeMetadata();
		return oChangeTypeMetadata;
	};

	/**
	 * Retrieves the <code>sap.ui.fl.registry.ChangeRegistryItem</code> for the given change and control
	 *
	 * @param {sap.ui.fl.Change} oChange Change instance
	 * @param {sap.ui.core.Control} oControl Control instance
	 * @returns {sap.ui.fl.registry.ChangeRegistryItem} the registry item containing the change handler. Undefined if not found.
	 * @private
	 */
	FlexController.prototype._getChangeRegistryItem = function(oChange, oControl) {
		var sChangeType, sControlType, oChangeRegistryItem, sLayer;
		if (!oChange || !oControl) {
			return undefined;
		}

		sChangeType = oChange.getChangeType();
		sControlType = Utils.getControlType(oControl);

		if (!sChangeType || !sControlType) {
			return undefined;
		}

		sLayer = oChange.getLayer();

		oChangeRegistryItem = this._getChangeRegistry().getRegistryItems({
			"changeTypeName": sChangeType,
			"controlType": sControlType,
			"layer": sLayer
		});
		if (oChangeRegistryItem && oChangeRegistryItem[sControlType] && oChangeRegistryItem[sControlType][sChangeType]) {
			return oChangeRegistryItem[sControlType][sChangeType];
		} else if (oChangeRegistryItem && oChangeRegistryItem[sControlType]) {
			return oChangeRegistryItem[sControlType];
		} else {
			return oChangeRegistryItem;
		}
	};

	/**
	 * Returns the change registry
	 *
	 * @returns {sap.ui.fl.registry.ChangeRegistry} Instance of the change registry
	 * @private
	 */
	FlexController.prototype._getChangeRegistry = function() {
		var oInstance = ChangeRegistry.getInstance();
		// make sure to use the most current flex settings that have been retrieved during processView
		oInstance.initSettings(this.getComponentName());
		return oInstance;
	};

	/**
	 * Returns the control where the change will be applied to. Undefined if control cannot be found.
	 *
	 * @param {sap.ui.fl.Change} oChange Change
	 * @returns {sap.ui.core.Control} Control where the change will be applied to
	 * @private
	 */
	FlexController.prototype._getControlByChange = function(oChange) {
		var oSelector;

		if (!oChange) {
			return undefined;
		}
		oSelector = oChange.getSelector();
		if (oSelector && typeof oSelector.id === "string") {
			return sap.ui.getCore().byId(oSelector.id);
		}

		return undefined;
	};

	/**
	 * Retrieves the changes for the complete UI5 component
	 * @param {map} mPropertyBag - (optional) contains additional data that are needed for reading of changes
	 * - appDescriptor that belongs to actual component
	 * - siteId that belongs to actual component
	 * @returns {Promise} Promise resolves with a map of all {sap.ui.fl.Change} having the changeId as key
	 * @public
	 */
	FlexController.prototype.getComponentChanges = function(mPropertyBag) {
		return this._oChangePersistence.getChangesForComponent(mPropertyBag);
	};

	/**
	 * Retrieves the changes for the view and its siblings (except nested views)
	 *
	 * @params {object} oView - the view
	 * @param {map} mPropertyBag - (optional) contains additional data that are needed for reading of changes
	 * - appDescriptor that belongs to actual component
	 * - siteId that belongs to actual component
	 * @returns {Promise} Promise resolves with a map of all {sap.ui.fl.Change} of a component
	 * @private
	 */
	FlexController.prototype._getChangesForView = function(oView, mPropertyBag) {
		return this._oChangePersistence.getChangesForView(oView.getId(), mPropertyBag);
	};

	/**
	 * Creates a new instance of sap.ui.fl.Persistence based on the current component and caches the instance in a private member
	 *
	 * @returns {sap.ui.fl.Persistence} persistence instance
	 * @private
	 */
	FlexController.prototype._createChangePersistence = function() {
		this._oChangePersistence = ChangePersistenceFactory.getChangePersistenceForComponent(this.getComponentName());
		return this._oChangePersistence;
	};

	/**
	 * Discard changes on the server.
	 *
	 * @param {array} aChanges array of {sap.ui.fl.Change} to be discarded
	 * @returns {Promise} promise that resolves without parameters.
	 */
	FlexController.prototype.discardChanges = function(aChanges) {
		var sActiveLayer = Utils.getCurrentLayer(false);
		aChanges.forEach(function(oChange) {
			// only discard changes of the currently active layer (CUSTOMER vs PARTNER vs VENDOR)
			if (oChange && oChange.getLayer && oChange.getLayer() === sActiveLayer) {
				this._oChangePersistence.deleteChange(oChange);
			}
		}.bind(this));

		return this._oChangePersistence.saveDirtyChanges();
	};

	/**
	 * Searches for controls in the view control tree, which enable flexibility features.
	 *
	 * @param {sap.ui.core.Control} oParentControl Parent control instance
	 * @returns {boolean} true if the view contains controls, which enable flexibility features, false if not.
	 * @private
	 */
	FlexController.prototype._isFlexEnabled = function(oParentControl) {
		var that = this;
		var bIsFlexEnabled = false;

		if (oParentControl.getMetadata) {
			var oParentControlMetadata = oParentControl.getMetadata();
			var oAggregations = oParentControlMetadata.getAllAggregations();
			var aAggregationKeys = Object.keys(oAggregations);
			jQuery.each(aAggregationKeys, function(iAggragationKeyIndex, sAggregationKey) {
				if (sAggregationKey != "data" && oParentControlMetadata.getAggregation) {
					// data has no flex, but cannot be accessed if the data contains a FlattenedDataset (resulting in an error)
					var oAggregation = oParentControlMetadata.getAggregation(sAggregationKey);
					if ( oAggregation && oAggregation.get) {
						var aAggregations = oAggregation.get(oParentControl);
						if (aAggregations) {
							if (!Array.isArray(aAggregations)) {
								// in case of an aggregation with a cardinality of 0..1 the object is returned not in an array.
								aAggregations = [
									aAggregations
								];
							}
							jQuery.each(aAggregations, function(index, oChildControl) {
								if (typeof oChildControl.getFlexEnabled === 'function' && oChildControl.getFlexEnabled()) {
									bIsFlexEnabled = true;
									return false; // break inner jQuery.each
								} else {
									bIsFlexEnabled = that._isFlexEnabled(oChildControl);
									if (bIsFlexEnabled === true) {
										return false; // break inner jQuery.each
									}
								}
							});
							if (bIsFlexEnabled === true) {
								return false; // break outer jQuery.each
							}
						}
					}
				}
			});
		}
		return bIsFlexEnabled;
	};

	FlexController.prototype.deleteChangesForControlDeeply = function(oControl) {
		return Promise.resolve();
	};

	/**
	 * Set flag if an error has occured when merging changes
	 *
	 * @param {Boolean} bHasErrorOccured Indicator if an error has occured
	 * @private
	 */
	FlexController.prototype._setMergeError = function(bHasErrorOccured) {

		// in this case FlexSettings.getInstance does not get passed (AppDescriptorId and SiteId) as setMergeErrorOccured ONLY enrich setting instance
		// with runtime data. No direct backend call
		return FlexSettings.getInstance(this.getComponentName()).then(function(oSettings) {
			oSettings.setMergeErrorOccured(true);
		});
	};

	return FlexController;
}, true);

}; // end of sap/ui/fl/FlexController.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.FlexControllerFactory') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.FlexControllerFactory'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/FlexControllerFactory",[
	"jquery.sap.global", "sap/ui/fl/FlexController", "sap/ui/fl/Utils"
], function(jQuery, FlexController, Utils) {
	"use strict";

	/**
	 * Factory to create new instances of {sap.ui.fl.FlexController}
	 * @constructor
	 * @alias sap.ui.fl.FlexControllerFactory
	 * @experimental Since 1.27.0
	 * @author SAP SE
	 * @version 1.36.12
	 */
	var FlexControllerFactory = {};

	FlexControllerFactory._instanceCache = {};

	/**
	 * Creates or returns an instance of the FlexController
	 *
	 * @public
	 * @param {String} sComponentName The name of the component
	 * @returns {sap.ui.fl.FlexController} instance
	 *
	 */
	FlexControllerFactory.create = function(sComponentName) {
		var oFlexController = FlexControllerFactory._instanceCache[sComponentName];

		if (!oFlexController){
			oFlexController = new FlexController(sComponentName);
			FlexControllerFactory._instanceCache[sComponentName] = oFlexController;
		}

		return oFlexController;
	};

	/**
	 * Creates or returns an instance of the FlexController for the specified control.
	 * The control needs to be embedded into a View and the view needs to be embedded into a component.
	 * If one of this prerequisites is not fulfilled, no instance of FlexController will be returned.
	 *
	 * @public
	 * @param {sap.ui.core.Control} oControl The control
	 * @returns {sap.ui.fl.FlexController} instance
	 */
	FlexControllerFactory.createForControl = function(oControl) {
		var sComponentName = Utils.getComponentClassName(oControl);
		return FlexControllerFactory.create(sComponentName);
	};

	return FlexControllerFactory;
}, true);

}; // end of sap/ui/fl/FlexControllerFactory.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.PreprocessorImpl') ) {
/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
/*global Promise */

// Provides object sap.ui.fl.ProcessorImpl
jQuery.sap.declare('sap.ui.fl.PreprocessorImpl'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Component'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/PreprocessorImpl",[
	'jquery.sap.global', 'sap/ui/core/Component', 'sap/ui/fl/FlexControllerFactory', 'sap/ui/fl/Utils', 'sap/ui/fl/LrepConnector', 'sap/ui/fl/Cache'
], function(jQuery, Component, FlexControllerFactory, Utils, LrepConnector, Cache) {
	'use strict';

	/**
	 * The implementation of the <code>Preprocessor</code> for the SAPUI5 flexibility services that can be hooked in the <code>View</code> life cycle.
	 *
	 * @name sap.ui.fl.PreprocessorImpl
	 * @class
	 * @constructor
	 * @author <NAME>
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 */
	var FlexPreprocessorImpl = function(){
	};

	jQuery.sap.require("sap.ui.core.mvc.Controller");
	sap.ui.require("sap/ui/core/mvc/Controller").registerExtensionProvider("sap.ui.fl.PreprocessorImpl");

	/**
	 * Provides an array of extension providers. An extension provider is an object which were defined as controller extensions. These objects
	 * provides lifecycle and event handler functions of a specific controller.
	 *
	 * @param {string} sControllerName - name of the controller
	 * @param {string} sComponentId - unique id for the running controller - unique as well for manifest first
	 * @param {boolean} bAsync - flag whether <code>Promise</code> should be returned or not (async=true)
	 * @see sap.ui.controller for an overview of the available functions on controllers.
	 * @since 1.34.0
	 * @public
	 */
	FlexPreprocessorImpl.prototype.getControllerExtensions = function(sControllerName, sComponentId, bAsync) {
		//D050664: Commented out due to ticket 1670158697. It will be corrected with backlog item CPOUIFDALLAS-919.
		/*if (bAsync) {
			return Cache.getChangesFillingCache(LrepConnector.createConnector(), sComponentId, undefined).then(function(oFileContent) {

				var oChanges = oFileContent.changes;
				var aExtensionProviders = [];

				if (oChanges) {
					jQuery.each(oChanges, function (index, oChange) {
						if (oChange.changeType === "CodingExtension" && oChange.content && sControllerName === oChange.content.controllerName) {
							aExtensionProviders.push(FlexPreprocessorImpl.getExtensionProvider(oChange));
						}
					});
				}

				return aExtensionProviders;
			});
		}*/
	};

	FlexPreprocessorImpl.getExtensionProvider = function(oChange) {
		var sConvertedAsciiCodeContent = oChange.content.code;
		var sConvertedCodeContent = Utils.asciiToString(sConvertedAsciiCodeContent);
		var oExtensionProvider;

		/*eslint-disable */
		eval("oExtensionProvider = { " + sConvertedCodeContent + " } ");
		/*eslint-enable */

		return oExtensionProvider;
	};

	/**
	 * Asynchronous view processing method.
	 *
	 * @param {sap.ui.core.mvc.View} oView view to process
	 * @returns {jquery.sap.promise} result of the processing, promise if executed asynchronously
	 *
	 * @public
	 */
	 FlexPreprocessorImpl.process = function(oView){
		 return Promise.resolve().then(function(){
			 var sComponentName = Utils.getComponentClassName(oView);
			 if ( !sComponentName || sComponentName.length === 0 ){
				 var sError = "no component name found for " + oView.getId();
				 jQuery.sap.log.info(sError);
				 throw new Error(sError);
			 }else {
			     var oFlexController = FlexControllerFactory.create(sComponentName);
			     return oFlexController.processView(oView);
			 }
		 }).then(function() {
			 jQuery.sap.log.debug("flex processing view " + oView.getId() + " finished");
			 return oView;
		 })["catch"](function(error) {
			 var sError = "view " + oView.getId() + ": " + error;
			 jQuery.sap.log.info(sError); //to allow control usage in applications that do not work with UI flex and components
			 // throw new Error(sError); // throw again, wenn caller handles the promise
			 return oView;
		 });
	 };

	 return FlexPreprocessorImpl;

}, /* bExport= */true);

}; // end of sap/ui/fl/PreprocessorImpl.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.core.EventDelegate') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.core.EventDelegate'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.base.EventProvider'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/core/EventDelegate",[
	"jquery.sap.global", "sap/ui/fl/Utils", "sap/ui/base/EventProvider", "sap/ui/fl/registry/ChangeRegistry", "sap/ui/fl/core/FlexVisualizer"
], function(jQuery, Utils, EventProvider, ChangeRegistry, FlexVisualizer) {
	"use strict";

	/**
	 * 
	 * @constructor	 	 
	 * @param {sap.ui.core.Control} oControl Control reference of the control which is currently in focus
	 * @param {Object} oSupportedRegistryItems Object with supported changes as registry items. Structure matches the returnvalue of @see sap.ui.fl.registry.ChangeRegistry#getRegistryItems	 * 
	 * @alias sap.ui.fl.core.EventDelegate
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 * @private
	 *
	 */
	var EventDelegate = function(oControl, oSupportedRegistryItems) {
		if (!oControl) {
			Utils.log.error("sap.ui.fl.core.EventDelegate: Control required");
		}
		if (!oSupportedRegistryItems) {
			Utils.log.error("sap.ui.fl.core.EventDelegate: Supported registry items required");
		}

		EventProvider.apply(this);

		this._oControl = oControl;
		this._oSupportedRegistryItems = oSupportedRegistryItems;
	};

	EventDelegate.prototype = jQuery.sap.newObject(EventProvider.prototype);

	/**
	 * Register a control for using flexibility
	 * @param {sap.ui.core.Control} oControl Control which should be registered
	 *
	 * @public	 
	 */
	EventDelegate.registerControl = function(oControl) {
		if (oControl) {
			// check if the control is already registered
			var i = 0;
			if (oControl.aDelegates) {
				for (i = 0; i < oControl.aDelegates.length; i++) {
					var sType = "";
					if (oControl.aDelegates[i].oDelegate && oControl.aDelegates[i].oDelegate.getType) {
						sType = (oControl.aDelegates[i].oDelegate.getType());
					}
					if (sType === "Flexibility") {
						return; // already added
					}
				}
			}
			EventDelegate.registerExplicitChanges(oControl);
		}
	};

	/**
	 * Register a control for explicit changes - changes which use a dialog or similar to do the change and can only be activated in a certain mode
	 * @param {sap.ui.core.Control} oControl Control which should be registered
	 *
	 * @public	 
	 */
	EventDelegate.registerExplicitChanges = function(oControl) {
		var oRegistry = ChangeRegistry.getInstance();
		var mParam = {
			controlType: Utils.getControlType(oControl)
		};
		var oSupportedRegistryItems = oRegistry.getRegistryItems(mParam);

		// check if the control will be handled by personalization
		if (Object.keys(oSupportedRegistryItems).length > 0) {
			oControl.addEventDelegate(new EventDelegate(oControl, oSupportedRegistryItems));
		}
	};

	/**
	 * Unregister the control which was registered before	
	 *
	 * @public	 
	 */
	EventDelegate.unregisterControl = function() {

	};

	/**
	 * Function which is called on mouse-over on the registered control to trigger the flexibility framework
	 * @param {sap.ui.core.Event} oEvent Event parameters
	 *
	 * @public	 
	 */
	EventDelegate.prototype.onmouseover = function(oEvent) {
		oEvent.stopPropagation();
		// stopPropagation unfortunately kills column resize of table
		// therefore custom property on the event
		if (oEvent.handled) {
			return;
		} else {
			oEvent.handled = true;
		}

		//TODO: Get from FlexController, once checked-in
		if (FlexVisualizer.isPersonalizationMode()) {
			if (this._oControl && !jQuery(this._oControl.getDomRef()).hasClass("sapuiflex-highlight")) {
				FlexVisualizer.showDialog(this._oControl);
			}
		}
	};

	/**
	 * Function which is called on mouse-out on the registered control to notify that the control is not in scope anymore for flexibility
	 * @param {sap.ui.core.Event} oEvent Event parameters
	 *
	 * @public	 
	 */
	EventDelegate.prototype.onmouseout = function(oEvent) {
		//TODO: Get from FlexController, once checked-in
		if (FlexVisualizer.isPersonalizationMode()) {
			if (this._oControl) {
				FlexVisualizer.closeDialog();
			}
		}
	};

	return EventDelegate;
}, true);

}; // end of sap/ui/fl/core/EventDelegate.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.library') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare('sap.ui.fl.library'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('sap.ui.core.Core'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.library'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.mvc.XMLView'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.mvc.View'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/library",[
		"sap/ui/core/Core",
		"sap/ui/core/library",
		"sap/ui/core/mvc/XMLView",
		"sap/ui/core/mvc/View",
		"sap/ui/fl/registry/ChangeRegistry",
		"sap/ui/fl/registry/SimpleChanges"
	],
	function(Core, corelibrary, XMLView, View, ChangeRegistry, SimpleChanges) {
	"use strict";

	sap.ui.getCore().initLibrary({
		name:"sap.ui.fl",
		version:"1.36.12",
		dependencies:["sap.ui.core"],
		noLibraryCSS: true
	});

    if ( XMLView.registerPreprocessor ){
        // Register preprocessor for TINAF changes
        XMLView.registerPreprocessor('controls', "sap.ui.fl.Preprocessor", true);
    }else {
        //workaround solution until registerPreprocessor is available
        //PreprocessorImpl because in the workaround case there is no preprocessor base object
        View._sContentPreprocessor = "sap.ui.fl.PreprocessorImpl";
    }


    var registerChangeHandlerForOpenUI5Controls = function () {
      //Flex Change Handler registration
      var oChangeRegistry = ChangeRegistry.getInstance();
      oChangeRegistry.registerControlsForChanges({
             "sap.uxap.ObjectPageLayout": [
                    SimpleChanges.moveElements,
                    SimpleChanges.propertyChange
             ],
             "sap.uxap.ObjectPageSection": [
                    SimpleChanges.hideControl,
                    SimpleChanges.unhideControl
             ],
             "sap.uxap.ObjectPageHeader": [
                    SimpleChanges.propertyChange
             ],
             "sap.uxap.ObjectPageHeaderActionButton": [
                    SimpleChanges.propertyChange
             ],
             "sap.ui.table.Column": [
                    SimpleChanges.propertyChange
             ],
             "sap.ui.table.Table" : [
                    SimpleChanges.moveElements
             ],
             "sap.ui.table.AnalyticalTable" : [
                    SimpleChanges.moveElements
             ]
      });
    };

    registerChangeHandlerForOpenUI5Controls();

	return sap.ui.fl;

}, /* bExport= */ true);

}; // end of sap/ui/fl/library.js
if ( !jQuery.sap.isDeclared('sap.ui.fl.Preprocessor') ) {
/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

// Provides object sap.ui.fl.Processor
jQuery.sap.declare('sap.ui.fl.Preprocessor'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.base.Object'); // unlisted dependency retained
sap.ui.define("sap/ui/fl/Preprocessor",[
	'jquery.sap.global', 'sap/ui/base/Object', 'sap/ui/fl/PreprocessorImpl'
], function(jQuery, BaseObject, PreprocessorImpl) {
	'use strict';

	/**
	 * The implementation of the <code>Preprocessor</code> for the SAPUI5 flexibility services that can be hooked in the <code>View</code> life cycle.
	 * 
	 * @name sap.ui.fl.Preprocessor
	 * @class
	 * @constructor
	 * @author <NAME>
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 * @implements sap.ui.core.mvc.View.Preprocessor
	 */
	var FlexPreprocessor = BaseObject.extend("sap.ui.fl.Preprocessor", {
	});
	
	/**
	 * Asynchronous processing method that should be implemented by the inheriting Preprocessor class.
	 * 
	 * @param {sap.ui.core.mvc.View} oView view to process
	 * @returns {jquery.sap.promise} result of the processing, promise if executed asynchronously
	 * 
	 * @public
	 */
	 FlexPreprocessor.process = function(oView){
		return PreprocessorImpl.process(oView);
	 };
	 
	 return FlexPreprocessor;

}, /* bExport= */true);
}; // end of sap/ui/fl/Preprocessor.js
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

// Provides control sap.ui.comp.variants.EditableVariantItem.
sap.ui.define(['jquery.sap.global', 'sap/m/ColumnListItem', 'sap/m/ColumnListItemRenderer', 'sap/ui/comp/library'],
	function(jQuery, ColumnListItem, ColumnListItemRenderer, library) {
	"use strict";


	
	/**
	 * Constructor for a new variants/EditableVariantItem.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no id is given 
	 * @param {object} [mSettings] Initial settings for the new control
	 *
	 * @class
	 * The EditableVariantItem class describes an editable variant list item for the Manage Variants popup.
	 * @extends sap.m.ColumnListItem
	 *
	 * @constructor
	 * @public
	 * @alias sap.ui.comp.variants.EditableVariantItem
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var EditableVariantItem = ColumnListItem.extend("sap.ui.comp.variants.EditableVariantItem", /** @lends sap.ui.comp.variants.EditableVariantItem.prototype */ { metadata : {
	
		library : "sap.ui.comp",
		properties : {
	
			/**
			 * Key of the List Item
			 * @since 1.22.0
			 */
			key : {type : "string", group : "Misc", defaultValue : null},
	
			/**
			 * Indicator if a variant is visible for all users.
			 * @since 1.26.0
			 */
			global : {type : "boolean", group : "Misc", defaultValue : null},
	
			/**
			 * ABAP Package the variant is assigned. Used for transport functionality
			 * @since 1.26.0
			 */
			lifecyclePackage : {type : "string", group : "Misc", defaultValue : null},
	
			/**
			 * Identifier of the transport object the variant is assigned to.
			 * @since 1.26.0
			 */
			lifecycleTransportId : {type : "string", group : "Misc", defaultValue : null},
	
			/**
			 * Variant namespace
			 * @since 1.26.0
			 */
			namespace : {type : "string", group : "Misc", defaultValue : null},
	
			/**
			 * Indication if variant can be changed
			 * @since 1.26.0
			 */
			readOnly : {type : "boolean", group : "Misc", defaultValue : false},
	
			/**
			 * Flags for a variant to indicate why it might be read-only
			 * @since 1.26.0
			 * @deprecated Since version 1.28.0. Replaced by property <code>labelReadOnly</code> 
			 */
			accessOptions : {type : "string", group : "Misc", defaultValue : null, deprecated: true},
	
			/**
			 * Indicates if the variant label can be changed
			 * @since 1.28.0
			 */
			labelReadOnly : {type : "boolean", group : "Misc", defaultValue : false}
		}
	},
	renderer: ColumnListItemRenderer.render
	});
	

	return EditableVariantItem;

}, /* bExport= */ true);
<file_sep>/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
/* global Promise */
sap.ui.define([], function() {
	"use strict";

	/**
	 * @namespace
	 * @alias sap.ui.fl.fieldExt.Access
	 * @experimental Since 1.25.0
	 * @author SAP SE
	 * @version 1.36.12
	 */
	var Access = {};

	/**
	 * Returns all Business Contexts for given service and EntityTypeName/EntitySetName. Not that only EntityTypeName or EntitySetName can be
	 * supplied. Providing both results in an exception
	 * 
	 * @param {string} sServiceUri
	 * @param {string} sEntityTypeName
	 * @param {string} sEntitySetName
	 * @returns {array} aBusinessContexts
	 * @public
	 */
	Access.getBusinessContexts = function(sServiceUri, sEntityTypeName, sEntitySetName) {
		// Determine ServiceName and ServiceVersion from Service URI
		var sServiceName = this._parseServiceName(sServiceUri);
		var sServiceVersion = this._parseServiceVersion(sServiceUri, sServiceName);

		// Build URL for BusinessContextRetrievalService based on ServiceName, ServiceVersion, EntityName
		var sBusinessContextRetrievalUri = this._buildBusinessContextRetrievalUri(sServiceName, sServiceVersion, sEntityTypeName, sEntitySetName);

		// Execute Ajax call
		var mAjaxSettings = this._getAjaxSettings();
		var promise = this._executeAjaxCall(sBusinessContextRetrievalUri, mAjaxSettings, sServiceName, sServiceVersion, sEntityTypeName, sEntitySetName);

		return promise;
	};

	/**
	 * Extracts ServiceName out of Service URI
	 * 
	 * @private
	 * @param {string} sServiceUri
	 * @returns {string} sVersionName
	 */
	Access._parseServiceName = function(sServiceUri) {
		var sServiceName, sServiceNameWithVersion;
		var sODataPath = "sap/opu/odata";

		var iIndexOfODataPath = sServiceUri.indexOf(sODataPath);
		if (iIndexOfODataPath !== -1) {
			// Remove service path prefix
			var iEndOfsODataPath = iIndexOfODataPath + sODataPath.length;
			sServiceNameWithVersion = sServiceUri.substring(iEndOfsODataPath);

            var sSapPrefix = "/SAP";
            var bHasSapPrefix = jQuery.sap.startsWith(sServiceNameWithVersion, sSapPrefix);
            if (bHasSapPrefix) {
				// case of sap specific namespace for the service
                sServiceNameWithVersion = sServiceNameWithVersion.substring(sSapPrefix.length);
            }
        } else {
			// Remove all stuff before and including the first slash
			var iStartPositionOfServiceName = sServiceUri.lastIndexOf("/") + 1;
			sServiceNameWithVersion = sServiceUri.substring(iStartPositionOfServiceName);
		}

		if (sServiceNameWithVersion.indexOf(";v=") != -1) {
			// Cut away all URI stuff that comes before the serviceName
			sServiceName = sServiceNameWithVersion.substring(0, sServiceNameWithVersion.indexOf(";v="));
		} else {
			sServiceName = sServiceNameWithVersion;
		}
		return sServiceName;
	};

	/**
	 * Extracts ServiceVersion out of Service URI
	 * 
	 * @private
	 * @param {string} sServiceUri
	 * @param {string} sServiceName
	 * @returns {string} sVersionNumber
	 */
	Access._parseServiceVersion = function(sServiceUri, sServiceName) {
		if (sServiceUri.indexOf(sServiceName + ";v=") != -1) {
			// Cut away all URI stuff that comes before the serviceName
			var iPositionOfServiceWithVersionFragment = sServiceUri.indexOf(sServiceName + ";v=");
			var sRemainingUri = sServiceUri.substring(iPositionOfServiceWithVersionFragment);

			// Get String from ";v=" up to the next "/" --> this is the version
			// number
			var iPositionAfterVersionPrefix = sServiceName.length + 3;
			var sVersionNumber = sRemainingUri.slice(iPositionAfterVersionPrefix, sRemainingUri.indexOf("/"));

			return sVersionNumber;
		} else {// In this case there is no version information and so it is
			// version 1
			return "0001";
		}
	};

	/**
	 * Builds URI for BusinessContext Retrieval
	 * 
	 * @private
	 * @param {string} sServiceUri
	 * @param {string} sServiceName
	 * @param {string} sEntityName
	 * @param {string} sEntitySetName
	 * @returns {string} sBusinessContextRetrievalUri
	 */
	Access._buildBusinessContextRetrievalUri = function(sServiceName, sServiceVersion, sEntityName, sEntitySetName) {
		if (sEntityName == null) {
			sEntityName = '';
		}
		if (sEntitySetName == null) {
			sEntitySetName = '';
		}

		if (((sEntitySetName.length == 0) && (sEntityName.length == 0)) || (!(sEntitySetName.length == 0) && !(sEntityName.length == 0))) {
			throw new Error("sap.ui.fl.fieldExt.Access._buildBusinessContextRetrievalUri()" + "Inconsistent input parameters EntityName: " + sEntityName + " EntitySet: " + sEntitySetName);
		}

		// Example call:
		// sap/opu/odata/SAP/APS_CUSTOM_FIELD_MAINTENANCE_SRV/GetBusinessContextsByEntityType?EntitySetName=''&EntityTypeName='BusinessPartner'&ServiceName='CFD_TSM_BUPA_MAINT_SRV'&ServiceVersion='0001'&$format=json
		var sBusinessContextRetrievalUri = "/sap/opu/odata/SAP/APS_CUSTOM_FIELD_MAINTENANCE_SRV/GetBusinessContextsByEntityType?" + "EntitySetName=\'" + sEntitySetName + "\'" + "&EntityTypeName=\'" + sEntityName + "\'" + "&ServiceName=\'" + sServiceName + "\'" + "&ServiceVersion=\'" + sServiceVersion + "\'" + "&$format=json";
		return sBusinessContextRetrievalUri;
	};

	/**
	 * Executes Ajax Call for BusinessContext Retrieval
	 * 
	 * @private
	 * @param {string} sBusinessContextRetrievalUri
	 * @param {map} mRequestSettings
	 * @param {string} sServiceName
	 * @param {string} sServiceVersion
	 * @param {string} sEntityName
	 * @returns {Object} oPromise
	 */
	Access._executeAjaxCall = function(sBusinessContextRetrievalUri, mRequestSettings, sServiceName, sServiceVersion, sEntityType, sEntitySetName) {
		var that = this;
		var oDeferred = jQuery.Deferred();

		jQuery.ajax(sBusinessContextRetrievalUri, mRequestSettings).done(function(data, textStatus, jqXHR) {
			var aBusinessContexts = [];
			if (data) {
				var aBusinessContexts = that._extractBusinessContexts(data);
			}

			var oResult = {
				BusinessContexts: aBusinessContexts,
				ServiceName: sServiceName,
				ServiceVersion: sServiceVersion
			};
			oDeferred.resolve(oResult);

		}).fail(function(jqXHR, textStatus, errorThrown) {
			var aErrorMessages = that._getMessagesFromXHR(jqXHR);
			var oError = {
				errorOccured: true,
				errorMessages: aErrorMessages,
				serviceName: sServiceName,
				serviceVersion: sServiceVersion,
				entityType: sEntityType,
				entitySet: sEntitySetName
			};
			oDeferred.reject(oError);
		});

		return oDeferred.promise();
	};

	/**
	 * @private
	 * @returns {map} mSettings
	 */
	Access._getAjaxSettings = function() {
		var mSettings = {
			type: "GET",
			async: true,
			dataType: 'json'
		};
		return mSettings;
	};

	/**
	 * Extracts BusinessContext out of Request response data
	 * 
	 * @private
	 * @param {object} oData
	 * @returns {array} BusinessContexts
	 */
	Access._extractBusinessContexts = function(data) {
		var aResults = null;
		var aBusinessContexts = [];
		if (data && data.d) {
			aResults = data.d.results;
		}

		if (aResults !== null && aResults.length > 0) {
			for (var i = 0; i < aResults.length; i++) {
				if (aResults[i].BusinessContext !== null) {
					aBusinessContexts.push(aResults[i].BusinessContext);
				}
			}
		}

		return aBusinessContexts;
	};

	/**
	 * Extracts error messages from request failure response
	 * 
	 * @private
	 * @param {object} oXHR
	 * @returns {array} errorMessages
	 */
	Access._getMessagesFromXHR = function(oXHR) {
		var aMessages = [];
		try {
			var oErrorResponse = JSON.parse(oXHR.responseText);
			if (oErrorResponse && oErrorResponse.error && oErrorResponse.error.message && oErrorResponse.error.message.value && oErrorResponse.error.message.value !== '') {
				aMessages.push({
					severity: "error",
					text: oErrorResponse.error.message.value
				});
			} else {
				aMessages.push({
					severity: "error",
					text: oXHR.responseText
				});
			}

		} catch (e) {
			// ignore
		}
		return aMessages;
	};

	return Access;
}, /* bExport= */true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */
jQuery.sap.declare("sap.ui.comp.smartmicrochart.SmartAreaMicroChartRenderer");jQuery.sap.require("sap.ui.core.Renderer");jQuery.sap.require("sap.suite.ui.microchart.AreaMicroChartRenderer");sap.ui.comp.smartmicrochart.SmartAreaMicroChartRenderer=sap.ui.core.Renderer.extend(sap.suite.ui.microchart.AreaMicroChartRenderer);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

// Provides control sap.ui.comp.smartform.flexibility.FieldList.
sap.ui.define(['jquery.sap.global', 'sap/ui/comp/library', 'sap/ui/core/Control'],
	function(jQuery, library, Control) {
	"use strict";



	/**
	 * Constructor for a new smartform/flexibility/FieldList.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Contains list of forms, groups and fields which can could be modified by the SAPUI5 flexibility services
	 * @extends sap.ui.core.Control
	 *
	 * @constructor
	 * @public
	 * @alias sap.ui.comp.smartform.flexibility.FieldList
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var FieldList = Control.extend("sap.ui.comp.smartform.flexibility.FieldList", /** @lends sap.ui.comp.smartform.flexibility.FieldList.prototype */ { metadata : {

		library : "sap.ui.comp",
		aggregations : {

			/**
			 * Nodes representing either a Form, a Group or a field
			 */
			nodes : {type : "sap.ui.comp.smartform.flexibility.FieldListNode", multiple : true, singularName : "node"}
		},
		events : {

			/**
			 * Event is fired when the selected node has changed
			 */
			selectionChanged : {},

			/**
			 * Event is fired when the label of the node has changed
			 */
			labelChanged : {},

			/**
			 * Event is fired when a node was hidden
			 */
			nodeHidden : {}
		}
	}});

	/**
	 * init
	 *
	 * @public
	 */
	FieldList.prototype.init = function() {
		// do something for initialization...
		this._oSelectedNode = null;
	};

	/**
	 * Returns the currently selected field list node
	 *
	 * @returns {sap.ui.comp.smartform.flexibility.FieldListNode} field list node
	 * @public
	 */
	FieldList.prototype.getSelectedNode = function() {
		return this._oSelectedNode;
	};

	/**
	 * Registers to the Selected event of the provided field list node
	 *
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oNode field list node
	 * @private
	 */
	FieldList.prototype._registerNodeSelectionChangedEvent = function(oNode) {
		if (oNode) {
			oNode.attachSelected(this._handleSelectionChanged.bind(this));
		}
	};

	/**
	 * Registers to the LabelChanged event of the provided field list node
	 *
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oNode field list node
	 * @private
	 */
	FieldList.prototype._registerNodeLabelChangedEvent = function(oNode) {
		if (oNode) {
			oNode.attachLabelChanged(this._handleLabelChanged.bind(this));
		}
	};

	/**
	 * Registers to the NodeHidden event of the provided field list node
	 *
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oNode field list node
	 * @private
	 */
	FieldList.prototype._registerNodeHiddenEvent = function(oNode) {
		if (oNode) {
			oNode.attachNodeHidden(this._handleNodeHidden.bind(this));
		}
	};

	/**
	 * Deregisters to the Selected event of the provided field list node
	 *
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oNode field list node
	 * @private
	 */
	FieldList.prototype._deregisterNodeSelectionChangedEvent = function(oNode) {
		if (oNode) {
			oNode.detachSelected(this._handleSelectionChanged.bind(this));
		}
	};

	/**
	 * Deregisters to the LabelChanged event of the provided field list node
	 *
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oNode field list node
	 * @private
	 */	FieldList.prototype._deregisterNodeLabelChangedEvent = function(oNode) {
		if (oNode) {
			oNode.detachLabelChanged(this._handleLabelChanged.bind(this));
		}
	};

	/**
	 * Deregisters to the NodeHidden event of the provided field list node
	 *
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oNode field list node
	 * @private
	 */	FieldList.prototype._deregisterNodeHiddenEvent = function(oNode) {
		if (oNode) {
			oNode.detachNodeHidden(this._handleNodeHidden.bind(this));
		}
	};

	/**
	 * Event handler for Selected event of the field list node
	 *
	 * @param {object} oEvent event
	 * @private
	 */
	FieldList.prototype._handleSelectionChanged = function(oEvent) {
		var oNode;
		oNode = oEvent.getParameter("target");
		if (oNode) {
			// this._setSelectedNode(oNode);
			this.fireSelectionChanged({
				node: oNode
			});
		}
	};

	/**
	 * Event handler for LabelChanged event of the field list node
	 *
	 * @param {object} oEvent event
	 * @private
	 */
	FieldList.prototype._handleLabelChanged = function(oEvent) {
		var oNode;
		oNode = oEvent.getParameter("target");
		if (oNode) {
			this.fireLabelChanged({
				node: oNode
			});
		}
	};

	/**
	 * Event handler for NodeHidden event of the field list node
	 *
	 * @param {object} oEvent event
	 * @private
	 */
	FieldList.prototype._handleNodeHidden = function(oEvent) {
		var oNode;
		oNode = oEvent.getParameter("target");
		if (oNode) {
			this.fireNodeHidden({
				node: oNode
			});
		}
	};

	/**
	 * Unselects the previoulsy registered field list node and selects the new field list node
	 *
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oNode field list node
	 * @private
	 */
	FieldList.prototype._setSelectedNode = function(oNode) {
		if (!oNode) {
			return;
		}

		if (this._oSelectedNode) {
			this._oSelectedNode.setIsSelected(false);
		}
		this._oSelectedNode = oNode;
		this._oSelectedNode.setIsSelected(true);
	};

	/**
	 * @private Overwritten - called when field list node is added
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oNode field list node
	 * @returns {sap.ui.comp.smartform.flexibility.FieldListNode} added field list node
	 */
	FieldList.prototype.addNode = function(oNode) {
		this.addAggregation("nodes", oNode, true);
		this._registerNodeSelectionChangedEvent(oNode);
		this._registerNodeLabelChangedEvent(oNode);
		this._registerNodeHiddenEvent(oNode);
		return this;
	};

	/**
	 * @private Overwritten - called when field list node is destroyed
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oNode field list node
	 * @returns {sap.ui.comp.smartform.flexibility.FieldListNode} destroyed field list node
	 */
	FieldList.prototype.destroyNodes = function(oNode) {
		var aNodes, length, i;
		aNodes = this.getNodes();
		length = aNodes.length;
		for (i = 0; i < length; i++) {
			this._deregisterNodeSelectionChangedEvent(aNodes[i]);
			this._deregisterNodeLabelChangedEvent(aNodes[i]);
			this._deregisterNodeHiddenEvent(aNodes[i]);
		}
		this.destroyAggregation("nodes");
		return this;
	};

	/**
	 * @private Overwritten - called when field list node is removed
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oNode field list node
	 * @returns {sap.ui.comp.smartform.flexibility.FieldListNode | number} removed field list node
	 */
	FieldList.prototype.removeNode = function(oNode) {
		this.removeAggregation("nodes", oNode);

		if (typeof oNode === 'number') {
			oNode = this.getNodes([
				oNode
			]);
		}
		this._deregisterNodeSelectionChangedEvent(oNode);
		this._deregisterNodeLabelChangedEvent(oNode);
		this._deregisterNodeHiddenEvent(oNode);

		return this;
	};


	return FieldList;

}, /* bExport= */ true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
sap.ui.define(['jquery.sap.global','./Base'],function(q,B){"use strict";var U=function(){};U.prototype=q.sap.newObject(B.prototype);U.prototype.applyChange=function(c,C){if(C.setVisible){C.setVisible(true);}else{throw new Error("Provided control instance has no setVisible method");}};U.prototype.completeChangeContent=function(c,s){var C=c.getDefinition();if(!C.content){C.content={};}};return U;},true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */

sap.ui.define([
	'jquery.sap.global', './Base'
], function(jQuery, Base) {
	"use strict";

	/**
	 * Change handler for hiding of a control.
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.HideControl
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 */
	var HideControl = function() {
	};
	HideControl.prototype = jQuery.sap.newObject(Base.prototype);

	/**
	 * Hides a control.
	 *
	 * @param {sap.ui.fl.Change} oChange change object with instructions to be applied on the control map
	 * @param {sap.ui.core.Control} oControl control that matches the change selector for applying the change
	 * @public
	 */
	HideControl.prototype.applyChange = function(oChange, oControl) {

		if (oControl.setVisible) {
			oControl.setVisible(false);
		} else {
			throw new Error("Provided control instance has no setVisible method");
		}
	};

	/**
	 * Completes the change by adding change handler specific content
	 *
	 * @param {sap.ui.fl.Change} oChange change object to be completed
	 * @param {object} oSpecificChangeInfo as an empty object since no additional attributes are required for this operation
	 * @public
	 */
	HideControl.prototype.completeChangeContent = function(oChange, oSpecificChangeInfo) {

		var oChangeJson = oChange.getDefinition();

		if (!oChangeJson.content) {
			oChangeJson.content = {};
		}

	};

	return HideControl;
},
/* bExport= */true);
<file_sep>/*!
 * SAP APF Analysis Path Framework
 *
 * (c) Copyright 2012-2014 SAP SE. All rights reserved
 */
/* global window*/
/**
 *@class selectionDisplay
 *@name  selectionDisplay Fragment
 *@description Holds the selections on the active step and displays them in a dialog using js fragment
 *@memberOf sap.apf.ui.reuse.view
 * 
 */
sap.ui.jsfragment("sap.apf.ui.reuse.fragment.selectionDisplay", {
	createContent : function(oController){
		this.oController = oController;
		this.contentWidth = jQuery(window).height() * 0.6 + "px"; // height and width for the dialog relative to the window
		this.contentHeight = jQuery(window).height() * 0.6 + "px";
		var self = this;
		this.oCoreApi = oController.oCoreApi;
		this.oUiApi = oController.oUiApi;
		var closeButton = new sap.m.Button({
			text : self.oCoreApi.getTextNotHtmlEncoded("close"),
			press : function() {
				self.selectionDisplayDialog.close();
				self.selectionDisplayDialog.destroy();
			}
		});
		var oActiveStep = this.oCoreApi.getActiveStep();
		var selectedRepresentation = oActiveStep.getSelectedRepresentation();
		var selectionData =  typeof selectedRepresentation.getSelections === "function" ? selectedRepresentation.getSelections() : undefined; //Returns the filter selections
		var selectedDimension = selectedRepresentation.getMetaData().getPropertyMetadata(selectedRepresentation.getParameter().requiredFilters[0]).label;
		var oModel = new sap.ui.model.json.JSONModel();
		//Preparing the data list in the dialog
		if(selectionData !== undefined){
			var oData = {
					selectionData : selectionData
			};
			var selectionList = new sap.m.List({
				items : {
					path : "/selectionData",
					template: new sap.m.StandardListItem({
					   title : "{text}"
					})
				}
			});
			oModel.setSizeLimit(selectedRepresentation.getSelections().length);
			oModel.setData(oData);
			selectionList.setModel(oModel);
			self.selectionDisplayDialog = new sap.m.Dialog({
				title : this.oCoreApi.getTextNotHtmlEncoded("selected-required-filter", [selectedDimension]) + " (" + selectionData.length + ")",
				contentWidth : self.contentWidth,
				contentHeight : self.contentHeight,	
				buttons : [closeButton],
				content : [selectionList],
			   afterClose : function() {
				   self.selectionDisplayDialog.destroy();
			}
			});
			return self.selectionDisplayDialog;
		}
	}
});<file_sep>sap.apf[version] = 1.36.10
sap.apf[dependencies] = sap.ui.core,sap.ca.ui,sap.m,sap.ui.layout,sap.ushell,sap.viz
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2015 SAP SE. All rights reserved
	
 */
sap.ui.define(["./LegendBase"],function(L){"use strict";var D=L.extend({metadata:{properties:{shape:{type:"sap.gantt.config.Shape"},xDimension:{type:"string"},yDimension:{type:"string"},xDomain:{type:"array"},yDomain:{type:"array"}}}});return D;},true);
<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
/* global  window*/
jQuery.sap.declare("sap.apf.ui.utils.print");
jQuery.sap.require("sap.apf.ui.utils.formatter");
/** 
 *@class PrintHelper
 *@memberOf sap.apf.ui.utils
 *@description has functions to perform printing of Analysis Path
 *  
 */
sap.apf.ui.utils.PrintHelper = function(oInject) {
	"use strict";
	var oCoreApi = oInject.oCoreApi;
	var oUiApi = oInject.uiApi;
	var oFilterIdHandler = oInject.oFilterIdHandler;
	var nStepRenderCount, oChartSelectionPromise, nNoOfSteps;
	this.oPrintLayout = {};
	/**
	 *@method _increaseStepRenderCount increases the step render count as and when each step is rendered
	 **/
	function _increaseStepRenderCount() {
		++nStepRenderCount;
		if (nNoOfSteps === nStepRenderCount) {
			oChartSelectionPromise.resolve();
		}
	}
	/**
	 *@method _createDivForPrint removes the existing div apfPrintArea. Later creates the div apfPrintArea
	 **/
	function _createDivForPrint(oContext) {
		if (!jQuery.isEmptyObject(oContext.oPrintLayout)) {
			oContext.oPrintLayout.removeContent();
		}
		jQuery('#apfPrintArea').remove(); // removing the div which holds the printable content
		jQuery("body").append('<div id="apfPrintArea"></div>'); //div which holds the printable content
		oUiApi.createApplicationLayout(false).setBusy(true);//sets the Local Busy Indicator for the print
	}
	/**
	 *@method _getHeaderForFirstPage creates a header for the first page of print
	 *@returns header for first page of print
	 */
	function _getHeaderForFirstPage() {
		var date = new Date();
		var sAppName = oCoreApi.getApplicationConfigProperties().appName;
		var sAnalysisPathTitle = oUiApi.getAnalysisPath().oSavedPathName.getTitle();
		var headerForFirstPage = new sap.ui.core.HTML({
			id : 'idAPFHeaderForFirstPage',
			content : [ '<div class="subHeaderPrintWrapper"><p class="printHeaderTitle"> ' + oCoreApi.getTextHtmlEncoded(sAppName) + ' : ' + jQuery.sap.encodeHTML(sAnalysisPathTitle) + '</p>',
					'<p class="printHeaderDate"> ' + date.toTimeString() + ' </p></div><div class="clear"></div>' ].join(""),
			sanitizeContent : true
		});
		return headerForFirstPage;
	}
	/**
	 *@method _getPrintLayoutForFacetFiltersAndFooters creates a layout for facet filter and footers page
	 *@description Gets application specific filters and formats them for printing. Gets facet filter values for printing.
	 *@returns print layout for facet filters and footers
	 */
	function _getPrintLayoutForFacetFiltersAndFooters() {
		var i, j, nIndex, oFacetFilterLists, oAppSpecificFilter, mFilterName, mFilterValue, aFiltersForPrining, filterObj, oFormatter, oFacetFilter, aSelectedItems, oFacetAndFooterLayout;
		var aAppSpecificFilterExp = [], aAppSpecificFilters = [], sFilterValue = "", sFilterName = "", aSelectedFilters = [], filterValues = [], aAppSpecificFormattedFilters = [], aFacetFilters = [], oFilterValue = {};
		//First : Get application specific filter values
		var callback = oUiApi.getEventCallback(sap.apf.core.constants.eventTypes.printTriggered);
		var callbackContext = {
			getTextNotHtmlEncoded : oCoreApi.getTextNotHtmlEncoded
		};
		var aAllAppSpecificFilterIds = oFilterIdHandler.getAllInternalIds(); //get application specific filters
		//Get the filter expression for the application specific filters(footers)
		if (aAllAppSpecificFilterIds.length > 0) {
			for(i = 0; i < aAllAppSpecificFilterIds.length; i++) {
				oAppSpecificFilter = oFilterIdHandler.get(aAllAppSpecificFilterIds[i]).getExpressions();
				aAppSpecificFilterExp.push(oAppSpecificFilter[0]);
			}
		}
		//Returns formatted filter values from APF for application specific filters
		function getAppSpecificFormattedFilters() {
			function prepareFormattedFilterValues(oPropertyMetadata) {
				sFilterName = "";
				filterValues = [];
				oFormatter = new sap.apf.ui.utils.formatter({
					getEventCallback : oUiApi.getEventCallback.bind(oUiApi),
					getTextNotHtmlEncoded : oCoreApi.getTextNotHtmlEncoded
				}, oPropertyMetadata);
				sFilterName = oPropertyMetadata.label;
				filterValues.push(oFormatter.getFormattedValue(oPropertyMetadata.name, aAppSpecificFilterExp[i][j].value));
			}
			for(i = 0; i < aAppSpecificFilterExp.length; i++) {
				for(j = 0; j < aAppSpecificFilterExp[i].length; j++) {
					filterObj = aAppSpecificFilterExp[i][j];
					oCoreApi.getMetadataFacade().getProperty(aAppSpecificFilterExp[i][j].name, prepareFormattedFilterValues);
					filterObj["sName"] = sFilterName;
					filterObj["value"] = filterValues;
					aAppSpecificFilters.push(filterObj);
				}
			}
			return aAppSpecificFilters;
		}
		if (callback !== undefined) { //If application has a print functionality on its own use it otherwise get formatted filter values for application specific filters from APF
			aAppSpecificFormattedFilters = callback.apply(callbackContext, aAppSpecificFilterExp) || [];
			aAppSpecificFormattedFilters = (aAppSpecificFormattedFilters.length > 0) ? aAppSpecificFormattedFilters : getAppSpecificFormattedFilters();
		} else { //APF default formatting
			aAppSpecificFormattedFilters = getAppSpecificFormattedFilters();
		}
		//Second : Get all the configured facet filters from APF
		oFacetFilter = oUiApi.getFacetFilterForPrint();
		function getTextsFromSelectedItems(aSelectedItems) {
			aSelectedFilters = [];
			aSelectedItems.forEach(function(oItem) {
				aSelectedFilters.push(oItem.getText());
			});
		}
		if (oFacetFilter) {//If there is a facet filter
			oFacetFilterLists = oFacetFilter.getLists();
			for(nIndex = 0; nIndex < oFacetFilterLists.length; nIndex++) {
				aSelectedItems = [];
				oFilterValue = {};
				oFilterValue.sName = oFacetFilterLists[nIndex].getTitle();
				if (!oFacetFilterLists[nIndex].getSelectedItems().length) {
					aSelectedItems = oFacetFilterLists[nIndex].getItems();
				} else {
					aSelectedItems = oFacetFilterLists[nIndex].getSelectedItems();
				}
				getTextsFromSelectedItems(aSelectedItems);
				oFilterValue.value = aSelectedFilters;
				aFacetFilters.push(oFilterValue);
			}
		}
		//Later : Merge the APF filters and application specific filters for printing; Application specific filters if available are printed first
		aFiltersForPrining = aAppSpecificFormattedFilters.length > 0 ? aAppSpecificFormattedFilters.concat(aFacetFilters) : aFacetFilters;
		oFacetAndFooterLayout = new sap.ui.layout.VerticalLayout({
			id : 'idAPFFacetAndFooterLayout'
		});
		//Formatting the filter array
		for(i = 0; i < aFiltersForPrining.length; i++) {
			sFilterName = aFiltersForPrining[i].sName;
			for(j = 0; j < aFiltersForPrining[i].value.length; j++) {
				if (j !== aFiltersForPrining[i].value.length - 1) {
					sFilterValue += aFiltersForPrining[i].value[j] + ", ";
				} else {
					sFilterValue += aFiltersForPrining[i].value[j];
				}
			}
			mFilterName = new sap.m.Text({
				text : sFilterName
			}).addStyleClass("printFilterName");
			mFilterValue = new sap.m.Text({
				text : sFilterValue
			}).addStyleClass("printFilterValue");
			//Facet UI Layout
			oFacetAndFooterLayout.addContent(mFilterName);
			oFacetAndFooterLayout.addContent(mFilterValue);
			//Reset the filter value
			sFilterValue = "";
		}
		return oFacetAndFooterLayout;
	}
	/**
	 *@method _getHeaderForEachStep creates a header for each step page
	 *@returns header for step page
	 */
	function _getHeaderForEachStep(nIndex, nStepsLength) {
		var oMessageObject;
		var date = new Date();
		var sAppName = oCoreApi.getApplicationConfigProperties().appName;
		var sAnalysisPathTitle = oUiApi.getAnalysisPath().oSavedPathName.getTitle();
		if (!sAppName) {
			oMessageObject = oCoreApi.createMessageObject({
				code : "6003",
				aParameters : [ "sAppName" ]
			});
			oCoreApi.putMessage(oMessageObject);
		}
		var headerForEachStep = new sap.ui.core.HTML({
			id : 'idAPFHeaderForEachStep' + nIndex,
			content : [ '<div class="subHeaderPrintWrapper"><p class="printHeaderTitle"> ' + oCoreApi.getTextHtmlEncoded(sAppName) + ' : ' + jQuery.sap.encodeHTML(sAnalysisPathTitle) + '</p>',
					'<p class="printHeaderDate"> ' + date.toTimeString() + ' </p></div><div class="clear"></div>', '<div class="printChipName"><p>' + oCoreApi.getTextHtmlEncoded("print-step-number", [ nIndex, nStepsLength ]) + '</p></div>' ]
					.join(""),
			sanitizeContent : true
		});
		return headerForEachStep;
	}
	/**
	 *@method _getRepresentationForPrint
	 *@param oStep is used to get the step information
	 *@returns the representation for printing
	 */
	function _getRepresentationForPrint(oStep) {
		var data, metadata, oPrintContent, bIsLegendVisible = false, oRepresentation = {};
		var oStepTitle = oCoreApi.getTextNotHtmlEncoded(oStep.title);
		var oSelectedRepresentation = oStep.getSelectedRepresentation();
		var oStepRepresentation = oSelectedRepresentation.bIsAlternateView ? oSelectedRepresentation.toggleInstance : oSelectedRepresentation;
		//If alternate view(table representation)
		if (oSelectedRepresentation.bIsAlternateView) {
			data = oStep.getSelectedRepresentation().getData();
			metadata = oStep.getSelectedRepresentation().getMetaData();
			oStepRepresentation.setData(data, metadata);
		}
		if (oStepRepresentation.type === sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) {
			oPrintContent = oStepRepresentation.getPrintContent(oStepTitle);
			oRepresentation = oPrintContent.oTableForPrint.getContent()[0];
			var aSelectedItems = oPrintContent.aSelectedListItems;
			oRepresentation.attachUpdateFinished(function() {
				aSelectedItems.forEach(function(item) {
					oRepresentation.setSelectedItem(item);
				});
				_increaseStepRenderCount();
			});
			oRepresentation.setWidth("1000px");
		} else {//If not a table representation
			oPrintContent = oStepRepresentation.getPrintContent(oStepTitle);
			oRepresentation = oPrintContent.oChartForPrinting;
			//If the chart is vizFrame make selections after rendering of chart and update the step render count
			if (oRepresentation.vizSelection) {
				oRepresentation.attachRenderComplete(function() {
					oRepresentation.vizSelection(oPrintContent.aSelectionOnChart);
					_increaseStepRenderCount();
				});
			} else {//If the chart is Viz make selections after initialization of chart and update the step render count
				oRepresentation.attachInitialized(function() {
					oRepresentation.selection(oPrintContent.aSelectionOnChart);
					_increaseStepRenderCount();
				});
			}
		}
		//Show/Hide Legend for print content
		if (oStepRepresentation.bIsLegendVisible === undefined || oStepRepresentation.bIsLegendVisible === true) {
			bIsLegendVisible = true;
		}
		if (oRepresentation.setVizProperties) { //Check if it is Viz Frame Charts
			oRepresentation.setVizProperties({
				legend : {
					visible : bIsLegendVisible
				},
				sizeLegend : {
					visible : bIsLegendVisible
				}
			});
		} else {//fall back for viz charts
			if (oRepresentation.setLegend !== undefined) {
				oRepresentation.setLegend(new sap.viz.ui5.types.legend.Common({
					visible : bIsLegendVisible
				}));
			}
			if (oRepresentation.setSizeLegend !== undefined) {
				oRepresentation.setSizeLegend(new sap.viz.ui5.types.legend.Common({
					visible : bIsLegendVisible
				}));
			}
		}
		return oRepresentation;
	}
	/**
	 *@method _getPrintLayoutForEachStep defines layout used by each step when being printed
	 *@usage _getPrintLayoutForEachStep has to be used to get the layout for individual steps in analysis path.
	 *@param oStep is used to get the step information
	 *@param nIndex is index of the step being printed
	 *@param nStepsLength is the total number of steps in an Analysis Path
	 *@returns the printLayout for a step in an Analysis Path.
	 */
	function _getPrintLayoutForEachStep(oStep, nIndex, nStepsLength) {
		var oStepLayout;
		var oChartLayout = new sap.ui.layout.VerticalLayout({
			id : 'idAPFChartLayout' + nIndex
		});
		oChartLayout.addContent(_getRepresentationForPrint(oStep));
		oStepLayout = new sap.ui.layout.VerticalLayout({
			id : 'idAPFStepLayout' + nIndex,
			content : [ _getHeaderForEachStep(nIndex, nStepsLength), oChartLayout ]
		}).addStyleClass("representationContent"); // @comment : apfoPrintLayout class not provided in css
		return oStepLayout;
	}
	/**
	 *@method Print used to print all the steps in Analysis Path.
	 *@usage PrintHelper().doPrint has to be used for printing Analysis Path
	 */
	this.doPrint = function() {
		var i, j, nIndex, oChart, colCount, table, stepNo, oSelectedRepresentation, oPrintFirstPageLayout;
		var domContent = "", pTimer = 2000, self = this;
		nStepRenderCount = 0;
		var aAllSteps = oCoreApi.getSteps();
		nNoOfSteps = aAllSteps.length;
		this.oPrintLayout = new sap.ui.layout.VerticalLayout({
			id : "idAPFPrintLayout"
		});
		_createDivForPrint(this);
		oChartSelectionPromise = jQuery.Deferred();
		if (nNoOfSteps === 0) {
			oChartSelectionPromise.resolve();
		}
		//Facet Filter and footers are printed in the initial page along with the header
		oPrintFirstPageLayout = new sap.ui.layout.VerticalLayout({
			id : 'idAPFPrintFirstPageLayout',
			content : [ _getHeaderForFirstPage(), _getPrintLayoutForFacetFiltersAndFooters() ]
		}).addStyleClass("representationContent");
		this.oPrintLayout.addContent(oPrintFirstPageLayout);
		//Consecutive pages with one step each is printed
		for(j = 0; j < aAllSteps.length; j++) {
			nIndex = parseInt(j, 10) + 1;
			this.oPrintLayout.addContent(_getPrintLayoutForEachStep(aAllSteps[j], nIndex, aAllSteps.length));
		}
		this.oPrintLayout.placeAt("apfPrintArea");
		if (jQuery(".v-geo-container").length) {//set the timer if geomap exists
			pTimer = 4000;
		}
		window.setTimeout(function() {
			oUiApi.createApplicationLayout(false).setBusy(false); //Removes the Local Busy Indicator after the print
		}, pTimer - 150);
		window.setTimeout(function() { //Set Timeout to load the content on to dom
			jQuery("#" + self.oPrintLayout.sId + " > div:not(:last-child)").after("<div class='page-break'> </div>");
			domContent = self.oPrintLayout.getDomRef(); // Get the DOM Reference
			table = jQuery('#apfPrintArea .sapUiTable');
			if (table.length) {
				colCount = jQuery('#apfPrintArea .printTable .sapMListTblHeader .sapMListTblCell').length;
				if (colCount > 11) {
					jQuery("#setPrintMode").remove();
					jQuery("<style id='setPrintMode' > @media print and (min-resolution: 300dpi) { @page {size : landscape;}}</style>").appendTo("head");
				} else {
					jQuery("#setPrintMode").remove();
					jQuery("<style id='setPrintMode'>@media print and (min-resolution: 300dpi) { @page {size : portrait;}}</style>").appendTo("head");
				}
			}
			jQuery("#apfPrintArea").empty(); //Clear the apfPrintArea
			jQuery("#sap-ui-static > div").hide(); // Hide popup
			jQuery("#apfPrintArea").append(jQuery(domContent).html()); //Push it to apfPrintArea
			for(i = 0; i < jQuery("#apfPrintArea").siblings().length; i++) {
				//TODO alternate way of hiding the content and printing only the representations?????     
				jQuery("#apfPrintArea").siblings()[i].hidden = true; // hiding the content apart from apfPrintArea div
			}
			//Wait until all the have been rendered with selections and then print
			oChartSelectionPromise.then(function() {
				window.print(); //print the content
			});
			window.setTimeout(function() {
				for(i = 0; i < jQuery("#apfPrintArea").siblings().length; i++) {
					jQuery("#apfPrintArea").siblings()[i].hidden = false;
				}
				for(stepNo = 0; stepNo < aAllSteps.length; stepNo++) {
					oSelectedRepresentation = aAllSteps[stepNo].getSelectedRepresentation();
					oSelectedRepresentation = oSelectedRepresentation.bIsAlternateView ? oSelectedRepresentation.toggleInstance : oSelectedRepresentation;
					//Check if the representation is not a table representation; if not destroy the chart instance
					if (oSelectedRepresentation.type !== sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION) {
						//Access layout content to retrieve the chart; Destroy the chart to prevent memory leaks
						oChart = self.oPrintLayout.getContent()[stepNo + 1].getContent()[1].getContent()[0];
						oChart.destroy();
						oChart = null;
					}
				}
				self.oPrintLayout.destroy(); //Destroy the reference & remove from dom
				self.oPrintLayout = null;
			}, 10);
		}, pTimer);
	};
};<file_sep>// Copyright (c) 2009-2014 SAP SE, All Rights Reserved
/**
 * @fileOverview This file contains miscellaneous utility functions.
 */

(function () {
    "use strict";
    /*global dispatchEvent, document, jQuery, localStorage, sap */

    // ensure that sap.ushell exists
    jQuery.sap.declare("sap.ovp.cards.AnnotationHelper");

    sap.ovp.cards.AnnotationHelper = {};
    sap.ovp.cards.AnnotationHelper.formatFunctions = {count: 0};
    sap.ovp.cards.AnnotationHelper.NumberFormatFunctions = {};

    sap.ovp.cards.AnnotationHelper.criticalityConstants = {
        StateValues : {
            None : "None",
            Negative : "Error",
            Critical : "Warning",
            Positive : "Success"
        },
        ColorValues : {
            None : "Neutral",
            Negative : "Error",
            Critical : "Critical",
            Positive : "Good"
        }
    };

    function getCacheEntry(iContext, sKey) {
        if (iContext.getSetting) {
            var oCache = iContext.getSetting("_ovpCache");
            return oCache[sKey];
        }
        return undefined;
    }

    function setCacheEntry(iContext, sKey, oValue) {
        if (iContext.getSetting) {
            var oCache = iContext.getSetting("_ovpCache");
            oCache[sKey] = oValue;
        }
    }

    function criticality2state(criticality, oCriticalityConfigValues) {
        var sState = oCriticalityConfigValues.None;
        if (criticality && criticality.EnumMember) {
            var val = criticality.EnumMember;
            if (endsWith(val, 'Negative')) {
                sState = oCriticalityConfigValues.Negative;
            } else if (endsWith(val, 'Critical')) {
                sState = oCriticalityConfigValues.Critical;
            } else if (endsWith(val, 'Positive')) {
                sState = oCriticalityConfigValues.Positive;
            }
        }
        return sState;
    }

    function endsWith(sString, sSuffix) {
        return sString && sString.indexOf(sSuffix, sString.length - sSuffix.length) !== -1;
    }

    function generateCriticalityCalculationStateFunction(criticalityCalculation, oCriticalityConfigValues) {

        return function (value) {

            value = Number(value);
            var sDirection = criticalityCalculation.ImprovementDirection.EnumMember;
            var oCriticality = {};
            var deviationLow = getNumberValue(criticalityCalculation.DeviationRangeLowValue);
            var deviationHigh = getNumberValue(criticalityCalculation.DeviationRangeHighValue);
            var toleranceLow = getNumberValue(criticalityCalculation.ToleranceRangeLowValue);
            var toleranceHigh = getNumberValue(criticalityCalculation.ToleranceRangeHighValue);
            if (endsWith(sDirection, "Minimize") || endsWith(sDirection, "Minimizing")) {
                if (value <= toleranceHigh) {
                    oCriticality.EnumMember = "Positive";
                } else if (value > deviationHigh) {
                    oCriticality.EnumMember = "Negative";
                } else {
                    oCriticality.EnumMember = "Critical";
                }
            } else if (endsWith(sDirection, "Maximize") || endsWith(sDirection, "Maximizing")) {
                if (value >= toleranceLow) {
                    oCriticality.EnumMember = "Positive";
                } else if (value < deviationLow) {
                    oCriticality.EnumMember = "Negative";
                } else {
                    oCriticality.EnumMember = "Critical";
                }
            } else if (endsWith(sDirection, "Target")) {
                if (value >= toleranceLow && value <= toleranceHigh) {
                    oCriticality.EnumMember = "Positive";
                } else if (value < deviationLow || value > deviationHigh) {
                    oCriticality.EnumMember = "Negative";
                } else {
                    oCriticality.EnumMember = "Critical";
                }
            }

            return criticality2state(oCriticality, oCriticalityConfigValues);
        };
    }

    function getSortedDataFields(iContext, aCollection) {
        var sCacheKey = iContext.getPath() + "-DataFields-Sorted";
        var aSortedFields = getCacheEntry(iContext, sCacheKey);
        if (!aSortedFields) {
            var aDataPoints = getSortedDataPoints(iContext, aCollection);
            var aDataPointsValues = aDataPoints.map(function (oDataPoint) {
                return oDataPoint.Value.Path;
            });
            aDataPointsValues = aDataPointsValues.filter(function (element) {
                return !!element;
            });
            aSortedFields = aCollection.filter(function (item) {
                if (item.RecordType === "com.sap.vocabularies.UI.v1.DataField" && aDataPointsValues.indexOf(item.Value.Path) === -1) {
                    return true;
                }
                return false;
            });
            sortCollectionByImportance(aSortedFields);
            setCacheEntry(iContext, sCacheKey, aSortedFields);
        }
        return aSortedFields;
    }

    function getSortedDataPoints(iContext, aCollection) {
        var sCacheKey = iContext.getPath() + "-DataPoints-Sorted";
        var aSortedFields = getCacheEntry(iContext, sCacheKey);
        if (!aSortedFields) {
            aSortedFields = aCollection.filter(isDataFieldForAnnotation);
            sortCollectionByImportance(aSortedFields);
            var sEntityTypePath;
            for (var i = 0; i < aSortedFields.length; i++) {
                sEntityTypePath = iContext.getPath().substr(0, iContext.getPath().lastIndexOf("/") + 1);
                aSortedFields[i] = iContext.getModel().getProperty(getTargetPathForDataFieldForAnnotation(sEntityTypePath,aSortedFields[i]));
                sEntityTypePath = "";
            }
            setCacheEntry(iContext, sCacheKey, aSortedFields);
        }
        return aSortedFields;
    }

    function isDataFieldForAnnotation(oItem) {
        if (oItem.RecordType === "com.sap.vocabularies.UI.v1.DataFieldForAnnotation"
            &&
            oItem.Target.AnnotationPath.match(/@com.sap.vocabularies.UI.v1.DataPoint.*/)) {
            return true;
        }
        return false;
    }

    function getTargetPathForDataFieldForAnnotation(sEntityTypePath, oDataFieldForAnnotation) {
        if (sEntityTypePath && !endsWith(sEntityTypePath,'/')) {
            sEntityTypePath += '/';
        }
        return sEntityTypePath + oDataFieldForAnnotation.Target.AnnotationPath.slice(1);
    }

    function getImportance(oDataField) {
        var sImportance;
        if (oDataField["com.sap.vocabularies.UI.v1.Importance"]) {
            sImportance = oDataField["com.sap.vocabularies.UI.v1.Importance"].EnumMember;
        }
        return sImportance;
    }

    function sortCollectionByImportance(aCollection) {
        aCollection.sort(function (a, b) {
            var aImportance = getImportance(a),
                bImportance = getImportance(b);

            if (aImportance === bImportance) {
                return 0;
            }

            if (aImportance === "com.sap.vocabularies.UI.v1.ImportanceType/High") {
                return -1;
            } else if (bImportance === "com.sap.vocabularies.UI.v1.ImportanceType/High") {
                return 1;
            } else if (aImportance === "com.sap.vocabularies.UI.v1.ImportanceType/Medium") {
                return -1;
            } else if (bImportance === "com.sap.vocabularies.UI.v1.ImportanceType/Medium") {
                return 1;
            } else if (aImportance === "com.sap.vocabularies.UI.v1.ImportanceType/Low") {
                return -1;
            } else if (bImportance === "com.sap.vocabularies.UI.v1.ImportanceType/Low") {
                return 1;
            }
            return -1;
        });
        return aCollection;
    }

    function formatDataField(iContext, aCollection, index) {
        var item = getSortedDataFields(iContext, aCollection)[index];
        if (item) {
            return formatField(iContext, item);
        }
        return "";
    }

    function getDataFieldName(iContext, aCollection, index) {
        var item = getSortedDataFields(iContext, aCollection)[index];

        if (item) {
            return item.Label.String;
        }
        return "";
    }

    function getDataPointName(iContext, aCollection, index) {
        var item = getSortedDataPoints(iContext, aCollection)[index];

        if (item && item.Title) {
            return item.Title.String;
        }
        return "";
    }

    function formatDataPoint(iContext, aCollection, index) {
        var item = getSortedDataPoints(iContext, aCollection)[index];
        if (!item) {
            return "";
        }

        var oModel = iContext.getSetting('ovpCardProperties');
        var oEntityType = oModel.getProperty("/entityType");
        var oMetaModel = oModel.getProperty("/metaModel");

        return _formatDataPoint(iContext, item, oEntityType, oMetaModel);
    }

    function _formatDataPoint(iContext, oItem, oEntityType, oMetaModel) {

        if (!oItem || !oItem.Value) {
            return "";
        }

        var oEntityTypeProperty = oMetaModel.getODataProperty(oEntityType, oItem.Value.Path);
        //Support sap:text attribute
        if (oEntityTypeProperty && oEntityTypeProperty["sap:text"]) {
            oEntityTypeProperty = oMetaModel.getODataProperty(oEntityType, oEntityTypeProperty["sap:text"]);
            oItem = {Value: {Path: oEntityTypeProperty.name}};
        }
        return formatField(iContext, oItem);
    }

    function formatField(iContext, item, bDontIncludeUOM, bIncludeOnlyUOM) {

        if (item.Value.Apply) {
            return sap.ui.model.odata.AnnotationHelper.format(iContext, item.Value);
        }

        var oModel = iContext.getSetting('ovpCardProperties');
        var oEntityType = oModel.getProperty("/entityType");
        var oMetaModel = oModel.getProperty("/metaModel");

        return _formatField(iContext, item, oEntityType, oMetaModel, bDontIncludeUOM, bIncludeOnlyUOM);
    }

    function _formatField(iContext, oItem, oEntityType, oMetaModel, bDontIncludeUOM, bIncludeOnlyUOM) {

        if (oItem.Value.Apply) {
            return sap.ui.model.odata.AnnotationHelper.format(iContext, oItem.Value);
        }

        var oEntityTypeProperty = oMetaModel.getODataProperty(oEntityType, oItem.Value.Path);
        var result = "";
        var functionName;

        if (!bIncludeOnlyUOM) {

            //Support association
            if (oItem.Value.Path.split("/").length > 1) {
                oEntityTypeProperty = getNavigationSuffix(oMetaModel, oEntityType, oItem.Value.Path);
            }

            if (!oEntityTypeProperty) {
                return "";
            }

            //Item has ValueFormat annotation
            if (oItem.ValueFormat && oItem.ValueFormat.NumberOfFractionalDigits) {
                functionName = getNumberFormatFunctionName(oItem.ValueFormat.NumberOfFractionalDigits.Int);
                result = "{path:'" + oItem.Value.Path + "', formatter: '" + functionName + "'}";
            } else if (oEntityTypeProperty["scale"]) {
                //If there is no value format annotation, we will use the metadata scale property
                functionName = getNumberFormatFunctionName(oEntityTypeProperty["scale"]);
                result = "{path:'" + oEntityTypeProperty.name + "', formatter: '" + functionName + "'}";
            } else {
                result = sap.ui.model.odata.AnnotationHelper.format(iContext, oItem.Value);
            }
        }

        if (!bDontIncludeUOM) {
            //Add currency using path or string
            if (oEntityTypeProperty["Org.OData.Measures.V1.ISOCurrency"]) {
                var oCurrency = oEntityTypeProperty["Org.OData.Measures.V1.ISOCurrency"];
                if (oCurrency.Path) {
                    result = result + " {path: '" + oCurrency.Path + "'}";
                } else if (oCurrency.String) {
                    result = result + " " + oCurrency.String;
                }
            }

            //Add unit using path or string
            if (oEntityTypeProperty["Org.OData.Measures.V1.Unit"]) {
                var oUnit = oEntityTypeProperty["Org.OData.Measures.V1.Unit"];
                if (oUnit.Path) {
                    result = result + " {path: '" + oUnit.Path + "'}";
                } else if (oUnit.String) {
                    result = result + " " + oUnit.String;
                }
            }
        }

        if (result[0] === " "){
            result = result.substring(1);
        }

        return result;
    }

    function getNumberFormatFunctionName(numberOfFractionalDigits) {
        var functionName = "formatNumberCalculation" + numberOfFractionalDigits;
        if (!sap.ovp.cards.AnnotationHelper.NumberFormatFunctions[functionName]) {
            sap.ovp.cards.AnnotationHelper.NumberFormatFunctions[functionName] = generateNumberFormatFunc(Number(numberOfFractionalDigits));
        }
        return "sap.ovp.cards.AnnotationHelper.NumberFormatFunctions." + functionName;
    }

    function generateNumberFormatFunc(numOfFragmentDigit) {
        return function (value) {
            jQuery.sap.require("sap.ui.core.format.NumberFormat");
            var formatNumber = sap.ui.core.format.NumberFormat.getFloatInstance({
                style: 'short',
                showMeasure: false,
                minFractionDigits: numOfFragmentDigit,
                maxFractionDigits: numOfFragmentDigit
            });
            return formatNumber.format(Number(value));
        };
    }

    function getNavigationSuffix(oMetaModel, oEntityType, sProperty) {
        var aParts = sProperty.split("/");

        if (aParts.length > 1) {
            for (var i = 0; i < (aParts.length - 1); i++) {
                var oAssociationEnd = oMetaModel.getODataAssociationEnd(oEntityType, aParts[i]);
                if (oAssociationEnd) {
                    oEntityType = oMetaModel.getODataEntityType(oAssociationEnd.type);
                }
            }

            return oMetaModel.getODataProperty(oEntityType, aParts[aParts.length - 1]);
        }
    }

    function formatDataPointState(iContext, aCollection, index) {
        var aDataPoints = getSortedDataPoints(iContext, aCollection);
        var sState = "None";
        if (aDataPoints.length > index) {
            var item = aDataPoints[index];
           sState = formatDataPointToValue(iContext, item, sap.ovp.cards.AnnotationHelper.criticalityConstants.StateValues);
        }
        return sState;
    }

    function formatDataPointToValue(iContext, oDataPoint, oCriticalityConfigValues) {
        var sState = oCriticalityConfigValues.None;
        if (oDataPoint.Criticality) {
            sState = criticality2state(oDataPoint.Criticality, oCriticalityConfigValues);
        } else if (oDataPoint.CriticalityCalculation) {
            var sFormattedPath = sap.ui.model.odata.AnnotationHelper.format(iContext, oDataPoint.Value);
            var sPath = sFormattedPath.match(/path *: *'.*?',/g);
            if (sPath) {
                var fFormatFunc = generateCriticalityCalculationStateFunction(oDataPoint.CriticalityCalculation, oCriticalityConfigValues);
                sap.ovp.cards.AnnotationHelper.formatFunctions.count++;
                var fName = "formatCriticalityCalculation" + sap.ovp.cards.AnnotationHelper.formatFunctions.count;
                sap.ovp.cards.AnnotationHelper.formatFunctions[fName] = fFormatFunc;
                sState = "{" + sPath + " formatter: 'sap.ovp.cards.AnnotationHelper.formatFunctions." + fName + "'}";
            }
        }

        return sState;
    }

    function getNavigationPrefix(oMetaModel, oEntityType, sProperty) {
        var sExpand = "";
        var aParts = sProperty.split("/");

        if (aParts.length > 1) {
            for (var i = 0; i < (aParts.length - 1); i++) {
                var oAssociationEnd = oMetaModel.getODataAssociationEnd(oEntityType, aParts[i]);
                if (oAssociationEnd) {
                    oEntityType = oMetaModel.getODataEntityType(oAssociationEnd.type);
                    if (sExpand) {
                        sExpand = sExpand + "/";
                    }
                    sExpand = sExpand + aParts[i];
                } else {
                    return sExpand;
                }
            }
        }

        return sExpand;
    }

    sap.ovp.cards.AnnotationHelper.formatField = function (iContext, oItem) {
        return formatField(iContext,oItem);
    };

    /*
     * This formatter method parses the List-Card List's items aggregation path in the Model.
     * The returned path may contain also sorter definition (for the List) sorting is defined
     * appropriately via respected Annotations.
     *
     * @param iContext
     * @param itemsPath
     * @returns List-Card List's items aggregation path in the Model
     */
    sap.ovp.cards.AnnotationHelper.formatItems = function (iContext, oEntitySet) {
        var oModel = iContext.getSetting('ovpCardProperties');

        var bAddODataSelect = oModel.getProperty("/addODataSelect");
        var oMetaModel = oModel.getProperty("/metaModel");
        var oEntityType = oMetaModel.getODataEntityType(oEntitySet.entityType);
        var oSelectionVariant = oEntityType[oModel.getProperty('/selectionAnnotationPath')];
        var oPresentationVariant = oEntityType[oModel.getProperty('/presentationAnnotationPath')];
        var sEntitySetPath = "/" + oEntitySet.name;
        var aAnnotationsPath = Array.prototype.slice.call(arguments, 2);

        //check if entity set needs parameters
        // if selection-annotations path is supplied - we need to resolve it in order to resolve the full entity-set path
        if (oSelectionVariant) {
            if (oSelectionVariant && oSelectionVariant.Parameters) {
                // in case we have UI.SelectionVariant annotation defined on the entityType including Parameters - we need to resolve the entity-set path to include it
                sEntitySetPath = sap.ovp.cards.AnnotationHelper.resolveParameterizedEntitySet(iContext.getSetting('dataModel'), oEntitySet, oSelectionVariant);
            }
        }

        var result = "{path: '" + sEntitySetPath + "', length: " + getItemsLength(oModel);


        //prepare the select fields in case flag is on
        var aSelectFields = [];
        if (bAddODataSelect) {
            aSelectFields = getSelectFields(iContext, oMetaModel, oEntityType, aAnnotationsPath);
        }
        //prepare the expand list if navigation properties are used
        var aExpand = getExpandList(oMetaModel, oEntityType, aAnnotationsPath);

        //add select and expand parameters to the binding info string if needed
        if (aSelectFields.length > 0 || aExpand.length > 0) {
            result = result + ", parameters: {";
            if (aSelectFields.length > 0) {
                result = result + "select: '" + aSelectFields.join(',') + "'";
            }

            if (aExpand.length > 0) {
                if (aSelectFields.length > 0) {
                    result = result + ", ";
                }
                result = result + "expand: '" + aExpand.join(',') + "'";
            }
            result = result + "}";
        }

        //apply sorters information
        var aSorters = getSorters(oModel, oPresentationVariant);
        if (aSorters.length > 0) {
            result = result + ", sorter:" + JSON.stringify(aSorters);
        }

        //apply filters information
        var aFilters = getFilters(oModel, oSelectionVariant);
        if (aFilters.length > 0) {
            result = result + ", filters:" + JSON.stringify(aFilters);
        }
        result = result + "}";

        // returning the parsed path for the Card's items-aggregation binding
        return result;
    };

    /**
     * returns an array of navigation properties prefixes to be used in an odata $expand parameter
     *
     * @param oMetaModel - metamodel to get the annotations to query
     * @param oEntityType - the relevant entityType
     * @param aAnnotationsPath - an array of annotation path to check
     * @returns {Array} of navigation properties prefixes to be used in an odata $expand parameter
     */
    function getExpandList(oMetaModel, oEntityType, aAnnotationsPath) {
        var aExpand = [];
        var sAnnotationPath, oBindingContext, aColl, sExpand;

        //loop over the annotation paths
        for (var i = 0; i < aAnnotationsPath.length; i++) {
            if (!aAnnotationsPath[i]) {
                continue;
            }
            sAnnotationPath = oEntityType.$path + "/" + aAnnotationsPath[i];
            oBindingContext = oMetaModel.createBindingContext(sAnnotationPath);
            aColl = oBindingContext.getObject();
            //if the annotationPath does not exists there is no BindingContext
            aColl = aColl ? aColl : [];
            for (var j = 0; j < aColl.length; j++) {
                if (aColl[j].Value && aColl[j].Value.Path) {
                    sExpand = getNavigationPrefix(oMetaModel, oEntityType, aColl[j].Value.Path);
                    if (sExpand && aExpand.indexOf(sExpand) === -1) {
                        aExpand.push(sExpand);
                    }
                }
            }
        }
        return aExpand;
    }

    /**
     * returns an array of properties paths to be used in an odata $select parameter
     *
     * @param oMetaModel - metamodel to get the annotations to query
     * @param oEntityType - the relevant entityType
     * @param aAnnotationsPath - an array of annotation path to check
     * @returns {Array} of properties paths to be used in an odata $select parameter
     */
    function getSelectFields(iContext, oMetaModel, oEntityType, aAnnotationsPath) {

        var aSelectFields = [];
        var sAnnotationPath, oBindingContext, aColl;

        //loop over the annotation paths
        for (var i = 0; i < aAnnotationsPath.length; i++) {
            if (!aAnnotationsPath[i]) {
                continue;
            }
            sAnnotationPath = oEntityType.$path + "/" + aAnnotationsPath[i];
            oBindingContext = oMetaModel.createBindingContext(sAnnotationPath);
            aColl = oBindingContext.getObject();
            //if the annotationPath does not exists there is no BindingContext
            aColl = aColl ? aColl : [];

            var oItem;
            var aItemValue;
            var sFormattedField;
            var sRecordType;
            for (var j = 0; j < aColl.length; j++) {

                aItemValue = [];
                oItem = aColl[j];
                sFormattedField = "";

                sRecordType = oItem.RecordType;

                if (sRecordType === "com.sap.vocabularies.UI.v1.DataField") {
                    // in case of a DataField we format the field to get biding string
                    sFormattedField = _formatField(iContext,oItem,oEntityType,oMetaModel);

                } else if (sRecordType === "com.sap.vocabularies.UI.v1.DataFieldForAnnotation") {

                    // in case of DataFieldForAnnotation we resolve the DataPoint target path of the DataField and format the field to get biding string
                    var sTargetPath = getTargetPathForDataFieldForAnnotation(oEntityType.$path, oItem);
                    sFormattedField = _formatDataPoint(iContext, oMetaModel.getProperty(sTargetPath), oEntityType, oMetaModel);

                } else if (sRecordType === "com.sap.vocabularies.UI.v1.DataFieldWithUrl" && oItem.Url) {

                    // format the URL ONLY IN CASE NO UrlRef member resides under it
                    var sFormattedUrl;
                    if (!oItem.Url.UrlRef) {
                        sFormattedUrl = sap.ui.model.odata.AnnotationHelper.format(iContext, oItem.Url);
                    }

                    // meaning binding which needs to be evaluated at runtime
                    if (sFormattedUrl && sFormattedUrl.substring(0,2) === "{=") {
                        sFormattedField = sFormattedUrl;
                    }
                }

                // if we have found a relevant binding-info-string this iteration then parse it to get binded properties
                if (sFormattedField) {
                    aItemValue = getPropertiesFromBindingString(sFormattedField);
                }

                if (aItemValue && aItemValue.length > 0) {
                    // for each property found we check if has sap:unit and sap:text
                    var sItemValue;
                    for (var k = 0; k < aItemValue.length; k++) {
                        sItemValue = aItemValue[k];

                        // if this property is found for the first time - look for its unit and text properties as well
                        if (!aSelectFields[sItemValue]) {

                            aSelectFields[sItemValue] = true;

                            // checking if we need to add also the sap:unit property of the field's value
                            var sUnitPropName = getUnitColumn(sItemValue, oEntityType);
                            if (sUnitPropName && sUnitPropName !== sItemValue) {
                                aSelectFields[sUnitPropName] = true;
                            }

                            // checking if we need to add also the sap:text property of the field's value
                            var sTextPropName = getTextPropertyForEntityProperty(oMetaModel, oEntityType, sItemValue);
                            if (sTextPropName && sTextPropName !== sItemValue) {
                                aSelectFields[sTextPropName] = true;
                            }
                        }
                    }
                }
            }
        }
        // return all relevant property names
        return Object.keys(aSelectFields);
    }

    function getPropertiesFromBindingString(sBinding) {

        var regexBindingEvaluation = /\${([a-zA-Z0-9|\/]*)/g;
        var regexBindingNoPath = /[^[{]*[a-zA-Z0-9]/g;
        var regexBindingPath = /path *\: *\'([a-zA-Z0-9]+)*\'/g;

        var regex, index, matches = [];

        if (sBinding.substring(0, 2) === "{=") {
            /*
             meaning binding string looks like "{= <rest of the binding string>}"
             which is a binding which needs to be evaluated using some supported function
             properties appear as ${propertyName} inside the string
             */
            regex = regexBindingEvaluation;

            /* index is 1 as each match found by this regular expression (by invoking regex.exec(string) below) */
            /* is an array of 2 items, for example ["${Address}", "Address"] so we need the 2nd result each match found */
            index = 1;

        } else if (sBinding.indexOf("path") !== -1) {

            /* In a scenario where binding contains string like "{propertyName} {path:'propertyName'}" */
            /* Here we get the properties without path and add it to array matches*/
            var matchWithNoPath = regexBindingNoPath.exec(sBinding);
            while (matchWithNoPath) {
                if (matchWithNoPath[0].indexOf("path") === -1) {
                    matches.push(matchWithNoPath[0]);
                }
                matchWithNoPath = regexBindingNoPath.exec(sBinding);
            }

            /* meaning binding contains string like "{path:'propertyName'}" */
            regex = regexBindingPath;

            /* index is 1 as each match found by this regular expression (by invoking regex.exec(string) below) */
            /* is an array of 2 items, for example ["{path: 'Address'}", "Address"] so we need the 2nd result each match found */
            index = 1;

        } else {
            /* meaning binding contains string like "{'propertyName'}" */
            regex = regexBindingNoPath;

            /* index is 0 as each match found by this regular expression (by invoking regex.exec(string) below) */
            /* is an array of one item, for example ["Address"] so we need the 1st result each match found */
            index = 0;
        }

        var match = regex.exec(sBinding);
        while (match) {
            if (match[index]) {
                matches.push(match[index]);
            }
            match = regex.exec(sBinding);
        }
        return matches;
    }

    /**
     * return the sorters that need to be applyed on an aggregation
     *
     * @param ovpCardProperties - card properties model which might contains sort configurations
     * @param oPresentationVariant - optional presentation variant annotation with SortOrder configuration
     * @returns {Array} of model sorters
     */
    function getSorters(ovpCardProperties, oPresentationVariant) {
        var aSorters = [];
        var oSorter, bDescending;

        //get the configured sorter if exist and append them to the sorters array
        var sPropertyPath = ovpCardProperties.getProperty("/sortBy");
        if (sPropertyPath) {
            // If sorting is enabled by card configuration
            var sSortOrder = ovpCardProperties.getProperty('/sortOrder');
            if (sSortOrder && sSortOrder.toLowerCase() !== 'descending') {
                bDescending = false;
            } else {
                bDescending = true;
            }
            oSorter = {
                path: sPropertyPath,
                descending: bDescending
            };
            aSorters.push(oSorter);
        }

        //get the sorters from the presentation variant annotations if exists
        var aSortOrder = oPresentationVariant && oPresentationVariant.SortOrder || undefined;
        var oSortOrder, sPropertyPath;
        if (aSortOrder) {
            for (var i = 0; i < aSortOrder.length; i++) {
                oSortOrder = aSortOrder[i];
                sPropertyPath = oSortOrder.Property.PropertyPath;
                bDescending = getBooleanValue(oSortOrder.Descending, true);
                oSorter = {
                    path: sPropertyPath,
                    descending: bDescending
                };
                aSorters.push(oSorter);
            }
        }

        return aSorters;
    }


    sap.ovp.cards.AnnotationHelper.getCardFilters = function (ovpCardProperties) {
        var oEntityType = ovpCardProperties.getProperty('/entityType');
        var oSelectionVariant = oEntityType[ovpCardProperties.getProperty('/selectionAnnotationPath')];

        return getFilters(ovpCardProperties, oSelectionVariant);
    };

    /**
     * return the filters that need to be applyed on an aggregation
     *
     * @param ovpCardProperties - card properties model which might contains filters configurations
     * @param oSelectionVariant - optional selection variant annotation with SelectOptions configuration
     * @returns {Array} of model filters
     */
    function getFilters(ovpCardProperties, oSelectionVariant) {
        var aFilters = [];
        //get the configured filters if exist and append them to the filter array
        var aConfigFilters = ovpCardProperties.getProperty("/filters");
        if (aConfigFilters) {
            aFilters = aFilters.concat(aConfigFilters);
        }

        //get the filters from the selection variant annotations if exists
        var aSelectOptions = oSelectionVariant && oSelectionVariant.SelectOptions;
        var oSelectOption, sPropertyPath, oRange;
        if (aSelectOptions) {
            for (var i = 0; i < aSelectOptions.length; i++) {
                oSelectOption = aSelectOptions[i];
                sPropertyPath = oSelectOption.PropertyName.PropertyPath;
                //a select option might contains more then one filter in the Ranges array
                for (var j = 0; j < oSelectOption.Ranges.length; j++) {
                    oRange = oSelectOption.Ranges[j];
                    if (oRange.Sign.EnumMember === "com.sap.vocabularies.UI.v1.SelectionRangeSignType/I") {
                        //create the filter. the Low value is mandatory
                        var oFilter = {
                            path: sPropertyPath,
                            operator: oRange.Option.EnumMember.split("/")[1],
                            value1: getPrimitiveValue(oRange.Low),
                            value2: getPrimitiveValue(oRange.High)
                        };
                        //append the filter to the filters array
                        aFilters.push(oFilter);
                    }
                }
            }
        }

        return aFilters;
    }

    function getBooleanValue(oValue, bDefault) {
        if (oValue && oValue.Boolean) {
            if (oValue.Boolean.toLowerCase() === "true") {
                return true;
            } else if (oValue.Boolean.toLowerCase() === "false") {
                return false;
            }
        }
        return bDefault;
    }

    function getNumberValue(oValue) {
        var value;

        if (oValue) {
            if (oValue.String) {
                value = Number(oValue.String);
            } else if (oValue.Int) {
                value = Number(oValue.Int);
            } else if (oValue.Decimal) {
                value = Number(oValue.Decimal);
            } else if (oValue.Double) {
                value = Number(oValue.Double);
            } else if (oValue.Single) {
                value = Number(oValue.Single);
            }
        }

        return value;
    }

    function getPrimitiveValue(oValue) {
        var value;

        if (oValue) {
            if (oValue.String) {
                value = oValue.String;
            } else if (oValue.Boolean) {
                value = getBooleanValue(oValue);
            } else {
                value = getNumberValue(oValue);
            }
        }

        return value;
    }


    //This object is responsive for devices
    //the id build by Type-ListType-flavor
    var ITEM_LENGTH = {
        "List_condensed": {phone: 5, tablet: 5, desktop: 5},
        "List_extended": {phone: 3, tablet: 3, desktop: 3},
        "List_condensed_bar": {phone: 5, tablet: 5, desktop: 5},
        "List_extended_bar": {phone: 3, tablet: 3, desktop: 3},
        "Table": {phone: 5, tablet: 5, desktop: 5},
        "Stack_simple": {phone: 20, tablet: 20, desktop: 20},
        "Stack_complex": {phone: 5, tablet: 5, desktop: 5}
    };

    function getItemsLength(oOvpCardPropertiesModel) {
        var type = oOvpCardPropertiesModel.getProperty('/contentFragment');
        var listType = oOvpCardPropertiesModel.getProperty('/listType');
        var flavor = oOvpCardPropertiesModel.getProperty('/listFlavor');
        var oItemSizes;

        var device = "desktop";

        //get current device
        if (sap.ui.Device.system.phone) {
            device = "phone";
        } else if (sap.ui.Device.system.tablet) {
            device = "tablet";
        }

        //check the current card type and get the sizes objects
        if (type == "sap.ovp.cards.list.List") {
            if (listType == "extended") {
                if (flavor == "bar") {
                    oItemSizes = ITEM_LENGTH["List_extended_bar"];
                } else {
                    oItemSizes = ITEM_LENGTH["List_extended"];
                }
            } else if (flavor == "bar") {
                oItemSizes = ITEM_LENGTH["List_condensed_bar"];
            } else {
                oItemSizes = ITEM_LENGTH["List_condensed"];
            }
        } else if (type == "sap.ovp.cards.table.Table") {
            oItemSizes = ITEM_LENGTH["Table"];
        } else if (type == "sap.ovp.cards.stack.Stack") {

            if (oOvpCardPropertiesModel.getProperty('/objectStreamCardsNavigationProperty')) {
                oItemSizes = ITEM_LENGTH["Stack_complex"];
            } else {
                oItemSizes = ITEM_LENGTH["Stack_simple"];
            }
        }

        if (oItemSizes) {
            return oItemSizes[device];
        }

        return 5;
    }

    sap.ovp.cards.AnnotationHelper.formatUrl = function (iContext, sUrl) {
        if (sUrl.charAt(0) === '/' || sUrl.indexOf("http") === 0) {
            return sUrl;
        }
        var sBaseUrl = iContext.getModel().getProperty("/baseUrl");
        if (sBaseUrl) {
            return sBaseUrl + "/" + sUrl;
        }
        return sUrl;
    };

    sap.ovp.cards.AnnotationHelper.getDataPointsCount = function (iContext, aCollection) {
        var aDataPoints = getSortedDataPoints(iContext, aCollection);
        return aDataPoints.length;
    };

    sap.ovp.cards.AnnotationHelper.getFirstDataPointValue = function (iContext, aCollection) {
        return sap.ovp.cards.AnnotationHelper.getDataPointValue(iContext, aCollection, 0);
    };

    sap.ovp.cards.AnnotationHelper.getSecondDataPointValue = function (iContext, aCollection) {
        return sap.ovp.cards.AnnotationHelper.getDataPointValue(iContext, aCollection, 1);
    };

    sap.ovp.cards.AnnotationHelper.getDataPointValue = function (iContext, aCollection, index) {
        var aDataPoints = getSortedDataPoints(iContext, aCollection),
            oDataPoint = aDataPoints[index];

        if (oDataPoint && oDataPoint.Value && oDataPoint.Value.Path) {
            return oDataPoint.Value.Path;
        }
        return "";
    };

    sap.ovp.cards.AnnotationHelper.getFirstDataFieldName = function (iContext, aCollection) {
        return getDataFieldName(iContext, aCollection, 0);
    };

    sap.ovp.cards.AnnotationHelper.getSecondDataFieldName = function (iContext, aCollection) {
        return getDataFieldName(iContext, aCollection, 1);
    };

    sap.ovp.cards.AnnotationHelper.getThirdDataFieldName = function (iContext, aCollection) {
        return getDataFieldName(iContext, aCollection, 2);
    };

    sap.ovp.cards.AnnotationHelper.formatFirstDataFieldValue = function (iContext, aCollection) {
        return formatDataField(iContext, aCollection, 0);
    };

    sap.ovp.cards.AnnotationHelper.formatSecondDataFieldValue = function (iContext, aCollection) {
        return formatDataField(iContext, aCollection, 1);
    };

    sap.ovp.cards.AnnotationHelper.formatThirdDataFieldValue = function (iContext, aCollection) {
        return formatDataField(iContext, aCollection, 2);
    };

    sap.ovp.cards.AnnotationHelper.formatFourthDataFieldValue = function (iContext, aCollection) {
        return formatDataField(iContext, aCollection, 3);
    };

    sap.ovp.cards.AnnotationHelper.formatFifthDataFieldValue = function (iContext, aCollection) {
        return formatDataField(iContext, aCollection, 4);
    };

    sap.ovp.cards.AnnotationHelper.formatSixthDataFieldValue = function (iContext, aCollection) {
        return formatDataField(iContext, aCollection, 5);
    };

    sap.ovp.cards.AnnotationHelper.getFirstDataPointName = function (iContext, aCollection) {
        return getDataPointName(iContext, aCollection, 0);
    };

    sap.ovp.cards.AnnotationHelper.getSecondDataPointName = function (iContext, aCollection) {
        return getDataPointName(iContext, aCollection, 1);
    };

    sap.ovp.cards.AnnotationHelper.getThirdDataPointName = function (iContext, aCollection) {
        return getDataPointName(iContext, aCollection, 2);
    };

    sap.ovp.cards.AnnotationHelper.formatFirstDataPointValue = function (iContext, aCollection) {
        return formatDataPoint(iContext, aCollection, 0);
    };

    sap.ovp.cards.AnnotationHelper.formatSecondDataPointValue = function (iContext, aCollection) {
        return formatDataPoint(iContext, aCollection, 1);
    };

    sap.ovp.cards.AnnotationHelper.formatThirdDataPointValue = function (iContext, aCollection) {
        return formatDataPoint(iContext, aCollection, 2);
    };

    sap.ovp.cards.AnnotationHelper.formatFirstDataPointState = function (iContext, aCollection) {
        return formatDataPointState(iContext, aCollection, 0);
    };

    sap.ovp.cards.AnnotationHelper.formatSecondDataPointState = function (iContext, aCollection) {
        return formatDataPointState(iContext, aCollection, 1);
    };

    sap.ovp.cards.AnnotationHelper.formatThirdDataPointState = function (iContext, aCollection) {
        return formatDataPointState(iContext, aCollection, 2);
    };

    sap.ovp.cards.AnnotationHelper.formatKPIHeaderState = function (iContext, oDataPoint) {
        return formatDataPointToValue(iContext, oDataPoint, sap.ovp.cards.AnnotationHelper.criticalityConstants.ColorValues);
    };

    /*
     * @param iContext
     * @returns 0 for false - there are no actions for this context
     *          1 for true - there are actions for this context
     *          does not return actual boolean - so we won't need to parse the result in the xml
     */
    sap.ovp.cards.AnnotationHelper.hasActions = function (iContext, aCollection) {
        var oItem;
        for (var i = 0; i < aCollection.length; i++){
            oItem = aCollection[i];
            if (oItem.RecordType === "com.sap.vocabularies.UI.v1.DataFieldForIntentBasedNavigation" ||
                oItem.RecordType === "com.sap.vocabularies.UI.v1.DataFieldForAction" ||
                oItem.RecordType === "com.sap.vocabularies.UI.v1.DataFieldWithUrl"){
                return 1;
            }
        }
        return 0;
    };

    sap.ovp.cards.AnnotationHelper.isFirstDataPointPercentageUnit = function (iContext, aCollection) {
        var oDataPoint = getSortedDataPoints(iContext, aCollection)[0];

        if (oDataPoint && oDataPoint.Value && oDataPoint.Value.Path) {
            var sEntityTypePath = iContext.getPath().substr(0, iContext.getPath().lastIndexOf("/") + 1);
            var oModel = iContext.getModel();
            var oEntityType = oModel.getProperty(sEntityTypePath);
            var oProperty = oModel.getODataProperty(oEntityType, oDataPoint.Value.Path);
            if (oProperty && oProperty["Org.OData.Measures.V1.Unit"]) {
                return oProperty["Org.OData.Measures.V1.Unit"].String === "%";
            }
        }
        return false;
    };

    sap.ovp.cards.AnnotationHelper.resolveEntityTypePath = function (oAnnotationPathContext) {
        var sAnnotationPath = oAnnotationPathContext.getObject();
        var oModel = oAnnotationPathContext.getModel();
        var oMetaModel = oModel.getProperty("/metaModel");
        var oEntitySet = oMetaModel.getODataEntitySet(oModel.getProperty("/entitySet"));
        var oEntityType = oMetaModel.getODataEntityType(oEntitySet.entityType);
        sAnnotationPath = oEntityType.$path + "/" + sAnnotationPath;
        return oMetaModel.createBindingContext(sAnnotationPath);
    };

    sap.ovp.cards.AnnotationHelper.resolveParameterizedEntitySet = function (oDataModel, oEntitySet, oSelectionVariant) {

        jQuery.sap.require("sap.ui.model.analytics.odata4analytics");
        var path = "";
        var o4a = new sap.ui.model.analytics.odata4analytics.Model(sap.ui.model.analytics.odata4analytics.Model.ReferenceByModel(oDataModel));
        var queryResult = o4a.findQueryResultByName(oEntitySet.name);
        var queryResultRequest = new sap.ui.model.analytics.odata4analytics.QueryResultRequest(queryResult);
        var parameterization = queryResult.getParameterization();

        if (parameterization) {
            queryResultRequest.setParameterizationRequest(new sap.ui.model.analytics.odata4analytics.ParameterizationRequest(parameterization));
            jQuery.each(oSelectionVariant.Parameters, function () {
                if (this.RecordType === "com.sap.vocabularies.UI.v1.IntervalParameter") {
                    queryResultRequest.getParameterizationRequest().setParameterValue(
                        this.PropertyName.PropertyPath,
                        this.PropertyValueFrom.String,
                        this.PropertyValueTo.String
                    );
                } else {
                    queryResultRequest.getParameterizationRequest().setParameterValue(
                        this.PropertyName.PropertyPath,
                        this.PropertyValue.String
                    );
                }
            });
        }

        try {
            path = queryResultRequest.getURIToQueryResultEntitySet();
        } catch (exception) {
            queryResult = queryResultRequest.getQueryResult();
            path = "/" + queryResult.getEntitySet().getQName();
            jQuery.sap.log.error("getEntitySetPathWithParameters", "binding path with parameters failed - " + exception
                || exception.message);
        }
        return path;
    };

    sap.ovp.cards.AnnotationHelper.getAssociationObject = function (oModel, sAssociation, ns) {
        // find a nicer way of getting association set entry in meta model
        var aAssociations = oModel.getServiceMetadata().dataServices.schema[0].association;
        for (var i = 0; i < aAssociations.length; i++) {
            if (ns + "." + aAssociations[i].name === sAssociation) {
                return aAssociations[i];
            }
        }
    };


    /**************************** Formatters & Helpers for KPI-Header logic  ****************************/

    /* Returns binding path for singleton */
    sap.ovp.cards.AnnotationHelper.getAggregateNumber = function (iContext, oEntitySet, oDataPoint, oSelectionVariant) {
        var measure = oDataPoint.Value.Path;
        var ret = "";
        var bParams = oSelectionVariant && oSelectionVariant.Parameters;
        var filtersString = "";

        if (bParams) {
            var dataModel = iContext.getSetting("dataModel");
            var path = sap.ovp.cards.AnnotationHelper.resolveParameterizedEntitySet(dataModel, oEntitySet, oSelectionVariant);
            ret += "{path: '" + path + "'";
        } else {
            ret += "{path: '/" + oEntitySet.name + "'";
        }

        ret += ", length: 1";
        var oOvpCardSettings = iContext.getSetting('ovpCardProperties');
        var oEntityType = oOvpCardSettings.getProperty("/entityType");
        var unitColumn = getUnitColumn(measure, oEntityType);
        var aFilters = getFilters(oOvpCardSettings, oSelectionVariant);

        if (aFilters.length > 0) {
            filtersString += ", filters: " + JSON.stringify(aFilters);
        }

        var selectArr = [];
        selectArr.push(measure);
        if (unitColumn) {
            selectArr.push(unitColumn);
        }
        if (oDataPoint.TrendCalculation && oDataPoint.TrendCalculation.ReferenceValue && oDataPoint.TrendCalculation.ReferenceValue.Path) {
            selectArr.push(oDataPoint.TrendCalculation.ReferenceValue.Path);
        }

        return ret + ", parameters:{select:'" + selectArr.join(",") + "'}" + filtersString + "}";
    };


    /* Creates binding path for NumericContent value */
    sap.ovp.cards.AnnotationHelper.formThePathForAggregateNumber = function (iContext, dataPoint) {
        if (!dataPoint || !dataPoint.Value || !dataPoint.Value.Path) {
            return "";
        }

        return formatField(iContext, dataPoint, true, false);
    };


    /* Creates binding path for trend icon */
    sap.ovp.cards.AnnotationHelper.formThePathForTrendIcon = function (dataPoint) {
        if (!dataPoint || !dataPoint.Value || !dataPoint.Value.Path || !dataPoint.TrendCalculation) {
            return "";
        }

        if (dataPoint.TrendCalculation &&
            dataPoint.TrendCalculation.ReferenceValue &&
            dataPoint.TrendCalculation.ReferenceValue.Path) {
            return "{parts: [{path:'" + dataPoint.Value.Path + "'}, {path:'" + dataPoint.TrendCalculation.ReferenceValue.Path + "'}], formatter: 'sap.ovp.cards.AnnotationHelper.returnTrendDirection'}";
        } else {
            return "{parts: [{path:'" + dataPoint.Value.Path + "'}], formatter: 'sap.ovp.cards.AnnotationHelper.returnTrendDirection'}";
        }
    };

    /* Formatter for Trend Direction for Header */
    sap.ovp.cards.AnnotationHelper.returnTrendDirection = function (aggregateValue, referenceValue) {
        aggregateValue = Number(aggregateValue);
        var ovpModel = this.getModel("ovpCardProperties");
        if (!ovpModel) {
            return;
        }
        var fullQualifier = ovpModel.getProperty("/dataPointAnnotationPath");
        var dataPoint = ovpModel.getProperty("/entityType")[fullQualifier];
        var finalReferenceValue, upDifference, downDifference;

        if (dataPoint.TrendCalculation.ReferenceValue) {
            if (dataPoint.TrendCalculation.ReferenceValue.Path) {
                finalReferenceValue = Number(referenceValue);
            } else {
                finalReferenceValue = getNumberValue(dataPoint.TrendCalculation.ReferenceValue);
            }
        }
        if (dataPoint.TrendCalculation.UpDifference) {
            upDifference = getNumberValue(dataPoint.TrendCalculation.UpDifference);
        }
        if (dataPoint.TrendCalculation.DownDifference) {
            downDifference = getNumberValue(dataPoint.TrendCalculation.DownDifference);
        }
        if (!dataPoint.TrendCalculation.UpDifference && (aggregateValue - finalReferenceValue >= 0)) {
            return "Up";
        }
        if (!dataPoint.TrendCalculation.DownDifference && (aggregateValue - finalReferenceValue <= 0)) {
            return "Down";
        }

        if (finalReferenceValue && upDifference && (aggregateValue - finalReferenceValue >= upDifference)) {
            return "Up";
        }
        if (finalReferenceValue && downDifference && (aggregateValue - finalReferenceValue <= downDifference)) {
            return "Down";
        }
    };

    /* Creates binding path for UOM placeholder */
    sap.ovp.cards.AnnotationHelper.formThePathForUOM = function (iContext, dataPoint) {
        if (!dataPoint || !dataPoint.Value || !dataPoint.Value.Path) {
            return "";
        }

        return formatField(iContext, dataPoint, false, true);
    };


    /* Creates binding path for % change */
    sap.ovp.cards.AnnotationHelper.formPathForPercentageChange = function (dataPoint) {
        if (!dataPoint || !dataPoint.TrendCalculation || !dataPoint.TrendCalculation.ReferenceValue) {
            return "";
        }
        if (dataPoint.TrendCalculation.ReferenceValue.Path) {
            return "{parts: [{path:'" + dataPoint.Value.Path + "'}, {path:'" + dataPoint.TrendCalculation.ReferenceValue.Path + "'}], formatter: 'sap.ovp.cards.AnnotationHelper.returnPercentageChange'}";
        } else {
            return "{parts: [{path:'" + dataPoint.Value.Path + "'}], formatter: 'sap.ovp.cards.AnnotationHelper.returnPercentageChange'}";
        }
    };


    /* Formatter for % change for Header */
    sap.ovp.cards.AnnotationHelper.returnPercentageChange = function (aggregateValue, referenceValuePath) {
        jQuery.sap.require("sap.ui.core.format.NumberFormat");
        var ret = "";
        aggregateValue = Number(aggregateValue);
        var ovpModel = this.getModel("ovpCardProperties");
        if (!ovpModel) {
            return ret;
        }
        var fullQualifier = ovpModel.getProperty("/dataPointAnnotationPath");
        var dataPoint = ovpModel.getProperty("/entityType")[fullQualifier];
        var referenceValue;
        if (!dataPoint.TrendCalculation) {
            return ret;
        }
        if (dataPoint.TrendCalculation.ReferenceValue) {
            if (dataPoint.TrendCalculation.ReferenceValue.String) {
                referenceValue = Number(dataPoint.TrendCalculation.ReferenceValue.String);
            }
            if (dataPoint.TrendCalculation.ReferenceValue.Path) {
                referenceValue = Number(referenceValuePath);
            }
            if (!referenceValue || referenceValue == 0) {
                return ret;
            }
            var percentNumber = ((Number(aggregateValue) - referenceValue) / referenceValue);
            var percentFormatter = sap.ui.core.format.NumberFormat.getPercentInstance({
                style: 'short',
                minFractionDigits: 2,
                maxFractionDigits: 2
            });
         
            return percentFormatter.format(percentNumber);
        }
    };


    /*
     * Reads groupBy from annotation and prepares comma separated list
     */
    sap.ovp.cards.AnnotationHelper.listGroupBy = function (oPresentationVariant) {
        var result = "";
        var bPV = oPresentationVariant && oPresentationVariant.GroupBy;
        if (!bPV) {
            return result;
        }

        var metaModel = this.getModel('ovpCardProperties').getProperty("/metaModel");
        var oEntityType = this.getModel('ovpCardProperties').getProperty("/entityType");
        var groupByList;

        if (oPresentationVariant.GroupBy.constructor === Array) {
            groupByList = oPresentationVariant.GroupBy;
        } else if (!oPresentationVariant.GroupBy.Collection) {
            return result;
        } else {
            groupByList = oPresentationVariant.GroupBy.Collection;
        }


        var propVal;
        jQuery.each(groupByList, function () {

            propVal = getLabelForEntityProperty(metaModel, oEntityType, this.PropertyPath);
            if (!propVal) {
                return;
            }

            result += propVal;
            result += ", ";
        });
        if (result[result.length - 1] === " " && result[result.length - 2] === ",") {
            result = result.substring(0, result.length - 2);
        }
        return result == "" ? "" : sap.ui.getCore().getLibraryResourceBundle("sap.ovp").getText("By", [result]);
    };

    /*
    * returns the string for the filter-by values of the KPI Header
    * */
    sap.ovp.cards.AnnotationHelper.formTheFilterByString = function(iContext, oSelectionVariant) {
        var oCardPropsModel = iContext.getSetting('ovpCardProperties');
        var oEntityType = oCardPropsModel.getProperty("/entityType");
        var oMetaModel = oCardPropsModel.getProperty("/metaModel");
        var aFilters = getFilters(oCardPropsModel, oSelectionVariant);
        var sProp;
        var sTextPropKey;

        //Clean from Filter array all the filters with sap-text that the filter array contains there sap-text
        for (var i = 0; i < aFilters.length; i++ ) {
            sProp = aFilters[i].path;
            sTextPropKey = getTextPropertyForEntityProperty(oMetaModel, oEntityType, sProp);

            //Check if there is sap-text, in case there is checks that the Filter array contains it
            if (sTextPropKey !== sProp) {
                for (var j = 0; j < aFilters.length; j++ ) {

                    // if there is sap test - we won't show the original filter (instead we will show the sap-text) and we clean it from the array
                    if ((aFilters[j].path == sTextPropKey)){
                        aFilters.splice(i, 1);
                        break;
                    }
                }
            }
        }
        // build the filter string
        return generateStringForFilters(aFilters);
    };

    /************************ METADATA PARSERS ************************/

    function generateStringForFilters(aFilters) {
        var aFormatterFilters = [];

        for (var i = 0; i < aFilters.length; i++ ) {
            aFormatterFilters.push(generateSingleFilter(aFilters[i]));
        }

        return aFormatterFilters.join(', ');
    }

    function generateSingleFilter(oFilter) {
        var bNotOperator = false;
        var sFormattedFilter = oFilter.value1;

        if (oFilter.operator[0] === "N") {
            bNotOperator = true;
        }

        if (oFilter.value2) {
            sFormattedFilter += " - " + oFilter.value2;
        }

        if (bNotOperator) {
            sFormattedFilter = sap.ui.getCore().getLibraryResourceBundle("sap.ovp").getText("kpiHeader_Filter_NotOperator", [sFormattedFilter]);
        }

        return sFormattedFilter;
    }


    /* Returns column name that contains the unit for the measure */
    function getUnitColumn (measure, oEntityType) {
        var properties = oEntityType.property;
        for (var i = 0, len = properties.length; i < len; i++) {
            if (properties[i].name == measure) {
                if (properties[i].hasOwnProperty("sap:unit")) {
                    return properties[i]["sap:unit"];
                }
                break;
            }
        }
        return null;
    }

    function getLabelForEntityProperty(oMetadata, oEntityType, sPropertyName) {
        return getAttributeValueForEntityProperty(oMetadata, oEntityType,
            sPropertyName, "com.sap.vocabularies.Common.v1.Label");
    }

    function getTextPropertyForEntityProperty(oMetamodel, oEntityType, sPropertyName) {
        return getAttributeValueForEntityProperty(oMetamodel, oEntityType,
            sPropertyName, "sap:text");
    }

    function getAttributeValueForEntityProperty(oMetamodel, oEntityType, sPropertyName, sAttributeName) {
        var oProp = oMetamodel.getODataProperty(oEntityType, sPropertyName);
        if (!oProp) {
            jQuery.sap.log.error("No Property Found for with Name '" + sPropertyName
                + " For Entity-Type '" + oEntityType.name + "'");
            return;
        }
        var oPropAttVal = oProp[sAttributeName];
        if (oPropAttVal) {
            if (sAttributeName === "com.sap.vocabularies.Common.v1.Label") {
                return oPropAttVal.String;
            }
            return oPropAttVal;
        }

        return oProp.name;
    }

    sap.ovp.cards.AnnotationHelper._criticality2state = criticality2state;
    sap.ovp.cards.AnnotationHelper._generateCriticalityCalculationStateFunction = generateCriticalityCalculationStateFunction;
    sap.ovp.cards.AnnotationHelper._getPropertiesFromBindingString = getPropertiesFromBindingString;
    sap.ovp.cards.AnnotationHelper.sortCollectionByImportance = sortCollectionByImportance;

    sap.ovp.cards.AnnotationHelper.formatField.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formThePathForAggregateNumber.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formThePathForUOM.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formTheFilterByString.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getAggregateNumber.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getFirstDataFieldName.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getSecondDataFieldName.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getThirdDataFieldName.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatFirstDataFieldValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatSecondDataFieldValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatThirdDataFieldValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatFourthDataFieldValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatFifthDataFieldValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatSixthDataFieldValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getDataPointsCount.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getFirstDataPointName.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getSecondDataPointName.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getThirdDataPointName.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatFirstDataPointValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatSecondDataPointValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatThirdDataPointValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatFirstDataPointState.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatSecondDataPointState.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatThirdDataPointState.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatKPIHeaderState.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatItems.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.formatUrl.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.hasActions.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getFirstDataPointValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.getSecondDataPointValue.requiresIContext = true;
    sap.ovp.cards.AnnotationHelper.isFirstDataPointPercentageUnit.requiresIContext = true;

}());
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

// Provides control sap.ui.comp.smartform.flexibility.FieldListNode.
sap.ui.define(['jquery.sap.global', 'sap/m/CheckBox', 'sap/m/FlexBox', 'sap/ui/comp/library', './Input', 'sap/ui/core/Control', 'sap/m/Button'],
	function(jQuery, CheckBox, FlexBox, library, Input, Control, Button) {
	"use strict";



	/**
	 * Constructor for a new smartform/flexibility/FieldListNode.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * A node within the field list control
	 * @extends sap.ui.core.Control
	 *
	 * @constructor
	 * @public
	 * @alias sap.ui.comp.smartform.flexibility.FieldListNode
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var FieldListNode = Control.extend("sap.ui.comp.smartform.flexibility.FieldListNode", /** @lends sap.ui.comp.smartform.flexibility.FieldListNode.prototype */ { metadata : {

		library : "sap.ui.comp",
		properties : {

			/**
			 * The label
			 */
			label : {type : "string", group : "Misc", defaultValue : null},

			/**
			 * is visible flag
			 */
			isVisible : {type : "boolean", group : "Misc", defaultValue : null},

			/**
			 * is node selected
			 */
			isSelected : {type : "boolean", group : "Misc", defaultValue : null}
		},
		aggregations : {

			/**
			 * Nodes representing either a Form, a Group or a field
			 */
			nodes : {type : "sap.ui.comp.smartform.flexibility.FieldListNode", multiple : true, singularName : "node"},

			/**
			 * private aggregation
			 */
			layout : {type : "sap.ui.core.Control", multiple : false}
		},
		events : {

			/**
			 * node was selected
			 */
			selected : {
				parameters : {

					/**
					 * The inner node which was clicked
					 */
					target : {type : "sap.ui.comp.smartform.flexibility.FieldListNode"}
				}
			},
			/**
			 * label of node was changed
			 */
			labelChanged : {
				parameters : {

					/**
					 * The inner node which was clicked
					 */
					target : {type : "sap.ui.comp.smartform.flexibility.FieldListNode"}
				}
			},
			/**
			 * node was hidden
			 */
			nodeHidden : {
				parameters : {

					/**
					 * The inner node which was hidden
					 */
					target : {type : "sap.ui.comp.smartform.flexibility.FieldListNode"}
				}
			}
		}
	}});


	/**
	 * Init
	 *
	 * @private
	 */
	FieldListNode.prototype.init = function() {
		this._textResources = sap.ui.getCore().getLibraryResourceBundle("sap.ui.comp");

		this._oLayout = new FlexBox({
			direction : sap.m.FlexDirection.Row,
			justifyContent: sap.m.FlexJustifyContent.SpaceBetween
		});

		// inputField
		this._oLabelInputField = new Input(this.getId() + '-Input');
		this._oLabelInputField.addStyleClass("sapUiCompFieldListNodeLabelInputField");
		this._oLabelInputField.setValue(this.getLabel());
		this._oLabelInputField.setEditable(false);
		this._oLabelInputField.attachChange(this._onLabelChanged.bind(this));
		this._oLabelInputField.attachSelectedByKeyboard(this._onLabelSelectedByKeyboard.bind(this));
		this._oLabelInputField.setLayoutData(new sap.m.FlexItemData({
		}));
		this._oLayout.addItem(this._oLabelInputField);

		// delete button
		this._oDeleteButton = new Button(this.getId() + '_Button');
		this._oDeleteButton.setType("Transparent");
		this._oDeleteButton.setIcon("sap-icon://decline");
		this._oDeleteButton.setIconDensityAware(false);
		this._oDeleteButton.setTooltip(this._textResources.getText("FORM_PERS_VIS_CHECKBOX_TOOLTIP"));
		this._oDeleteButton.attachPress(this._hideNode.bind(this));
		this._oDeleteButton.setLayoutData(new sap.m.FlexItemData({
		}));
		this._oLayout.addItem(this._oDeleteButton);

		this.setLayout(this._oLayout);
	};

	/**
	 * Overwritten - Sets the label property
	 *
	 * @param {string} sLabel Label
	 * @public
	 */
	FieldListNode.prototype.setLabel = function(sLabel) {
		this._oLabelInputField.setValue(sLabel);
		this.setProperty("label", sLabel);
	};

	/**
	 * Overwritten - Sets the isVisible property
	 *
	 * @param {boolean} bIsVisible isVisible
	 * @public
	 */
	FieldListNode.prototype.setIsVisible = function(bIsVisible) {
		if (this.getModel()) {
			this.getModel().setData(this.getModel().getData());
		}
		this.setProperty("isVisible", bIsVisible);
		this.setVisible(bIsVisible);
	};

	/**
	 * Overwritten - Sets the isSelected property
	 *
	 * @param {boolean} bIsSelected field list node selected
	 * @public
	 */
	FieldListNode.prototype.setIsSelected = function(bIsSelected) {
		if (!bIsSelected) {
			this._oLabelInputField.setEditable(false);
		}
		this.setProperty("isSelected", bIsSelected);
	};

	/**
	 * Event handler - called when the user press the hide button
	 *
	 * @param {object} oEvent Event
	 * @private
	 */
	FieldListNode.prototype._hideNode = function(oEvent) {
		this.setIsVisible(false);
		this._fireNodeHiddenAndDelegateToParent(this);
	};


	/**
	 * Event handler - called when the user changes the label
	 *
	 * @param {object} oEvent Event
	 * @public
	 */
	FieldListNode.prototype._onLabelChanged = function(oEvent) {
		var sLabel;
		sLabel = this._oLabelInputField.getValue();
		if (sLabel !== this.getLabel()) {
			this.setProperty("label", sLabel);
		}
		this._oLabelInputField.setEditable(false);
		this._fireLabelChangedAndDelegateToParent(this);
	};

	/**
	 * Event handler - called when the user has selected the label using the keyboard
	 *
	 * @param {object} oEvent Event
	 * @public
	 */
	FieldListNode.prototype._onLabelSelectedByKeyboard = function(oEvent) {
		this._oLabelInputField.setEditable(true);
		this._fireSelectedAndDelegateToParent(this);
	};

	/**
	 * Overwritten - Registers to DOM events after rendering
	 *
	 * @private
	 */
	FieldListNode.prototype.onAfterRendering = function() {
		this.registerToDOMEvents();
	};

	/**
	 * Overwritten - Registers to DOM events before rendering
	 *
	 * @private
	 */
	FieldListNode.prototype.onBeforeRendering = function() {
		this.deregisterToDOMEvents();
	};

	/**
	 * @private Registers to DOM events like mouse events
	 */
	FieldListNode.prototype.registerToDOMEvents = function() {
		jQuery("#" + this.getId()).on('click', jQuery.proxy(this._handleClick, this));
	};

	/**
	 * @private Deregisters from DOM events
	 */
	FieldListNode.prototype.deregisterToDOMEvents = function() {
		jQuery("#" + this.getId()).off('click');
	};

	/**
	 * @private Event handler, called when the user clicks somewhere into the form. Raises the Selected event.
	 * @param {object} oEvent event
	 */
	FieldListNode.prototype._handleClick = function(oEvent) {
		var target, oSourceNode;
		target = oEvent.target || oEvent.srcElement;

		if (target) {
			oSourceNode = sap.ui.getCore().byId(target.id); // Get SAPUI5 control by DOM reference
			if (!(oSourceNode instanceof FieldListNode)) {
				if (target.parentElement) {
					oSourceNode = sap.ui.getCore().byId(target.parentElement.id); // Get SAPUI5 control by DOM reference
				}
			}
		}

		// If node is already selected and label is clicked, make label editable
		if ((oSourceNode === this._oLabelInputField) && this.getIsSelected()) {
			this._oLabelInputField.setEditable(true);
		}

		// Fire event only if a field list node was clicked
		if (oSourceNode === this || oSourceNode === this._oLabelInputField) {
			this._fireSelectedAndDelegateToParent(this);
		}
	};

	/**
	 * @private Fires the is selected event for itself and for the parent field list node
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oFieldListNode field list node instance
	 */
	FieldListNode.prototype._fireSelectedAndDelegateToParent = createFireEventAndDelegateToParent('fireSelected', '_fireSelectedAndDelegateToParent');

	/**
	 * @private Fires the is labelChanged event for itself and for the parent field list node
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oFieldListNode field list node instance
	 */
	FieldListNode.prototype._fireLabelChangedAndDelegateToParent = createFireEventAndDelegateToParent('fireLabelChanged', '_fireLabelChangedAndDelegateToParent');

	/**
	 * @private Fires the is NodeHidden event for itself and for the parent field list node
	 * @param {sap.ui.comp.smartform.flexibility.FieldListNode} oFieldListNode field list node instance
	 */
	FieldListNode.prototype._fireNodeHiddenAndDelegateToParent = createFireEventAndDelegateToParent('fireNodeHidden', '_fireNodeHiddenAndDelegateToParent');

	function createFireEventAndDelegateToParent(sFunctionNameToFireEvent, sFunctionNameOnParent){
		return function(oFieldListNode){
			var oParent;

			if (!(oFieldListNode instanceof FieldListNode)) {
				return;
			}

			this[sFunctionNameToFireEvent]({
				target: oFieldListNode
			});

			// Call parent to fire event, too
			oParent = this.getParent();
			if (oParent && oParent instanceof FieldListNode) {
				oParent[sFunctionNameOnParent](oFieldListNode);
			}
		};
	}

	return FieldListNode;

}, /* bExport= */ true);
<file_sep>/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
/* global Promise */

sap.ui.define([
	"jquery.sap.global", "sap/ui/fl/Persistence", "sap/ui/fl/registry/ChangeRegistry", "sap/ui/fl/Utils", "sap/ui/fl/Change", "sap/ui/fl/registry/Settings", "sap/ui/fl/ChangePersistenceFactory", "sap/ui/core/mvc/View"
], function(jQuery, Persistence, ChangeRegistry, Utils, Change, FlexSettings, ChangePersistenceFactory, View) {
	"use strict";

	/**
	 * Retrieves changes (LabelChange, etc.) for a sap.ui.core.mvc.View and applies these changes
	 *
	 * @params {string} sComponentName -the component name the flex controler is responsible for
	 * @constructor
	 * @class
	 * @alias sap.ui.fl.FlexController
	 * @experimental Since 1.27.0
	 * @author SAP SE
	 * @version 1.36.12
	 */
	var FlexController = function(sComponentName) {
		this._oChangePersistence = undefined;
		this._sComponentName = sComponentName || "";
		if (this._sComponentName) {
			this._createChangePersistence();
		}
	};

	/**
	 * Sets the component name of the FlexController
	 *
	 * @param {String} sComponentName The name of the component
	 * @public
	 */
	FlexController.prototype.setComponentName = function(sComponentName) {
		this._sComponentName = sComponentName;
		this._createChangePersistence();
	};

	/**
	 * Returns the component name of the FlexController
	 *
	 * @returns {String} the name of the component
	 * @public
	 */
	FlexController.prototype.getComponentName = function() {
		return this._sComponentName;
	};
	/**
	 * Create a change
	 *
	 * @param {object} oChangeSpecificData property bag (nvp) holding the change information (see sap.ui.fl.Change#createInitialFileContent
	 *        oPropertyBag). The property "packageName" is set to $TMP and internally since flex changes are always local when they are created.
	 * @param {sap.ui.core.Control} oControl control for which the change will be added
	 * @returns {sap.ui.fl.Change} the created change
	 * @public
	 */
	FlexController.prototype.createChange = function(oChangeSpecificData, oControl) {

		var oChangeFileContent, oChange, ChangeHandler, oChangeHandler;
		var oAppDescr = Utils.getAppDescriptor(oControl);
		var sComponentName = this.getComponentName();
		oChangeSpecificData.reference = sComponentName; //in this case the component name can also be the value of sap-app-id
		if ( oAppDescr && oAppDescr["sap.app"] ){
			oChangeSpecificData.componentName = oAppDescr["sap.app"].componentName || oAppDescr["sap.app"].id;
		}else {
			//fallback in case no appdescriptor is available (e.g. during unit testing)
			oChangeSpecificData.componentName = sComponentName;
		}
		oChangeSpecificData.packageName = '$TMP'; // first a flex change is always local, until all changes of a component are made transportable

		oChangeFileContent = Change.createInitialFileContent(oChangeSpecificData);
		oChange = new Change(oChangeFileContent);
		// for getting the change handler the control type and the change type are needed
		ChangeHandler = this._getChangeHandler(oChange, oControl);
		if (ChangeHandler) {
			oChangeHandler = new ChangeHandler();
			oChangeHandler.completeChangeContent(oChange, oChangeSpecificData);
		} else {
			throw new Error('Change handler could not be retrieved for change ' + JSON.stringify(oChangeSpecificData));
		}
// first a flex change is always local, until all changes of a component are made transportable
// if ( oChangeSpecificData.transport ){
// oChange.setRequest(oChangeSpecificData.transport);
// }
		return oChange;
	};
	/**
	 * Adds a change to the flex persistence (not yet saved). Will be saved with #saveAll.
	 *
	 * @param {object} oChangeSpecificData property bag (nvp) holding the change information (see sap.ui.fl.Change#createInitialFileContent
	 *        oPropertyBag). The property "packageName" is set to $TMP and internally since flex changes are always local when they are created.
	 * @param {sap.ui.core.Control} oControl control for which the change will be added
	 * @returns {sap.ui.fl.Change} the created change
	 * @public
	 */
	FlexController.prototype.addChange = function(oChangeSpecificData, oControl) {
		var oChange = this.createChange(oChangeSpecificData, oControl);

		this._oChangePersistence.addChange(oChange);

		return oChange;
	};

	/**
	 * Creates a new change and applies it immediately
	 *
	 * @param {object} oChangeSpecificData The data specific to the change, e.g. the new label for a RenameField change
	 * @param {sap.ui.core.Control} oControl The control where the change will be applied to
	 * @public
	 */
	FlexController.prototype.createAndApplyChange = function(oChangeSpecificData, oControl) {
		var oChange = this.addChange(oChangeSpecificData, oControl);
		try {
			this.applyChange(oChange, oControl);
		} catch (ex) {
			this._oChangePersistence.deleteChange(oChange);
			throw ex;
		}
	};

	/**
	 * Saves all changes of a persistence instance.
	 *
	 * @returns {Promise} resolving with an array of responses or rejecting with the first error
	 * @public
	 */
	FlexController.prototype.saveAll = function() {
		return this._oChangePersistence.saveDirtyChanges();
	};

	/**
	 * Loads and applies all changes for the specified view
	 *
	 * @params {object} oView - the view to process
	 * @returns {Promise} without parameters. Promise resolves once all changes of the view have been applied
	 * @public
	 */
	FlexController.prototype.processView = function(oView) {
		var that = this;
		var mPropertyBag = {
			appDescriptor: Utils.getAppDescriptor(oView),
			siteId: Utils.getSiteId(oView)
		};

		var bIsFlexEnabled = this._isFlexEnabled(oView);
		if (!bIsFlexEnabled) {
			return Promise.resolve("No control found, which enable flexibility features. Processing skipped.");
		}

		// do an async fetch of the flex settings
		// to work with that settings during the session
		return FlexSettings.getInstance(this.getComponentName(), mPropertyBag).then(function(oSettings) {
			return that._getChangesForView(oView, mPropertyBag);
		}).then(that._resolveGetChangesForView.bind(that))['catch'](function(error) {
			Utils.log.error('Error processing view ' + error);
		});
	};

	FlexController.prototype._resolveGetChangesForView = function(aChanges) {
		var that = this;
		var fChangeHandler, oChangeHandler;
		
		aChanges.forEach(function(oChange) {
			var oControl = that._getControlByChange(oChange);
			if (oControl) {
				fChangeHandler = that._getChangeHandler(oChange, oControl);
				if (fChangeHandler) {
					oChangeHandler = new fChangeHandler();
				} else {
					Utils.log.error("A change handler of type '" + oChange.getDefinition().changeType + "' does not exist");
				}
				if (oChangeHandler && oChangeHandler.getControlIdFromChangeContent) {
					// check to avoid duplicate IDs
					var sControlId = oChangeHandler.getControlIdFromChangeContent(oChange);
					var bIsControlAlreadyInDOM = !!sap.ui.getCore().byId(sControlId);
					if (!bIsControlAlreadyInDOM) {
						that.applyChangeAndCatchExceptions(oChange, oControl);
					} else {
						var sId = oChange.getSelector().id;
						Utils.log.error("A change of type '" + oChange.getDefinition().changeType + "' tries to add a object with an already existing ID ('" + sId + "')");
					}
				} else {
					that.applyChangeAndCatchExceptions(oChange, oControl);
				}
			} else {
				var oDefinition = oChange.getDefinition();
				var sChangeType = oDefinition.changeType;
				var sTargetControlId = oDefinition.selector.id;
				var fullQualifiedName = oDefinition.namespace  + "/" + oDefinition.fileName + "." + oDefinition.fileType;
				Utils.log.error("A flexibility change tries to change a non existing control.",
						"\n   type of change: '" + sChangeType + "'" +
						"\n   LRep location of the change: " + fullQualifiedName +
						"\n   id of targeted control: '" + sTargetControlId + "'");
			}
		});
	};

	/**
	 * Triggers applyChange and catches exceptions, if some were thrown (logs changes that could not be applied)
	 *
	 * @param {sap.ui.fl.Change} oChange Change instance
	 * @param {sap.ui.core.Control} oControl Control instance
	 * @public
	 */
	FlexController.prototype.applyChangeAndCatchExceptions = function(oChange, oControl) {
		var oChangeDefinition = oChange.getDefinition();
		var sChangeNameSpace = oChangeDefinition.namespace;

		try {
			this.applyChange(oChange, oControl);
		} catch (ex) {
			Utils.log.error("Change could not be applied: [" + oChangeDefinition.layer + "]" + sChangeNameSpace + "/" + oChangeDefinition.fileName + "." + oChangeDefinition.fileType + ": " + ex);
		}
	};

	/**
	 * Retrieves the corresponding change handler for the change and applies the change to the control
	 *
	 * @param {sap.ui.fl.Change} oChange Change instance
	 * @param {sap.ui.core.Control} oControl Control instance
	 * @public
	 */
	FlexController.prototype.applyChange = function(oChange, oControl) {
		var ChangeHandler, oChangeHandler;
		ChangeHandler = this._getChangeHandler(oChange, oControl);
		if (!ChangeHandler) {
			if (oChange && oControl) {
				Utils.log.warning("Change handler implementation for change not found - Change ignored");
			}
			return;
		}

		try {
			oChangeHandler = new ChangeHandler();
			if (oChangeHandler && typeof oChangeHandler.applyChange === 'function') {
				oChangeHandler.applyChange(oChange, oControl);
			}
		} catch (ex) {
			this._setMergeError(true);
			Utils.log.error("Change could not be applied. Merge error detected.");
			throw ex;
		}
	};

	/**
	 * Retrieves the <code>sap.ui.fl.registry.ChangeRegistryItem</code> for the given change and control
	 *
	 * @param {sap.ui.fl.Change} oChange - Change instance
	 * @param {sap.ui.core.Control} oControl Control instance
	 * @returns {sap.ui.fl.changeHandler.Base} the change handler. Undefined if not found.
	 * @private
	 */
	FlexController.prototype._getChangeHandler = function(oChange, oControl) {
		var oChangeTypeMetadata, fChangeHandler;

		oChangeTypeMetadata = this._getChangeTypeMetadata(oChange, oControl);
		if (!oChangeTypeMetadata) {
			return undefined;
		}

		fChangeHandler = oChangeTypeMetadata.getChangeHandler();
		return fChangeHandler;
	};

	/**
	 * Retrieves the <code>sap.ui.fl.registry.ChangeRegistryItem</code> for the given change and control
	 *
	 * @param {sap.ui.fl.Change} oChange Change instance
	 * @param {sap.ui.core.Control} oControl Control instance
	 * @returns {sap.ui.fl.registry.ChangeTypeMetadata} the registry item containing the change handler. Undefined if not found.
	 * @private
	 */
	FlexController.prototype._getChangeTypeMetadata = function(oChange, oControl) {
		var oChangeRegistryItem, oChangeTypeMetadata;

		oChangeRegistryItem = this._getChangeRegistryItem(oChange, oControl);
		if (!oChangeRegistryItem || !oChangeRegistryItem.getChangeTypeMetadata) {
			return undefined;
		}

		oChangeTypeMetadata = oChangeRegistryItem.getChangeTypeMetadata();
		return oChangeTypeMetadata;
	};

	/**
	 * Retrieves the <code>sap.ui.fl.registry.ChangeRegistryItem</code> for the given change and control
	 *
	 * @param {sap.ui.fl.Change} oChange Change instance
	 * @param {sap.ui.core.Control} oControl Control instance
	 * @returns {sap.ui.fl.registry.ChangeRegistryItem} the registry item containing the change handler. Undefined if not found.
	 * @private
	 */
	FlexController.prototype._getChangeRegistryItem = function(oChange, oControl) {
		var sChangeType, sControlType, oChangeRegistryItem, sLayer;
		if (!oChange || !oControl) {
			return undefined;
		}

		sChangeType = oChange.getChangeType();
		sControlType = Utils.getControlType(oControl);

		if (!sChangeType || !sControlType) {
			return undefined;
		}

		sLayer = oChange.getLayer();

		oChangeRegistryItem = this._getChangeRegistry().getRegistryItems({
			"changeTypeName": sChangeType,
			"controlType": sControlType,
			"layer": sLayer
		});
		if (oChangeRegistryItem && oChangeRegistryItem[sControlType] && oChangeRegistryItem[sControlType][sChangeType]) {
			return oChangeRegistryItem[sControlType][sChangeType];
		} else if (oChangeRegistryItem && oChangeRegistryItem[sControlType]) {
			return oChangeRegistryItem[sControlType];
		} else {
			return oChangeRegistryItem;
		}
	};

	/**
	 * Returns the change registry
	 *
	 * @returns {sap.ui.fl.registry.ChangeRegistry} Instance of the change registry
	 * @private
	 */
	FlexController.prototype._getChangeRegistry = function() {
		var oInstance = ChangeRegistry.getInstance();
		// make sure to use the most current flex settings that have been retrieved during processView
		oInstance.initSettings(this.getComponentName());
		return oInstance;
	};

	/**
	 * Returns the control where the change will be applied to. Undefined if control cannot be found.
	 *
	 * @param {sap.ui.fl.Change} oChange Change
	 * @returns {sap.ui.core.Control} Control where the change will be applied to
	 * @private
	 */
	FlexController.prototype._getControlByChange = function(oChange) {
		var oSelector;

		if (!oChange) {
			return undefined;
		}
		oSelector = oChange.getSelector();
		if (oSelector && typeof oSelector.id === "string") {
			return sap.ui.getCore().byId(oSelector.id);
		}

		return undefined;
	};

	/**
	 * Retrieves the changes for the complete UI5 component
	 * @param {map} mPropertyBag - (optional) contains additional data that are needed for reading of changes
	 * - appDescriptor that belongs to actual component
	 * - siteId that belongs to actual component
	 * @returns {Promise} Promise resolves with a map of all {sap.ui.fl.Change} having the changeId as key
	 * @public
	 */
	FlexController.prototype.getComponentChanges = function(mPropertyBag) {
		return this._oChangePersistence.getChangesForComponent(mPropertyBag);
	};

	/**
	 * Retrieves the changes for the view and its siblings (except nested views)
	 *
	 * @params {object} oView - the view
	 * @param {map} mPropertyBag - (optional) contains additional data that are needed for reading of changes
	 * - appDescriptor that belongs to actual component
	 * - siteId that belongs to actual component
	 * @returns {Promise} Promise resolves with a map of all {sap.ui.fl.Change} of a component
	 * @private
	 */
	FlexController.prototype._getChangesForView = function(oView, mPropertyBag) {
		return this._oChangePersistence.getChangesForView(oView.getId(), mPropertyBag);
	};

	/**
	 * Creates a new instance of sap.ui.fl.Persistence based on the current component and caches the instance in a private member
	 *
	 * @returns {sap.ui.fl.Persistence} persistence instance
	 * @private
	 */
	FlexController.prototype._createChangePersistence = function() {
		this._oChangePersistence = ChangePersistenceFactory.getChangePersistenceForComponent(this.getComponentName());
		return this._oChangePersistence;
	};

	/**
	 * Discard changes on the server.
	 *
	 * @param {array} aChanges array of {sap.ui.fl.Change} to be discarded
	 * @returns {Promise} promise that resolves without parameters.
	 */
	FlexController.prototype.discardChanges = function(aChanges) {
		var sActiveLayer = Utils.getCurrentLayer(false);
		aChanges.forEach(function(oChange) {
			// only discard changes of the currently active layer (CUSTOMER vs PARTNER vs VENDOR)
			if (oChange && oChange.getLayer && oChange.getLayer() === sActiveLayer) {
				this._oChangePersistence.deleteChange(oChange);
			}
		}.bind(this));

		return this._oChangePersistence.saveDirtyChanges();
	};

	/**
	 * Searches for controls in the view control tree, which enable flexibility features.
	 *
	 * @param {sap.ui.core.Control} oParentControl Parent control instance
	 * @returns {boolean} true if the view contains controls, which enable flexibility features, false if not.
	 * @private
	 */
	FlexController.prototype._isFlexEnabled = function(oParentControl) {
		var that = this;
		var bIsFlexEnabled = false;

		if (oParentControl.getMetadata) {
			var oParentControlMetadata = oParentControl.getMetadata();
			var oAggregations = oParentControlMetadata.getAllAggregations();
			var aAggregationKeys = Object.keys(oAggregations);
			jQuery.each(aAggregationKeys, function(iAggragationKeyIndex, sAggregationKey) {
				if (sAggregationKey != "data" && oParentControlMetadata.getAggregation) {
					// data has no flex, but cannot be accessed if the data contains a FlattenedDataset (resulting in an error)
					var oAggregation = oParentControlMetadata.getAggregation(sAggregationKey);
					if ( oAggregation && oAggregation.get) {
						var aAggregations = oAggregation.get(oParentControl);
						if (aAggregations) {
							if (!Array.isArray(aAggregations)) {
								// in case of an aggregation with a cardinality of 0..1 the object is returned not in an array.
								aAggregations = [
									aAggregations
								];
							}
							jQuery.each(aAggregations, function(index, oChildControl) {
								if (typeof oChildControl.getFlexEnabled === 'function' && oChildControl.getFlexEnabled()) {
									bIsFlexEnabled = true;
									return false; // break inner jQuery.each
								} else {
									bIsFlexEnabled = that._isFlexEnabled(oChildControl);
									if (bIsFlexEnabled === true) {
										return false; // break inner jQuery.each
									}
								}
							});
							if (bIsFlexEnabled === true) {
								return false; // break outer jQuery.each
							}
						}
					}
				}
			});
		}
		return bIsFlexEnabled;
	};

	FlexController.prototype.deleteChangesForControlDeeply = function(oControl) {
		return Promise.resolve();
	};

	/**
	 * Set flag if an error has occured when merging changes
	 *
	 * @param {Boolean} bHasErrorOccured Indicator if an error has occured
	 * @private
	 */
	FlexController.prototype._setMergeError = function(bHasErrorOccured) {

		// in this case FlexSettings.getInstance does not get passed (AppDescriptorId and SiteId) as setMergeErrorOccured ONLY enrich setting instance
		// with runtime data. No direct backend call
		return FlexSettings.getInstance(this.getComponentName()).then(function(oSettings) {
			oSettings.setMergeErrorOccured(true);
		});
	};

	return FlexController;
}, true);
<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
/**
 * @class messageHandler
 * @memberOf sap.apf.ui.reuse.view
 * @name messageHandler
 */
sap.ui.jsview("sap.apf.ui.reuse.view.messageHandler", {
	/**
	 * @this {sap.apf.ui.reuse.view.messageHandler}
	 * @description messageHandler view
	 */
	/**
	 * @memberOf sap.apf.ui.reuse.view.messageHandler
	 * @method initializeHandler
	 * @param oMessageObject
	 * @description UI handle for error messages to be shown on notification bar
	 */
	initializeHandler : function(oMessageObject) {
		this.getController().showMessage(oMessageObject);
	},
	getControllerName : function() {
		return "sap.apf.ui.reuse.controller.messageHandler";
	},
	createContent : function(oController) {
		jQuery.sap.require("sap.m.MessageToast");
		jQuery.sap.require("sap.ca.ui.message.message");
		
	}
});<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
/*global sap, jQuery, OData */
jQuery.sap.declare('sap.apf.core.request');
jQuery.sap.require('sap.apf.utils.utils');
jQuery.sap.require('sap.apf.core.utils.filter');
jQuery.sap.require('sap.apf.core.utils.filterTerm');
jQuery.sap.require('sap.ui.thirdparty.datajs');
jQuery.sap.require("sap.apf.core.utils.filterSimplify");
(function() {
	'use strict';
	/**
	 * @class The Request object represents an OData GET request. It receives a
	 *        filter which is then mapped to a URI query and appended to the request
	 *        URI. Its role is to send an asynchronous OData request to the server,
	 *        receive the response, parse it and provision it as an array of
	 *        objects. The request will use a callback mechanism handling the
	 *        asynchronous request behavior. The callback routes control back to the
	 *        Path object.
	 * @param {Object} oInject - references to other handlers
	 * @param oConfig - Configuration Object for a Request.
	 */
	sap.apf.core.Request = function(oInject, oConfig) {
		var oMessageHandler = oInject.messageHandler;
		var oCoreApi = oInject.coreApi;
		var sServiceRootPath = oConfig.service;
		var selectProperties = oConfig.selectProperties;
		var oUriGenerator = oCoreApi.getUriGenerator();
		var oMessageObject;
		if (sServiceRootPath === undefined) {
			oMessageObject = oMessageHandler.createMessageObject({
				code : '5015',
				aParameters : [ oConfig.id ]
			});
			oMessageHandler.putMessage(oMessageObject);
		}
		var oMetadata = oCoreApi.getMetadata(sServiceRootPath);
		var oUriComponents = oMetadata.getUriComponents(oConfig.entityType);
		var sEntitySet, snavigationProperty;
		if (oUriComponents) {
			sEntitySet = oUriComponents.entitySet;
			snavigationProperty = oUriComponents.navigationProperty;
		}
		oMessageHandler.check(sEntitySet !== undefined, 'Invalid request configuration: An entityset does not exist under the service ' + oConfig.entityType);
		oMessageHandler.check(snavigationProperty !== undefined, 'Invalid request configuration: A usable navigation does not exist for the service ' + oConfig.entityType);
		this.type = oConfig.type;
		/**
		 * @description A request object that can send (many) asynchronous OData GET requests to the server. It uses a POST $batch operation wrapping the GET.
		 * @param {Object} oFilter - An sap.apf.core.utils filter object.
		 * @param {Function} fnCallback - A function called after the response was successfully received and parsed.
		 * @param {Object} oRequestOptions - An optional object containing additional query string options
		 * Format: { orderby : [{ property : <property_name>, order : <asc|desc>}], top : <integer>, skip : <integer> }
		 */
		this.sendGetInBatch = function(oFilter, fnCallback, oRequestOptions) {
		 
			var oParameters = retrieveParameters(oFilter);
			var oFilterApplicableForRequest;
			var filterSimplify;
			checkFilterForRequiredProperties(oFilter);
			if (oFilter && oFilter.getProperties) {
				oFilterApplicableForRequest = oFilter.reduceToProperty(oMetadata.getFilterableProperties(sEntitySet));
				 
				if (oCoreApi.getStartParameterFacade().isFilterReductionActive()) {
					filterSimplify = new sap.apf.core.utils.FilterReduction();
					oFilterApplicableForRequest = filterSimplify.filterReduction(oMessageHandler, oFilterApplicableForRequest);
				}
			}
			checkRequestOptionsConsistency(oRequestOptions);
			var oPaging = oRequestOptions && oRequestOptions.paging;
			var oSortingFields = oRequestOptions && oRequestOptions.orderby;
			var sUrlEntityType = oUriGenerator.buildUri(oMessageHandler, sEntitySet, selectProperties, oFilterApplicableForRequest, oParameters, oSortingFields, oPaging, undefined, formatValue, snavigationProperty);
			var oRequest = {
				method : 'POST',
				headers : {
					'x-csrf-token' : oCoreApi.getXsrfToken(sServiceRootPath)
				},
				requestUri : oUriGenerator.getAbsolutePath(sServiceRootPath) + '$batch',
				data : {
					__batchRequests : [ {
						requestUri : sUrlEntityType,
						method : 'GET',
						headers : {
							'Accept-Language' : sap.ui.getCore().getConfiguration().getLanguage(),
							'x-csrf-token' : oCoreApi.getXsrfToken(sServiceRootPath)
						}
					} ]
				}
			};
			var fnSuccess = function(data, response) {
				var oResponse = {};
				var sUrl = '';
				if (data && data.__batchResponses && data.__batchResponses[0].data) {
					oResponse.data = data.__batchResponses[0].data.results;
					oResponse.metadata = oCoreApi.getEntityTypeMetadata(oConfig.service, oConfig.entityType);
					if (data.__batchResponses[0].data.__count) {
						oResponse.count = parseInt(data.__batchResponses[0].data.__count, 10);
					}
				} else if (data && data.__batchResponses[0] && data.__batchResponses[0].response && data.__batchResponses[0].message) {
					sUrl = response.requestUri;
					var sMessage = data.__batchResponses[0].message;
					var sErrorDetails = data.__batchResponses[0].response.body;
					var sHttpStatusCode = data.__batchResponses[0].response.statusCode;
					oResponse = oMessageHandler.createMessageObject({
						code : '5001',
						aParameters : [ sHttpStatusCode, sMessage, sErrorDetails, sUrl ]
					});
				} else {
					sUrl = response.requestUri || sUrlEntityType;
					oResponse = oMessageHandler.createMessageObject({
						code : '5001',
						aParameters : [ 'unknown', 'unknown error', 'unknown error', sUrl ]
					});
				}
				fnCallback(oResponse, false);
			};
			var fnError = function(error) {
				var sMessage = 'unknown error';
				var sErrorDetails = 'unknown error';
				var sUrl = sUrlEntityType;
				if (error.message !== undefined) {
					sMessage = error.message;
				}
				var sHttpStatusCode = 'unknown';
				if (error.response && error.response.statusCode) {
					sHttpStatusCode = error.response.statusCode;
					sErrorDetails = error.response.statusText || '';
					sUrl = error.response.requestUri || sUrlEntityType;
				}
				if (error.messageObject && error.messageObject.type === 'messageObject') {
					fnCallback(error.messageObject);
				} else {
					fnCallback(oMessageHandler.createMessageObject({
						code : '5001',
						aParameters : [ sHttpStatusCode, sMessage, sErrorDetails, sUrl ]
					}));
				}
			};
			oCoreApi.odataRequest(oRequest, fnSuccess, fnError, OData.batchHandler);
		};
		function formatValue(sProperty, value) {
			var strDelimiter = "'";
			var oEntityMetadata = oMetadata.getPropertyMetadata(sEntitySet, sProperty);
			if (oEntityMetadata && oEntityMetadata.dataType) {
				return sap.apf.utils.formatValue(value, oEntityMetadata.dataType.type);
			}
			if (typeof value === 'number') {
				return value;
			}
			return strDelimiter + sap.apf.utils.escapeOdata(value) + strDelimiter;
		}
		function checkRequestOptionsConsistency(oRequestOptions) {
			var aPropertyNames, i;
			if (!oRequestOptions) {
				return;
			}
			aPropertyNames = Object.getOwnPropertyNames(oRequestOptions);
			for(i = 0; i < aPropertyNames.length; i++) {
				if (aPropertyNames[i] !== 'orderby' && aPropertyNames[i] !== 'paging') {
					oMessageHandler.putMessage(oMessageHandler.createMessageObject({
						code : '5032',
						aParameters : [ sEntitySet, aPropertyNames[i] ]
					}));
				}
			}
		}
		function checkFilterForRequiredProperties(oFilter) {
			var aFilterableProperties = oMetadata.getFilterableProperties(sEntitySet);
			var sRequiredFilterProperty = '';
			var oEntityTypeMetadata = oMetadata.getEntityTypeAnnotations(sEntitySet);
			var oMessageObject2;
			if (oEntityTypeMetadata.requiresFilter !== undefined && oEntityTypeMetadata.requiresFilter === 'true') {
				if (oEntityTypeMetadata.requiredProperties !== undefined) {
					sRequiredFilterProperty = oEntityTypeMetadata.requiredProperties;
				}
			}
			if (sRequiredFilterProperty === '') {
				return;
			}
			if (jQuery.inArray(sRequiredFilterProperty, aFilterableProperties) === -1) {
				oMessageObject2 = oMessageHandler.createMessageObject({
					code : '5006',
					aParameters : [ sEntitySet, sRequiredFilterProperty ]
				});
				oMessageHandler.putMessage(oMessageObject2);
			}
			var aPropertiesInFilter = oFilter.getProperties();
			// test, whether all required properties are in filter
			if (jQuery.inArray(sRequiredFilterProperty, aPropertiesInFilter) === -1) {
				oMessageObject2 = oMessageHandler.createMessageObject({
					code : '5005',
					aParameters : [ sEntitySet, sRequiredFilterProperty ]
				});
				oMessageHandler.putMessage(oMessageObject2);
			}
		}
		function retrieveParameters(oFilter) {
			var oParameters = {};
			var aParameters;
			var numberOfParameters;
			var aTermsContainingParameter;
			var i;
			var oParameterTerm;
			aParameters = oMetadata.getParameterEntitySetKeyProperties(sEntitySet);
			if (aParameters !== undefined) {
				numberOfParameters = aParameters.length;
			} else {
				numberOfParameters = 0;
			}
			if (numberOfParameters > 0) {
				for(i = 0; i < numberOfParameters; i++) {
					if (oFilter && oFilter instanceof sap.apf.core.utils.Filter) {
						aTermsContainingParameter = oFilter.getFilterTermsForProperty(aParameters[i].name);
						oParameterTerm = aTermsContainingParameter[aTermsContainingParameter.length - 1];
					}
					if (oParameterTerm instanceof sap.apf.core.utils.FilterTerm) {
						addParameter(i, oParameterTerm.getValue());
					} else if (aParameters[i].defaultValue) {
						addParameter(i, aParameters[i].defaultValue);
					} else {
						oMessageHandler.putMessage(oMessageHandler.createMessageObject({
							code : '5016',
							aParameters : [ aParameters[i].name ]
						}));
					}
				}
			}
			return oParameters;
			function addParameter(index, value) {
				var formatedValue;
				if (aParameters[index].dataType.type === 'Edm.String') {
					oParameters[aParameters[index].name] = (jQuery.sap.encodeURL("'" + sap.apf.utils.escapeOdata(value) + "'"));
				} else if (aParameters[index].dataType.type) {
					formatedValue = sap.apf.utils.formatValue(value, aParameters[index].dataType.type);
					if (typeof formatedValue === 'string') {
						oParameters[aParameters[index].name] = jQuery.sap.encodeURL(formatedValue);
					} else {
						oParameters[aParameters[index].name] = formatedValue;
					}
				} else if (typeof value === 'string') {
					oParameters[aParameters[index].name] = jQuery.sap.encodeURL(sap.apf.utils.escapeOdata(value));
				} else {
					oParameters[aParameters[index].name] = value;
				}
			}
		}
	};
}());
<file_sep>(function () {
    "use strict";
    /*global jQuery, sap */

    jQuery.sap.declare("sap.ovp.cards.generic.Component");
    jQuery.sap.require("sap.ui.core.UIComponent");
    jQuery.sap.require("sap.ovp.cards.AnnotationHelper");

    sap.ui.core.UIComponent.extend("sap.ovp.cards.generic.Component", {
        // use inline declaration instead of component.json to save 1 round trip
        metadata: {
            properties: {
                "contentFragment": {
                    "type": "string"
                },
                "headerExtensionFragment": {
                    "type": "string"
                },
                "contentPosition": {
                    "type": "string",
                    "defaultValue": "Middle"
                },
                "footerFragment": {
                    "type": "string"
                },
                "identificationAnnotationPath":{
                    "type": "string",
                    "defaultValue": "com.sap.vocabularies.UI.v1.Identification"
                },
                "selectionAnnotationPath":{
                    "type": "string"
                },
                "filters": {
                    "type": "object"
                },
                "addODataSelect": {
                    "type": "boolean",
                    "defaultValue": false
                }
            },
            version: "1.36.12",

            library: "sap.ovp",

            includes: [],

            dependencies: {
                libs: [ "sap.m" ],
                components: []
            },
            config: {}
        },

        /**
         * Default "abstract" empty function.
         * In case there is a need to enrich the default preprocessor which provided by OVP, the extended Component should provide this function and return a preprocessor object.
         * @public
         * @returns {Object} SAPUI5 preprocessor object
         */
        getCustomPreprocessor: function () {},

        getPreprocessors : function(ovplibResourceBundle) {
            var oComponentData = this.getComponentData(),
                oSettings = oComponentData.settings,
                oModel = oComponentData.model,
                oMetaModel,
                oEntityTypeContext,
                oEntitySetContext;

            //Backwards compatibility to support "description" property
            if (oSettings.description && !oSettings.subTitle) {
                oSettings.subTitle = oSettings.description;
            }
            if (oModel){
                var oMetaModel = oModel.getMetaModel();
                var oEntitySet = oMetaModel.getODataEntitySet(oSettings.entitySet);
                var sEntitySetPath = oMetaModel.getODataEntitySet(oSettings.entitySet, true);
                var oEntityType = oMetaModel.getODataEntityType(oEntitySet.entityType);

                oEntitySetContext = oMetaModel.createBindingContext(sEntitySetPath);
                oEntityTypeContext = oMetaModel.createBindingContext(oEntityType.$path);
            }

            var oCardProperties = this._getCardPropertyDefaults();

            oCardProperties = jQuery.extend(true, {metaModel: oMetaModel, entityType: oEntityType}, oCardProperties, oSettings);

            var oOvpCardPropertiesModel = new sap.ui.model.json.JSONModel(oCardProperties);
            var ovplibResourceBundle = this.getOvplibResourceBundle();

            var oDefaultPreprocessors = {
                xml: {
                    bindingContexts: {entityType: oEntityTypeContext, entitySet: oEntitySetContext},
                    models: {entityType: oMetaModel, entitySet:oMetaModel, ovpMeta: oMetaModel, ovpCardProperties: oOvpCardPropertiesModel, ovplibResourceBundle: ovplibResourceBundle},
                    ovpCardProperties: oOvpCardPropertiesModel,
                    dataModel: oModel,
                    _ovpCache: {}
                }
            };

            return jQuery.extend(true, {}, this.getCustomPreprocessor(), oDefaultPreprocessors);
        },

        _getCardPropertyDefaults: function(){
            var oCardProperties = {};
            var oPropsDef = this.getMetadata().getAllProperties();
            var oPropDef;
            for (var propName in oPropsDef){
                oPropDef = oPropsDef[propName];
                if (oPropDef.defaultValue !== undefined){
                    oCardProperties[oPropDef.name] = oPropDef.defaultValue;
                }
            }
            return oCardProperties;
        },

        getOvplibResourceBundle: function(){
            if (!this.ovplibResourceBundle){
                var oResourceBundle = sap.ui.getCore().getLibraryResourceBundle("sap.ovp");
                this.ovplibResourceBundle = oResourceBundle ? new sap.ui.model.resource.ResourceModel({bundleUrl: oResourceBundle.oUrlInfo.url}) : null;
            }
            return this.ovplibResourceBundle;
        },

        createContent: function () {
            var oComponentData = this.getComponentData && this.getComponentData();
            var oModel = oComponentData.model;
            var oPreprocessors = this.getPreprocessors();

            var oView;
            oView = sap.ui.view({
                preprocessors: oPreprocessors,
                type: sap.ui.core.mvc.ViewType.XML,
                viewName: "sap.ovp.cards.generic.Card"
            });

            oView.setModel(oModel);
            // check if i18n model is available and then add it to card view
            if (oComponentData.i18n) {
                oView.setModel(oComponentData.i18n, "@i18n");
            }
            oView.setModel(oPreprocessors.xml.ovpCardProperties, "ovpCardProperties");
            oView.setModel(this.getOvplibResourceBundle(), "ovplibResourceBundle");

            return oView;
        }
    });
})();
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

// Provides control sap.ui.comp.smartform.flexibility.Input.
sap.ui.define(['jquery.sap.global', 'sap/m/Input', 'sap/ui/comp/library'],
	function(jQuery, Input1, library) {
	"use strict";


	/**
	 * Constructor for a new smartform/flexibility/Input.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given 
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Input field with special focus handling
	 * @extends sap.m.Input
	 *
	 * @constructor
	 * @public
	 * @alias sap.ui.comp.smartform.flexibility.Input
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var Input = Input1.extend("sap.ui.comp.smartform.flexibility.Input", /** @lends sap.ui.comp.smartform.flexibility.Input.prototype */ { metadata : {

		library : "sap.ui.comp",
		events : {

			/**
			 * Fired when the field is readonly, focused and user pressed Space
			 */
			selectedByKeyboard : {}
		}
	}});

	Input.prototype.init = function() {
		Input1.prototype.init.call(this);
	};

	Input.prototype.onAfterRendering = function() {
		var oDomRef;

		Input1.prototype.onAfterRendering.apply(this);
		oDomRef = this.getDomRef();
		if (oDomRef) {
			oDomRef.tabIndex = 0;
		}
	};

	Input.prototype.onkeydown = function(oEvent) {
		var nKeyCode;

		Input1.prototype.onkeydown.apply(this, arguments);
		nKeyCode = oEvent.keyCode;
		if (nKeyCode === 32) { // Blank pressed
			if (this.getEditable() === false) {
				this.fireSelectedByKeyboard();
			}
		}
	};

	Input.prototype.onsapescape = function(oEvent) {
		Input1.prototype.onsapescape.apply(this, arguments);
		oEvent.stopPropagation(); // Prevent closing the dialog
		this.setEditable(false);
	};

	// onsapenter (compared to onkeydown) is called before the value is saved
	Input.prototype.onsapenter = function (oEvent) {
		if (!this.getValue()) {
			this.resetOnEmptyValue();
		}

		Input1.prototype.onsapenter.apply(this, arguments);
		this.setEditable(false);
	};

	Input.prototype.resetOnEmptyValue = function (oEvent) {
		if (!this.getValue()) {
			this.setValue(this._lastValue);
			this.onValueRevertedByEscape(this._lastValue);
		}
	};

	Input.prototype.onsapfocusleave = function (oEvent) {
		this.resetOnEmptyValue();
		Input1.prototype.onsapfocusleave.apply(this, arguments);
	};

	return Input;

}, /* bExport= */ true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

sap.ui.define([
	'sap/ui/fl/Utils', 'jquery.sap.global', 'sap/ui/fl/changeHandler/Base'
], function(Utils, jQuery, Base) {
	"use strict";

	/**
	 * Change handler for renaming a smart form group element.
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.RenameField
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 */
	var RenameField = function() {
	};
	RenameField.prototype = jQuery.sap.newObject(Base.prototype);

	/**
	 * Renames a smart form group element.
	 *
	 * @param {sap.ui.fl.Change} oChangeWrapper change wrapper object with instructions to be applied on the control map
	 * @param {sap.ui.core.Control} oControl control that matches the change selector for applying the change
	 * @public
	 */
	RenameField.prototype.applyChange = function(oChangeWrapper, oControl) {
		var oChange = oChangeWrapper.getDefinition();
		if (oChange.texts && oChange.texts.fieldLabel && this._isProvided(oChange.texts.fieldLabel.value)) {
			if (!oControl) {
				throw new Error("no Control provided for renaming");
			}

			if (typeof oControl.setLabel === 'function') {
				oControl.unbindProperty("label");
				oControl.setLabel(oChange.texts.fieldLabel.value);
			} else if (typeof oControl.setTitle === 'function') {
				oControl.unbindProperty("title");
				oControl.setTitle(oChange.texts.fieldLabel.value);
			} else {
				throw new Error('Control does not support "renameField" change');
			}
		} else {
			Utils.log.error("Change does not contain sufficient information to be applied: [" + oChange.layer + "]" + oChange.namespace + "/" + oChange.fileName + "." + oChange.fileType);
			//however subsequent changes should be applied
		}
	};

	/**
	 * Completes the change by adding change handler specific content
	 *
	 * @param {sap.ui.fl.Change} oChangeWrapper change wrapper object to be completed
	 * @param {object} oSpecificChangeInfo with attribute fieldLabel, the new field label to be included in the change
	 * @public
	 */
	RenameField.prototype.completeChangeContent = function(oChangeWrapper, oSpecificChangeInfo) {
		var oChange = oChangeWrapper.getDefinition();
		if (this._isProvided(oSpecificChangeInfo.fieldLabel)) {
			this.setTextInChange(oChange, "fieldLabel", oSpecificChangeInfo.fieldLabel, "XFLD");
		} else {
			throw new Error("oSpecificChangeInfo.fieldLabel attribute required");
		}
	};
	
	/**
	 * Checks if a string is provided as also empty strings are allowed for the fields
	 */
	RenameField.prototype._isProvided = function(sString){
		return typeof (sString) === "string";
	};
	
	return RenameField;
},
/* bExport= */true);
<file_sep>/*!
 * 
 * 		SAP UI development toolkit for HTML5 (SAPUI5)
 * 		(c) Copyright 2009-2015 SAP SE. All rights reserved
 * 	
 */

/* ----------------------------------------------------------------------------------
 * Hint: This is a derived (generated) file. Changes should be done in the underlying 
 * source files only (*.control, *.js) or they will be lost after the next generation.
 * ---------------------------------------------------------------------------------- */

// Provides control sap.suite.ui.commons.ProcessFlow.
jQuery.sap.declare("sap.suite.ui.commons.ProcessFlow");
jQuery.sap.require("sap.suite.ui.commons.library");
jQuery.sap.require("sap.ui.core.Control");


/**
 * Constructor for a new ProcessFlow.
 * 
 * Accepts an object literal <code>mSettings</code> that defines initial 
 * property values, aggregated and associated objects as well as event handlers. 
 * 
 * If the name of a setting is ambiguous (e.g. a property has the same name as an event), 
 * then the framework assumes property, aggregation, association, event in that order. 
 * To override this automatic resolution, one of the prefixes "aggregation:", "association:" 
 * or "event:" can be added to the name of the setting (such a prefixed name must be
 * enclosed in single or double quotes).
 *
 * The supported settings are:
 * <ul>
 * <li>Properties
 * <ul>
 * <li>{@link #getFoldedCorners foldedCorners} : boolean (default: false)</li>
 * <li>{@link #getScrollable scrollable} : boolean (default: true)</li>
 * <li>{@link #getWheelZoomable wheelZoomable} : boolean (default: true)</li>
 * <li>{@link #getShowLabels showLabels} : boolean (default: false)</li></ul>
 * </li>
 * <li>Aggregations
 * <ul>
 * <li>{@link #getNodes nodes} : sap.suite.ui.commons.ProcessFlowNode[]</li>
 * <li>{@link #getLanes lanes} <strong>(default aggregation)</strong> : sap.suite.ui.commons.ProcessFlowLaneHeader[]</li></ul>
 * </li>
 * <li>Associations
 * <ul></ul>
 * </li>
 * <li>Events
 * <ul>
 * <li>{@link sap.suite.ui.commons.ProcessFlow#event:nodeTitlePress nodeTitlePress} : fnListenerFunction or [fnListenerFunction, oListenerObject] or [oData, fnListenerFunction, oListenerObject]</li>
 * <li>{@link sap.suite.ui.commons.ProcessFlow#event:nodePress nodePress} : fnListenerFunction or [fnListenerFunction, oListenerObject] or [oData, fnListenerFunction, oListenerObject]</li>
 * <li>{@link sap.suite.ui.commons.ProcessFlow#event:labelPress labelPress} : fnListenerFunction or [fnListenerFunction, oListenerObject] or [oData, fnListenerFunction, oListenerObject]</li>
 * <li>{@link sap.suite.ui.commons.ProcessFlow#event:headerPress headerPress} : fnListenerFunction or [fnListenerFunction, oListenerObject] or [oData, fnListenerFunction, oListenerObject]</li>
 * <li>{@link sap.suite.ui.commons.ProcessFlow#event:onError onError} : fnListenerFunction or [fnListenerFunction, oListenerObject] or [oData, fnListenerFunction, oListenerObject]</li></ul>
 * </li>
 * </ul> 

 *
 * @param {string} [sId] id for the new control, generated automatically if no id is given 
 * @param {object} [mSettings] initial settings for the new control
 *
 * @class
 * Complex control that enables you to display documents or other items in their flow.
 * @extends sap.ui.core.Control
 *
 * @author SAP SE
 * @version 1.36.8
 *
 * @constructor
 * @public
 * @name sap.suite.ui.commons.ProcessFlow
 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
 */
sap.ui.core.Control.extend("sap.suite.ui.commons.ProcessFlow", { metadata : {

	publicMethods : [
		// methods
		"getZoomLevel", "setZoomLevel", "zoomIn", "zoomOut", "updateModel", "getFocusedNode", "updateNodesOnly", "setSelectedPath"
	],
	library : "sap.suite.ui.commons",
	properties : {
		"foldedCorners" : {type : "boolean", group : "Misc", defaultValue : false},
		"scrollable" : {type : "boolean", group : "Misc", defaultValue : true},
		"wheelZoomable" : {type : "boolean", group : "Behavior", defaultValue : true},
		"showLabels" : {type : "boolean", group : "Appearance", defaultValue : false}
	},
	defaultAggregation : "lanes",
	aggregations : {
		"_connections" : {type : "sap.suite.ui.commons.ProcessFlowConnection", multiple : true, singularName : "_connection", visibility : "hidden"}, 
		"nodes" : {type : "sap.suite.ui.commons.ProcessFlowNode", multiple : true, singularName : "node"}, 
		"lanes" : {type : "sap.suite.ui.commons.ProcessFlowLaneHeader", multiple : true, singularName : "lane"}
	},
	events : {
		"nodeTitlePress" : {deprecated: true}, 
		"nodePress" : {}, 
		"labelPress" : {}, 
		"headerPress" : {}, 
		"onError" : {}
	}
}});


/**
 * Creates a new subclass of class sap.suite.ui.commons.ProcessFlow with name <code>sClassName</code> 
 * and enriches it with the information contained in <code>oClassInfo</code>.
 * 
 * <code>oClassInfo</code> might contain the same kind of informations as described in {@link sap.ui.core.Element.extend Element.extend}.
 *   
 * @param {string} sClassName name of the class to be created
 * @param {object} [oClassInfo] object literal with informations about the class  
 * @param {function} [FNMetaImpl] constructor function for the metadata object. If not given, it defaults to sap.ui.core.ElementMetadata.
 * @return {function} the created class / constructor function
 * @public
 * @static
 * @name sap.suite.ui.commons.ProcessFlow.extend
 * @function
 */

sap.suite.ui.commons.ProcessFlow.M_EVENTS = {'nodeTitlePress':'nodeTitlePress','nodePress':'nodePress','labelPress':'labelPress','headerPress':'headerPress','onError':'onError'};


/**
 * Getter for property <code>foldedCorners</code>.
 * This property defines the folded corners for the single node control. The following values exist:
 * - true: means folded corner
 * - false/null/undefined: means normal corner
 *
 * Default value is <code>false</code>
 *
 * @return {boolean} the value of property <code>foldedCorners</code>
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#getFoldedCorners
 * @function
 */

/**
 * Setter for property <code>foldedCorners</code>.
 *
 * Default value is <code>false</code> 
 *
 * @param {boolean} bFoldedCorners  new value for property <code>foldedCorners</code>
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#setFoldedCorners
 * @function
 */


/**
 * Getter for property <code>scrollable</code>.
 * By default, the control body is embedded into a scroll container of fixed size, so the user
 * can put the control into a fixe sized layout.
 * When the control body (the graph) gets larger than the container cuts the overflowing parts of the graph and the cut parts can be viewed by scroling the control body.
 * When the control body fits into the container limits, obviously no scrolling is possible (and makes sense).
 * 
 * The scrolling feature can be turned off by setting this property value to false,
 * so the width/height of the whole control will change as the flow graph gets smaller/larger.
 * In this case the control body could not be scrolled, as the control body size matches the control container size.
 *
 * Default value is <code>true</code>
 *
 * @return {boolean} the value of property <code>scrollable</code>
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#getScrollable
 * @function
 */

/**
 * Setter for property <code>scrollable</code>.
 *
 * Default value is <code>true</code> 
 *
 * @param {boolean} bScrollable  new value for property <code>scrollable</code>
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#setScrollable
 * @function
 */


/**
 * Getter for property <code>wheelZoomable</code>.
 * The property specifies if to enable semantic zooming by mouse wheel events on desktop browsers.
 *
 * Default value is <code>true</code>
 *
 * @return {boolean} the value of property <code>wheelZoomable</code>
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#getWheelZoomable
 * @function
 */

/**
 * Setter for property <code>wheelZoomable</code>.
 *
 * Default value is <code>true</code> 
 *
 * @param {boolean} bWheelZoomable  new value for property <code>wheelZoomable</code>
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#setWheelZoomable
 * @function
 */


/**
 * Getter for property <code>showLabels</code>.
 * Defines if the connection labels are shown or not.
 *
 * Default value is <code>false</code>
 *
 * @return {boolean} the value of property <code>showLabels</code>
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#getShowLabels
 * @function
 */

/**
 * Setter for property <code>showLabels</code>.
 *
 * Default value is <code>false</code> 
 *
 * @param {boolean} bShowLabels  new value for property <code>showLabels</code>
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#setShowLabels
 * @function
 */


/**
 * Getter for aggregation <code>nodes</code>.<br/>
 * This is the aggregation of the node controls put into the table to the calculated cells.
 * 
 * @return {sap.suite.ui.commons.ProcessFlowNode[]}
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#getNodes
 * @function
 */


/**
 * Inserts a node into the aggregation named <code>nodes</code>.
 *
 * @param {sap.suite.ui.commons.ProcessFlowNode}
 *          oNode the node to insert; if empty, nothing is inserted
 * @param {int}
 *             iIndex the <code>0</code>-based index the node should be inserted at; for 
 *             a negative value of <code>iIndex</code>, the node is inserted at position 0; for a value 
 *             greater than the current size of the aggregation, the node is inserted at 
 *             the last position        
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#insertNode
 * @function
 */

/**
 * Adds some node <code>oNode</code> 
 * to the aggregation named <code>nodes</code>.
 *
 * @param {sap.suite.ui.commons.ProcessFlowNode}
 *            oNode the node to add; if empty, nothing is inserted
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#addNode
 * @function
 */

/**
 * Removes an node from the aggregation named <code>nodes</code>.
 *
 * @param {int | string | sap.suite.ui.commons.ProcessFlowNode} vNode the node to remove or its index or id
 * @return {sap.suite.ui.commons.ProcessFlowNode} the removed node or null
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#removeNode
 * @function
 */

/**
 * Removes all the controls in the aggregation named <code>nodes</code>.<br/>
 * Additionally unregisters them from the hosting UIArea.
 * @return {sap.suite.ui.commons.ProcessFlowNode[]} an array of the removed elements (might be empty)
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#removeAllNodes
 * @function
 */

/**
 * Checks for the provided <code>sap.suite.ui.commons.ProcessFlowNode</code> in the aggregation named <code>nodes</code> 
 * and returns its index if found or -1 otherwise.
 *
 * @param {sap.suite.ui.commons.ProcessFlowNode}
 *            oNode the node whose index is looked for.
 * @return {int} the index of the provided control in the aggregation if found, or -1 otherwise
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#indexOfNode
 * @function
 */
	

/**
 * Destroys all the nodes in the aggregation 
 * named <code>nodes</code>.
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#destroyNodes
 * @function
 */


/**
 * Getter for aggregation <code>lanes</code>.<br/>
 * This is a header of the table for the process flow control.
 * 
 * <strong>Note</strong>: this is the default aggregation for ProcessFlow.
 * @return {sap.suite.ui.commons.ProcessFlowLaneHeader[]}
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#getLanes
 * @function
 */


/**
 * Inserts a lane into the aggregation named <code>lanes</code>.
 *
 * @param {sap.suite.ui.commons.ProcessFlowLaneHeader}
 *          oLane the lane to insert; if empty, nothing is inserted
 * @param {int}
 *             iIndex the <code>0</code>-based index the lane should be inserted at; for 
 *             a negative value of <code>iIndex</code>, the lane is inserted at position 0; for a value 
 *             greater than the current size of the aggregation, the lane is inserted at 
 *             the last position        
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#insertLane
 * @function
 */

/**
 * Adds some lane <code>oLane</code> 
 * to the aggregation named <code>lanes</code>.
 *
 * @param {sap.suite.ui.commons.ProcessFlowLaneHeader}
 *            oLane the lane to add; if empty, nothing is inserted
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#addLane
 * @function
 */

/**
 * Removes an lane from the aggregation named <code>lanes</code>.
 *
 * @param {int | string | sap.suite.ui.commons.ProcessFlowLaneHeader} vLane the lane to remove or its index or id
 * @return {sap.suite.ui.commons.ProcessFlowLaneHeader} the removed lane or null
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#removeLane
 * @function
 */

/**
 * Removes all the controls in the aggregation named <code>lanes</code>.<br/>
 * Additionally unregisters them from the hosting UIArea.
 * @return {sap.suite.ui.commons.ProcessFlowLaneHeader[]} an array of the removed elements (might be empty)
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#removeAllLanes
 * @function
 */

/**
 * Checks for the provided <code>sap.suite.ui.commons.ProcessFlowLaneHeader</code> in the aggregation named <code>lanes</code> 
 * and returns its index if found or -1 otherwise.
 *
 * @param {sap.suite.ui.commons.ProcessFlowLaneHeader}
 *            oLane the lane whose index is looked for.
 * @return {int} the index of the provided control in the aggregation if found, or -1 otherwise
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#indexOfLane
 * @function
 */
	

/**
 * Destroys all the lanes in the aggregation 
 * named <code>lanes</code>.
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#destroyLanes
 * @function
 */


/**
 * This event is fired when a process flow node title was
 * clicked. The user can access the clicked process flow node control object which is the only argument of the event handler.
 *
 * @name sap.suite.ui.commons.ProcessFlow#nodeTitlePress
 * @event
 * @deprecated Since version 1.26. 
 * Should not be used any longer, use nodePress event instead ( click on the node)
 * @param {sap.ui.base.Event} oControlEvent
 * @param {sap.ui.base.EventProvider} oControlEvent.getSource
 * @param {object} oControlEvent.getParameters
 * @param {object} oControlEvent.getParameters.oEvent This object represents the wrapped process flow node object.
 * @public
 */
 
/**
 * Attach event handler <code>fnFunction</code> to the 'nodeTitlePress' event of this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/>.
 * When called, the context of the event handler (its <code>this</code>) will be bound to <code>oListener<code> if specified
 * otherwise to this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/> itself. 
 *  
 * This event is fired when a process flow node title was
 * clicked. The user can access the clicked process flow node control object which is the only argument of the event handler.
 *
 * @param {object}
 *            [oData] An application specific payload object, that will be passed to the event handler along with the event object when firing the event.
 * @param {function}
 *            fnFunction The function to call, when the event occurs.  
 * @param {object}
 *            [oListener] Context object to call the event handler with. Defaults to this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/> itself.
 *
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @deprecated Since version 1.26. 
 * Should not be used any longer, use nodePress event instead ( click on the node)
 * @name sap.suite.ui.commons.ProcessFlow#attachNodeTitlePress
 * @function
 */

/**
 * Detach event handler <code>fnFunction</code> from the 'nodeTitlePress' event of this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/>
 *
 * The passed function and listener object must match the ones used for event registration.
 *
 * @param {function}
 *            fnFunction The function to call, when the event occurs.
 * @param {object}
 *            oListener Context object on which the given function had to be called.
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @deprecated Since version 1.26. 
 * Should not be used any longer, use nodePress event instead ( click on the node)
 * @name sap.suite.ui.commons.ProcessFlow#detachNodeTitlePress
 * @function
 */

/**
 * Fire event nodeTitlePress to attached listeners.
 * 
 * Expects following event parameters:
 * <ul>
 * <li>'oEvent' of type <code>object</code> This object represents the wrapped process flow node object.</li>
 * </ul>
 *
 * @param {Map} [mArguments] the arguments to pass along with the event.
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @protected
 * @deprecated Since version 1.26. 
 * Should not be used any longer, use nodePress event instead ( click on the node)
 * @name sap.suite.ui.commons.ProcessFlow#fireNodeTitlePress
 * @function
 */


/**
 * This event is fired when a process flow node was clicked.
 *
 * @name sap.suite.ui.commons.ProcessFlow#nodePress
 * @event
 * @param {sap.ui.base.Event} oControlEvent
 * @param {sap.ui.base.EventProvider} oControlEvent.getSource
 * @param {object} oControlEvent.getParameters
 * @param {object} oControlEvent.getParameters.oEvent This object represents the wrapped process flow node object.
 * @public
 */
 
/**
 * Attach event handler <code>fnFunction</code> to the 'nodePress' event of this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/>.
 * When called, the context of the event handler (its <code>this</code>) will be bound to <code>oListener<code> if specified
 * otherwise to this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/> itself. 
 *  
 * This event is fired when a process flow node was clicked.
 *
 * @param {object}
 *            [oData] An application specific payload object, that will be passed to the event handler along with the event object when firing the event.
 * @param {function}
 *            fnFunction The function to call, when the event occurs.  
 * @param {object}
 *            [oListener] Context object to call the event handler with. Defaults to this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/> itself.
 *
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#attachNodePress
 * @function
 */

/**
 * Detach event handler <code>fnFunction</code> from the 'nodePress' event of this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/>
 *
 * The passed function and listener object must match the ones used for event registration.
 *
 * @param {function}
 *            fnFunction The function to call, when the event occurs.
 * @param {object}
 *            oListener Context object on which the given function had to be called.
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#detachNodePress
 * @function
 */

/**
 * Fire event nodePress to attached listeners.
 * 
 * Expects following event parameters:
 * <ul>
 * <li>'oEvent' of type <code>object</code> This object represents the wrapped process flow node object.</li>
 * </ul>
 *
 * @param {Map} [mArguments] the arguments to pass along with the event.
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @protected
 * @name sap.suite.ui.commons.ProcessFlow#fireNodePress
 * @function
 */


/**
 * This event is fired when a process flow connection label was clicked.
 *
 * @name sap.suite.ui.commons.ProcessFlow#labelPress
 * @event
 * @param {sap.ui.base.Event} oControlEvent
 * @param {sap.ui.base.EventProvider} oControlEvent.getSource
 * @param {object} oControlEvent.getParameters
 * @param {object} oControlEvent.getParameters.oEvent This object represents the label information.
 * @public
 */
 
/**
 * Attach event handler <code>fnFunction</code> to the 'labelPress' event of this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/>.
 * When called, the context of the event handler (its <code>this</code>) will be bound to <code>oListener<code> if specified
 * otherwise to this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/> itself. 
 *  
 * This event is fired when a process flow connection label was clicked.
 *
 * @param {object}
 *            [oData] An application specific payload object, that will be passed to the event handler along with the event object when firing the event.
 * @param {function}
 *            fnFunction The function to call, when the event occurs.  
 * @param {object}
 *            [oListener] Context object to call the event handler with. Defaults to this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/> itself.
 *
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#attachLabelPress
 * @function
 */

/**
 * Detach event handler <code>fnFunction</code> from the 'labelPress' event of this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/>
 *
 * The passed function and listener object must match the ones used for event registration.
 *
 * @param {function}
 *            fnFunction The function to call, when the event occurs.
 * @param {object}
 *            oListener Context object on which the given function had to be called.
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#detachLabelPress
 * @function
 */

/**
 * Fire event labelPress to attached listeners.
 * 
 * Expects following event parameters:
 * <ul>
 * <li>'oEvent' of type <code>object</code> This object represents the label information.</li>
 * </ul>
 *
 * @param {Map} [mArguments] the arguments to pass along with the event.
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @protected
 * @name sap.suite.ui.commons.ProcessFlow#fireLabelPress
 * @function
 */


/**
 * This event is fired when the header column was clicked.
 *
 * @name sap.suite.ui.commons.ProcessFlow#headerPress
 * @event
 * @param {sap.ui.base.Event} oControlEvent
 * @param {sap.ui.base.EventProvider} oControlEvent.getSource
 * @param {object} oControlEvent.getParameters
 * @param {object} oControlEvent.getParameters.oEvent This object represents the wrapped process flow lane header object.
 * @public
 */
 
/**
 * Attach event handler <code>fnFunction</code> to the 'headerPress' event of this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/>.
 * When called, the context of the event handler (its <code>this</code>) will be bound to <code>oListener<code> if specified
 * otherwise to this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/> itself. 
 *  
 * This event is fired when the header column was clicked.
 *
 * @param {object}
 *            [oData] An application specific payload object, that will be passed to the event handler along with the event object when firing the event.
 * @param {function}
 *            fnFunction The function to call, when the event occurs.  
 * @param {object}
 *            [oListener] Context object to call the event handler with. Defaults to this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/> itself.
 *
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#attachHeaderPress
 * @function
 */

/**
 * Detach event handler <code>fnFunction</code> from the 'headerPress' event of this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/>
 *
 * The passed function and listener object must match the ones used for event registration.
 *
 * @param {function}
 *            fnFunction The function to call, when the event occurs.
 * @param {object}
 *            oListener Context object on which the given function had to be called.
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#detachHeaderPress
 * @function
 */

/**
 * Fire event headerPress to attached listeners.
 * 
 * Expects following event parameters:
 * <ul>
 * <li>'oEvent' of type <code>object</code> This object represents the wrapped process flow lane header object.</li>
 * </ul>
 *
 * @param {Map} [mArguments] the arguments to pass along with the event.
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @protected
 * @name sap.suite.ui.commons.ProcessFlow#fireHeaderPress
 * @function
 */


/**
 * This event is fired when an issue occurs with the process flow calculation. In most cases, there is an issue with the data. The console contains the detailed error description with the errors.
 *
 * @name sap.suite.ui.commons.ProcessFlow#onError
 * @event
 * @param {sap.ui.base.Event} oControlEvent
 * @param {sap.ui.base.EventProvider} oControlEvent.getSource
 * @param {object} oControlEvent.getParameters
 * @param {object} oControlEvent.getParameters.oEvent This parameters contains the localized string with error message.
 * @public
 */
 
/**
 * Attach event handler <code>fnFunction</code> to the 'onError' event of this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/>.
 * When called, the context of the event handler (its <code>this</code>) will be bound to <code>oListener<code> if specified
 * otherwise to this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/> itself. 
 *  
 * This event is fired when an issue occurs with the process flow calculation. In most cases, there is an issue with the data. The console contains the detailed error description with the errors.
 *
 * @param {object}
 *            [oData] An application specific payload object, that will be passed to the event handler along with the event object when firing the event.
 * @param {function}
 *            fnFunction The function to call, when the event occurs.  
 * @param {object}
 *            [oListener] Context object to call the event handler with. Defaults to this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/> itself.
 *
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#attachOnError
 * @function
 */

/**
 * Detach event handler <code>fnFunction</code> from the 'onError' event of this <code>sap.suite.ui.commons.ProcessFlow</code>.<br/>
 *
 * The passed function and listener object must match the ones used for event registration.
 *
 * @param {function}
 *            fnFunction The function to call, when the event occurs.
 * @param {object}
 *            oListener Context object on which the given function had to be called.
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @public
 * @name sap.suite.ui.commons.ProcessFlow#detachOnError
 * @function
 */

/**
 * Fire event onError to attached listeners.
 * 
 * Expects following event parameters:
 * <ul>
 * <li>'oEvent' of type <code>object</code> This parameters contains the localized string with error message.</li>
 * </ul>
 *
 * @param {Map} [mArguments] the arguments to pass along with the event.
 * @return {sap.suite.ui.commons.ProcessFlow} <code>this</code> to allow method chaining
 * @protected
 * @name sap.suite.ui.commons.ProcessFlow#fireOnError
 * @function
 */


/**
 * This method returns the current zoom level of the control.
 *
 * @name sap.suite.ui.commons.ProcessFlow#getZoomLevel
 * @function
 * @type sap.suite.ui.commons.ProcessFlowZoomLevel
 * @public
 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
 */


/**
 * This method sets the new zoom level. If the input is wrong, it is ignored and the previous value stays.
 *
 * @name sap.suite.ui.commons.ProcessFlow#setZoomLevel
 * @function
 * @param {sap.suite.ui.commons.ProcessFlowZoomLevel} oNewZoomLevel
 *         This method sets new zoom level. The enumeration ensures that only available levels are used.
 * @type sap.suite.ui.commons.ProcessFlowZoomLevel
 * @public
 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
 */


/**
 * This method decreases the zoom level. More details are displayed in the node.
 *
 * @name sap.suite.ui.commons.ProcessFlow#zoomIn
 * @function
 * @type sap.suite.ui.commons.ProcessFlowZoomLevel
 * @public
 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
 */


/**
 * This method increases the zoom level. Less details are displayed in the node.
 *
 * @name sap.suite.ui.commons.ProcessFlow#zoomOut
 * @function
 * @type sap.suite.ui.commons.ProcessFlowZoomLevel
 * @public
 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
 */


/**
 * This method triggers the update of the model and correspondingly the rerender method.
 *
 * @name sap.suite.ui.commons.ProcessFlow#updateModel
 * @function
 * @type void
 * @public
 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
 */


/**
 * This method returns the nodeId of the node, which is focused.
 *
 * @name sap.suite.ui.commons.ProcessFlow#getFocusedNode
 * @function
 * @type string
 * @public
 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
 */


/**
 * This method should be called when the contents of the nodes were changed. It updates only the nodes and rerenders the ProcessFlow.
 *
 * @name sap.suite.ui.commons.ProcessFlow#updateNodesOnly
 * @function
 * @type void
 * @public
 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
 */


/**
 * This method sets or resets the selected path between two nodes. To reset the selected path, the method has to be called with null/null.
 *
 * @name sap.suite.ui.commons.ProcessFlow#setSelectedPath
 * @function
 * @type void
 * @public
 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
 */

// Start of sap/suite/ui/commons/ProcessFlow.js
///**
// * This file defines behavior for the control.
// */

jQuery.sap.require("sap.m.Image");
/*
 * Resource bundle for the localized strings.
 */
sap.suite.ui.commons.ProcessFlow.prototype._resBundle = null;


/**
 * Zoom level for the control. It is propagated to all created sub controls.
 */
sap.suite.ui.commons.ProcessFlow.prototype._zoomLevel = sap.suite.ui.commons.ProcessFlowZoomLevel.Two;

/**
 * The wheel events time-out.
 */
sap.suite.ui.commons.ProcessFlow.prototype._wheelTimeout = null;

/**
 * Set to true when the focus is changing to another node.
 */
sap.suite.ui.commons.ProcessFlow.prototype._isFocusChanged = false;

/**
 * The wheel events timestamp for the last wheel event occurrence.
 */
sap.suite.ui.commons.ProcessFlow.prototype._wheelTimestamp = null;

/**
 * The wheel events flag, if a wheel event was recently processed.
 */
sap.suite.ui.commons.ProcessFlow.prototype._wheelCalled = false;

/**
 * The internal matrix after calculation. Use for keyboard movement.
 */
sap.suite.ui.commons.ProcessFlow.prototype._internalCalcMatrix = false;

/**
 * The internal list of connection mappings (source/target/connectionParts)
 */
sap.suite.ui.commons.ProcessFlow.prototype._internalConnectionMap = null;

/**
 * Internal lanes, which can differ from original ones. Especially when more nodes are in
 * the same lane.
 */
sap.suite.ui.commons.ProcessFlow.prototype._internalLanes = false;

/**
 * Definition for jump over more elements based on the visual design.
 */
sap.suite.ui.commons.ProcessFlow.prototype._jumpOverElements = 5;
/**
 * Last node with navigation focus. It is marked when the focus out event
 * is handled.
 */
sap.suite.ui.commons.ProcessFlow.prototype._lastNavigationFocusNode = false;

/**
 * Set up the cursor classes.
 */
sap.suite.ui.commons.ProcessFlow.prototype._defaultCursorClass = "sapSuiteUiDefaultCursorPF";

if (sap.ui.Device.browser.msie) {
  sap.suite.ui.commons.ProcessFlow.prototype._grabCursorClass = "sapSuiteUiGrabCursorIEPF";
  sap.suite.ui.commons.ProcessFlow.prototype._grabbingCursorClass = "sapSuiteUiGrabbingCursorIEPF";
} else {
  sap.suite.ui.commons.ProcessFlow.prototype._grabCursorClass = "sapSuiteUiGrabCursorPF";
  sap.suite.ui.commons.ProcessFlow.prototype._grabbingCursorClass = "sapSuiteUiGrabbingCursorPF";
}

sap.suite.ui.commons.ProcessFlow.prototype._mousePreventEvents = 'contextmenu dblclick';
sap.suite.ui.commons.ProcessFlow.prototype._mouseEvents = 'contextmenu mousemove mouseleave mousedown mouseup mouseenter';
sap.suite.ui.commons.ProcessFlow.prototype._mouseWheelEvent = (sap.ui.Device.browser.mozilla) ? 'DOMMouseScroll MozMousePixelScroll' : 'mousewheel wheel';
sap.suite.ui.commons.ProcessFlow.prototype._headerHasFocus = false;
sap.suite.ui.commons.ProcessFlow.prototype._isInitialZoomLevelNeeded = true;

/**
 * Variables used for overflow scrolling.
 */
sap.suite.ui.commons.ProcessFlow.prototype._bDoScroll = !sap.ui.Device.system.desktop || (sap.ui.Device.os.windows && sap.ui.Device.os.version === 8);
sap.suite.ui.commons.ProcessFlow.prototype._scrollStep = 192;
sap.suite.ui.commons.ProcessFlow.prototype._bPreviousScrollForward = false; //Remember the item overflow state.
sap.suite.ui.commons.ProcessFlow.prototype._bPreviousScrollBack = false;
sap.suite.ui.commons.ProcessFlow.prototype._iInitialArrowTop = undefined;
sap.suite.ui.commons.ProcessFlow.prototype._iInitialCounterTop = undefined;
sap.suite.ui.commons.ProcessFlow.prototype._bRtl = false;
sap.suite.ui.commons.ProcessFlow.prototype._arrowScrollable = null;
sap.suite.ui.commons.ProcessFlow.prototype._iTouchStartScrollTop = undefined;
sap.suite.ui.commons.ProcessFlow.prototype._iTouchStartScrollLeft = undefined;
sap.suite.ui.commons.ProcessFlow.prototype._bSetFocusOnce = true;

sap.suite.ui.commons.ProcessFlow.prototype.init = function () {
  this._bRtl = sap.ui.getCore().getConfiguration().getRTL();

  if (!this._resBundle) {
    this._resBundle = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.commons");
  }
  this._internalLanes = this.getLanes();

  this.$("scrollContainer").bind('keydown', jQuery.proxy(this.onkeydown, this));
  this.$("scrollContainer").bind('keyup', jQuery.proxy(this.onkeyup, this));
};

/**
 * Function destroys all the object components.
 */
sap.suite.ui.commons.ProcessFlow.prototype.exit = function () {
  if (this.getNodes()) {
    for (var i = 0; i < this.getNodes().length; i++) {
      this.getNodes()[i].destroy();
    }
    this.getNodes = null;
  }

  if (this._internalLanes) {
    for (var i = 0; i < this._internalLanes.length; i++) {
      this._internalLanes[i].destroy();
    }
    this._internalLanes = null;
  }
  var aInternalConnectionAgg = this.getAggregation("_connections");
  if (aInternalConnectionAgg) {
    for (var i = 0; i < aInternalConnectionAgg.length; i++) {
      aInternalConnectionAgg[i].destroy();
    }
    aInternalConnectionAgg = null;
  }
  if (this._oArrowLeft) {
    this._oArrowLeft.destroy();
  }
  if (this._oArrowRight) {
    this._oArrowRight.destroy();
  }

  if (this._resizeRegId) {
    sap.ui.core.ResizeHandler.deregister(this._resizeRegId);
  }
  if (this._internalCalcMatrix) {
    delete this._internalCalcMatrix;
    this._internalCalcMatrix = null;
  }

  this.$("scrollContainer").unbind(this._mousePreventEvents, this._handlePrevent);
  this.$("scrollContainer").unbind(this._mouseEvents, jQuery.proxy(this._registerMouseEvents, this));
  this.$("scrollContainer").unbind(this._mouseWheelEvent, jQuery.proxy(this._registerMouseWheel, this));
  this.$("scrollContainer").unbind('keydown', jQuery.proxy(this.onkeydown, this));
  this.$("scrollContainer").unbind('scroll', jQuery.proxy(this._onScroll, this));
};

sap.suite.ui.commons.ProcessFlow.prototype.onBeforeRendering = function () {
  this.$("scrollContainer").unbind(this._mousePreventEvents, this._handlePrevent);
  this.$("scrollContainer").unbind(this._mouseEvents, jQuery.proxy(this._registerMouseEvents, this));
  this.$("scrollContainer").unbind(this._mouseWheelEvent, jQuery.proxy(this._registerMouseWheel, this));
  this.$("scrollContainer").unbind('keydown', jQuery.proxy(this.onkeydown, this));
  this.$("scrollContainer").unbind('scroll', jQuery.proxy(this._onScroll, this));
};

/**
 * Function handles the exception based on the business requirements.
 */
sap.suite.ui.commons.ProcessFlow.prototype._handleException = function (exc) {
  var textToDisplay = this._resBundle.getText('PF_ERROR_INPUT_DATA');
  this.fireOnError({ text: textToDisplay });
  jQuery.sap.log.error("Error loading data for the process flow with id : " + this.getId());

  if (exc instanceof Array) {
    for (var i = 0 ; i < exc.length; i++) {
      jQuery.sap.log.error("Detailed description (" + i + ") :" + exc[i]);
    }
  } else {
    jQuery.sap.log.error("Detailed description  :" + exc);
  }
};

/**
 * Function updates the lanes, if more nodes belong to the same lane
 * it must check the node consistency, so this is done the first time the consistency check runs.
 *
 * @private
 */
sap.suite.ui.commons.ProcessFlow.prototype._updateLanesFromNodes = function () {
  sap.suite.ui.commons.ProcessFlow.NodeElement.createNodeElementsFromProcessFlowNodes(this.getNodes(), this.getLanes());
  var aInternalNodes = this._arrangeNodesByParentChildRelation(this.getNodes());
  this._internalLanes = sap.suite.ui.commons.ProcessFlow.NodeElement.updateLanesFromNodes(this.getLanes(), aInternalNodes).lanes;
};

/**
 * Function creates the lane header objects.
 *
 * @private
 * @returns {sap.suite.ui.commons.ProcessFlowLaneHeader[]} Array containing lane headers for current ProcessFlow
 */
sap.suite.ui.commons.ProcessFlow.prototype._getOrCreateLaneMap = function () {
  if (!this._internalLanes || this._internalLanes.length <= 0) {
    this._updateLanesFromNodes();
  }
  var mapPositionToLane = sap.suite.ui.commons.ProcessFlow.NodeElement.createMapFromLanes(this._internalLanes,
      jQuery.proxy(this.ontouchend, this), this._isHeaderMode()).positionMap;
  return mapPositionToLane;
};

/**
 * This function sorts the internal array of nodes in terms all parents are followed by their children, i.e. no child occurs before his parent in the array.
 *
 * @private
 * @param {sap.suite.ui.commons.ProcessFlowNode[]} aInternalNodes an internal array of nodes to be sorted.
 * @returns {sap.suite.ui.commons.ProcessFlowNode[]} aInternalNodes sorted internal array of nodes.
 * @since 1.26
 */
sap.suite.ui.commons.ProcessFlow.prototype._arrangeNodesByParentChildRelation = function (aInternalNodes) {
  var cInternalNodes = aInternalNodes ? aInternalNodes.length : 0;
  var aChildren = [];
  var i, j;
  // Move parents before their children, if they are in the same lane.
  if (cInternalNodes > 0) {
    this._setParentForNodes(aInternalNodes);
    for (i = 0; i < cInternalNodes; i++) {
      aChildren = aInternalNodes[i].getChildren();
      if (aChildren) {
        var cChildren = aChildren.length;
        for (j = 0; j < cChildren; j++) {
          aChildren[j] = sap.suite.ui.commons.ProcessFlow._getChildIdByElement(aChildren[j]).toString();
        }
      }
      for (j = 0; j < i; j++) {
        if (jQuery.inArray(aInternalNodes[j].getNodeId(), aChildren) > -1 && aInternalNodes[j].getLaneId() === aInternalNodes[i].getLaneId()) {
          aInternalNodes.splice(j, 0, aInternalNodes[i]);
          aInternalNodes.splice(i + 1, 1);
          aInternalNodes = this._arrangeNodesByParentChildRelation(aInternalNodes);
          break;
        }
      }
    }
  }
  return aInternalNodes;
};

/**
 * Function creates matrix with positions of nodes and connections. This is
 * relative node connection representation and does not cover real page layout.
 *
 * @private
 * @returns The created ProcessFlow control
 */
sap.suite.ui.commons.ProcessFlow.prototype._getOrCreateProcessFlow = function () {
  if (!this._internalLanes || this._internalLanes.length <= 0) {
    this._updateLanesFromNodes();
  }

  this.applyNodeDisplayState();
  var internalNodes = this.getNodes();

  /*tempNodeArray is internal node representation */
  var result = sap.suite.ui.commons.ProcessFlow.NodeElement.createNodeElementsFromProcessFlowNodes(internalNodes, this._internalLanes);
  var elementForId = result.elementForId;
  var elementsForLane = result.elementsForLane;

  sap.suite.ui.commons.ProcessFlow.NodeElement.calculateLaneStatePieChart(elementsForLane, this._internalLanes, internalNodes, this);

  var calcMatrix = this.calculateMatrix(elementForId);
  calcMatrix = this.addFirstAndLastColumn(calcMatrix);
  //Convert NodeElements back to ProcessFlowNodes.
  for (var i = 0; i < calcMatrix.length; i++) {
    for (var j = 0; j < calcMatrix[i].length; j++) {
      if (calcMatrix[i][j] instanceof sap.suite.ui.commons.ProcessFlow.NodeElement) {
        calcMatrix[i][j] = elementForId[calcMatrix[i][j].nodeId].oNode;
      }
    }
  }
  this._internalCalcMatrix = calcMatrix;
  return calcMatrix;
};

/**
 * Function applies the changes to the display state based on the requirements.
 * If any node is in the highlighted state all others go to the dimmed state.
 *
 * @public
 */
sap.suite.ui.commons.ProcessFlow.prototype.applyNodeDisplayState = function () {
  var aInternalNodes = this.getNodes(),
      iNodeCount = aInternalNodes ? aInternalNodes.length : 0,
      i = 0;

  if (iNodeCount === 0) {
    return;
  } else {
    // First put all the nodes to the regular state - if possible
    while (i < iNodeCount) {
      aInternalNodes[i]._setRegularState();
      i++;
    }

    // Check for the highlighted or selected node- at least one is required
    i = 0;
    while ((i < iNodeCount) && !aInternalNodes[i].getHighlighted() && !aInternalNodes[i].getSelected()) {
      i++;
    }

    // If a highlighted or selected node was found, set the others to dimmed state
    if (i < iNodeCount) {
      i = 0;
      while (i < iNodeCount) {
        if (!aInternalNodes[i].getHighlighted() && !aInternalNodes[i].getSelected()) {
          aInternalNodes[i]._setDimmedState();
        }
        i++;
      }
    }
  }
};

/**
 * Function adds first and last column, which serves for the special header signs. It has to add
 * single cell to all internal arrays.
 *
 * @param calculatedMatrix
 * @returns {Object[]} The calculated matrix including first and last column
 */
sap.suite.ui.commons.ProcessFlow.prototype.addFirstAndLastColumn = function (calculatedMatrix) {

  if (!calculatedMatrix || calculatedMatrix.length <= 0) {
    return [];
  }

  var originalX = calculatedMatrix.length;

  for (var i = 0; i < originalX; i++) {
    calculatedMatrix[i].unshift(null);
    calculatedMatrix[i].push(null);
  }

  return calculatedMatrix;
};

/**
 * Function calculates a virtual matrix with nodes and connections.
 *
 * @private
 * @param elementForId contains a map of the node id's to node elements
 * @throws an array with messages on processing errors
 * @returns {Object[]} The composed virtual matrix
 */
sap.suite.ui.commons.ProcessFlow.prototype.calculateMatrix = function (elementForId) {
  var internalMatrixCalculation,
      oElementInfo,
      highestLaneNumber,
      rows,
      return2DimArray;

  //No calculation in case of zero input.
  if (!elementForId || (elementForId.length === 0)) {
    return [];
  }

  internalMatrixCalculation = new sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation(this);
  internalMatrixCalculation.checkInputNodeConsistency(elementForId);
  oElementInfo = internalMatrixCalculation.retrieveInfoFromInputArray(elementForId);
  internalMatrixCalculation.resetPositions();
  highestLaneNumber = oElementInfo.highestLanePosition + 1;

  // Worst case, all children are in the same lane with so many rows.
  rows = Object.keys(elementForId).length > 3 ? Object.keys(elementForId).length - 1 : 2;
  return2DimArray = internalMatrixCalculation.createMatrix(rows, highestLaneNumber);

  for (var i = 0; i < oElementInfo.rootElements.length; i++) {
    internalMatrixCalculation.posy = oElementInfo.rootElements[i].lane;
    return2DimArray = internalMatrixCalculation.processCurrentElement(oElementInfo.rootElements[i], elementForId, return2DimArray);
  }

  return2DimArray = internalMatrixCalculation.doubleColumnsInMatrix(return2DimArray);
  return2DimArray = internalMatrixCalculation.calculatePathInMatrix(return2DimArray);
  return2DimArray = internalMatrixCalculation.removeEmptyLines(return2DimArray);
  return return2DimArray;
};


/**
 * This is a virtual node holding necessary data to create virtual matrix.
 *
 * @private
 * @param {string} id id of the PF node
 * @param {number} oLane lane position of the node
 * @param {sap.suite.ui.commons.ProcessFlowNode} oNode a PF node
 * @param {Number[]} aNodeParents array of parent id's of the oNode
 */
sap.suite.ui.commons.ProcessFlow.NodeElement = function (id, oLane, oNode, aNodeParents) {
  this.nodeId = id;
  this.lane = oLane;
  this.state = oNode.getState();
  this.displayState = oNode._getDisplayState();
  this.isProcessed = false;

  if (jQuery.isArray(aNodeParents)) {
    this.aParent = aNodeParents;
  } else {
    this.oParent = aNodeParents;
  }
  this.oNode = oNode;
};

/**
 * Another type of the node element constructor.
 *
 * @private
 * @param id node id
 * @param lane lane position
 * @param oNode reference to a PF node control
 * @param aNodeParents reference to the ids of parents of the oNode
 * @returns A new node element
 */
sap.suite.ui.commons.ProcessFlow.NodeElement.initNodeElement = function (sId, oLane, oNode, aNodeParents) {
  return new sap.suite.ui.commons.ProcessFlow.NodeElement(sId, oLane, oNode, aNodeParents);
};

/**
 * Extend the NodeElement object with to String function.
 *
 * @private
 */
sap.suite.ui.commons.ProcessFlow.NodeElement.prototype = {
  toString: function () {
    return this.nodeId;
  },
  containsChildren: function (that) {
    if (!that) {
      return false;
    }
    if (!(that instanceof sap.suite.ui.commons.ProcessFlow.NodeElement)) {
      return false;
    }
    if (this.oNode.getChildren() && that.oNode.getChildren() && this.oNode.getChildren().length && that.oNode.getChildren().length) {
      for (var i = 0; i < this.oNode.getChildren().length; i++) {
        if (that.oNode.getChildren().indexOf(this.oNode.getChildren()[i]) >= 0) {
          return true;
        }
      }
    }
    return false;
  }
};

/**
 * Function calculates the state part of the lane from nodes belong to this lane.
 */
sap.suite.ui.commons.ProcessFlow.NodeElement.calculateLaneStatePieChart = function (elementsForLane, laneArray, internalNodes, processFlowObject) {
  // Check input parameters.
  if (!elementsForLane || !laneArray || !internalNodes) {
    return;
  }

  //First, check if all nodes are in the regular state. If not, only the highlighted ones are taken into calculation.
  for (var i = 0; i < internalNodes.length; i++) {
    processFlowObject._bHighlightedMode = internalNodes[i].getHighlighted();
    if (processFlowObject._bHighlightedMode) {
      break;
    }
  }
  var positive = 0;
  var negative = 0;
  var neutral = 0;
  var planned = 0;
  for (var i = 0; i < laneArray.length; i++) {
    var laneObject = laneArray[i];
    var elements = elementsForLane[laneObject.getLaneId()];

    //If we do not have nodes, nothing needs to be calculated.
    if (!elements) {
      continue;
    }

    positive = 0;
    negative = 0;
    neutral = 0;
    planned = 0;

    for (var j = 0; j < elements.length; j++) {
      //Maybe ...oNode.getHighlighted() can be used instead of the big selector which needs to be maintained in case of extensions.
      if (!processFlowObject._bHighlightedMode ||
          (elements[j].oNode._getDisplayState() == sap.suite.ui.commons.ProcessFlowDisplayState.Highlighted ||
           elements[j].oNode._getDisplayState() == sap.suite.ui.commons.ProcessFlowDisplayState.HighlightedFocused ||
           elements[j].oNode._getDisplayState() == sap.suite.ui.commons.ProcessFlowDisplayState.SelectedHighlighted ||
           elements[j].oNode._getDisplayState() == sap.suite.ui.commons.ProcessFlowDisplayState.SelectedHighlightedFocused)) {
        switch (elements[j].oNode.getState()) {
          case sap.suite.ui.commons.ProcessFlowNodeState.Positive:
            positive++;
            break;
          case sap.suite.ui.commons.ProcessFlowNodeState.Negative:
            negative++;
            break;
          case sap.suite.ui.commons.ProcessFlowNodeState.Planned:
            planned++;
            break;
          case sap.suite.ui.commons.ProcessFlowNodeState.Neutral:
            neutral++;
            break;
            //plannedNegative belong to the Negative group
          case sap.suite.ui.commons.ProcessFlowNodeState.PlannedNegative:
            negative++;
            break;
        }
      }
    } // End of nodes for single lane.
    var stateData = [{state: sap.suite.ui.commons.ProcessFlowNodeState.Positive, value:positive},
                     {state: sap.suite.ui.commons.ProcessFlowNodeState.Negative, value:negative},
                     {state: sap.suite.ui.commons.ProcessFlowNodeState.Neutral, value:neutral},
                     {state: sap.suite.ui.commons.ProcessFlowNodeState.Planned, value:planned}];
    laneObject.setState(stateData);
  }
};

/**
 * This function must check and calculate the potentially new lanes.
 * This is, because more nodes can be located in the same lane. In this case,
 * the new artificial lane is created and positioned just after original one.
 *
 * @param aProcessFlowLanes the original lane array
 * @param aInternalNodes internal nodes
 * @returns {Object} Dynamic object containing laines and nodes
 */
sap.suite.ui.commons.ProcessFlow.NodeElement.updateLanesFromNodes = function (aProcessFlowLanes, aInternalNodes) {
  var createMapResult = sap.suite.ui.commons.ProcessFlow.NodeElement.createMapFromLanes(aProcessFlowLanes, null, false);
  var mapLanesArrayPosition = createMapResult.positionMap;
  var mapLanesArrayId = createMapResult.idMap;
  var oNode = {};
  var tempProcessFlowLanes = aProcessFlowLanes.slice();
  var bPotentialNewLaneExists;
  var tempLanesPos = {};
  var nPos = 0;

  for (var i = 0; i < aInternalNodes.length; i++) {
    oNode[aInternalNodes[i].getNodeId()] = aInternalNodes[i];
  }

  for (var i = 0; i < aInternalNodes.length; i++) {
    var node = aInternalNodes[i];
    var children = node.getChildren() || [];
    var positionUp = 1; //Check the move up for the given sublanes of the lane. Every new sublane creation.
    var potentialNewLaneId = null;
    var potentialNewLane = null;
    // Makes plus 1 effect.
    for (var j = 0; j < children.length; j++) { // Check the children.
      var sChildId = sap.suite.ui.commons.ProcessFlow._getChildIdByElement(children[j]);
      var childrenNode = oNode[sChildId];
      if (childrenNode && (node.getLaneId() == childrenNode.getLaneId())) {
        // Create new lane id and check the lane.
        potentialNewLaneId = childrenNode.getLaneId() + positionUp;
        potentialNewLane = mapLanesArrayId[potentialNewLaneId];
        if (!potentialNewLane) { // If we have the lane already.
          var origLaneObject = mapLanesArrayId[node.getLaneId()];
          potentialNewLane = sap.suite.ui.commons.ProcessFlow.NodeElement.createNewProcessFlowElement(origLaneObject, potentialNewLaneId, origLaneObject.getPosition() + positionUp);
          // Update the maps and output array.
          mapLanesArrayId[potentialNewLane.getLaneId()] = potentialNewLane;
          tempProcessFlowLanes.splice(potentialNewLane.getPosition(), 0, potentialNewLane);
        }
        // Assign new lane to children
        // The new laneId should not override the old one, therefore it is stored in a hidden property
        childrenNode._setMergedLaneId(potentialNewLane.getLaneId());
      }
      // Move also the assignment of this lane for all children. Otherwise it is bad ...
      // so, take the children of current children and move the lane position to the new lane, if necessary
      // it is in the case when the lane is the same as was PARENT node. this is important to understand,
      // that this children is already moved to new one, so parent lane is compared.
      // This is a recursion.
      sap.suite.ui.commons.ProcessFlow.NodeElement.changeLaneOfChildren(node.getLaneId(), childrenNode, oNode);
    }
    // Now we should move all positions up about the number positionUp.
    // Also the position map is in wrong state now.
    // Now work with all vector, later on we can move only to lanes with higher position than working one.
    if (potentialNewLane) {
      tempLanesPos = {};
      bPotentialNewLaneExists = false;
      for (var key in mapLanesArrayPosition) {
        if (potentialNewLane.getLaneId() == mapLanesArrayPosition[key].getLaneId()) {
          bPotentialNewLaneExists = true;
          break;
        }
        if (parseInt(key) >= potentialNewLane.getPosition()) {
          var tempLaneObject = mapLanesArrayPosition[key];
          tempLanesPos[tempLaneObject.getPosition() + positionUp] = tempLaneObject;
          // tempLaneObject.setPosition(tempLaneObject.getPosition()+positionUp);
        }
      }
      if (!bPotentialNewLaneExists) {
        for (var w in tempLanesPos) {
          nPos = parseInt(w);
       // The moved position should not override the old one, therefore it is stored in a hidden property
          tempLanesPos[nPos]._setMergedPosition(nPos);
        }
        tempLanesPos[potentialNewLane.getPosition()] = potentialNewLane;
        for (var v = 0; v < potentialNewLane.getPosition(); v++) {
          tempLanesPos[v] = mapLanesArrayPosition[v];
        }
        mapLanesArrayPosition = tempLanesPos;
      }
    }
  }
  return { lanes: tempProcessFlowLanes, nodes: aInternalNodes };
};

sap.suite.ui.commons.ProcessFlow.NodeElement.changeLaneOfChildren = function (origLaneId, currentNode, nodeArray) {
  var children = currentNode.getChildren();
  if (children) {
    for (var i = 0; i < children.length; i++) {
      var childId = sap.suite.ui.commons.ProcessFlow._getChildIdByElement(children[i]);
      var childrenNode = nodeArray[childId];
      if (childrenNode.getLaneId() == origLaneId) {
        childrenNode._setMergedLaneId(currentNode.getLaneId());
        sap.suite.ui.commons.ProcessFlow.NodeElement.changeLaneOfChildren(origLaneId, childrenNode, nodeArray);
      }
    }
  }
};

sap.suite.ui.commons.ProcessFlow.NodeElement.createNewProcessFlowElement = function (originalElement, newLaneId, newPosition) {
  var cloneElement = new sap.suite.ui.commons.ProcessFlowLaneHeader({
    laneId: newLaneId,
    iconSrc: originalElement.getIconSrc(),
    text: originalElement.getText(),
    state: originalElement.getState(),
    position: newPosition,
    zoomLevel: originalElement.getZoomLevel()
  });
  return cloneElement;
};

/**
 * This function creates the map where key = position value - lane element.
 *
 * @private
 * @param {sap.suite.ui.commons.ProcessFlowLaneHeader[]} aProcessFlowLanes array of lanes
 * @param {function} fnTapHandler tap handler for the lane header element
 * @param {boolean} bHeaderMode should be true, if the process flow is in the header mode
 * @returns {Object} Map of lane positions to lane header element control instances
 */
sap.suite.ui.commons.ProcessFlow.NodeElement.createMapFromLanes = function (aProcessFlowLanes, fnTapHandler, bHeaderMode) {
  var oLane,
      aMapLaneArrayPosition = {},
      aMapLaneArrayId = {},
      nLanes = aProcessFlowLanes ? aProcessFlowLanes.length : 0,
      i = 0;

  if (!nLanes) {
    return {};
  } else {
    while (i < nLanes) {
      oLane = aProcessFlowLanes[i];
      if (oLane instanceof sap.suite.ui.commons.ProcessFlowLaneHeader) {
        aMapLaneArrayPosition[oLane.getPosition()] = oLane;
        aMapLaneArrayId[oLane.getLaneId()] = oLane;
        // Forward the icon click events from the lane header items to the ProcessFlow control.
        if (fnTapHandler) {
          oLane.attachPress(fnTapHandler);
        }
        oLane._setHeaderMode(bHeaderMode);
      }
      i++;
    }

    return { positionMap: aMapLaneArrayPosition, idMap: aMapLaneArrayId };
  }
};

/**
*
* This function transforms from process flow node element into the internal
* node element. The strategy is to work inside algorithm only with internal
* representation.
*
* @private
* @parameter processFlowNodes PF nodes from the controls interface, preprocessed - so they all have a valid (user entered, resp. generated) lane id
* @parameter elementsForLane
* @returns {Object} Element containing elementForId(NodeElement) and elementsForLane (NodeElement[])
*/
sap.suite.ui.commons.ProcessFlow.NodeElement.createNodeElementsFromProcessFlowNodes = function (processFlowNodes, processFlowLanes) {
  var aPositionForLaneId = {}, // Map holds the transition between lane id and position.
      aElementsForLane = {}, // Holds a map from laneId to array of the elements for given laneId.
      aParentsForChild = {},
      oNode,
      iNodeCount = processFlowNodes ? processFlowNodes.length : 0,
      sNodeId,
      oLane,
      iLaneCount = processFlowLanes ? processFlowLanes.length : 0,
      sLaneId,
      aPositions = [],
      iLanePosition,
      aChildren,
      sChild,
      nChildCount,
      i,
      j,
      aElementForId = {};

  if (iNodeCount === 0) {
    return { elementForId: {}, elementsForLane: {} };
  }

  if (iLaneCount === 0) {
    throw ["No lane definition although there is a node definition."];
  }

  i = 0;
  while (i < iLaneCount) {
    oLane = processFlowLanes[i];
    sLaneId = oLane.getLaneId();
    iLanePosition = oLane.getPosition();

    if (aPositionForLaneId[sLaneId]) {
      throw ["The lane with id: " + sLaneId + " is defined at least twice. (Lane error)"];
    }

    aPositionForLaneId[sLaneId] = iLanePosition;

    if (jQuery.inArray(iLanePosition, aPositions) > -1) {
      throw ["The position " + iLanePosition + " is defined at least twice. (Lane error)."];
    } else {
      aPositions.push(iLanePosition);
    }

    aElementsForLane[sLaneId] = [];
    i++;
  }

  // search for the parent
  i = 0;
  while (i < iNodeCount) {
    oNode = processFlowNodes[i];
    if (oNode instanceof sap.suite.ui.commons.ProcessFlowNode) {
      sNodeId = oNode.getNodeId();
      sLaneId = oNode.getLaneId();

      aChildren = oNode.getChildren() || [];
      nChildCount = aChildren.length;
      j = 0;
      while (j < nChildCount) {
        sChild = sap.suite.ui.commons.ProcessFlow._getChildIdByElement(aChildren[j]);
        aParentsForChild[sChild] = aParentsForChild[sChild] || [];
        aParentsForChild[sChild].push(sNodeId);
        j++;
      }
    }
    i++;
  }

  i = 0;
  while (i < iNodeCount) {
    oNode = processFlowNodes[i];
    if (oNode instanceof sap.suite.ui.commons.ProcessFlowNode) {
      sNodeId = oNode.getNodeId();

      if (!sNodeId) {
        throw ["There is a node which has no node id defined. (Title=" + oNode.getTitle() + ") and array position: " + i];
      }

      sLaneId = oNode.getLaneId();

      iLanePosition = aPositionForLaneId[sLaneId];
      if (typeof iLanePosition !== 'number') {
        throw ["For the node " + sNodeId + " position (lane) is not defined."];
      }

      if (!aElementForId[sNodeId]) {
        aElementForId[sNodeId] = sap.suite.ui.commons.ProcessFlow.NodeElement.initNodeElement(sNodeId, iLanePosition, oNode, aParentsForChild[sNodeId]);

        aElementsForLane[sLaneId].push(aElementForId[sNodeId]);
      } else {
        throw ["The node id " + sNodeId + " is used second time."];
      }
    }
    i++;
  }

  return { elementForId: aElementForId, elementsForLane: aElementsForLane };
};

/**
 * Constructor of the algorithm object.
 *
 * @private
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation = function (parentControl) {
  this.parentControl = parentControl;
  this.posx = 0;
  this.posy = 0;

  this.nodePositions = {};
  this.mapChildToNode = {};
};

/**
 * Function checks consistency of the node array. It checks,
 * if all children defined for the nodes are also presented as the nodes themselves.
 *
 * @public
 * @param elementForId Map of node id's to NodeElements. Expectation is to have at least 1 element there. No check for empty array.
 * @throws array of error messages produced during the consistency check
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.checkInputNodeConsistency = function (elementForId) {
  var returnArr = [],
      j,
      sChildId,
      nChildCount,
      aChildren,
      oElement;

  //Preparation phase
  Object.keys(elementForId).forEach(function (sElementId) {
    oElement = elementForId[sElementId];
    aChildren = oElement.oNode.getChildren();
    nChildCount = aChildren ? aChildren.length : 0;

    j = 0;
    while (j < nChildCount) {
      sChildId = sap.suite.ui.commons.ProcessFlow._getChildIdByElement(aChildren[j]);
      if (!elementForId[sChildId]) {
        returnArr.push("Node identificator " + sChildId + " used in children definition is not presented as the node itself. Element : " + oElement.nodeId);
      }
      j++;
    }
  });

  if (returnArr.length > 0) {
    throw returnArr;
  }
};

/**
 * Function resets the positions into initial one to keep new calculation
 * without side effects.
 *
 * @private
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.resetPositions = function () {
  this.posx = 0;
  this.posy = 0;

  delete this.nodePositions;
  delete this.mapChildToNode;

  this.nodePositions = {};
  this.mapChildToNode = {};
};

/**
 * Function creates matrix based on the length.
 *
 * @private
 * @param {String} length number of columns
 * @returns {Object[]} Array with two dimensions
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.createMatrix = function (length) {
  length = parseInt(length, 10);
  var arr = new Array(length || 0);
  var i = length;

  if (arguments.length > 1) {
    var args = Array.prototype.slice.call(arguments, 1);
    while (i--) {
      arr[length - 1 - i] = this.createMatrix.apply(this, args);
    }
  }
  return arr;
};

/**
 * Function retrieves the important information from input array.
 *
 * @private
 * @param elementForId map of element id's to elements
 * @returns {Object} Element containing highestLanePosition(number) and rootElements (Element[])
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.retrieveInfoFromInputArray = function (elementForId) {

  var highestLanePosition = 0,
      rootElements = [],
      oElement;

  Object.keys(elementForId).forEach(function (sElementId) {
    oElement = elementForId[sElementId];

    if (!oElement.oParent && !oElement.aParent) {
      rootElements.push(oElement);
    }

    if (highestLanePosition < oElement.lane) {
      highestLanePosition = oElement.lane;
    }
  });

  return {
    'highestLanePosition': highestLanePosition,
    'rootElements': rootElements
  };
};

/**
 * Function doubles the matrix for drawing purposes and it only doubles the columns and add undefined values there.
 *
 * @private
 * @returns {Object[]} Array with doubled colummns
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.doubleColumnsInMatrix = function (currentMatrix) {
  var matrixY = 0;

  for (var i = 0; i < currentMatrix.length; i++) {
    matrixY = matrixY > currentMatrix[i].length ? matrixY : currentMatrix[i].length;
  }

  var doubleArray = new Array(currentMatrix.length || 0);

  for (var i = 0; i < doubleArray.length; i++) {
    doubleArray[i] = new Array(matrixY * 2 - 1);
    for (var j = 0; j < matrixY; j++) {
      if (currentMatrix[i][j]) {
        doubleArray[i][2 * j] = currentMatrix[i][j];
      }
    }
  }
  return doubleArray;
};

/**
 * Function removes empty lines from the matrix.
 *
 * @returns {Object[]} Array where empty lines have been removed
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.removeEmptyLines = function (originalMatrix) {
  //First check the number of valid lines.
  var numberOfLines = 0;
  for (var i = 0; i < originalMatrix.length; i++) {
    for (var j = 0; j < originalMatrix[i].length; j++) {
      if (originalMatrix[i][j]) {
        numberOfLines++;
        break;
      }
    }
  }

  var returnArray = this.createMatrix(numberOfLines, originalMatrix[0].length);

  for (var i = 0; i < numberOfLines; i++) {
    for (var j = 0; j < originalMatrix[i].length; j++) {
      returnArray[i][j] = null; // everything is at least null
      if (originalMatrix[i][j]) {
        returnArray[i][j] = originalMatrix[i][j];
      }
    }
  }
  return returnArray;
};

/**
 * Creates the matrix where the nodes are already positioned correctly.
 *
 * @public
 * @param currentElement actually processed element
 * @param elementForId map of all the available elements
 * @param return2DimArray the updated virtual matrix
 * @returns The updated virtual matrix
 */

sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.processCurrentElement = function (currentElement, elementForId, return2DimArray) {
  var aElementsChildIds,
      aElementsChildren,
      that = this,
      bNoChildInUpperRow = true, // If there is a child already drawn in an upper row, it is required to move to the next line
      bMoveToNextLine = true; // This is the check for repeated parent-child relationship. The childrenArr is not empty but
  // in fact it is required to move to the next line.

  if (currentElement.isProcessed) {
    return return2DimArray;
  }

  this.nodePositions[currentElement.nodeId] = {
    'c': currentElement,
    'x': this.posx,
    'y': this.posy * 2
  };

  return2DimArray[this.posx][this.posy++] = currentElement;
  aElementsChildIds = currentElement.oNode.getChildren();
  currentElement.isProcessed = true;
  aElementsChildren = this.sortBasedOnChildren(aElementsChildIds, elementForId);

  if (aElementsChildren) {
    aElementsChildren.forEach(function (oChild) {
      if (!oChild.isProcessed) {
        bMoveToNextLine = false;
        while (that.posy < oChild.lane) {
          return2DimArray[that.posx][that.posy++] = null;
        }
        return2DimArray = that.processCurrentElement(oChild, elementForId, return2DimArray);
      }
      else {
        // Child has already been processed, which means there is a connection pointing to the right.
        // Therefore it is necessary to move to the next line so that the next child element is not drawn in the connection.
        if (bNoChildInUpperRow && bMoveToNextLine) {
          that.posx++;
          bNoChildInUpperRow = false;
        }
      }
    });
  }

  if (!aElementsChildIds || bMoveToNextLine) {
      // Check if we moved already to the next line in the forEach loop
    if (bNoChildInUpperRow) {
      this.posx++;
    }
    this.posy = 0;
  }

  return return2DimArray;
};

/**
 * Sort based on the child proximity. If 2 children has some common children they get next to each other.
 *
 * @private
 * @param aElementsChildIds child ids of the currently processed node
 * @param elementForId  contains a map of the node id's to node elements
 * @returns {sap.suite.ui.commons.ProcessFlow.NodeElement} Array containing sorted child elements (first sort by lanes, than the elements having the same children gets next to each other)
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.sortBasedOnChildren = function (aElementsChildIds, elementForId) {
  var oElementsForLane = {},
      aElements,
      laneId = null,
      aLaneIds,
      aNmbrChildren,
      bNmbrChildren,
      finalSortedArray = [],
      aSingleLaneContent,
      aSingleContent,
      oProcessedChildElement;

  if (aElementsChildIds) {
    aElementsChildIds.forEach(function (oChildId) {
      var sChildId = sap.suite.ui.commons.ProcessFlow._getChildIdByElement(oChildId);
      aElements = oElementsForLane[elementForId[sChildId].lane];
      if (!aElements) {
        oElementsForLane[elementForId[sChildId].lane] = aElements = [];
      }
      aElements.push(elementForId[sChildId]);
    });
  } else {
    return [];
  }

  aLaneIds = [];
  for (laneId in oElementsForLane) {
    aLaneIds.push(laneId);
    //Sort the Nodes (related to currend lane) descending by amount of children.
    oElementsForLane[laneId].sort(function (a, b) {
      //Lane needs not to be checked.
      //If it is the same one, check for the same children. 
      //In this case return 0
      aNmbrChildren = (a.oNode.getChildren() || []).length;
      bNmbrChildren = (b.oNode.getChildren() || []).length;
      return bNmbrChildren - aNmbrChildren;
    });
  }

  //Sort the Lanes descending by laneId.
  aLaneIds = aLaneIds.sort(function (a, b) {
    return b - a;
  });

  //Now we have in aLaneIds the lane orderd (descending by laneId)
  //Based on that we take from map the elements for the lanes.
  //Now order based on the children.
  aLaneIds.forEach(function (laneId) {
    aSingleLaneContent = oElementsForLane[laneId];

    if (aSingleLaneContent.length > 1) {
      aSingleContent = [];
      //We iterate through all the children and
      //put all the nodes having at least 1 common child next to each other.
      oProcessedChildElement = aSingleLaneContent.shift();
      while (oProcessedChildElement) {
        if (aSingleContent.indexOf(oProcessedChildElement) < 0) {
          aSingleContent.push(oProcessedChildElement);
        }

        aSingleLaneContent.forEach(function (oSiblingElement) {
          if (oProcessedChildElement.containsChildren(oSiblingElement)) {
            aSingleContent.push(oSiblingElement);
          }
        });
        oProcessedChildElement = aSingleLaneContent.shift();
      }
      finalSortedArray = finalSortedArray.concat(aSingleContent);
    } else {
      finalSortedArray = finalSortedArray.concat(aSingleLaneContent);
    }
  });
  return finalSortedArray;
};

/**
 * Function calculates the connection and writes into the virtual matrix. It gets the matrix plus
 * parent children relationship.
 * 
 * @param OriginalMatrix the matrix with the setup of nodes
 * @returns {Object[]} The matrix updated with the calculated paths
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.calculatePathInMatrix = function (originalMatrix) {
  var currentElement = null;
  for (var key in this.nodePositions) {
    if (this.nodePositions.hasOwnProperty(key)) {
      currentElement = this.nodePositions[key];
      var aChildren = currentElement.c.oNode.getChildren();
      for (var i = 0; aChildren && i < aChildren.length; i++) {
        var sChildId = sap.suite.ui.commons.ProcessFlow._getChildIdByElement(aChildren[i]);
        var positionChildrenObject = this.nodePositions[sChildId];
        originalMatrix = this.calculateSingleNodeConnection(currentElement,
                         positionChildrenObject, currentElement.x, currentElement.y,
                         positionChildrenObject.x, positionChildrenObject.y, originalMatrix);
      }
    }
  }
  return originalMatrix;
};

/**
 * Function based on the parent children position calculated the path from parent to children. The idea is like following
 * go from parent half right and use next connection column to go up or down. Afterwards on the line with children go
 * horizontal.
 *
 * @param nodeParent
 * @param nodeChildren
 * @param parentX
 * @param parentY
 * @param childrenX
 * @param childrenY
 * @param originalMatrix
 * @returns {Object[]} The original Matrix
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.calculateSingleNodeConnection = function (
    nodeParent, nodeChildren, parentX, parentY, childrenX, childrenY, originalMatrix) {
  var hor = childrenY - parentY;
  var ver = childrenX - parentX;
  if (hor < 0) {
    var errMsg = ["Problem with negative horizontal movement",
                  "Parent node is " + nodeParent.c.toString(),
                  "Children node is " + nodeChildren.c.toString(),
                  "Coordinates : '" + parentX + "','" + parentY + "','" + childrenX + "','" + childrenY + "'"];
    throw errMsg;
  } else if (ver <= -1) {
    // Half left and up
    var bNormalHorizontalLinePossible = this.checkIfHorizontalLinePossible(originalMatrix, childrenX, parentY + 2, childrenY);
    var yPosition = childrenY - 1;
    if (bNormalHorizontalLinePossible) {
      yPosition = parentY + 1;
    }
    var xPosition = parentX;
    if (bNormalHorizontalLinePossible) {
      xPosition = childrenX;
    }
    originalMatrix[parentX][yPosition] = this.createConnectionElement(
        originalMatrix[parentX][yPosition], sap.suite.ui.commons.ProcessFlow.cellEdgeConstants.LU,
        nodeParent, nodeChildren, false);

    //Going up to the children.
    originalMatrix = this.writeVerticalLine(originalMatrix, parentX, childrenX, yPosition, nodeParent, nodeChildren);

    originalMatrix[childrenX][yPosition] =
      this.createConnectionElement(originalMatrix[childrenX][yPosition],
      sap.suite.ui.commons.ProcessFlow.cellEdgeConstants.UR, nodeParent,
      nodeChildren, (yPosition == childrenY - 1));
    //Pure right.
    var startY = parentY + 2;
    var endY = childrenY;
    if (!bNormalHorizontalLinePossible) {
      startY = parentY + 1;
      endY = yPosition + 1;
    }
    originalMatrix = this.writeHorizontalLine(originalMatrix, xPosition, startY, endY, nodeParent, nodeChildren);
  } else if (ver === 0) {
    originalMatrix = this.writeHorizontalLine(originalMatrix, parentX, parentY + 1, childrenY, nodeParent, nodeChildren);
  } else if (ver === 1) {
    //1 row down and do horizontal line.
    //Half and down.
    originalMatrix[parentX][parentY + 1] = this.createConnectionElement(originalMatrix[parentX][parentY + 1],
                                           sap.suite.ui.commons.ProcessFlow.cellEdgeConstants.LD, nodeParent,
                                           nodeChildren, false);
    //Down and right.
    originalMatrix[childrenX][parentY + 1] = this.createConnectionElement(originalMatrix[childrenX][parentY + 1],
                                             sap.suite.ui.commons.ProcessFlow.cellEdgeConstants.DR, nodeParent,
                                             nodeChildren, (parentY + 1) === (childrenY - 1));
    //Horizontal line to the target.
    originalMatrix = this.writeHorizontalLine(originalMatrix, childrenX, parentY + 2, childrenY, nodeParent, nodeChildren);
  } else { //ver > 1
    //Go down until children and do horizontal line.
    //Half left and down.
    originalMatrix[parentX][parentY + 1] = this.createConnectionElement(originalMatrix[parentX][parentY + 1],
                                           sap.suite.ui.commons.ProcessFlow.cellEdgeConstants.LD, nodeParent,
                                           nodeChildren, false);
    originalMatrix = this.writeVerticalLine(originalMatrix, childrenX, parentX, parentY + 1, nodeParent, nodeChildren);
    //Half down and right.
    originalMatrix[childrenX][parentY + 1] = this.createConnectionElement(originalMatrix[childrenX][parentY + 1],
                                             sap.suite.ui.commons.ProcessFlow.cellEdgeConstants.DR, nodeParent,
                                             nodeChildren, (parentY + 1) === (childrenY - 1));
    originalMatrix = this.writeHorizontalLine(originalMatrix, childrenX, parentY + 2, childrenY, nodeParent, nodeChildren);
  }
  return originalMatrix;
};

/**
 * Write vertical line from firstrow to lastrow on the column position.
 *
 * @private
 * @returns {Object[]} The original matrix containing vertical line connections
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.writeVerticalLine = function (originalMatrix, firstRow, lastRow, column, nodeParent, nodeChildren) {
  for (var j = firstRow - 1; j > lastRow; j--) {
    originalMatrix[j][column] = this.createConnectionElement(originalMatrix[j][column],
                                sap.suite.ui.commons.ProcessFlow.cellEdgeConstants.DU, nodeParent,
                                nodeChildren, false);
  }
  return originalMatrix;
};

/**
 * Checks if the horizontal line is possible.
 * 
 * @private
 * @param originalMatrix
 * @param row
 * @param firstColumn
 * @param lastColumn
 * @returns {boolean} Function return true, if the path is free, otherwise false
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.checkIfHorizontalLinePossible = function (
    originalMatrix, row, firstColumn, lastColumn) {
  var bLinePossible = true;
  for (var i = firstColumn; i < lastColumn; i++) {
    if (originalMatrix[row][i] instanceof sap.suite.ui.commons.ProcessFlow.NodeElement) {
      bLinePossible = false;
      break;
    }
  }

  return bLinePossible;
};

/**
 * Function calculated and writes horizontal line.
 *
 * @param originalMatrix matrix to write to
 * @param row the horizontal position
 * @param firstColumn where to start
 * @param lastColumn where to stop
 * @param nodeParent definition of initial node
 * @param nodeChildren definition of target node
 * @returns {Object[]} The original Matrix including the horizontal lines
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.writeHorizontalLine = function (
    originalMatrix, row, firstColumn, lastColumn, nodeParent, nodeChildren) {
  var bPotentialArrow = (row == nodeChildren.x);
  //No arrow, no last line ... somewhere else will be (up and right).
  if (!bPotentialArrow) {
    lastColumn--;
  }
  for (var i = firstColumn; i < lastColumn; i++) {
    originalMatrix[row][i] =
      this.createConnectionElement(originalMatrix[row][i], sap.suite.ui.commons.ProcessFlow.cellEdgeConstants.LR, nodeParent, nodeChildren, (i == (lastColumn - 1)) && bPotentialArrow);
  }
  return originalMatrix;
};

/**
 * Function adds new connection element to the cell in the matrix. It is an additive approach where during the
 * drawing phase all the connections in one cell will be joined together.
 *
 * @private
 * @param originalConnectionValue
 * @param addStringValue
 * @param initialNode
 * @param targetNode
 * @param bArrowRequired
 * @returns {sap.suite.ui.commons.ProcessFlowConnection} The connection element
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype.createConnectionElement = function (originalConnectionValue, addStringValue, initialNode, targetNode, bArrowRequired) {

  var tempOriginalConnectionValue = originalConnectionValue;
  if (!tempOriginalConnectionValue) {
    tempOriginalConnectionValue = new sap.suite.ui.commons.ProcessFlowConnection();
  }
  if (tempOriginalConnectionValue instanceof sap.suite.ui.commons.ProcessFlowConnection) {
    var displayState = this._calculateConnectionDisplayStateBySourceAndTargetNode(initialNode.c.oNode, targetNode.c.oNode);
    var objConn = {
      flowLine: addStringValue,
      targetNodeState: targetNode.c.state,
      displayState: displayState,
      hasArrow: bArrowRequired
    };
    tempOriginalConnectionValue.addConnectionData(objConn);
  }
  return tempOriginalConnectionValue;
};

/**
 * Calculates the correct display state for a connection based on the source and the target node.
 *
 * @private
 * @param {sap.suite.ui.commons.ProcessFlowNode} sourceNode for calculation
 * @param {sap.suite.ui.commons.ProcessFlowNode} targetNode for calculation
 * @returns {sap.suite.ui.commons.ProcessFlowDisplayState} The resulting displayState
 */
sap.suite.ui.commons.ProcessFlow.InternalMatrixCalculation.prototype._calculateConnectionDisplayStateBySourceAndTargetNode = function (sourceNode, targetNode) {
  var bSourceIsHighlighted = sourceNode.getHighlighted();
  var bSourceIsSelected = sourceNode.getSelected();
  var bSourceIsDimmed = sourceNode._getDimmed();
  var bTargetIsHighlighted = targetNode.getHighlighted();
  var bTargetIsSelected = targetNode.getSelected();
  var bTargetIsDimmed = targetNode._getDimmed();

  var displayState = sap.suite.ui.commons.ProcessFlowDisplayState.Regular;
  if (bSourceIsSelected && bTargetIsSelected) {
    displayState = sap.suite.ui.commons.ProcessFlowDisplayState.Selected;
  } else if (bSourceIsHighlighted && bTargetIsHighlighted) {
    displayState = sap.suite.ui.commons.ProcessFlowDisplayState.Highlighted;
  } else if ((bSourceIsDimmed || bTargetIsDimmed) ||
              bSourceIsHighlighted && bTargetIsSelected ||
              bSourceIsSelected && bTargetIsHighlighted) {
    //If the node is not in state dimmed and no direct connection between select/highlighted nodes is available, set dimmed state.
    displayState = sap.suite.ui.commons.ProcessFlowDisplayState.Dimmed;
  }

  return displayState;
};

sap.suite.ui.commons.ProcessFlow.cellEdgeConstants = {
  'LU': 'tl', //It is going from Left to the middle and afterwards Up = top left.
  'LD': 'lb', //It is going from Left to the middle and afterwards Down = left bottom.
  'DU': 'tb', //It is going from Down to the middle and afterwards Up = top bottom.
  'LR': 'rl', //It is going from Left to the middle and afterwards Right = right left.
  'DR': 'rt', //It is going from Down to the middle and afterwards Right = right top.
  'UR': 'rb'  //It is going from Up to the middle and afterwards Right = right bottom.
};

sap.suite.ui.commons.ProcessFlow.prototype.addNode = function (addNode) {
  return this.addAggregation("nodes", addNode, false);
};

/**
 * Function sets the zoom level.
 *
 * @param zoomLevel. this is a new zoom level of the type sap.suite.ui.commons.ProcessFlowZoomLevel
 */
sap.suite.ui.commons.ProcessFlow.prototype.setZoomLevel = function (zoomLevel) {
  var $scrollContainer = this.$("scrollContainer");
  var oScrollContainerContextOld;
  var oScrollContainerContextNew;
  if ($scrollContainer.context) {
    oScrollContainerContextOld = {
      scrollWidth: $scrollContainer.context.scrollWidth,
      scrollHeight: $scrollContainer.context.scrollHeight,
      scrollLeft: $scrollContainer.context.scrollLeft,
      scrollTop: $scrollContainer.context.scrollTop
    };
    oScrollContainerContextNew = oScrollContainerContextOld;
    if (this._zoomLevel === zoomLevel) {
      this._isInitialZoomLevelNeeded = false;
      return;
    }
  }
  if (!(zoomLevel in sap.suite.ui.commons.ProcessFlowZoomLevel)) { // Enumeration
    this._handleException("\"" + zoomLevel + "\" is not a valid entry of the enumeration for property zoom level of ProcessFlow");
    return;
  }
  this._zoomLevel = zoomLevel;
  //When setting the initial zoomlevel, invalidate() has to be called,
  //because the method call comes from onAfterRendering() and to call the rerender() is not allowed.
  if (this._isInitialZoomLevelNeeded) {
    this._isInitialZoomLevelNeeded = false;
    this.invalidate();
    //In all other cases, the rerender() has to be called, so that the offset can be set afterwards.
  } else {
    this.rerender();
  }

  if (oScrollContainerContextOld) {
    //Set the grab cursor class in case for touch devices
    if (sap.ui.Device.support.touch || jQuery.sap.simulateMobileOnDesktop) {
      var iHeight = parseInt(this.$("scrollContainer").css("height").slice(0, -2), 10);
      var iWidth = parseInt(this.$("scrollContainer").css("width").slice(0, -2), 10);
      var iScrollHeight = this.$("scrollContainer")[0].scrollHeight;
      var iScrollWidth = this.$("scrollContainer")[0].scrollWidth;
      if (this.getScrollable() && (iScrollHeight > iHeight || iScrollWidth > iWidth)) {
        this._switchCursors(this.$("scrollContainer"), this._defaultCursorClass, this._grabCursorClass);
        this.$("scrollContainer").css("overflow", "auto");
      }
    }
    //Sets the scroll offset to the scrollContainer.
    $scrollContainer = this.$("scrollContainer");
    oScrollContainerContextNew = this._getScrollContainerOnZoomChanged(oScrollContainerContextOld, $scrollContainer);
    $scrollContainer.scrollLeft(oScrollContainerContextNew.scrollLeft);
    $scrollContainer.scrollTop(oScrollContainerContextNew.scrollTop);
    this._adjustAndShowArrow();
    //Avoids not setting the focus on clickable elements.
    if (this._isFocusChanged) {
      this._setFocusToNode();
      this._isFocusChanged = false;
    }
  }
};

/**
 * Function returns current zoom level.
 *
 * @returns {String} The zoomLevel
*/
sap.suite.ui.commons.ProcessFlow.prototype.getZoomLevel = function () {
  return this._zoomLevel;
};

/**
 * Function sets new zoom level with smaller level of details. Having the least detail view it stays as it is.
 *
 * @returns {String} The updated zoomLevel
 */
sap.suite.ui.commons.ProcessFlow.prototype.zoomOut = function () {
  var currentZoomLevel = this.getZoomLevel();
  var newLevel = currentZoomLevel;
  switch (currentZoomLevel) {
    case (sap.suite.ui.commons.ProcessFlowZoomLevel.One):
      newLevel = sap.suite.ui.commons.ProcessFlowZoomLevel.Two;
      break;
    case (sap.suite.ui.commons.ProcessFlowZoomLevel.Two):
      newLevel = sap.suite.ui.commons.ProcessFlowZoomLevel.Three;
      break;
    case (sap.suite.ui.commons.ProcessFlowZoomLevel.Three):
      newLevel = sap.suite.ui.commons.ProcessFlowZoomLevel.Four;
      break;
  }
  this.setZoomLevel(newLevel);
  return this.getZoomLevel();
};

/**
 * Function sets new zoom level with higher level of details. Having max details it stays as it is.
 *
 * @returns {String} The updated zoomLevel
 */
sap.suite.ui.commons.ProcessFlow.prototype.zoomIn = function () {
  var currentZoomLevel = this.getZoomLevel();
  var newLevel = currentZoomLevel;
  switch (currentZoomLevel) {
    case (sap.suite.ui.commons.ProcessFlowZoomLevel.Four):
      newLevel = sap.suite.ui.commons.ProcessFlowZoomLevel.Three;
      break;
    case (sap.suite.ui.commons.ProcessFlowZoomLevel.Three):
      newLevel = sap.suite.ui.commons.ProcessFlowZoomLevel.Two;
      break;
    case (sap.suite.ui.commons.ProcessFlowZoomLevel.Two):
      newLevel = sap.suite.ui.commons.ProcessFlowZoomLevel.One;
      break;
  }
  this.setZoomLevel(newLevel);
  return this.getZoomLevel();
};

/**
 * Updates the model and rerenders the control.
 */
sap.suite.ui.commons.ProcessFlow.prototype.updateModel = function () {
  //reset nodes' laneIds for merged lanes
  var aNodes = this.getNodes();
  var that = this;
  aNodes.forEach(function(that){
    that._mergedLaneId = false;
  })
  // reset lanes' position that was created for merged lanes
  var aLanes = this.getLanes();
  var that = this;
  aLanes.forEach(function(that){
    that._mergedLanePosition = false;
  })

  //Initialize internalLanes so that they get recalculated from the new nodes.
  this._internalLanes = [];
  if (this._isHeaderMode()) {
    var laneModel = this.getBindingInfo("lanes");
    this.getModel(laneModel.model).refresh();
  }
  else {
    var nodeModel = this.getBindingInfo("nodes");
    this.getModel(nodeModel.model).refresh();
  }
  this.rerender();
};

/**
 * Updates the nodes and rerenders the control.
 */
sap.suite.ui.commons.ProcessFlow.prototype.updateNodesOnly = function () {
  var nodeModel = this.getBindingInfo("nodes");
  this.getModel(nodeModel.model).refresh();
  this.rerender();
};

/**
 * Function returns the nodeId of the node which is focused.
 *
 * @returns {String} The id of focused node
 */
sap.suite.ui.commons.ProcessFlow.prototype.getFocusedNode = function () {
  if (this._lastNavigationFocusNode.sId) {
    return this._lastNavigationFocusNode.sId;
  }
};

/**
 * Handles the ontouched event.
 *
 * @private
 * @param {sap.ui.base.Event} oEvent
 */
sap.suite.ui.commons.ProcessFlow.prototype.ontouchend = function (oEvent) {
  if (oEvent.target && oEvent.target.id.indexOf("arrowScroll") != -1) {
    this._onArrowClick(oEvent);
  }
  else {
    if (!sap.ui.Device.support.touch && !jQuery.sap.simulateMobileOnDesktop) {
      this.onAfterRendering();
    } else {
      this._adjustAndShowArrow();
    }
    if (oEvent === null || oEvent.oSource === undefined) {
      return false;
    }
    oEvent.preventDefault();

    if (this && this._isHeaderMode()) {
      //Reset lanes as they could be redefined completely in headerPress Event - also necessary for merged lanes.
      this._internalLanes = [];
      this.fireHeaderPress(this);
    }
  }
  return false;
};

/**
 * Checks if ProcessFlow is in header mode.
 * 
 * @returns {Boolean} Value which describes if ProcessFlow is in header mode
 */
sap.suite.ui.commons.ProcessFlow.prototype._isHeaderMode = function () {
  var aNodes = this.getNodes();
  return !aNodes || (aNodes.length === 0);
};

/**
 * Switch cursors for scrollable/non-scrollable content.
 *
 * @private
 * @param {object} $scrollContainer the affected scroll container (jQuery object)
 * @param {String} sCursorClassFrom class containing the original cursor definition
 * @param {String} sCursorClassTo class containing the new cursor definition
 * @since 1.22
 */
sap.suite.ui.commons.ProcessFlow.prototype._switchCursors = function ($scrollContainer, sCursorClassFrom, sCursorClassTo) {
  if ($scrollContainer.hasClass(sCursorClassFrom)) {
    $scrollContainer.removeClass(sCursorClassFrom);
  }
  if (!$scrollContainer.hasClass(sCursorClassTo)) {
    $scrollContainer.addClass(sCursorClassTo);
  }
};

/**
 * Clear the mouse handlers for the scrolling functionality.
 *
 * @private
 * @since 1.22
 */
sap.suite.ui.commons.ProcessFlow.prototype._clearHandlers = function ($scrollContainer) {
  $scrollContainer.bind(this._mousePreventEvents, jQuery.proxy(this._handlePrevent, this));
};

sap.suite.ui.commons.ProcessFlow.prototype._handlePrevent = function (oEvent) {
  if (oEvent && !oEvent.isDefaultPrevented()) {
    oEvent.preventDefault();
  }
  if (oEvent && !oEvent.isPropagationStopped()) {
    oEvent.stopPropagation();
  }
  if (oEvent && !oEvent.isImmediatePropagationStopped()) {
    oEvent.stopImmediatePropagation();
  }
};

/**
 * Standard method called after the control rendering.
 */
sap.suite.ui.commons.ProcessFlow.prototype.onAfterRendering = function () {
  var bScrollable = false,
      $content = this.$("scroll-content"),
      iHeight,
      iWidth,
      iScrollWidth,
      iScrollHeight;

  //Initializes scrolling.
  this._checkOverflow(this.getDomRef("scrollContainer"), this.$());

  this.nCursorXPosition = 0;
  this.nCursorYPosition = 0;

  if ($content && $content.length) {
    //Sets PF node icon cursors, because these are unfortunately set as inline styles, so they cannot be overriden by applying a CSS class.
    this.$("scrollContainer").find('.sapSuiteUiCommonsProcessFlowNode .sapUiIcon').css("cursor", "inherit");

    if (this.getScrollable()) {
      iHeight = parseInt(this.$("scrollContainer").css("height").slice(0, -2), 10);
      iWidth = parseInt(this.$("scrollContainer").css("width").slice(0, -2), 10);
      iScrollHeight = $content[0].scrollHeight;
      iScrollWidth = $content[0].scrollWidth;

      if (iScrollHeight <= iHeight && iScrollWidth <= iWidth) {
        this._clearHandlers(this.$("scrollContainer"));
        //No scrolling makes sense, so clean up the mouse handlers and switch the cursors.
        this._switchCursors(this.$("scrollContainer"), this._grabCursorClass, this._defaultCursorClass);
      } else {
        this._switchCursors(this.$("scrollContainer"), this._defaultCursorClass, this._grabCursorClass);
        bScrollable = true;
      }
    } else {
      this._clearHandlers(this.$("scrollContainer"));
      this._switchCursors(this.$("scrollContainer"), this._grabCursorClass, this._defaultCursorClass);
      $content.css("position", "static");
    }
    if (bScrollable) {
      //Initialize top margin of arrow and counter.
      if (!this._iInitialArrowTop || !this._iInitialCounterTop) {
        this._iInitialArrowTop = parseInt(this.$("arrowScrollRight").css("top"), 10);
        this._iInitialCounterTop = parseInt(this.$("counterRight").css("top"), 10);
      }

      if (sap.ui.Device.os.windows && sap.ui.Device.system.combi && sap.ui.Device.browser.chrome) {
        //Win8 Surface: Chrome.
        this.$("scrollContainer").bind(this._mouseEvents, jQuery.proxy(this._registerMouseEvents, this));
        this.$("scrollContainer").css("overflow", "auto");
      } else if (sap.ui.Device.os.windows && sap.ui.Device.system.combi && sap.ui.Device.browser.msie && (sap.ui.Device.browser.version > 9)) {
        //Win8 Surface: IE 10 and higher.
        this.$("scrollContainer").bind(this._mouseEvents, jQuery.proxy(this._registerMouseEvents, this));
        this.$("scrollContainer").css("overflow", "auto");
        this.$("scrollContainer").css("-ms-overflow-style", "none");
      } else if (!sap.ui.Device.support.touch && !jQuery.sap.simulateMobileOnDesktop) {
        // Desktop
        this.$("scrollContainer").bind(this._mouseEvents, jQuery.proxy(this._registerMouseEvents, this));
      } else {
        // Mobile: use native scrolling.
        this._clearHandlers(this.$("scrollContainer"));
        this.$("scrollContainer").css("overflow", "auto");
      }
    } else { //Not scrollable ProcessFlow: Set overflow for chevron navigation anyway.
      if (this._bDoScroll) {
        //Is Not Desktop OR Is Win8.
        this.$("scrollContainer").css("overflow", "auto");
      } else {
        this.$("scrollContainer").css("overflow", "hidden");
      }
    }
    if (this.getWheelZoomable() && sap.ui.Device.system.desktop && !this._isHeaderMode()) {
      this.$("scrollContainer").bind(this._mouseWheelEvent, jQuery.proxy(this._registerMouseWheel, this));
    }
    if (this._bDoScroll) {
      //Bind scroll event for mobile.
      this.$("scrollContainer").bind("scroll", jQuery.proxy(this._onScroll, this));
    }
    this._resizeRegId = sap.ui.core.ResizeHandler.register(this, jQuery.proxy(sap.suite.ui.commons.ProcessFlow.prototype._onResize, this));
    if (this._isInitialZoomLevelNeeded) {
      this._initZoomLevel();
    }
    //Sets the focus to the next node if PF was in headers mode before rerendering.
    if (this._headerHasFocus) {
      this._headerHasFocus = false;
      var $nodeToFocus = this.$("scroll-content").children().children().children(1).children("td[tabindex='0']").first().children();
      var oNodeToFocus = sap.ui.getCore().byId($nodeToFocus[0].id);
      this._changeNavigationFocus(null, oNodeToFocus);
    }
  }
};

sap.suite.ui.commons.ProcessFlow.prototype._initZoomLevel = function () {
  //Set initial ZoomLevel according to ProcessFlow container size.
  //Breakpoints: until 599px = Level 4 / 600px-1023px = Level 3 / from 1024px = Level 2.
  if (this.$()) {
    var iWidth = this.$().width();
    if (iWidth) {
      if (iWidth < sap.m.ScreenSizes.tablet) {
        this.setZoomLevel(sap.suite.ui.commons.ProcessFlowZoomLevel.Four);
      } else if (iWidth < sap.m.ScreenSizes.desktop) {
        this.setZoomLevel(sap.suite.ui.commons.ProcessFlowZoomLevel.Three);
      } else {
        this.setZoomLevel(sap.suite.ui.commons.ProcessFlowZoomLevel.Two);
      }
    }
  }
};

sap.suite.ui.commons.ProcessFlow.prototype._registerMouseWheel = function (oEvent) {
  var oDirection = oEvent.originalEvent.wheelDelta || -oEvent.originalEvent.detail;
  if (oDirection === 0) {
    //for IE only
    oDirection = -oEvent.originalEvent.deltaY;
  }
  var that = this;
  if (oEvent && !oEvent.isDefaultPrevented()) {
    oEvent.preventDefault();
    oEvent.originalEvent.returnValue = false;
  }

  var waitTime = 300;
  var doNotListen = function () {
    var diff = new Date() - that._wheelTimestamp;
    if (diff < waitTime) {
      that._wheelTimeout = jQuery.sap.delayedCall(waitTime - diff, that, doNotListen);
    } else {
      that._wheelTimeout = null;
      that._wheelCalled = false;
    }
  };
  if (!that._wheelCalled) {
    that._wheelCalled = true;

    if (oDirection < 0) {
      this._isFocusChanged = true;
      that.zoomOut();
    } else {
      this._isFocusChanged = true;
      that.zoomIn();
    }
  }
  if (!that._wheelTimeout) {
    that._wheelTimestamp = new Date();
    that._wheelTimeout = jQuery.sap.delayedCall(waitTime, that, doNotListen);
  }
  if (oEvent && !oEvent.isPropagationStopped()) {
    oEvent.stopPropagation();
  }
  if (oEvent && !oEvent.isImmediatePropagationStopped()) {
    oEvent.stopImmediatePropagation();
  }
};

/**
 * @private
 */
sap.suite.ui.commons.ProcessFlow.prototype._registerMouseEvents = function (oEvent) {
  if (oEvent && !oEvent.isDefaultPrevented()) {
    oEvent.preventDefault();
  }
  switch (oEvent.type) {
    case 'mousemove':
      if (this.$("scrollContainer").hasClass(this._grabbingCursorClass)) {
        if (sap.ui.getCore().getConfiguration().getRTL()) {
          this.$("scrollContainer").scrollLeftRTL(this.nCursorXPosition - oEvent.pageX);
        } else {
          this.$("scrollContainer").scrollLeft(this.nCursorXPosition - oEvent.pageX);
        }
        this.$("scrollContainer").scrollTop(this.nCursorYPosition - oEvent.pageY);
        this._adjustAndShowArrow();
      }
      break;
    case 'mousedown':
      this._switchCursors(this.$("scrollContainer"), this._defaultCursorClass, this._grabbingCursorClass);
      if (sap.ui.getCore().getConfiguration().getRTL()) {
        this.nCursorXPosition = this.$("scrollContainer").scrollLeftRTL() + oEvent.pageX;
      } else {
        this.nCursorXPosition = this.$("scrollContainer").scrollLeft() + oEvent.pageX;
      }
      this.nCursorYPosition = this.$("scrollContainer").scrollTop() + oEvent.pageY;
      if (sap.ui.Device.system.combi) {
        //For Win8 surface no touchstart event is fired, but the mousedown event instead do initialization here
        this._iTouchStartScrollLeft = this.$("scrollContainer").scrollLeft();
        if (this.getScrollable()) {
          this._iTouchStartScrollTop = this.$("scrollContainer").scrollTop();
        }
      }
      break;
    case 'mouseup':
      this._switchCursors(this.$("scrollContainer"), this._grabbingCursorClass, this._grabCursorClass);
      break;
    case 'mouseleave':
      this.$("scrollContainer").removeClass(this._grabbingCursorClass);
      this.$("scrollContainer").removeClass(this._grabCursorClass);
      this.$("scrollContainer").addClass(this._defaultCursorClass);
      break;
    case 'mouseenter':
      this.$("scrollContainer").removeClass(this._defaultCursorClass);
      if (oEvent.buttons === null) {
        if (oEvent.which === 1) {
          this.$("scrollContainer").addClass(this._grabbingCursorClass);
        } else {
          this.$("scrollContainer").addClass(this._grabCursorClass);
        }
      } else {
        if (oEvent.buttons === 0) {
          this.$("scrollContainer").addClass(this._grabCursorClass);
        } else if (oEvent.buttons === 1) {
          this.$("scrollContainer").addClass(this._grabbingCursorClass);
        }
      }
      break;
  }
  //Check if the event was triggered by a click on a Connection Label and allow the propagation of the event.
  //Otherwise default click event in Connection Label is interrupted.
  if (oEvent.target && oEvent.target.parentElement && oEvent.target.parentElement.parentElement &&
      oEvent.target.parentElement.parentElement instanceof sap.suite.ui.commons.ProcessFlowConnectionLabel) {
    if (oEvent && !oEvent.isPropagationStopped()) {
      oEvent.stopPropagation();
    }
    if (oEvent && !oEvent.isImmediatePropagationStopped()) {
      oEvent.stopImmediatePropagation();
    }
  }
};

/**
 * Control resize handler for setting the cursor type/scroll setup.
 *
 * @private
 */
sap.suite.ui.commons.ProcessFlow.prototype._onResize = function () {
  var iActualTime = new Date().getTime();

  if (!this._iLastResizeEventTime || ((iActualTime - this._iLastResizeEventTime) < 50)) {
    //Start to handle after the second resize event (below 50ms).
    if (!this._iLastResizeHandlingTime || (iActualTime - this._iLastResizeHandlingTime > 500)) { //Handle each .5s.
      this.onAfterRendering();
      this._iLastResizeHandlingTime = new Date().getTime();
    }
  } else {
    this._iLastResizeHandlingTime = null;
  }

  this._iLastResizeEventTime = new Date().getTime();
};

/*
 * Move Enumeration.
 *
 * @private
 */
sap.suite.ui.commons.ProcessFlow._enumMoveDirection = {
  'LEFT': 'left',
  'RIGHT': 'right',
  'UP': 'up',
  'DOWN': 'down'
};

/** Sets the tab focus on the given element or to _lastNavigationFocusNode if no parameter is given. If no parameter
 * is given and _lastNavigationFocusNode is false, nothing happens.
 *
 * @private
 * @param {sap.suite.ui.commons.ProcessFlowNode} the node to focus.
*/
sap.suite.ui.commons.ProcessFlow.prototype._setFocusToNode = function (oNode) {
  //If there's a node as parameter.
  if (oNode) {
    if (oNode instanceof sap.suite.ui.commons.ProcessFlowNode) {
      jQuery("#" + oNode.sId).parent().focus();
      oNode._setNavigationFocus(true);
      oNode.rerender();
    } else if (oNode instanceof sap.suite.ui.commons.ProcessFlowConnectionLabel) {
      oNode.$().focus();
      oNode._setNavigationFocus(true);
    }
    // If there's no parameter, set the focus to _lastNavigationFocusNode if is not false
  } else if (this._lastNavigationFocusNode) {
    if (this._lastNavigationFocusNode instanceof sap.suite.ui.commons.ProcessFlowNode) {
      jQuery("#" + this._lastNavigationFocusNode.sId).parent().focus();
      this._lastNavigationFocusNode._setNavigationFocus(true);
      this._lastNavigationFocusNode.rerender();
    } else if (this._lastNavigationFocusNode instanceof sap.suite.ui.commons.ProcessFlowConnectionLabel) {
      this._lastNavigationFocusNode.$().focus();
      this._lastNavigationFocusNode._setNavigationFocus(true);
    }
  }
};

/**
 * Changes the navigation focus from the actual node to the node specified as parameter.
 * Calls rerender on both nodes.
 *
 * @private
 * @param {sap.suite.ui.commons.ProcessFlowNode} oNodeFrom the old focused node
 * @param {sap.suite.ui.commons.ProcessFlowNode} oNodeTo the new node to focus to
 * @since 1.23
 */
sap.suite.ui.commons.ProcessFlow.prototype._changeNavigationFocus = function (oNodeFrom, oNodeTo) {
  if (oNodeFrom && oNodeTo && (oNodeFrom.getId() !== oNodeTo.getId())) {
    jQuery.sap.log.debug("Rerendering PREVIOUS node with id '" + oNodeFrom.getId() +
                         "' navigation focus : " + oNodeFrom._getNavigationFocus());
    oNodeFrom._setNavigationFocus(false);
    if (oNodeFrom instanceof sap.suite.ui.commons.ProcessFlowNode) {
      oNodeFrom.rerender();
    } 
  }

  if (oNodeTo) {
    jQuery.sap.log.debug("Rerendering CURRENT node with id '" + oNodeTo.getId() +
        "' navigation focus : " + oNodeTo._getNavigationFocus());
    oNodeTo._setNavigationFocus(true);
    if (oNodeTo instanceof sap.suite.ui.commons.ProcessFlowNode) {
      oNodeTo.rerender();
    }
    this._lastNavigationFocusNode = oNodeTo;
    this._onFocusChanged();
  }
};

/**
 * Function reacts on page up and page down. It should go 5 lines up or down
 * or little bit less if there is not enough space.
 * With alt page up move focus left by 5 items maximum.
 * With alt page down move focus right by 5 items maximum.
 *
 * @private
 * @param direction please see sap.suite.ui.commons.ProcessFlow._enumMoveDirection
 * @param altKey, true if alt key is pressed, false otherwise
 * @returns {Boolean} Value describes if a new node was found 
 */
sap.suite.ui.commons.ProcessFlow.prototype._moveOnePage = function (direction, altKey) {
  direction = direction || sap.suite.ui.commons.ProcessFlow._enumMoveDirection.UP;
  altKey = altKey || false;
  //Search for navigated element.
  var origX = 0, origY = 0;
  var newX = 0, newY = 0;
  var nodesOver = 0;
  var bNewNodeFound = false;
  for (var i = 0; i < this._internalCalcMatrix.length; i++) {
    for (var j = 0; j < this._internalCalcMatrix[i].length; j++) {
      if (this._internalCalcMatrix[i][j] instanceof sap.suite.ui.commons.ProcessFlowNode && this._internalCalcMatrix[i][j]._getNavigationFocus()) {
        origX = i;
        origY = j;
        break;
      } else if (this._internalCalcMatrix[i][j] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
        var label = this._internalCalcMatrix[i][j]._getVisibleLabel();
        if (label && label._getNavigationFocus()) {
          origX = i;
          origY = j;
          break;
        }
      }
    }
  }

  //Going 5 elements on the same row.
  if (altKey) {
    if (direction == sap.suite.ui.commons.ProcessFlow._enumMoveDirection.UP) {
      for (var j = origY - 1; j >= 0 && nodesOver < this._jumpOverElements; j--) {
        if (this._internalCalcMatrix[origX][j] instanceof sap.suite.ui.commons.ProcessFlowNode && (!this._bHighlightedMode || this._internalCalcMatrix[origX][j].getHighlighted())) {
          nodesOver++;
          newX = origX;
          newY = j;
          bNewNodeFound = true;
        } else if (this._internalCalcMatrix[origX][j] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[origX][j]._getVisibleLabel();
          if (label && label.getEnabled()) {
            nodesOver++;
            newX = origX;
            newY = j;
            bNewNodeFound = true;
          }
        }
      }
    } else if (direction === sap.suite.ui.commons.ProcessFlow._enumMoveDirection.DOWN) {
      for (var j = origY + 1; j < this._internalCalcMatrix[origX].length && nodesOver < this._jumpOverElements; j++) {
        if (this._internalCalcMatrix[origX][j] instanceof sap.suite.ui.commons.ProcessFlowNode && (!this._bHighlightedMode || this._internalCalcMatrix[origX][j].getHighlighted())) {
          nodesOver++;
          newX = origX;
          newY = j;
          bNewNodeFound = true;
        } else if (this._internalCalcMatrix[origX][j] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[origX][j]._getVisibleLabel();
          if (label && label.getEnabled()) {
            nodesOver++;
            newX = origX;
            newY = j;
            bNewNodeFound = true;
          }
        }
      }
    }
  } else {
    if (direction == sap.suite.ui.commons.ProcessFlow._enumMoveDirection.UP) {
      for (var i = origX - 1; i >= 0 && nodesOver < this._jumpOverElements; i--) {
        if (this._internalCalcMatrix[i][origY] instanceof sap.suite.ui.commons.ProcessFlowNode && (!this._bHighlightedMode || this._internalCalcMatrix[i][origY].getHighlighted())) {
          nodesOver++;
          newX = i;
          newY = origY;
          bNewNodeFound = true;
        } else if (this._internalCalcMatrix[i][origY] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[i][origY]._getVisibleLabel();
          if (label && label.getEnabled()) {
            nodesOver++;
            newX = i
            newY = origY;
            bNewNodeFound = true;
          }
        }
      }
    } else if (direction === sap.suite.ui.commons.ProcessFlow._enumMoveDirection.DOWN) {
      for (var i = origX + 1; i < this._internalCalcMatrix.length && nodesOver < this._jumpOverElements; i++) {
        if (this._internalCalcMatrix[i][origY] instanceof sap.suite.ui.commons.ProcessFlowNode && (!this._bHighlightedMode || this._internalCalcMatrix[i][origY].getHighlighted())) {
          nodesOver++;
          newX = i;
          newY = origY;
          bNewNodeFound = true;
        } else if (this._internalCalcMatrix[i][origY] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[i][origY]._getVisibleLabel();
          if (label && label.getEnabled()) {
            nodesOver++;
            newX = i
            newY = origY;
            bNewNodeFound = true;
          }
        }
      }
    }
  }

  if (bNewNodeFound) {
    if (this._internalCalcMatrix[origX][origY] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
      this._internalCalcMatrix[origX][origY]._getVisibleLabel()._setNavigationFocus(false);
    } else {
      this._internalCalcMatrix[origX][origY]._setNavigationFocus(false);
    }
    if (this._internalCalcMatrix[newX][newY] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
      var label = this._internalCalcMatrix[newX][newY]._getVisibleLabel();
      label._setNavigationFocus(true);
      this._lastNavigationFocusNode = label;
    } else {
      this._internalCalcMatrix[newX][newY]._setNavigationFocus(true);
      this._lastNavigationFocusNode = this._internalCalcMatrix[newX][newY];
    }
  }
  return bNewNodeFound;
};

/**
 * Function reacts on home/end. it should go to the first/last element on given row.
 * With ctrl it goes to the first/last active element on the process flow
 * or little bit less if there is not enough space.
 *
 * @private
 * @param direction please see sap.suite.ui.commons.ProcessFlow._enumMoveDirection LEFT -> HOME, RIGHT -> END
 * @param ctrlKey, true if ctrl key is pressed
 * @returns {Boolean} Value describes if a new node was found
 */
sap.suite.ui.commons.ProcessFlow.prototype._moveHomeEnd = function (direction, ctrlKey) {
  direction = direction || sap.suite.ui.commons.ProcessFlow._enumMoveDirection.RIGHT;
  ctrlKey = ctrlKey || false;
  //Search for navigated element.
  var origX = 0, origY = 0;
  var newX = 0, newY = 0;
  var bNewNodeFound = false;
  for (var i = 0; i < this._internalCalcMatrix.length; i++) {
    for (var j = 0; j < this._internalCalcMatrix[i].length; j++) {
      if (this._internalCalcMatrix[i][j] instanceof sap.suite.ui.commons.ProcessFlowNode && this._internalCalcMatrix[i][j]._getNavigationFocus()) {
        origX = i;
        origY = j;
        break;
      } else if (this._internalCalcMatrix[i][j] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
        var label = this._internalCalcMatrix[i][j]._getVisibleLabel();
        if (label && label._getNavigationFocus()) {
          origX = i;
          origY = j;
          break;
        }
      }
    }
  }

  //Going to the first / last element on the given column.
  if (ctrlKey) {
    if (direction == sap.suite.ui.commons.ProcessFlow._enumMoveDirection.LEFT) {
      for (var i = 0; i < origX ; i++) {
        if (this._internalCalcMatrix[i][origY] instanceof sap.suite.ui.commons.ProcessFlowNode && (!this._bHighlightedMode || this._internalCalcMatrix[i][origY].getHighlighted())) {
          newX = i;
          newY = origY;
          bNewNodeFound = true;
          break;
        } else if (this._internalCalcMatrix[i][origY] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[i][origY]._getVisibleLabel();
          if (label && label.getEnabled()) {
            newX = i
            newY = origY;
            bNewNodeFound = true;
            break;
          }
        }
      }
    } else if (direction === sap.suite.ui.commons.ProcessFlow._enumMoveDirection.RIGHT) {
      for (var i = this._internalCalcMatrix.length - 1; i > origX; i--) {
        if (this._internalCalcMatrix[i][origY] instanceof sap.suite.ui.commons.ProcessFlowNode && (!this._bHighlightedMode || this._internalCalcMatrix[i][origY].getHighlighted())) {
          newX = i;
          newY = origY;
          bNewNodeFound = true;
          break;
        } else if (this._internalCalcMatrix[i][origY] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[i][origY]._getVisibleLabel();
          if (label && label.getEnabled()) {
            newX = i
            newY = origY;
            bNewNodeFound = true;
            break;
          }
        }
      }
    }
  } else { //Going to the first/last element of the row.
    if (direction == sap.suite.ui.commons.ProcessFlow._enumMoveDirection.LEFT) {
      for (var j = 0; j < origY; j++) {
        if (this._internalCalcMatrix[origX][j] instanceof sap.suite.ui.commons.ProcessFlowNode && (!this._bHighlightedMode || this._internalCalcMatrix[origX][j].getHighlighted())) {
          newX = origX;
          newY = j;
          bNewNodeFound = true;
          break;
        } else if (this._internalCalcMatrix[origX][j] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[origX][j]._getVisibleLabel();
          if (label && label.getEnabled()) {
            newX = origX;
            newY = j;
            bNewNodeFound = true;
            break;
          }
        }
      }
    } else if (direction === sap.suite.ui.commons.ProcessFlow._enumMoveDirection.RIGHT) {
      for (var j = this._internalCalcMatrix[origX].length - 1; j > origY; j--) {
        if (this._internalCalcMatrix[origX][j] instanceof sap.suite.ui.commons.ProcessFlowNode && (!this._bHighlightedMode || this._internalCalcMatrix[origX][j].getHighlighted())) {
          newX = origX;
          newY = j;
          bNewNodeFound = true;
          break;
        } else if (this._internalCalcMatrix[origX][j] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[origX][j]._getVisibleLabel();
          if (label && label.getEnabled()) {
            newX = origX;
            newY = j;
            bNewNodeFound = true;
            break;
          }
        }
      }
    }
  }

  if (bNewNodeFound) {
    if (this._internalCalcMatrix[origX][origY] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
      this._internalCalcMatrix[origX][origY]._getVisibleLabel()._setNavigationFocus(false);
    } else {
      this._internalCalcMatrix[origX][origY]._setNavigationFocus(false);
    }
    if (this._internalCalcMatrix[newX][newY] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
      var label = this._internalCalcMatrix[newX][newY]._getVisibleLabel();
      label._setNavigationFocus(true);
      this._lastNavigationFocusNode = label;
    } else {
      this._internalCalcMatrix[newX][newY]._setNavigationFocus(true);
      this._lastNavigationFocusNode = this._internalCalcMatrix[newX][newY];
    }
  }
  return bNewNodeFound;
};

/**
 * Function moves the focus to the next node based on tab behaviour.
 * First going left, after to the next row.
 *
 * @private
 * @param direction please see enumeration Direction ( sap.suite.ui.commons.ProcessFlow._enumMoveDirection )
 * @returns {Boolean} true if the next element is possible to set. False if there is not more elements to set.
 */
sap.suite.ui.commons.ProcessFlow.prototype._moveToNextNode = function (direction, step) {
  //First find the current focus element.
  direction = direction || sap.suite.ui.commons.ProcessFlow._enumMoveDirection.RIGHT;

  if (sap.ui.getCore().getConfiguration().getRTL()) {
    if (direction === sap.suite.ui.commons.ProcessFlow._enumMoveDirection.RIGHT) {
      direction = sap.suite.ui.commons.ProcessFlow._enumMoveDirection.LEFT;
    } else if (direction === sap.suite.ui.commons.ProcessFlow._enumMoveDirection.LEFT) {
      direction = sap.suite.ui.commons.ProcessFlow._enumMoveDirection.RIGHT;
    }
  }

  step = step || 1;

  var bFocusNodeFound = false;
  var bNewNodeSet = false;
  var origX = 0, origY = 1;
  if (!this._internalCalcMatrix) {
    return;
  }
  //First search for node which is focused.
  var posX = 0, posY = 0;
  for (var i = 0; i < this._internalCalcMatrix.length; i++) {
    for (var j = 0; j < this._internalCalcMatrix[i].length; j++) {
      if (this._internalCalcMatrix[i][j]) {
        if (this._internalCalcMatrix[i][j] instanceof sap.suite.ui.commons.ProcessFlowNode && this._internalCalcMatrix[i][j]._getNavigationFocus()) {
          origX = posX = i;
          origY = posY = j;
          bFocusNodeFound = true;
          break;
        } else if (this._internalCalcMatrix[i][j] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[i][j]._getVisibleLabel();
          if (label && label._getNavigationFocus() && label.getEnabled()) {
            origX = posX = i;
            origY = posY = j;
            bFocusNodeFound = true;
            break;
          }
        }
      }
    }
    if (bFocusNodeFound) {
      break;
    }
  }

  if (direction == sap.suite.ui.commons.ProcessFlow._enumMoveDirection.RIGHT) {
    for (var i = posX; i < this._internalCalcMatrix.length; i++) {
      for (var j = posY + 1; j < this._internalCalcMatrix[i].length; j++) {
        if (this._internalCalcMatrix[i][j] instanceof sap.suite.ui.commons.ProcessFlowNode) {
          if (bFocusNodeFound && (!this._bHighlightedMode || this._internalCalcMatrix[i][j].getHighlighted())) {
            this._internalCalcMatrix[i][j]._setNavigationFocus(true);
            this._lastNavigationFocusNode = this._internalCalcMatrix[i][j];
            bNewNodeSet = true;
            break;
          }
        } else if (this._internalCalcMatrix[i][j] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[i][j]._getVisibleLabel();
          if (label && bFocusNodeFound && label.getEnabled()) {
            label._setNavigationFocus(true);
            this._lastNavigationFocusNode = label;
            bNewNodeSet = true;
            break;
          }
        }
      }
      //Shortcut, we have done already everything.
      posY = 0; //First posX line was from posY, now from zero again. The plus one does not hurt, because first column is empty.
      if (bNewNodeSet) {
        break;
      }
    }
  }

  if (direction == sap.suite.ui.commons.ProcessFlow._enumMoveDirection.LEFT) {
    for (var i = posX; i >= 0 ; i--) {
      for (var j = posY - 1; j >= 0; j--) {
        if (this._internalCalcMatrix[i][j] instanceof sap.suite.ui.commons.ProcessFlowNode) {
          if (bFocusNodeFound && (!this._bHighlightedMode || this._internalCalcMatrix[i][j].getHighlighted())) {
            this._lastNavigationFocusNode = this._internalCalcMatrix[i][j]._setNavigationFocus(true);
            this._lastNavigationFocusNode = this._internalCalcMatrix[i][j];
            bNewNodeSet = true;
            break;
          }
        } else if (this._internalCalcMatrix[i][j] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[i][j]._getVisibleLabel();
          if (label && bFocusNodeFound && label.getEnabled()) {
            label._setNavigationFocus(true);
            this._lastNavigationFocusNode = label;
            bNewNodeSet = true;
            break;
          }
        }
      }
      if (i > 0) {
        posY = this._internalCalcMatrix[i - 1].length;
      }
      //Shortcut, we have done already everything.
      if (bNewNodeSet) {
        break;
      }
    }
  }

  var deviation,
      yPositionLeft,
      yPositionRight;
  if (direction == sap.suite.ui.commons.ProcessFlow._enumMoveDirection.UP) {
    for (var i = posX - 1; i >= 0 ; i--) {
      //We have single line, check from posY first left, after right.
      deviation = 0;
      while (!bNewNodeSet) {
        yPositionLeft = posY - deviation;
        yPositionRight = posY + deviation;
        if (yPositionLeft >= 0 && this._internalCalcMatrix[i][yPositionLeft] instanceof sap.suite.ui.commons.ProcessFlowNode) {
          if (bFocusNodeFound && (!this._bHighlightedMode || this._internalCalcMatrix[i][yPositionLeft].getHighlighted())) {
            this._internalCalcMatrix[i][yPositionLeft]._setNavigationFocus(true);
            this._lastNavigationFocusNode = this._internalCalcMatrix[i][yPositionLeft];
            bNewNodeSet = true;
            break;
          }
        } else if (yPositionLeft >= 0 && this._internalCalcMatrix[i][yPositionLeft] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[i][yPositionLeft]._getVisibleLabel();
          if (label && bFocusNodeFound && label.getEnabled()) {
            label._setNavigationFocus(true);
            this._lastNavigationFocusNode = label;
            bNewNodeSet = true;
            break;
          }
        }//End of processflownode for left.
        if (yPositionRight < this._internalCalcMatrix[i].length && this._internalCalcMatrix[i][yPositionRight] instanceof sap.suite.ui.commons.ProcessFlowNode) {
          if (bFocusNodeFound && (!this._bHighlightedMode || this._internalCalcMatrix[i][yPositionRight].getHighlighted())) {
            this._internalCalcMatrix[i][yPositionRight]._setNavigationFocus(true);
            this._lastNavigationFocusNode = this._internalCalcMatrix[i][yPositionRight];
            bNewNodeSet = true;
            break;
          }
        } else if (yPositionRight >= 0 && this._internalCalcMatrix[i][yPositionRight] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[i][yPositionRight]._getVisibleLabel();
          if (label && bFocusNodeFound && label.getEnabled()) {
            label._setNavigationFocus(true);
            this._lastNavigationFocusNode = label;
            bNewNodeSet = true;
            break;
          }
        } //End of processflownode for right.
        //We are out of this line for Y position.
        if (yPositionLeft < 0 && yPositionRight > this._internalCalcMatrix[i].length) {
          break;
        }
        deviation++;
      }
    }
  }

  if (direction == sap.suite.ui.commons.ProcessFlow._enumMoveDirection.DOWN) {
    for (var i = posX + 1; i < this._internalCalcMatrix.length ; i++) {
      //We have single line, check from posY first left, after right.
      deviation = 0;
      while (!bNewNodeSet) {
        yPositionLeft = posY - deviation;
        yPositionRight = posY + deviation;
        if (yPositionLeft >= 0 && this._internalCalcMatrix[i][yPositionLeft] instanceof sap.suite.ui.commons.ProcessFlowNode) {
          if (bFocusNodeFound && (!this._bHighlightedMode || this._internalCalcMatrix[i][yPositionLeft].getHighlighted())) {
            this._lastNavigationFocusNode = this._internalCalcMatrix[i][yPositionLeft]._setNavigationFocus(true);
            this._lastNavigationFocusNode = this._internalCalcMatrix[i][yPositionLeft];
            bNewNodeSet = true;
            break;
          }
        } else if (yPositionLeft >= 0 && this._internalCalcMatrix[i][yPositionLeft] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[i][yPositionLeft]._getVisibleLabel();
          if (label && bFocusNodeFound && label.getEnabled()) {
            label._setNavigationFocus(true);
            this._lastNavigationFocusNode = label;
            bNewNodeSet = true;
            break;
          }
        }//End of processflownode for left.
        if (yPositionRight < this._internalCalcMatrix[i].length && this._internalCalcMatrix[i][yPositionRight] instanceof sap.suite.ui.commons.ProcessFlowNode) {
          if (bFocusNodeFound && (!this._bHighlightedMode || this._internalCalcMatrix[i][yPositionRight].getHighlighted())) {
            this._lastNavigationFocusNode = this._internalCalcMatrix[i][yPositionRight]._setNavigationFocus(true);
            this._lastNavigationFocusNode = this._internalCalcMatrix[i][yPositionRight];
            bNewNodeSet = true;
            break;
          }
        } else if (yPositionRight >= 0 && this._internalCalcMatrix[i][yPositionRight] instanceof sap.suite.ui.commons.ProcessFlowConnection) {
          var label = this._internalCalcMatrix[i][yPositionRight]._getVisibleLabel();
          if (label && bFocusNodeFound && label.getEnabled()) {
            label._setNavigationFocus(true);
            this._lastNavigationFocusNode = label;
            bNewNodeSet = true;
            break;
          }
        }//End of processflownode for right.
        //We are out of this line for Y position.
        if (yPositionLeft < 0 && yPositionRight > this._internalCalcMatrix[i].length) {
          break;
        }
        deviation++;
      }
    }
  }

  if (bNewNodeSet) {
    if (this._internalCalcMatrix[origX][origY] instanceof sap.suite.ui.commons.ProcessFlowNode) {
      this._internalCalcMatrix[origX][origY]._setNavigationFocus(false);
    } else {
      this._internalCalcMatrix[origX][origY]._getVisibleLabel()._setNavigationFocus(false);
    }
  }
  return bNewNodeSet;
};

// ==============================================================================================
// == Keyboard events handling support
// ==============================================================================================
// Internal PF flag whether navigation focus should be released from this control.
sap.suite.ui.commons.ProcessFlow.prototype._bNFocusOutside = false;
// Internal PF flag whether we operate in highlighted mode.
sap.suite.ui.commons.ProcessFlow.prototype._bHighlightedMode = false;

//--------------------------------------------------------------------------------------------
/**
 * ProcessFlow has the focus, now it is neccessary to set the navigation
 * the method is called both when ProcessFlow gets the focus and at any click event.
 */
sap.suite.ui.commons.ProcessFlow.prototype.onfocusin = function (oEvent) {
  //Set the navigation focus to the lane header if in lanes-only mode.
  if (this._isHeaderMode()) {
    this._setFocusOnHeader(true);
  } else { //set the focus on the first node
    if (this._bSetFocusOnce) {
      this._bSetFocusOnce = false;
      if (!this._lastNavigationFocusNode) {
        var $nodeToFocus = this.$("scroll-content").children().children().children(1).children("td[tabindex='0']").first().children();
        var oNodeToFocus = sap.ui.getCore().byId($nodeToFocus[0].id);
        this._changeNavigationFocus(null, oNodeToFocus);
      } else {//there is a previous focus on process flow
        this._changeNavigationFocus(null, this._lastNavigationFocusNode);
      }
    }
  }
};

sap.suite.ui.commons.ProcessFlow.prototype.onfocusout = function (oEvent) {
  this._bSetFocusOnce = true;
  if (this._lastNavigationFocusNode && this._lastNavigationFocusNode._getNavigationFocus()) {
    this._lastNavigationFocusNode._setNavigationFocus(false);
    if (this._lastNavigationFocusNode instanceof sap.suite.ui.commons.ProcessFlowNode) {
      this._lastNavigationFocusNode.rerender();
    }
  }
  jQuery.sap.log.info("focus out");
};

/**
 * Method called on zoom change.
 * Scrolls the PF content after a zoom change so, that the focused content of the scroll container stays in focus (if possible).
 *
 * @private
 * @returns {Object} The scroll container context
 * @since 1.26
 */
sap.suite.ui.commons.ProcessFlow.prototype._getScrollContainerOnZoomChanged = function (oScrollContainerContext, $scrollContainer) {
  oScrollContainerContext.scrollLeft = Math.round($scrollContainer.context.scrollWidth / oScrollContainerContext.scrollWidth * oScrollContainerContext.scrollLeft);
  oScrollContainerContext.scrollTop = Math.round($scrollContainer.context.scrollHeight / oScrollContainerContext.scrollHeight * oScrollContainerContext.scrollTop);
  oScrollContainerContext.scrollWidth = $scrollContainer.context.scrollWidth;
  oScrollContainerContext.scrollHeight = $scrollContainer.context.scrollHeight;

  return oScrollContainerContext;
};

/**
 * Method called on navigation focus change.
 * Scrolls the PF content, so the node is as close to the middle of the scroll container viewport as possible.
 *
 * @private
 * @since 1.23
 */
sap.suite.ui.commons.ProcessFlow.prototype._onFocusChanged = function () {
  var oFocusedNode = this._lastNavigationFocusNode,
      $focusedNode = oFocusedNode ? oFocusedNode.$() : null,
      iScrollContainerInnerWidth,
      iScrollContainerInnerHeight,
      iScrollLeft,
      iScrollTop,
      $scrollContent,
      iContentInnerWidth,
      iContentInnerHeight,
      iNodeOuterWidth,
      iNodeOuterHeight,
      oPositionInContent,
      iNodeLeftPosition,
      iNodeTopPosition,
      iNodeRightPosition,
      iNodeBottomPosition,
      iCorrectionLeft, iCorrectionTop,
      iScrollTimeInMillis = 500;

  if (oFocusedNode && this.getScrollable()) {
    jQuery.sap.log.debug("The actually focused node is " + oFocusedNode.getId());

    // If the element (oNode) is a label, get the data from the TD parent element, otherwise it won't work precisely
    if (oFocusedNode instanceof sap.suite.ui.commons.ProcessFlowConnectionLabel) {
      iNodeOuterWidth = $focusedNode.parent().parent().parent().outerWidth();
      iNodeOuterHeight = $focusedNode.parent().parent().parent().outerHeight();
      oPositionInContent = $focusedNode.parent().parent().parent().position();
    } else {
      iNodeOuterWidth = $focusedNode.outerWidth();
      iNodeOuterHeight = $focusedNode.outerHeight();
      oPositionInContent = $focusedNode.position();
    }
    jQuery.sap.log.debug("Node outer width x height [" + iNodeOuterWidth + " x " + iNodeOuterHeight + "]");
    jQuery.sap.log.debug("Position of node in the content is [" + oPositionInContent.left + ", " + oPositionInContent.top + "]");

    $scrollContent = this.$("scroll-content");
    iScrollContainerInnerWidth = this.$("scrollContainer").innerWidth();
    iScrollContainerInnerHeight = this.$("scrollContainer").innerHeight();
    jQuery.sap.log.debug("Scroll container inner width x height [" + iScrollContainerInnerWidth + " x " + iScrollContainerInnerHeight + "]");

    iScrollLeft = this.$("scrollContainer").scrollLeft();
    iScrollTop = this.$("scrollContainer").scrollTop();
    jQuery.sap.log.debug("Current scroll offset is [" + iScrollLeft + ", " + iScrollTop + "]");

    iContentInnerWidth = $scrollContent.innerWidth();
    iContentInnerHeight = $scrollContent.innerHeight();
    jQuery.sap.log.debug("Scroll content inner width x height [" + iContentInnerWidth + " x " + iContentInnerHeight + "]");

    //Defines 4 borders (L: Left, R: Right, T: Top, B: Bottom) for position of the clicked node in the visible content.
    iNodeLeftPosition = -iScrollLeft + oPositionInContent.left;
    iNodeRightPosition = iNodeLeftPosition + iNodeOuterWidth;
    iNodeTopPosition = -iScrollTop + oPositionInContent.top;
    iNodeBottomPosition = iNodeTopPosition + iNodeOuterHeight;

    //Checks if the node lies (even in part) outside of the scroll container visible part.
    if ((iNodeRightPosition > iScrollContainerInnerWidth) || (iNodeLeftPosition < 0) || (iNodeBottomPosition > iScrollContainerInnerHeight) || (iNodeTopPosition < 0)) {
      //iCorrectionLeft, correction on left direction to center the node.
      iCorrectionLeft = Math.round((iScrollContainerInnerWidth - iNodeOuterWidth) / 2);
      iCorrectionLeft = Math.max(iScrollContainerInnerWidth - iContentInnerWidth + oPositionInContent.left, iCorrectionLeft);
      iCorrectionLeft = Math.min(oPositionInContent.left, iCorrectionLeft);

      //iCorrectionTop, correction on upwards to center the node.
      iCorrectionTop = Math.round((iScrollContainerInnerHeight - iNodeOuterHeight) / 2);
      iCorrectionTop = Math.max(iScrollContainerInnerHeight - iContentInnerHeight + oPositionInContent.top, iCorrectionTop);
      iCorrectionTop = Math.min(oPositionInContent.top, iCorrectionTop);
      jQuery.sap.log.debug("Node lies outside the scroll container, scrolling from [" + iNodeLeftPosition + "," + iNodeTopPosition + "] to [" + iCorrectionLeft + "," + iCorrectionTop + "]");
      this._isFocusChanged = true;
      this.$("scrollContainer").animate({
        scrollTop: oPositionInContent.top - iCorrectionTop,
        scrollLeft: oPositionInContent.left - iCorrectionLeft
      }, iScrollTimeInMillis, "swing", jQuery.proxy(this._adjustAndShowArrow, this));
    } else {
      jQuery.sap.log.debug("Node lies inside the scroll container, no scrolling happens.");
      this._setFocusToNode(oFocusedNode);
    }
  } else { //Non scrollable needs also to set the focus.
    this._setFocusToNode(oFocusedNode);
    this._adjustAndShowArrow();
  }
};

/**
 * Method called if the ProcessFlow has the navigation focus and the key '+' is pressed ( for keyboard support).
 *
 * @private
 * @since 1.26
 */
sap.suite.ui.commons.ProcessFlow.prototype.onsapplus = function (oEvent) {
  this._isFocusChanged = true;
  this.zoomIn();
};

/**
 * Method called if the ProcessFlow has the navigation focus and the key '-' is pressed ( for keyboard support).
 *
 * @private
 * @since 1.26
 */
sap.suite.ui.commons.ProcessFlow.prototype.onsapminus = function (oEvent) {
  this._isFocusChanged = true;
  this.zoomOut();
};

/**
 * Method called if ProcessFlow has the navigation focus and the Tab key is pressed.
 *
 * @private
 */
sap.suite.ui.commons.ProcessFlow.prototype.onsaptabnext = function (oEvent) {
  var bNextElementToFocus = true;
  var $activeElement = oEvent.target;
  if (oEvent.target && oEvent.target.childElementCount > 0) {
    $activeElement = oEvent.target.childNodes[0];
  }
  var oActiveElement = sap.ui.getCore().byId($activeElement.id);

  if (oActiveElement && !(oActiveElement instanceof sap.suite.ui.commons.ProcessFlowNode) && !(oActiveElement instanceof sap.suite.ui.commons.ProcessFlowConnectionLabel)) {
    if (!this._isHeaderMode() && !this._lastNavigationFocusNode) {
      var $nodeToFocus = this.$("scroll-content").children().children().children(1).children("td[tabindex='0']").first().children();
      var oNodeToFocus = sap.ui.getCore().byId($nodeToFocus[0].id);
      this._changeNavigationFocus(null, oNodeToFocus);
      bNextElementToFocus = false;
    } else if (this._lastNavigationFocusNode) {
      this._changeNavigationFocus(null, this._lastNavigationFocusNode);
      bNextElementToFocus = false;
    }
  }
  if (this._isHeaderMode() && bNextElementToFocus) { //lanes-only
    if (!this._headerHasFocus) {
      this._setFocusOnHeader(true);
    } else {
      this._setFocusOnHeader(false);
    }
  } else {
      if ((this._lastNavigationFocusNode instanceof sap.suite.ui.commons.ProcessFlowNode) || (this._lastNavigationFocusNode instanceof sap.suite.ui.commons.ProcessFlowConnectionLabel)) {
        this._lastNavigationFocusNode.rerender();
      }
  }

  //release focus
  if (bNextElementToFocus) {
    var oNextElementToFocus = this.$().nextAll().find(":focusable").first();

    if (oNextElementToFocus.length === 0) {
      setNextFocusableElement.bind(this)();
    }
    oNextElementToFocus.focus();
    jQuery.sap.log.debug("saptabnext: Keyboard focus has been changed to element:  id='" + oNextElementToFocus.id + "' outerHTML='" + bNextElementToFocus.outerHTML + "'");
    oNextElementToFocus = null;
  }
  oEvent.preventDefault();

  function setNextFocusableElement() {
    //set focus on the next element outside the ProcessFlow control
    var $parent = this.$().parent();
    do {
      oNextElementToFocus = $parent.next(":focusable");
      if (oNextElementToFocus.length === 0) {
        oNextElementToFocus = $parent.nextAll().find(":focusable").first();
      }
      $parent = $parent.parent();
    } while (($parent.length !== 0) && (oNextElementToFocus.length === 0));
    return;
  }
};

/**
 * Method called if ProcessFlow has the navigation focus and Tab and Shift keys are pressed simultaneously.
 *
 * @private
 */
sap.suite.ui.commons.ProcessFlow.prototype.onsaptabprevious = function (oEvent) {
  var oPrevElementToFocus = null;
  var $activeElement = oEvent.target;
  if ((!this._lastNavigationFocusNode || !this._lastNavigationFocusNode._getNavigationFocus()) && oEvent.target && oEvent.target.childElementCount > 0) {
    $activeElement = oEvent.target.childNodes[0];
  }
  var oActiveElement = sap.ui.getCore().byId($activeElement.id);

  if (oActiveElement && ((oActiveElement instanceof sap.suite.ui.commons.ProcessFlowNode) || (oActiveElement instanceof sap.suite.ui.commons.ProcessFlowConnection))) {
    if (!this._isHeaderMode() && !this._lastNavigationFocusNode) {
      var $nodeToFocus = this.$("scroll-content").children().children().children(1).children("td[tabindex='0']").first().children();
      var oNodeToFocus = sap.ui.getCore().byId($nodeToFocus[0].id);
      this._changeNavigationFocus(null, oNodeToFocus);
    } else if (this._lastNavigationFocusNode) {//there is a previous focus on process flow
      this._changeNavigationFocus(null, this._lastNavigationFocusNode);
      oEvent.preventDefault();
      return;
    }
  }
  if (this._isHeaderMode()) { //lanes-only.
    if (!this._headerHasFocus) {
      this._setFocusOnHeader(true);
    } else {
      this._setFocusOnHeader(false);
      oPrevElementToFocus = this.$().prevAll().find(":focusable").first();
    }
  } else {
    oPrevElementToFocus = this.$().prev(":focusable");
    if (oPrevElementToFocus.length === 0) {
      oPrevElementToFocus = this.$().prevAll().find(":focusable").first();
    }
    if (this._lastNavigationFocusNode) {
      this._lastNavigationFocusNode._setNavigationFocus(false);
    }
    if (this._lastNavigationFocusNode instanceof sap.suite.ui.commons.ProcessFlowNode) {
      this._lastNavigationFocusNode.rerender();
    }
  }

  //release focus
  if (oPrevElementToFocus) {
    //set focus on the previous element outside the ProcessFlow control
    if (oPrevElementToFocus.length === 0) {
      setPrevFocusableElement.bind(this)();
    } else if (oPrevElementToFocus.first().length !== 0) {
      oPrevElementToFocus = jQuery(oPrevElementToFocus.first());
    }
    oPrevElementToFocus.focus();
    jQuery.sap.log.debug("saptabnext: Keyboard focus has been set on element:  id='" + oPrevElementToFocus.id + "' outerHTML='" + oPrevElementToFocus.outerHTML + "'");
    oPrevElementToFocus = null;
  }

  oEvent.preventDefault();

  function setPrevFocusableElement() {
    var $parent = this.$();
    do {
      oPrevElementToFocus = $parent.prev(":focusable");
      if (oPrevElementToFocus.length === 0) {
        oPrevElementToFocus = $parent.prevAll().find(":focusable").last();
      }
      $parent = $parent.parent();
    } while (($parent.length !== 0) && (oPrevElementToFocus.length === 0));
    return;
  }
};

/**
 * Method called if ProcessFlow has the navigation focus and Spacebar or Enter key are pressed.
 *
 * @private
 */
sap.suite.ui.commons.ProcessFlow.prototype.onsapselect = function (oEvent) {
  if (this._isHeaderMode()) { //lanes-only.
    this._internalLanes = [];
    this.fireHeaderPress(this);
    var $nodeToFocus = this.$("scroll-content").children().children().children(1).children("td[tabindex='0']").first().children();
    var oNodeToFocus = sap.ui.getCore().byId($nodeToFocus[0].id);
    this._changeNavigationFocus(null, oNodeToFocus);
  } else {
    if (this._lastNavigationFocusNode instanceof sap.suite.ui.commons.ProcessFlowNode && this._lastNavigationFocusNode._getNavigationFocus()) {
      this.fireNodePress(this._lastNavigationFocusNode);
    }
  }
};

/**
 * Method called if ProcessFlow has the navigation focus and the Down arrow key is pressed
 *
 * @private
 */
sap.suite.ui.commons.ProcessFlow.prototype.onkeydown = function (oEvent) {
  var keycode = (oEvent.keyCode ? oEvent.keyCode : oEvent.which);
  jQuery.sap.log.debug("ProcessFlow::keyboard input has been catched and action going to start: keycode=" + keycode);

  var bElementFocusChanged = false;
  var ctrlKeyPressed = oEvent.ctrlKey;
  var altKeyPressed = oEvent.altKey;
  var oPreviousNavigationElement = this._lastNavigationFocusNode;

  switch (keycode) {
    case jQuery.sap.KeyCodes.ARROW_RIGHT:
      bElementFocusChanged = this._moveToNextNode(sap.suite.ui.commons.ProcessFlow._enumMoveDirection.RIGHT);
      break;
    case jQuery.sap.KeyCodes.ARROW_LEFT:
      bElementFocusChanged = this._moveToNextNode(sap.suite.ui.commons.ProcessFlow._enumMoveDirection.LEFT);
      break;
    case jQuery.sap.KeyCodes.ARROW_DOWN:
      bElementFocusChanged = this._moveToNextNode(sap.suite.ui.commons.ProcessFlow._enumMoveDirection.DOWN);
      break;
    case jQuery.sap.KeyCodes.ARROW_UP:
      bElementFocusChanged = this._moveToNextNode(sap.suite.ui.commons.ProcessFlow._enumMoveDirection.UP);
      break;
    case jQuery.sap.KeyCodes.PAGE_UP:
      bElementFocusChanged = this._moveOnePage(sap.suite.ui.commons.ProcessFlow._enumMoveDirection.UP, altKeyPressed);
      break;
    case jQuery.sap.KeyCodes.PAGE_DOWN:
      bElementFocusChanged = this._moveOnePage(sap.suite.ui.commons.ProcessFlow._enumMoveDirection.DOWN, altKeyPressed);
      break;
    case jQuery.sap.KeyCodes.HOME:
      bElementFocusChanged = this._moveHomeEnd(sap.suite.ui.commons.ProcessFlow._enumMoveDirection.LEFT, ctrlKeyPressed);
      break;
    case jQuery.sap.KeyCodes.END:
      bElementFocusChanged = this._moveHomeEnd(sap.suite.ui.commons.ProcessFlow._enumMoveDirection.RIGHT, ctrlKeyPressed);
      break;
    case jQuery.sap.KeyCodes.NUMPAD_0:
    case jQuery.sap.KeyCodes.DIGIT_0:
      this._initZoomLevel();
      break;
    case jQuery.sap.KeyCodes.ENTER:
    case jQuery.sap.KeyCodes.SPACE:
      //ENTER and SPACE (or sapselect) are fired according to the spec, but we need to prevent the default behavior.
      oEvent.preventDefault();
      return;
    default:
      //It was not our key, let default action be executed if any.
      return;
  }

  //It was our key, default action has to suppressed.
  oEvent.preventDefault();

  if (bElementFocusChanged) {
    //We have to re-render when we changed Element-focus inside our control.
    this._changeNavigationFocus(oPreviousNavigationElement, this._lastNavigationFocusNode);
  }
};

/**
 * Merge values of node states for several nodes.
 *
 * @private
 * @param {array} aLaneIdNodeStates node states for all nodes of the same laneId
 * @param altKey, true if alt key is pressed, false otherwise
 * @returns {Object[]} aResult Array of cumulated node states for aLaneIdNodeStates
 */
sap.suite.ui.commons.ProcessFlow.prototype._mergeLaneIdNodeStates = function (aLaneIdNodeStates) {
  var iPositive = 0;
  var iNegative = 0;
  var iNeutral = 0;
  var iPlanned = 0;

  for (var iState = 0; iState < 4; iState++) {
    for (var iNode = 0; iNode < aLaneIdNodeStates.length; iNode++) {
      switch (aLaneIdNodeStates[iNode][iState].state) {
        case sap.suite.ui.commons.ProcessFlowNodeState.Positive:
          iPositive = iPositive + aLaneIdNodeStates[iNode][iState].value;
          break;
        case sap.suite.ui.commons.ProcessFlowNodeState.Negative:
          iNegative = iNegative + aLaneIdNodeStates[iNode][iState].value;
          break;
        case sap.suite.ui.commons.ProcessFlowNodeState.Neutral:
          iNeutral = iNeutral + aLaneIdNodeStates[iNode][iState].value;
          break;
        case sap.suite.ui.commons.ProcessFlowNodeState.Planned:
          iPlanned = iPlanned + aLaneIdNodeStates[iNode][iState].value;
          break;
          //plannedNegative belong to Negative group
        case sap.suite.ui.commons.ProcessFlowNodeState.PlannedNegative:
          iNegative = iNegative + aLaneIdNodeStates[iNode][iState].value;
          break;
      }
    }
  }

  var aResult = [{ state: sap.suite.ui.commons.ProcessFlowNodeState.Positive, value: iPositive },
                 { state: sap.suite.ui.commons.ProcessFlowNodeState.Negative, value: iNegative },
                 { state: sap.suite.ui.commons.ProcessFlowNodeState.Neutral, value: iNeutral },
                 { state: sap.suite.ui.commons.ProcessFlowNodeState.Planned, value: iPlanned }];

  return aResult;
};

/**
 * Sets or removes navigation focus on the Lane header ( for keyboard support ).
 *
 * @private
 * @param {boolean} if true the navigation focus is set, if false the navigation focus is removed
 * @since 1.26
 */
sap.suite.ui.commons.ProcessFlow.prototype._setFocusOnHeader = function (setFlag) {
  var thead = jQuery.sap.byId(this.getId() + "-thead");
  if (setFlag) {
    thead.focus();
    thead.addClass("sapSuiteUiCommonsPFHeaderFocused");
    this._headerHasFocus = true;
  }
  else {
    thead.blur();
    thead.removeClass("sapSuiteUiCommonsPFHeaderFocused");
    this._headerHasFocus = false;
  }
};

/**
 * Handles the click on the arrows.
 *
 * @private
 * @since 1.30
 */
sap.suite.ui.commons.ProcessFlow.prototype._onArrowClick = function (oEvent) {
  var sTargetId = oEvent.target.id;
  if (sTargetId) {
    var sId = this.getId();
    //For scroll buttons: Prevent IE from firing beforeunload event -> see CSN 4378288 2012
    oEvent.preventDefault();
    //On mobile devices, the click on arrows has no effect.
    if (sTargetId == sId + "-arrowScrollLeft" && sap.ui.Device.system.desktop) {
      //Scroll back/left button.
      this._scroll(-this._scrollStep, 500);
    } else if (sTargetId == sId + "-arrowScrollRight" && sap.ui.Device.system.desktop) {
      //Scroll forward/right button.
      this._scroll(this._scrollStep, 500);
    }
  }
};

/**
 * Scrolls the header if possible, using an animation.
 *
 * @private
 * @param iDelta how far to scroll
 * @param iDuration how long to scroll (ms)
 * @since 1.30
 */
sap.suite.ui.commons.ProcessFlow.prototype._scroll = function (iDelta, iDuration) {
  var oDomRef = this.getDomRef("scrollContainer");
  var iScrollLeft = oDomRef.scrollLeft;
  if (!!!sap.ui.Device.browser.internet_explorer && this._bRtl) {
    iDelta = -iDelta;
  } //RTL lives in the negative space.
  var iScrollTarget = iScrollLeft + iDelta;
  jQuery(oDomRef).stop(true, true).animate({ scrollLeft: iScrollTarget }, iDuration, jQuery.proxy(this._adjustAndShowArrow, this));
};

/**
 * Adjusts the arrow position and shows the arrow.
 *
 * @private
 * @since 1.30
 */
sap.suite.ui.commons.ProcessFlow.prototype._adjustAndShowArrow = function () {
  this._checkOverflow(this.getDomRef("scrollContainer"), this.$());
  if (this.getScrollable()) {
    this._moveArrowAndCounterVertical();
  }
  if (this._isFocusChanged) {
    this._setFocusToNode(this._lastNavigationFocusNode);
    this._isFocusChanged = false;
  }
};

/**
 * Gets the icon of the requested arrow (left/right).
 *
 * @private
 * @param sName left or right
 * @returns icon of the requested arrow
 * @since 1.30
 */
sap.suite.ui.commons.ProcessFlow.prototype._getScrollingArrow = function (sName) {
  var src;

  if (sap.ui.Device.system.desktop) {
    //Use navigation arrows on desktop and win8 combi devices.
    src = "sap-icon://navigation-" + sName + "-arrow";
  } else {
    //Use slim arrows on mobile devices.
    src = "sap-icon://slim-arrow-" + sName;
  }

  var mProperties = {
    src: src
  };

  var sLeftArrowClass = "sapPFHArrowScrollLeft";
  var sRightArrowClass = "sapPFHArrowScrollRight";
  var aCssClassesToAddLeft = ["sapPFHArrowScroll", sLeftArrowClass];
  var aCssClassesToAddRight = ["sapPFHArrowScroll", sRightArrowClass];

  if (sName === "left") {
    if (!this._oArrowLeft) {
      this._oArrowLeft = sap.m.ImageHelper.getImageControl(this.getId() + "-arrowScrollLeft", null, this, mProperties, aCssClassesToAddLeft);
    }
    return this._oArrowLeft;
  }
  if (sName === "right") {
    if (!this._oArrowRight) {
      this._oArrowRight = sap.m.ImageHelper.getImageControl(this.getId() + "-arrowScrollRight", null, this, mProperties, aCssClassesToAddRight);
    }
    return this._oArrowRight;
  }
};

/**
 * Checks if scrolling is needed.
 *
 * @private
 * @param oScrollContainer the scroll container
 * @param $processFlow the ProcessFlow container
 * @returns true if scrolling is needed, otherwise false
 * @since 1.30
 */
sap.suite.ui.commons.ProcessFlow.prototype._checkScrolling = function (oScrollContainer, $processFlow) {
  var bScrolling = false;

  //Check if there are more lanes than displayed.
  if (oScrollContainer) {
    if (oScrollContainer.scrollWidth > oScrollContainer.clientWidth) {
      //Scrolling possible.
      bScrolling = true;
    }
  }

  if (this._arrowScrollable !== bScrolling) {
    $processFlow.toggleClass("sapPFHScrollable", bScrolling);
    $processFlow.toggleClass("sapPFHNotScrollable", !bScrolling);
    this._arrowScrollable = bScrolling;
  }

  return bScrolling;
};

/**
 * Sets the scroll width depending on the zoom level.
 *
 * @private
 * @param oScrollContainer the scroll container
 * @since 1.30
 */
sap.suite.ui.commons.ProcessFlow.prototype._setScrollWidth = function (oScrollContainer) {
  //The distance to scroll depends on the ZoomLevel.
  switch (this.getZoomLevel()) {
    case (sap.suite.ui.commons.ProcessFlowZoomLevel.One):
      this._scrollStep = 240;
      break;
    case (sap.suite.ui.commons.ProcessFlowZoomLevel.Two):
      this._scrollStep = 192;
      break;
    case (sap.suite.ui.commons.ProcessFlowZoomLevel.Three):
      this._scrollStep = 168;
      break;
    case (sap.suite.ui.commons.ProcessFlowZoomLevel.Four):
      this._scrollStep = 128;
      break;
  }
};

/**
 * Calculates the left counter.
 *
 * @private
 * @returns {Number} The left counter
 * @since 1.30
 */
sap.suite.ui.commons.ProcessFlow.prototype._updateLeftCounter = function () {
  var iScrollDelta;
  if (!this._bRtl) { //Normal LTR mode.
    iScrollDelta = this.$("scrollContainer").scrollLeft();
  }
  else { //RTL mode.
    iScrollDelta = this.$("scrollContainer").scrollRightRTL();
  }
  var counterLeft = Math.round(iScrollDelta / this._scrollStep);
  this.$("counterLeft").text(counterLeft.toString());
  return counterLeft;
};

/**
 * Calculates the right counter.
 *
 * @private
 * @param availableWidth
 * @param realWidth
 * @returns {Number} The right counter
 * @since 1.30
 */
sap.suite.ui.commons.ProcessFlow.prototype._updateRightCounter = function (availableWidth, realWidth) {
  var iScrollDelta;
  var counterRight;
  if (!this._bRtl) { //Normal LTR mode.
    iScrollDelta = this.$("scrollContainer").scrollLeft();
    counterRight = Math.round((realWidth - iScrollDelta - availableWidth) / this._scrollStep);
  }
  else { //RTL mode.
    iScrollDelta = this.$("scrollContainer").scrollLeftRTL();
    counterRight = Math.round(iScrollDelta / this._scrollStep);
  }
  this.$("counterRight").text(counterRight.toString());
  return counterRight;
};

/**
 * For scrollable ProcessFlow : move arrows and counter vertically when scrolling.
 *
 * @private
 * @since 1.30
 */
sap.suite.ui.commons.ProcessFlow.prototype._moveArrowAndCounterVertical = function () {
  var iScrollTop = this.$("scrollContainer").scrollTop();
  if (iScrollTop > 0) {
    var iArrowTop = this._iInitialArrowTop - iScrollTop;
    var iCounterTop = this._iInitialCounterTop - iScrollTop;
    var iDiffArrowCounter = this._iInitialCounterTop - this._iInitialArrowTop;
    if (iArrowTop > 0) {
      this.$("arrowScrollRight").css("top", iArrowTop + "px");
      this.$("arrowScrollLeft").css("top", iArrowTop + "px");
    }
    else {
      this.$("arrowScrollRight").css("top", "0px");
      this.$("arrowScrollLeft").css("top", "0px");
    }
    if (iCounterTop > iDiffArrowCounter) {
      this.$("counterRight").css("top", iCounterTop + "px");
      this.$("counterLeft").css("top", iCounterTop + "px");
    }
    else {
      this.$("counterRight").css("top", iDiffArrowCounter + "px");
      this.$("counterLeft").css("top", iDiffArrowCounter + "px");
    }
  }
  else {
    this.$("arrowScrollRight").css("top", this._iInitialArrowTop + "px");
    this.$("arrowScrollLeft").css("top", this._iInitialArrowTop + "px");
    this.$("counterRight").css("top", this._iInitialCounterTop + "px");
    this.$("counterLeft").css("top", this._iInitialCounterTop + "px");
  }
};

/**
 * Changes the state of the scroll arrows depending on whether they are required due to overflow.
 *
 * @private
 * @param oScrollContainer the scroll container
 * @param $processFlow the ProcessFlow container
 * @since 1.30
 */
sap.suite.ui.commons.ProcessFlow.prototype._checkOverflow = function (oScrollContainer, $processFlow) {
  if (this._checkScrolling(oScrollContainer, $processFlow) && oScrollContainer) {
    this._setScrollWidth(oScrollContainer);
    //Check whether scrolling to the left is possible.
    var bScrollBack = false;
    var bScrollForward = false;
    var iOffset = 20; //Display arrow and counter only if the distance to the end of the scroll container is at least 20px.
    var iScrollLeft = this.$("scrollContainer").scrollLeft();
    var realWidth = oScrollContainer.scrollWidth;
    var availableWidth = oScrollContainer.clientWidth;
    if (Math.abs(realWidth - availableWidth) == 1) { //Avoid rounding issues see CSN 1316630 2013
      realWidth = availableWidth;
    }

    if (!this._bRtl) { //Normal LTR mode.
      if (iScrollLeft > iOffset) {
        bScrollBack = true;
      }
      if ((realWidth > availableWidth) && (iScrollLeft + availableWidth + iOffset < realWidth)) {
        bScrollForward = true;
      }
    } else { //RTL mode.
      var $ScrollContainer = jQuery(oScrollContainer);
      if ($ScrollContainer.scrollLeftRTL() > iOffset) {
        bScrollForward = true;
      }
      if ($ScrollContainer.scrollRightRTL() > iOffset) {
        bScrollBack = true;
      }
    }
    //Update left and right counter.
    this._updateLeftCounter();
    this._updateRightCounter(availableWidth, realWidth);

    //Only do DOM changes if the state changed to avoid periodic application of identical values.
    if ((bScrollForward !== this._bPreviousScrollForward) || (bScrollBack !== this._bPreviousScrollBack)) {
      this._bPreviousScrollForward = bScrollForward;
      this._bPreviousScrollBack = bScrollBack;
      $processFlow.toggleClass("sapPFHScrollBack", bScrollBack);
      $processFlow.toggleClass("sapPFHNoScrollBack", !bScrollBack);
      $processFlow.toggleClass("sapPFHScrollForward", bScrollForward);
      $processFlow.toggleClass("sapPFHNoScrollForward", !bScrollForward);
    }
  } else {
    this._bPreviousScrollForward = false;
    this._bPreviousScrollBack = false;
  }
};

/**
 * Handles the onScroll event.
 * 
 * @private
 */
sap.suite.ui.commons.ProcessFlow.prototype._onScroll = function (oEvent) {
  var iScrollLeft = this.$("scrollContainer").scrollLeft();
  var iDelta = Math.abs(iScrollLeft - this._iTouchStartScrollLeft);
  //Only valid if the focus does not change.
  if (iDelta > (this._scrollStep / 4) && !this._isFocusChanged) {
    //Update arrows when 1/4 lane was scrolled.
    this._adjustAndShowArrow();
    this._iTouchStartScrollLeft = iScrollLeft;
  }
  else {
    //Update vertical alignment of arrows if only vertical scrolling is possible.
    if (this.getScrollable()) {
      var iScrollTop = this.$("scrollContainer").scrollTop();
      var iDeltaTop = Math.abs(iScrollTop - this._iTouchStartScrollTop);
      if (iDeltaTop > 10) {
        this._moveArrowAndCounterVertical();
        this._iTouchStartScrollTop = iScrollTop;
      }
    }
  }
};

/**
 * Initializes left and top distance when scrolling starts.
 *
 * @private
 * @param {jQuery.Event} oEvent
 * @since 1.30
 */
sap.suite.ui.commons.ProcessFlow.prototype.ontouchstart = function (oEvent) {
  this._iTouchStartScrollLeft = this.$("scrollContainer").scrollLeft();
  if (this.getScrollable()) {
    this._iTouchStartScrollTop = this.$("scrollContainer").scrollTop();
  }
};

/**
 * Sets the parent association for given nodes.
 *
 * @private
 * @param {sap.suite.ui.commons.ProcessFlowNode[]} aInternalNodes Array of nodes to set parents on
 */
sap.suite.ui.commons.ProcessFlow.prototype._setParentForNodes = function (aInternalNodes) {
  var cInternalNodes = aInternalNodes ? aInternalNodes.length : 0;
  var aChildren;
  var i, j;
  //Cleanup association to avoid duplicates.
  for (var currentNode in aInternalNodes) {
    aInternalNodes[currentNode].removeAllAssociation("parents", true);
  }
  for (i = 0; i < cInternalNodes; i++) {
    aChildren = aInternalNodes[i].getChildren();
    if (aChildren) {
      for (j = 0; j < aChildren.length; j++) {
        var childNode = this._getNode(sap.suite.ui.commons.ProcessFlow._getChildIdByElement(aChildren[j]), aInternalNodes);
        if (childNode) {
          childNode.addAssociation("parents", aInternalNodes[i], true);
        }
      }
    }
  }
};

/**
 * Returns the node from the given array which matches to the given nodeId.
 *
 * @private
 * @param {String} nodeId Id of node to retrieve
 * @param {sap.suite.ui.commons.ProcessFlowNode[]} aInternalNodes Array of nodes to search in
 * @returns {sap.suite.ui.commons.ProcessFlowNode} Found ProcessFlow node
 */
sap.suite.ui.commons.ProcessFlow.prototype._getNode = function (nodeId, aInternalNodes) {
  for (var i = 0; i < aInternalNodes.length; i++) {
    if (aInternalNodes[i].getNodeId() === nodeId.toString()) {
      return aInternalNodes[i];
    }
  }
};

/**
 * Returns the lane from the _internalLanes array which matches to the given laneId.
 *
 * @private
 * @param {String} laneId Id of lane to retrieve
 * @returns {sap.suite.ui.commons.ProcessFlowLaneHeader} The lane header element
 */
sap.suite.ui.commons.ProcessFlow.prototype._getLane = function (laneId) {
  for (var i = 0; i < this._internalLanes.length; i++) {
    if (this._internalLanes[i].getLaneId() === laneId) {
      return this._internalLanes[i];
    }
  }
};

/**
 * Returns the id of the given child node element. Since child elements can be string or object, this function checks the type and
 * returns the nodeId.
 *
 * @private
 * @param {Object/String} The child element containing the nodeId
 * @returns {Number} The id of the child element
 */
sap.suite.ui.commons.ProcessFlow._getChildIdByElement = function (oChildElement) {
  if (typeof oChildElement === 'object') {
    return oChildElement.nodeId;
  } else {
    return oChildElement;
  }
};

/**
 * Creates the connection map objects between the source and target nodes
 * incl. label information and connection parts, based on the calculated matrix.
 *
 * @private
 * @returns {Object} The Connection map
 */
sap.suite.ui.commons.ProcessFlow.prototype._getConnectionsMap = function () {

  //Example:
  //  var connectionMap = [];
  //  var connectionMapEntry = {};
  //  connectionMapEntry.sourceNode = matrix[0][1];
  //  connectionMapEntry.targetNode = matrix[4][3];
  //  connectionMapEntry.label = "label from code, needs to be mapped";
  //  connectionMapEntry.connectionParts = [
  //                                   {x:0, y:2},
  //                                   {x:1, y:2},
  //                                   {x:2, y:2},
  //                                   {x:3, y:2},
  //                                   {x:4, y:2}
  //                                   ];

  var aConnections = [];
  var aNodes = this.getNodes();
  for (var i = 0; i < aNodes.length; i++) {
    var oPositionOfSourceNode = this._getPositionOfNodeInMatrix(this._internalCalcMatrix, aNodes[i]);
    var aChildren = aNodes[i].getChildren();
    if (aChildren) {
      for (var j = 0; j < aChildren.length; j++) {
        var oConnectionMapEntry = {};
        oConnectionMapEntry.sourceNode = aNodes[i];
        var childId = sap.suite.ui.commons.ProcessFlow._getChildIdByElement(aChildren[j]);
        var childNode = this._getNode(childId, aNodes);
        if (childNode) {
          if (typeof aChildren[j] === 'object') {
            oConnectionMapEntry.label = aChildren[j].connectionLabel;
          }
          oConnectionMapEntry.targetNode = childNode;
          //Find position in matrix
          var oPositionOfTargetNode = this._getPositionOfNodeInMatrix(this._internalCalcMatrix, oConnectionMapEntry.targetNode);
          oConnectionMapEntry.connectionParts = this._calculateConnectionParts(this._internalCalcMatrix, oPositionOfSourceNode, oPositionOfTargetNode);
          aConnections.push(oConnectionMapEntry);
        }
      }
    }
  }
  this._internalConnectionMap = aConnections;
  return aConnections;
};

/**
 * Returns the position (coordinates x/y) of the given ProcessFlowNode in calculated matrix of ProcessFlow.
 *
 * @private
 * @param {Object} The calculated matrix of the current ProcessFlow
 * @param {sap.suite.ui.commons.ProcessFlowNode} The node for which the position is required
 * @returns {Object} The position of the node in the calculated matrix (x/y)
 */
sap.suite.ui.commons.ProcessFlow.prototype._getPositionOfNodeInMatrix = function (aMatrix, oNode) {
  var position = {};
  for (var i = 0; i < aMatrix.length; i++) {
    var currentLine = aMatrix[i];
    for (var j = 0; j < currentLine.length; j++) {
      var currentCell = currentLine[j];
      if (currentCell &&
          currentCell instanceof sap.suite.ui.commons.ProcessFlowNode &&
          currentCell.getNodeId() === oNode.getNodeId()) {
        position.y = i;
        position.x = j;
        return position;
      }
    }
  }
  return position;
};

/**
 * Calculates the connection parts (coordinates in matrix) between source and target node.
 *
 * @private
 * @param {Object} The calculated matrix of the current ProcessFlow
 * @param {Object} The position of the source node in the calculated matrix (x/y)
 * @param {Object} The position of the target node in the calculated matrix (x/y)
 * @returns {Object[]} Array of all connection parts, relevant for connection between source and target node
 */
sap.suite.ui.commons.ProcessFlow.prototype._calculateConnectionParts = function (aMatrix, oPositionOfSourceNode, oPositionOfTargetNode) {

  //Example:
  //var connectionParts = [
  //    {x:0, y:2},
  //    {x:1, y:2},
  //    {x:2, y:2},
  //    {x:3, y:2},
  //    {x:4, y:2}
  //  ];

  var aConnectionParts = [];
  var cY = oPositionOfSourceNode.y;
  var cX = oPositionOfSourceNode.x;

  //Increase column+1 (step 1 right), independent from target position since target will ever be right from source.
  cX++;
  aConnectionParts.push({ x: cX, y: cY });

  //Increase (row+1) till we are in the row of target node (n steps down) if target is below source in matrix.
  //Decrease (row-1) till we are in the row of target node (n steps up) if target is above source in matrix.
  if (oPositionOfTargetNode.y >= oPositionOfSourceNode.y) {
    while (cY < oPositionOfTargetNode.y) {
      cY++;
      aConnectionParts.push({ x: cX, y: cY });
    }
  } else {
    while (cY > oPositionOfTargetNode.y) {
      cY--;
      aConnectionParts.push({ x: cX, y: cY });
    }
  }

  //Increase column+1 till we are in column of target node (n steps right)
  while (cX < oPositionOfTargetNode.x - 1) {
    cX++;
    aConnectionParts.push({ x: cX, y: cY });
  }
  return aConnectionParts;
};

/**
 * Returns the connectionMapEntries which are relevant for the given sap.suite.ui.commonsProcessFlowConnectionLabel.
 * Means all entries having the same target node as current entry (based on current label).
 *
 * @private
 * @param {sap.suite.ui.commons.ProcessFlowConnectionLabel} The label for which the map entries are required
 * @returns {Object[]} Array with relevant connectionMapEntries for the given label
 */
sap.suite.ui.commons.ProcessFlow.prototype._getConnectionMapEntries = function (oConnectionLabel) {
  var aFilteredConnectionMaps = [];
  var connectionMapWithLabel = null;
  var oEntry = null;

  //Find relevant connectionMapEntry, containing given Label.
  if (this._internalConnectionMap) {
    for (var i = 0; i < this._internalConnectionMap.length; i++) {
      oEntry = this._internalConnectionMap[i];
      if (oEntry.label &&
          oEntry.label.getId() === oConnectionLabel.getId()) {
        connectionMapWithLabel = oEntry;
        break;
      }
    }

    //Collect all connectionMapEntries with same target node as the one, containing the Label.
    oEntry = null;
    for (var j = 0; j < this._internalConnectionMap.length; j++) {
      oEntry = this._internalConnectionMap[j];
      if (oEntry.targetNode &&
          oEntry.targetNode.getNodeId() === connectionMapWithLabel.targetNode.getNodeId()) {
        aFilteredConnectionMaps.push(oEntry);
      }
    }
  }
  return aFilteredConnectionMaps;
};

/**
 * Handles the click of labels and triggers the related ProcessFlow event.
 *
 * @private
 * @params {Object} Event Args, containing the label and related information
 */
sap.suite.ui.commons.ProcessFlow.prototype._handleLabelClick = function (oEvent) {
  if (oEvent) {
    var oConnectionLabel = oEvent.getSource();
    //Check if user clicked on icon.
    if (oConnectionLabel instanceof sap.ui.core.Icon) {
        oConnectionLabel = oConnectionLabel.getParent();
     }
    if (oConnectionLabel instanceof sap.suite.ui.commons.ProcessFlowConnectionLabel) {
      var aRelevantConnectionMapEntries = this._getConnectionMapEntries(oConnectionLabel);
      var eventArgsToFire = this._createLabelPressEventArgs(oConnectionLabel, aRelevantConnectionMapEntries);
      this.fireLabelPress(eventArgsToFire);
    }
  }
}

/**
 * Sets the path between source and target node to selected status and rerenders the control. If parameters are null, sets all nodes to normal status.
 *
 * @public
 * @param {String} sourceNodeId of the path or null
 * @param {String} targetNodeId of the path or null
 * @since 1.32
 */
sap.suite.ui.commons.ProcessFlow.prototype.setSelectedPath = function (sourceNodeId, targetNodeId) {
  var aNodes = this.getNodes();
  if (aNodes) {
    if (sourceNodeId && targetNodeId) {
      var cNodesFound = 0;
      for (var i = 0; i < aNodes.length; i++) {
        if (aNodes[i].getNodeId() === sourceNodeId || aNodes[i].getNodeId() === targetNodeId) {
          aNodes[i].setSelected(true);
          cNodesFound++;
        } else {
          aNodes[i].setSelected(false);
        }
      }
      if (cNodesFound == 2) {
        this.rerender();
      }
    } else if (!sourceNodeId && !targetNodeId) {
      for (var i = 0; i < aNodes.length; i++) {
        aNodes[i].setSelected(false);
      }
      this.rerender();
    }
  }
};

/**
 * Sets the focus to the given Label
 *
 * @public
 * @param {sap.suite.ui.commons.ProcessFlowConnectionlabel} Label to focus
 * @since 1.32
 */
sap.suite.ui.commons.ProcessFlow.prototype.setFocusToLabel = function (oLabel) {
  this._changeNavigationFocus(this._lastNavigationFocusNode, oLabel);
};

/**
 * Creates the eventArgs for fireLabelPress of ProcessFlow.
 * Additional object is necessary, since connectionmaps are containing too much information (e.g. parts).
 *
 * @private
 * @param {sap.suite.ui.commons.ProcessFlowConnectionlabel} Label which has been selected by user (clicked)
 * @param {Object[]} The relevant connection maps for the selected label
 * @returns {Object} Event args for fireLabelPress
 */
sap.suite.ui.commons.ProcessFlow.prototype._createLabelPressEventArgs = function (oConnectionLabel, aConnectionMapEntries) {
  var oEvent = {};
  var aEventArgsConnectionValues = [];

  if (aConnectionMapEntries) {
    for (var i = 0; i < aConnectionMapEntries.length; i++) {
      var oEventArgsConnectionValue = {
        sourceNode: aConnectionMapEntries[i].sourceNode,
        targetNode: aConnectionMapEntries[i].targetNode,
        label: aConnectionMapEntries[i].label
      };
      aEventArgsConnectionValues.push(oEventArgsConnectionValue);
    }
  }

  oEvent.selectedLabel = oConnectionLabel;
  oEvent.connections = aEventArgsConnectionValues;
  return oEvent;
};

/**
 * Overwrites setShowLabels of ProcessFlow control to apply additional functionality.
 *
 * @param {Boolean} New value for showLabels
 */
sap.suite.ui.commons.ProcessFlow.prototype.setShowLabels = function (bNewValue) {
  var bOldValue = this.getShowLabels();
  if (bOldValue && !bNewValue) { //Only if status has been changed from show to hide
    this.setProperty("showLabels", bNewValue, true);
    // Resets the selected path in case labels have been disabled for the current control.
    if (!this.getShowLabels()) {
      this.setSelectedPath(null, null);
    }
  } else {
    this.setProperty("showLabels", bNewValue);
  }
};<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
jQuery.sap.declare("sap.apf.core.odataRequest");jQuery.sap.require("sap.ui.thirdparty.datajs");jQuery.sap.require("sap.apf.core.utils.checkForTimeout");(function(){'use strict';sap.apf.core.odataRequestWrapper=function(m,r,s,e,b){function a(d,f){var M=sap.apf.core.utils.checkForTimeout(f);var E={};if(M){E.messageObject=M;e(E);}else{s(d,f);}}function c(E){var M=sap.apf.core.utils.checkForTimeout(E);if(M){E.messageObject=M;}e(E);}OData.request(r,a,c,b);};}());
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

jQuery.sap.declare("sap.ui.comp.smartmicrochart.SmartBulletMicroChartRenderer");
jQuery.sap.require("sap.ui.core.Renderer");
jQuery.sap.require("sap.suite.ui.microchart.BulletMicroChartRenderer");

/**
 * @class SmartBulletMicroChart renderer.
 * @version 1.36.12
 * @experimental Since 1.34.0 This is currently under development. The API could be changed at any point in time.
 * @static
 */
sap.ui.comp.smartmicrochart.SmartBulletMicroChartRenderer = sap.ui.core.Renderer.extend(sap.suite.ui.microchart.BulletMicroChartRenderer);<file_sep>/*!
 * SAP APF Analysis Path Framework
 *
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
/*global jQuery, sap*/
jQuery.sap.require("sap.apf.modeler.ui.utils.nullObjectChecker");
jQuery.sap.require("sap.apf.modeler.ui.utils.optionsValueModelBuilder");
jQuery.sap.require("sap.apf.modeler.ui.utils.viewValidator");
/**
* @class requestOptions
* @name requestOptions
* @description General controller for VHR, FRR and navigation target
* 			   The ViewData for this view needs the following parameters:
*  			   getCalatogServiceUri()- api to fetch uri
*  			   oConfigurationHandler - Handler for configuration
*  			   oConfigurationEditor -  manages the facet filter object
*  			   oTextReader - Method to getText
*  			   oParentObject - Object from which the controller gets instantiated
*/
sap.ui.define([ "sap/ui/core/mvc/Controller" ], function(Controller) {
	"use strict";
	var nullObjectChecker = new sap.apf.modeler.ui.utils.NullObjectChecker();
	var optionsValueModelBuilder = new sap.apf.modeler.ui.utils.OptionsValueModelBuilder();
	// Adds 'Auto Complete Feature' to the input field source in the view using sap.apf.modeler.ui.utils.TextPoolHelper
	function _enableAutoComplete(oController) {
		var oTextPoolHelper = new sap.apf.modeler.ui.utils.TextPoolHelper(oController.getView().getViewData().oConfigurationHandler.getTextPool());
		//auto complete for source
		var oDependenciesForService = {
			oConfigurationEditor : oController.oConfigurationEditor,
			type : "service"
		};
		oTextPoolHelper.setAutoCompleteOn(oController.byId("idSource"), oDependenciesForService);
	}
	// Sets source on init or change
	function _setSource(oController) {
		var sSource = oController.getSource();
		// Default state
		oController.byId("idSource").setValue("");
		if (!nullObjectChecker.checkIsNotNullOrUndefinedOrBlank(sSource)) {
			oController.addOrRemoveMandatoryFieldsAndRequiredFlag(false);
			return;
		}
		// setValue
		oController.byId("idSource").setValue(sSource);
		oController.addOrRemoveMandatoryFieldsAndRequiredFlag(true);
	}
	// Sets entity set on init or change
	function _setEntity(oController) {
		var oModelForEntity, sSource, sEntitySet, aAllEntities;
		sSource = oController.byId("idSource").getValue();
		// Default State
		oController.byId("idEntity").setModel(null);
		oController.byId("idEntity").clearSelection();
		if (!nullObjectChecker.checkIsNotNullOrUndefinedOrBlank(sSource)) {
			return;
		}
		if (!oController.oConfigurationEditor.registerService(sSource)) {
			return;
		}
		aAllEntities = oController.getAllEntities(sSource);
		// setModel
		oModelForEntity = optionsValueModelBuilder.convert(aAllEntities);
		oController.byId("idEntity").setModel(oModelForEntity);
		sEntitySet = oController.getEntity();
		// setSelectedKey as 0th entity -> in case new parent object(no entity available for new parent object)/ in case of change of source(if old entity is not present in the entities of new source)
		if (!nullObjectChecker.checkIsNotNullOrUndefinedOrBlank(sEntitySet) || aAllEntities.indexOf(sEntitySet) === -1) {
			if (nullObjectChecker.checkIsNotNullOrUndefinedOrBlank(aAllEntities)) {
				sEntitySet = oController.getAllEntities(sSource)[0];
			}
		}
		oController.byId("idEntity").setSelectedKey(sEntitySet);
	}
	// Sets select properties on init or change
	function _setSelectProperties(oController) {
		var sSource, sEntitySet, aSelectProperties, aProperties, oModelForSelectProps, aCommonProps;
		sSource = oController.byId("idSource").getValue();
		// Default state
		oController.byId("idSelectProperties").setModel(null);
		oController.byId("idSelectProperties").setSelectedKeys([]);
		// if no source nothing to set
		if (!nullObjectChecker.checkIsNotNullOrUndefinedOrBlank(sSource)) {
			return;
		}
		sEntitySet = oController.byId("idEntity").getSelectedKey();
		// if no entity nothing to set
		if (!nullObjectChecker.checkIsNotNullOrUndefinedOrBlank(sEntitySet)) {
			return;
		}
		// setModel
		aProperties = oController.getAllEntitySetProperties(sSource, sEntitySet);
		oModelForSelectProps = optionsValueModelBuilder.convert(aProperties);
		oController.byId("idSelectProperties").setModel(oModelForSelectProps);
		// setSelectedKeys
		// scenario:
		// 1. common properties in case of existing filter, intersection between already available select properties on parent object and all properties on entity/source
		// 2. common properties in case of new filter, intersection between already available select properties on parent object and all properties on entity/source is empty
		// 			implies that there is nothing to set.
		aSelectProperties = oController.getSelectProperties();
		if (nullObjectChecker.checkIsNotNullOrUndefinedOrBlank(aSelectProperties)) {
			aCommonProps = _getIntersection(aSelectProperties, aProperties);
			aSelectProperties = aCommonProps;
		}
		oController.byId("idSelectProperties").setSelectedKeys(aSelectProperties);
	}
	// attaches events to the current view.
	function _attachEvents(oController) {
		oController.byId("idSource").attachEvent("selectService", oController.handleSelectionOfService.bind(oController));
	}
	// Determines and returns intersection of existing properties and total entity set
	function _getIntersection(aExistingProps, aTotalSet) {
		var resultedIntersection = [];
		if (!nullObjectChecker.checkIsNotNullOrUndefinedOrBlank(aExistingProps) || !nullObjectChecker.checkIsNotNullOrUndefinedOrBlank(aTotalSet)) {
			return resultedIntersection;
		}
		// intersection logic
		aExistingProps.forEach(function(property) {
			if (aTotalSet.indexOf(property) !== -1) {
				resultedIntersection.push(property);
			}
		});
		return resultedIntersection;
	}
	return Controller.extend("sap.apf.modeler.ui.controller.requestOptions", {
		viewValidator : {},
		oConfigurationEditor : {},
		oParentObject : {},
		// Called on initialization of the sub view and set the static texts and data for all controls in sub view
		onInit : function() {
			var oController = this;
			oController.viewValidator = new sap.apf.modeler.ui.utils.ViewValidator(oController.getView());
			oController.oConfigurationEditor = oController.getView().getViewData().oConfigurationEditor;
			oController.oParentObject = oController.getView().getViewData().oParentObject;
			_enableAutoComplete(oController);
			oController.setDetailData();
			oController.setDisplayText();
			_attachEvents(oController);
		},
		// Called on initialization of the view to set data on fields of sub view
		setDetailData : function() {
			var oController = this;
			_setSource(oController);
			_setEntity(oController);
			_setSelectProperties(oController);
		},
		// Called on reset of parent object in order to update parent object instance and configuration editor instance
		updateSubViewInstancesOnReset : function(oEvent) {
			var oController = this;
			oController.oConfigurationEditor = oEvent.mParameters[0];
			oController.oParentObject = oEvent.mParameters[1];
			oController.setDetailData();
		},
		//Stub to be implemented in sub views to set display text of controls
		setDisplayText : function() {
		},
		// Updates service of sub view and later entity and select properties if needed and fires relevant events if implemented by sub view
		handleChangeForSource : function() {
			var oController = this, sEntity, aSelectProperties;
			var sSource = oController.byId("idSource").getValue().trim();
			if (nullObjectChecker.checkIsNotNullOrUndefinedOrBlank(sSource) && oController.oConfigurationEditor.registerService(sSource)) {
				oController.addOrRemoveMandatoryFieldsAndRequiredFlag(true);
				oController.updateSource(sSource);
			} else {
				oController.clearSource();
				oController.addOrRemoveMandatoryFieldsAndRequiredFlag(false);
			}
			_setEntity(oController);
			sEntity = oController.byId("idEntity").getSelectedKey();
			oController.updateEntity(sEntity);
			_setSelectProperties(oController);
			aSelectProperties = oController.byId("idSelectProperties").getSelectedKeys();
			oController.updateSelectProperties(aSelectProperties);
			oController.oConfigurationEditor.setIsUnsaved();
			oController.fireRelevantEvents();
		},
		// Updates entity set of sub view and later select properties if needed and fires relevant events if implemented by sub view
		handleChangeForEntity : function() {
			var oController = this, sEntity, aSelectProperties;
			sEntity = oController.byId("idEntity").getSelectedKey();
			oController.updateEntity(sEntity);
			_setSelectProperties(oController);
			aSelectProperties = oController.byId("idSelectProperties").getSelectedKeys();
			oController.updateSelectProperties(aSelectProperties);
			oController.oConfigurationEditor.setIsUnsaved();
			oController.fireRelevantEvents();
		},
		// Updates select properties of sub view and later fires relevant events if implemented by sub view
		handleChangeForSelectProperty : function() {
			var oController = this;
			var aSelectProperties = oController.byId("idSelectProperties").getSelectedKeys();
			oController.updateSelectProperties(aSelectProperties);
			oController.oConfigurationEditor.setIsUnsaved();
			oController.fireRelevantEvents();
		},
		//Stub to be implemented in sub views in case of any events to be handled on change of source, entity set or select properties
		fireRelevantEvents : function() {
		},
		// Adds/removes required tag to entity set and select properties fields and accepts a boolean to determine required
		addOrRemoveMandatoryFieldsAndRequiredFlag : function(bRequired) {
			var oController = this;
			oController.byId("idEntityLabel").setRequired(bRequired);
			oController.byId("idSelectPropertiesLabel").setRequired(bRequired);
			if (bRequired) {
				oController.viewValidator.addFields([ "idEntity", "idSelectProperties" ]);
			} else {
				oController.viewValidator.removeFields([ "idEntity", "idSelectProperties" ]);
			}
		},
		// Handles Service selection from the Select Dialog
		handleSelectionOfService : function(oEvent) {
			var selectedService = oEvent.getParameters()[0];
			oEvent.getSource().setValue(selectedService);
			// Event is getting trigered by service control
			oEvent.getSource().fireEvent("change");
		},
		// Handles Opening of Value Help Request Dialog.
		handleShowValueHelpRequest : function(oEvent) {
			var oController = this;
			var oViewData = {
				oTextReader : oController.getView().getViewData().oTextReader,
				// passing the source of control from which the event got triggered
				parentControl : oEvent.getSource(),
				getCalatogServiceUri : oController.getView().getViewData().getCalatogServiceUri
			};
			sap.ui.view({
				id : oController.createId("idCatalogServiceView"),
				viewName : "sap.apf.modeler.ui.view.catalogService",
				type : sap.ui.core.mvc.ViewType.XML,
				viewData : oViewData
			});
		},
		// Stubs to be implemented in sub views depending on sub view logic
		getSource : function() {
		},
		getAllEntities : function(sSource) {
		},
		getAllEntitySetProperties : function(sSource, sEntitySet) {
		},
		getEntity : function() {
		},
		clearSource : function() {
		},
		clearEntity : function() {
		},
		clearSelectProperties : function() {
		},
		updateSource : function(sSource) {
		},
		updateEntity : function(sEntity) {
		},
		updateSelectProperties : function(aSelectProperties) {
		},
		getSelectProperties : function() {
		}
	});
});
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// Provides control sap.suite.ui.microchart.Example.
sap.ui.define(['jquery.sap.global', './library', 'sap/ui/core/Control'],
	function(jQuery, library, Control) {
	"use strict";

	/**
	 * Constructor for a new DeltaMicroChart control.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Represents the delta of two values as a chart. This control replaces the deprecated sap.suite.ui.commons.DeltaMicroChart.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.DeltaMicroChart
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var DeltaMicroChart = Control.extend("sap.suite.ui.microchart.DeltaMicroChart", /** @lends sap.suite.ui.microchart.DeltaMicroChart.prototype */ { metadata: {

		library: "sap.suite.ui.microchart",
		properties: {

			/**
			 * The first value for delta calculation.
			 */
			value1: {type: "float", group: "Misc", defaultValue: null},

			/**
			 * The second value for delta calculation.
			 */
			value2: {type: "float", group: "Misc", defaultValue: null},

			/**
			 * The first value title.
			 */
			title1: {type: "string", group: "Misc", defaultValue: null},

			/**
			 * The second value title.
			 */
			title2: {type: "string", group: "Misc", defaultValue: null},

			/**
			 * If this property is set, it is rendered instead of value1.
			 */
			displayValue1: {type: "string", group: "Misc", defaultValue: null},

			/**
			 * If this property is set, it is rendered instead of value2.
			 */
			displayValue2: {type: "string", group: "Misc", defaultValue: null},

			/**
			 * If this property is set, it is rendered instead of a calculated delta.
			 */
			deltaDisplayValue: {type: "string", group: "Misc", defaultValue: null},

			/**
			 * The semantic color of the delta value.
			 */
			color: {type: "sap.m.ValueColor", group: "Misc", defaultValue: "Neutral"},

			/**
			 * The width of the chart.
			 */
			width: {type: "sap.ui.core.CSSSize", group: "Misc"},

			/**
			 * The size of the chart. If is not set, the default size is applied based on the device type.
			 */
			size: {type: "sap.m.Size", group: "Misc", defaultValue: "Auto"}
		},

		events: {

			/**
			 * The event is fired when the user chooses the delta micro chart.
			 */
			press: {}

		}

	}});

	DeltaMicroChart.prototype.init = function() {
		this._oRb = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.microchart");
		this.setTooltip("{AltText}");
	};

	DeltaMicroChart.prototype._calcChartData = function() {
		var fVal1 = this.getValue1();
		var fVal2 = this.getValue2();

		var fMin = Math.min(fVal1, fVal2, 0);
		var fMax = Math.max(fVal1, fVal2, 0);
		var fTotal = fMax - fMin;

		function calcPercent(fVal) {
			return (fTotal === 0 ?  0 : Math.abs(fVal) / fTotal * 100).toFixed(2);
		}

		var oConf = {};
		var fDelta = fVal1 - fVal2;

		oConf.delta = {
			left: fMax === 0,
			width: calcPercent(fDelta),
			isFirstStripeUp: fVal1 < fVal2,
			isMax: (fVal1 < 0 && fVal2 >= 0) || (fVal1 >= 0 && fVal2 < 0),
			isZero: fVal1 === 0 && fVal2 === 0,
			isEqual: fDelta === 0
		};

		oConf.bar1 = {
			left: fVal2 >= 0,
			width: calcPercent(fVal1),
			isSmaller: Math.abs(fVal1) < Math.abs(fVal2)
		};

		oConf.bar2 = {
			left: fVal1 >= 0,
			width: calcPercent(fVal2),
			isSmaller: Math.abs(fVal2) < Math.abs(fVal1)
		};

		return oConf;
	};

	DeltaMicroChart.prototype._getLocalizedColorMeaning = function(sColor) {
		return this._oRb.getText(("SEMANTIC_COLOR_" + sColor).toUpperCase());
	};

	/**
	 * Calculates the number of digits after the decimal point.
	 *
	 * @param {float} fValue float value
	 * @returns {int} number of digits after the decimal point in fValue.
	 * @private
	 */
	DeltaMicroChart.prototype._digitsAfterDecimalPoint = function(fValue) {
		var sAfter = ("" + fValue).match(/[.,](\d+)/g);
		return (sAfter) ? ("" + sAfter).length - 1 : 0;
	};

	DeltaMicroChart.prototype.getAltText = function() {
	    var sDv1 = this.getDisplayValue1();
	    var sDv2 = this.getDisplayValue2();
	    var sDdv = this.getDeltaDisplayValue();
		var fVal1 = this.getValue1();
		var fVal2 = this.getValue2();
		var sAdv1ToShow = sDv1 ? sDv1 : "" + fVal1;
		var sAdv2ToShow = sDv2 ? sDv2 : "" + fVal2;
		var sAddvToShow = sDdv ? sDdv : "" + Math.abs(fVal1 - fVal2).toFixed(Math.max(this._digitsAfterDecimalPoint(fVal1), this._digitsAfterDecimalPoint(fVal2)));
		var sMeaning = this._getLocalizedColorMeaning(this.getColor());

		return this.getTitle1() + " " + sAdv1ToShow + "\n" + this.getTitle2() + " " + sAdv2ToShow + "\n" +  this._oRb.getText("DELTAMICROCHART_DELTA_TOOLTIP", [sAddvToShow, sMeaning]);
	};

	DeltaMicroChart.prototype.getTooltip_AsString  = function() {
		var oTooltip = this.getTooltip();
		var sTooltip = this.getAltText();

		if (typeof oTooltip === "string" || oTooltip instanceof String) {
			sTooltip = oTooltip.split("{AltText}").join(sTooltip).split("((AltText))").join(sTooltip);
			return sTooltip;
		}
		return oTooltip ? oTooltip : "";
	};

	DeltaMicroChart.prototype._isCalcSupported = function() {
		return jQuery.sap.byId(this.getId() + "-calc").css("max-width") == "11px";
	};

	DeltaMicroChart.prototype._isRoundingSupported = function() {
		return jQuery.sap.byId(this.getId() + "-calc1").width() == 4;
	};

	DeltaMicroChart.prototype.onBeforeRendering = function() {
		this._oChartData = this._calcChartData();
	};

	DeltaMicroChart.prototype.onAfterRendering = function() {
		this._bCalc = this._isCalcSupported();
		this._bRounding = this._isRoundingSupported();

		if (!this._bCalc || !this._bRounding) {
			if (this._sResizeHandlerId) {
				sap.ui.core.ResizeHandler.deregister(this._sResizeHandlerId);
			}

		    var oChart = jQuery.sap.domById(this.getId() + "-dmc-chart");
		    this._sResizeHandlerId = sap.ui.core.ResizeHandler.register(oChart,  jQuery.proxy(this._adjust, this));

		    if (!this._bCalc) {
				this._adjustCalc();
		    }

		    if (!this._bRounding) {
				this._adjustRound();
		    }
		}
	};

	DeltaMicroChart.prototype._adjust = function() {
	    if (!this._bCalc) {
			this._adjustCalc();
	    }

	    if (!this._bRounding) {
			this._adjustRound();
	    }
	};

	DeltaMicroChart.prototype._adjustRound = function() {
		var iChartWidth = jQuery.sap.byId(this.getId() + "-dmc-chart").width();
		var iDeltaWidth = Math.round(iChartWidth * this._oChartData.delta.width / 100);

		jQuery.sap.byId(this.getId() + "-dmc-bar-delta").width(iDeltaWidth);

		if (this._oChartData.bar1.isSmaller && !this._oChartData.delta.isMax) {
			jQuery.sap.byId(this.getId() + "-dmc-bar1").width(iChartWidth - iDeltaWidth);
		}

		if (this._oChartData.bar2.isSmaller && !this._oChartData.delta.isMax) {
			jQuery.sap.byId(this.getId() + "-dmc-bar2").width(iChartWidth - iDeltaWidth);
		}
	};

	DeltaMicroChart.prototype._adjustCalc = function() {
		var iChartWidth = jQuery.sap.byId(this.getId() + "-dmc-chart").width();

		function adjustBar(oBar) {
			oBar.css("max-width", iChartWidth - parseInt(oBar.css("max-width"), 10) + "px");
		}

		adjustBar(jQuery.sap.byId(this.getId() + "-dmc-bar1"));
		adjustBar(jQuery.sap.byId(this.getId() + "-dmc-bar2"));
		adjustBar(jQuery.sap.byId(this.getId() + "-dmc-bar-delta"));
	};

	DeltaMicroChart.prototype.attachEvent = function(sEventId, oData, fnFunction, oListener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, sEventId, oData, fnFunction, oListener);
		if (this.hasListeners("press")) {
			this.$().attr("tabindex", 0).addClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	DeltaMicroChart.prototype.detachEvent = function(sEventId, fnFunction, oListener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, sEventId, fnFunction, oListener);
		if (!this.hasListeners("press")) {
			this.$().removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	DeltaMicroChart.prototype.ontap = function(oEvent) {
	     if (sap.ui.Device.browser.internet_explorer) {
	         this.$().focus();
	     }
	     this.firePress();
	};

	DeltaMicroChart.prototype.onkeydown = function(oEvent) {
	    if (oEvent.which == jQuery.sap.KeyCodes.SPACE) {
	        oEvent.preventDefault();
	    }
	};

	DeltaMicroChart.prototype.onkeyup = function(oEvent) {
	    if (oEvent.which == jQuery.sap.KeyCodes.ENTER || oEvent.which == jQuery.sap.KeyCodes.SPACE) {
	        this.firePress();
	        oEvent.preventDefault();
	    }
	};

	return DeltaMicroChart;
});
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

sap.ui.define(['jquery.sap.global'],
	function(jQuery) {
	"use strict";


	/**
	 * @class FieldList renderer.
	 * @static
	 */
	var FieldListRenderer = {};
	
	/**
	 * Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
	 * 
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.comp.smartform.flexibility.FieldList} oControl an object representation of the control that should be rendered
	 */
	FieldListRenderer.render = function(oRm, oControl) {

		// write the HTML into the render manager
		oRm.write("<div");
		oRm.writeControlData(oControl);
		oRm.addClass("sapUiCompFieldList");
		oRm.writeClasses();
		oRm.write(">"); // span element
	
		FieldListRenderer.renderNodes(oRm, oControl);
	
		oRm.write("</div>");
	};
	
	/**
	 * Renders the child nodes from the aggregation nodes
	 * 
	 * @param {sap.ui.core.RenderManager} oRm RenderManager
	 * @param {sap.ui.comp.smartform.flexibility.FieldList} oControl field list node
	 * @private
	 */
	FieldListRenderer.renderNodes = function(oRm, oControl) {

		var aNodes, length, i;
		aNodes = oControl.getNodes();
		length = aNodes.length;
		for (i = 0; i < length; i++) {
			oRm.renderControl(aNodes[i]);
		}
	};
	

	return FieldListRenderer;

}, /* bExport= */ true);
<file_sep>sap.ovp[version] = 1.36.12
sap.ovp[dependencies] = sap.ui.core,sap.ui.layout,sap.ui.generic.app,sap.m,sap.ui.comp
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

// Provides the Design Time Metadata for the sap.ui.comp.smartform.Group control
sap.ui.define([],
	function() {
	"use strict";

	return {
		aggregations : {
			groupElements : {
				ignore : true
			},
			formElements : {
				domRef : ":sap-domref"
			}
		},
		name: "{name}",
		description: "{description}"
	};

}, /* bExport= */ true);<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */
sap.ui.define(['jquery.sap.global'],function(q){"use strict";var F={};F.render=function(r,c){r.write("<div");r.writeControlData(c);r.addClass("sapUiCompFieldList");r.writeClasses();r.write(">");F.renderNodes(r,c);r.write("</div>");};F.renderNodes=function(r,c){var n,l,i;n=c.getNodes();l=n.length;for(i=0;i<l;i++){r.renderControl(n[i]);}};return F;},true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2015 SAP SE. All rights reserved
	
 */
sap.ui.define([
	"sap/ui/core/Control", "sap/gantt/misc/Utility", "../misc/AxisTime", "sap/ui/thirdparty/d3"
], function (Control, Utility, AxisTime) {
	"use strict";
	
	var LegendBase = Control.extend("sap.gantt.legend.LegendBase", {
		metadata: {
			abstract: true,
			properties: {
				svgDefs: {type: "array"},
				legendWidth: {type: "number", defaultValue: 32}, // width in pixels in compact mode
				legendHeight: {type: "number", defaultValue: 32}, // height in pixels in compact mode

				/**
				 * Font size of legend item texts.
				 */
				fontSize: {type: "number", defaultValue: 16} // font size for legend text
			}
		}
	});
	
	// timestamp to create a fake axistime.
	LegendBase.prototype.TIME_RANGE = ["20160101000000", "20160103000000"];
	// middle timestamp of the time axis.
	LegendBase.prototype.TIME = "20160102000000";
	
	LegendBase.prototype.init = function () {
		this._aTimeRange = [d3.time.format("%Y%m%d%H%M%S").parse(this.TIME_RANGE[0]),
			d3.time.format("%Y%m%d%H%M%S").parse(this.TIME_RANGE[1])];
	};
	
	LegendBase.prototype.getAxisTime = function () {
		return this._oAxisTime;
	};
	
	LegendBase.prototype.onBeforeRendering = function () {
		this._sUiSizeMode = Utility.findSapUiSizeClass();
		
		this._aViewRange = [0, this._getScaledLegendWidth()];
		this._oAxisTime = new AxisTime(this._aTimeRange, this._aViewRange);
//		for calendar
//		this._oStatusSet = {
//			aViewBoundary: this._aViewRange
//		};
	};
	
	LegendBase.prototype._getScaledLegendWidth = function () {
		return Utility.scaleBySapUiSize(this.getSapUiSizeClass(), this.getLegendWidth());
	};
	
	LegendBase.prototype._getScaledLegendHeight = function () {
		return Utility.scaleBySapUiSize(this.getSapUiSizeClass(), this.getLegendHeight());
	};

	LegendBase.prototype.getSapUiSizeClass = function () {
		return this._sUiSizeMode;
	};
	return LegendBase;
}, true);<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// Provides control sap.suite.ui.microchart.ComparisonMicroChart.
sap.ui.define(['jquery.sap.global', './library', 'sap/ui/core/Control'],
	function(jQuery, library, Control) {
	"use strict";

	/**
	 * Constructor for a new ComparisonMicroChart control.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Illustrates values as colored bar charts with title, numeric value, and scaling factor in the content area. This control replaces the deprecated sap.suite.ui.commons.ComparisonChart.
	 * @extends sap.ui.core.Control
	 *
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.ComparisonMicroChart
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var ComparisonMicroChart = Control.extend("sap.suite.ui.microchart.ComparisonMicroChart", /** @lends sap.suite.ui.microchart.ComparisonMicroChart.prototype */ { metadata : {

		library: "sap.suite.ui.microchart",
		properties: {
			/**
			 * The size of the microchart. If not set, the default size is applied based on the size of the device tile.
			 */
			size: {type: "sap.m.Size", group: "Misc", defaultValue: "Auto"},

			/**
			 * The scaling suffix that is added to the actual and target values.
			 */
			scale: {type: "string", group: "Misc", defaultValue: ""},

			/**
			 * The width of the chart. If it is not set, the size of the control is defined by the size property.
			 */
			width: {type: "sap.ui.core.CSSSize", group: "Misc"},

			/**
			 * The view of the chart. If not set, the Normal view is used by default.
			 */
			view: {type: "sap.suite.ui.microchart.ComparisonMicroChartViewType", group: "Appearance", defaultValue: "Normal"},

			/**
			 * The color palette for the chart. If this property is set, semantic colors defined in ComparisonData are ignored. Colors from the palette are assigned to each bar consequentially. When all the palette colors are used, assignment of the colors begins from the first palette color.
			 */
			colorPalette: {type: "string[]", group: "Appearance", defaultValue: []},

			/**
			 * If it is set to true, the height of the control is defined by its content.
			 */
			shrinkable: {type: "boolean", group: "Misc", defaultValue: "false"},

			/**
			 * Height of the chart.
			 */
			height: {type: "sap.ui.core.CSSSize", group: "Appearance"}
		},
		aggregations: {
			/**
			 * The comparison chart bar data.
			 */
			data: {type: "sap.suite.ui.microchart.ComparisonMicroChartData", multiple: true}
		},
		events: {
			/**
			 * The event is fired when the user chooses the comparison microchart.
			 */
			press : {}
		}
	}});

	ComparisonMicroChart.prototype.init = function(){
		this._oRb = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.microchart");
		this.setTooltip("{AltText}");
	};

	/**
	 * Calculates the width in percents of chart bars' elements accordingly with provided chart values.
	 *
	 * @returns {Array} array of calculated values for each chart bar.
	 * @private
	 */
	ComparisonMicroChart.prototype._calculateChartData = function() {
		var aResult = [];
		var aData = this.getData();
		var iCount = aData.length;
		var iMaxValue = 0;
		var iMinValue = 0;
		var iTotal;
		var iMaxPercent;
		var iMinPercent;
		var i;

		for (i = 0; i < iCount; i++) {
			var iDataValue = isNaN(aData[i].getValue()) ? 0 : aData[i].getValue();
			iMaxValue = Math.max(iMaxValue, iDataValue);
			iMinValue = Math.min(iMinValue, iDataValue);
		}

		iTotal = iMaxValue - iMinValue;
		iMaxPercent = (iTotal == 0) ? 0 : Math.round(iMaxValue * 100 / iTotal);

		if (iMaxPercent == 0 && iMaxValue != 0) {
			iMaxPercent = 1;
		} else if (iMaxPercent == 100 && iMinValue != 0) {
			iMaxPercent = 99;
		}

		iMinPercent = 100 - iMaxPercent;

		for (i = 0; i < iCount; i++) {
			var oItem = {};
			var iDataVal = isNaN(aData[i].getValue()) ? 0 : aData[i].getValue();

			oItem.value = (iTotal == 0) ? 0 : Math.round(iDataVal * 100 / iTotal);

			if (oItem.value == 0 && iDataVal != 0) {
				oItem.value = (iDataVal > 0) ? 1 : -1;
			} else if (oItem.value == 100) {
				oItem.value = iMaxPercent;
			} else if (oItem.value == -100) {
				oItem.value = -iMinPercent;
			}

			if (oItem.value >= 0) {
				oItem.negativeNoValue = iMinPercent;
				oItem.positiveNoValue = iMaxPercent - oItem.value;
			} else {
				oItem.value = -oItem.value;
				oItem.negativeNoValue = iMinPercent - oItem.value;
				oItem.positiveNoValue = iMaxPercent;
			}

			aResult.push(oItem);
		}

		return aResult;
	};

	ComparisonMicroChart.prototype.attachEvent = function(sEventId, oData, fnFunction, oListener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, sEventId, oData, fnFunction, oListener);
		if (this.hasListeners("press")) {
			this.$().attr("tabindex", 0).addClass("sapSuiteUiMicroChartPointer");
		}

		return this;
	};

	ComparisonMicroChart.prototype.detachEvent = function(sEventId, fnFunction, oListener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, sEventId, fnFunction, oListener);
		if (!this.hasListeners("press")) {
			this.$().removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	ComparisonMicroChart.prototype._getLocalizedColorMeaning = function(sColor) {
		return this._oRb.getText(("SEMANTIC_COLOR_" + sColor).toUpperCase());
	};

	ComparisonMicroChart.prototype.getAltText = function() {
		var sScale = this.getScale();
		var sAltText = "";

		for (var i = 0; i < this.getData().length; i++) {
			var oBar = this.getData()[i];
			var sMeaning = (this.getColorPalette().length) ? "" : this._getLocalizedColorMeaning(oBar.getColor());
			sAltText += ((i == 0) ? "" : "\n") + oBar.getTitle() + " " + (oBar.getDisplayValue() ? oBar.getDisplayValue() : oBar.getValue()) + sScale + " " + sMeaning;
		}

		return sAltText;
	};

	ComparisonMicroChart.prototype.getTooltip_AsString  = function() {
		var oTooltip = this.getTooltip();
		var sTooltip = this.getAltText();

		if (typeof oTooltip === "string" || oTooltip instanceof String) {
			sTooltip = oTooltip.split("{AltText}").join(sTooltip).split("((AltText))").join(sTooltip);
			return sTooltip;
		}
		return oTooltip ? oTooltip : "";
	};

	ComparisonMicroChart.prototype._adjustBars = function() {
		var iHeight = parseFloat(this.$().css("height"));
		var iBarCount = this.getData().length;
		var aBarContainers = this.$().find(".sapSuiteCmpChartItem");
		var iMinH = parseFloat(aBarContainers.css("min-height"));
		var iMaxH = parseFloat(aBarContainers.css("max-height"));
		var iBarContHeight;

		if (iBarCount != 0) {
			iBarContHeight = iHeight / iBarCount;

			if (iBarContHeight > iMaxH) {
				iBarContHeight = iMaxH;
			} else if (iBarContHeight < iMinH) {
				iBarContHeight = iMinH;
			}

			aBarContainers.css("height", iBarContHeight);

			if (this.getView() === "Wide" ) {
				this.$().find(".sapSuiteCmpChartBar>div").css("height", (iBarContHeight * 79 / 42) + "%");

			} else if (this.getView() === "Normal") {
				this.$().find(".sapSuiteCmpChartBar>div").css("height", (iBarContHeight - 19) + "%");
			}

			var iChartsHeightDelta = (iHeight - iBarContHeight * iBarCount) / 2;
			if (iChartsHeightDelta > 0) {
				jQuery(aBarContainers[0]).css("margin-top", iChartsHeightDelta + 7 + "px");
			}
		}
	};

	ComparisonMicroChart.prototype.onAfterRendering = function() {
		if (this.getHeight() != "") {
			var that = this;
			sap.ui.Device.media.attachHandler(function(){
				that._adjustBars();
			});
			this._adjustBars();
		}

	};

	ComparisonMicroChart.prototype._getBarAltText = function(iBarIndex) {
			var sScale = this.getScale();
			var oBar = this.getData()[iBarIndex];
			var sMeaning = (this.getColorPalette().length) ? "" : this._getLocalizedColorMeaning(oBar.getColor());
			return oBar.getTitle() + " " + (oBar.getDisplayValue() ? oBar.getDisplayValue() : oBar.getValue()) + sScale + " " + sMeaning;
	};

	ComparisonMicroChart.prototype.onsaptabnext = function(oEvent) {
		var oLast = this.$().find(":focusable").last();	// last tabstop in the control
		if (oLast) {
			this._bIgnoreFocusEvt = true;
			oLast.get(0).focus();
		}
	};

	ComparisonMicroChart.prototype.onsaptabprevious = function(oEvent) {
		if (oEvent.target.id != oEvent.currentTarget.id) {
			var oFirst = this.$().find(":focusable").first();	// first tabstop in the control
			if (oFirst) {
				oFirst.get(0).focus();
			}
		}
	};

	ComparisonMicroChart.prototype.ontap = function(oEvent) {
		if (sap.ui.Device.browser.edge) {
			this.onclick(oEvent);
		}
	};

	ComparisonMicroChart.prototype.onclick = function(oEvent) {
		if (!this.fireBarPress(oEvent)) {
			if (sap.ui.Device.browser.internet_explorer || sap.ui.Device.browser.edge) {
				this.$().focus();
			}
			this.firePress();
		}
	};

	ComparisonMicroChart.prototype.onkeydown = function(oEvent) {
		switch (oEvent.keyCode) {
			case jQuery.sap.KeyCodes.SPACE:
				oEvent.preventDefault();
				break;

			case jQuery.sap.KeyCodes.ARROW_LEFT:
			case jQuery.sap.KeyCodes.ARROW_UP:
				var oFocusables = this.$().find(":focusable");	// all tabstops in the control
				var iThis = oFocusables.index(oEvent.target);  // focused element index
				if (oFocusables.length > 0) {
					oFocusables.eq(iThis - 1).get(0).focus();	// previous tab stop element
					oEvent.preventDefault();
					oEvent.stopPropagation();
				}
				break;

			case jQuery.sap.KeyCodes.ARROW_DOWN:
			case jQuery.sap.KeyCodes.ARROW_RIGHT:
				var oFocusable = this.$().find(":focusable");	// all tabstops in the control
				var iThisEl = oFocusable.index(oEvent.target);  // focused element index
				if (oFocusable.length > 0) {
					oFocusable.eq((iThisEl + 1 < oFocusable.length) ? iThisEl + 1 : 0).get(0).focus();	// next tab stop element
					oEvent.preventDefault();
					oEvent.stopPropagation();
				}
				break;
			default:
		}
	};

	ComparisonMicroChart.prototype.onkeyup = function(oEvent) {
		if (oEvent.which == jQuery.sap.KeyCodes.ENTER || oEvent.which == jQuery.sap.KeyCodes.SPACE) {
			if (!this.fireBarPress(oEvent)) {
				this.firePress();
				oEvent.preventDefault();
			}
		}
	};

	ComparisonMicroChart.prototype.fireBarPress = function(oEvent) {
		var oBar = jQuery(oEvent.target);
		if (oBar && oBar.attr("data-bar-index")) {
			var iIndex = parseInt(oBar.attr("data-bar-index"), 10);
			var oComparisonData = this.getData()[iIndex];
			if (oComparisonData) {
				oComparisonData.firePress();
				oEvent.preventDefault();
				oEvent.stopPropagation();
				if (sap.ui.Device.browser.internet_explorer) {
					jQuery.sap.byId(this.getId() + "-chart-item-bar-" + iIndex).focus();
				}
				return true;
			}
		}
		return false;
	};


	ComparisonMicroChart.prototype.setBarPressable = function(iBarIndex, bPressable) {
		if (bPressable) {
			var sBarAltText = this._getBarAltText(iBarIndex);
			jQuery.sap.byId(this.getId() + "-chart-item-bar-" + iBarIndex).addClass("sapSuiteUiMicroChartPointer").attr("tabindex", 0).attr("title", sBarAltText).attr("role", "presentation").attr("aria-label", sBarAltText);
		} else {
			jQuery.sap.byId(this.getId() + "-chart-item-bar-" + iBarIndex).removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer").removeAttr("title").removeAttr("role").removeAttr("aria-label");
		}
	};

	ComparisonMicroChart.prototype.onfocusin = function(oEvent) {
		if (this._bIgnoreFocusEvt) {
			this._bIgnoreFocusEvt = false;
			return;
		}
		if (this.getId() + "-hidden" == oEvent.target.id) {
			this.$().focus();
			oEvent.preventDefault();
			oEvent.stopPropagation();
		}
	};

	return ComparisonMicroChart;

});
<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */

jQuery.sap.declare("sap.apf.core.ajax");

jQuery.sap.require("sap.apf.core.utils.checkForTimeout");

(function() {
	'use strict';
	/**
	 * @memberOf sap.apf.core
	 * @description Wraps a jQuery (jQuery.ajax) request in order to handle a server time-out.
	 * @param {object} oSettings Configuration of the jQuery.ajax request.
	 * @returns {object} jqXHR
	 */
	sap.apf.core.ajax = function(oSettings) {
		var oAjaxSettings = jQuery.extend(true, {}, oSettings);
		var fnBeforeSend = oAjaxSettings.beforeSend;
		var fnSuccess = oAjaxSettings.success;
		var fnError = oAjaxSettings.error;

		oAjaxSettings.beforeSend = function(jqXHR, settings) {
			if (fnBeforeSend) {
				fnBeforeSend(jqXHR, settings);
			}
		};
		oAjaxSettings.success = function(data, textStatus, jqXHR) {
			var oMessage = sap.apf.core.utils.checkForTimeout(jqXHR);

			if (oMessage) {
				fnError(data, "error", undefined, oMessage);
			} else {
				fnSuccess(data, textStatus, jqXHR);
			}
		};
		oAjaxSettings.error = function(jqXHR, textStatus, errorThrown) {
			var oMessage = sap.apf.core.utils.checkForTimeout(jqXHR);
			if (oMessage) {
				fnError(jqXHR, textStatus, errorThrown, oMessage);
			} else {
				fnError(jqXHR, textStatus, errorThrown);
			}
		};
		return jQuery.ajax(oAjaxSettings);
	};

}());<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
sap.ui.define(["jquery.sap.global","sap/ui/fl/FlexController","sap/ui/fl/Utils"],function(q,F,U){"use strict";var a={};a._instanceCache={};a.create=function(c){var f=a._instanceCache[c];if(!f){f=new F(c);a._instanceCache[c]=f;}return f;};a.createForControl=function(c){var C=U.getComponentClassName(c);return a.create(C);};return a;},true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2015 SAP SE. All rights reserved
	
 */
sap.ui.define([
	"sap/ui/core/Control", "sap/ui/layout/Splitter", "sap/ui/layout/SplitterLayoutData", "sap/ui/core/Orientation",
	"./legend/LegendContainer", "./control/Toolbar", "./control/AssociateContainer",
	"./config/TimeHorizon", "./misc/Utility"
], function (Control, Splitter, SplitterLayoutData, Orientation, LegendContainer, Toolbar, AssociateContainer,
	TimeHorizon, Utility) {
	"use strict";

	/**
	 * Creates and initializes a new Gantt chart container.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new control
	 *
	 * @class
	 * A container that holds one or more <code>GanttChartBase</code> instances.
	 *
	 * <p> This class has several built-in several controls to support <code>GanttChartBase</code> instances:
	 *  <ul>
	 * 		<li>A toolbar above all Gantt Charts. Many built-in controls can be enabled or disabled using configuration property <code>toolbarScheme</code>. Built-in functions include:
	 *			<ul>
	 *				<li>ComboBox for container selection</li>
	 *				<li>Buttons for Add View, Delete View, and Switch Splitter Orientation</li>
	 *				<li>Expand/Collapse groups for expandable charts</li>
	 *				<li>A zooming slider</li>
	 *				<li>A legend button</li>
	 *				<li>A Settings button</li>
	 *			</ul>
	 *			If nothing is added to the toolbar, the toolbar is hidden automatically. For more information about the functions and configuration, 
	 *			see the API documentation of <code>sap.gantt.config.ToolbarScheme.</code>
	 *		</li>
	 *		<li>A Splitter containing aggregation <code>ganttCharts</code></li>
	 *  </ul>
	 * </p>
	 *
	 * @extend sap.ui.core.Control
	 * 
	 * @author SAP SE
	 * @version 1.36.8
	 * 
	 * @constructor
	 * @public
	 * @alias sap.gantt.GanttChartContainer
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var GanttChartContainer = Control.extend("sap.gantt.GanttChartContainer", /** @lends sap.gantt.GanttChartContainer.prototype */ {
		metadata: {
			library: "sap.gantt",
			properties: {
				/**
				 * Width of the control
				 */
				width: {type: "sap.ui.core.CSSSize", defaultValue: "100%"},

				/**
				 * Height of the control
				 */
				height: {type: "sap.ui.core.CSSSize", defaultValue: "100%"},

				/**
				 * Switch to enable and disable scroll synchronization by time on instances of aggregation <code>ganttCharts</code>.
				 */
				enableTimeScrollSync: {type: "boolean", defaultValue: true},

				/**
				 * Switch to enable and disable scroll synchronization by row on instances of aggregation <code>ganttCharts</code>.
				 */
				enableRowScrollSync: {type: "boolean", defaultValue: false},

				/**
				 * Switch to enable and disable the cursor line that follows the cursor.
				 *
				 * When this value is set, it overrides the corresponding value on instances of aggregation <code>ganttCharts</code>.
				 */
				enableCursorLine: {type: "boolean", defaultValue: true},

				/**
				 * Switch to enable and disable the present time indicator.
				 *
				 * When this value is set, it overrides the corresponding value on instances of aggregation <code>ganttCharts</code>.
				 */
				enableNowLine: {type: "boolean", defaultValue: true},

				/**
				 * Switch to enable and disable vertical lines representing intervals along the time axis.
				 *
				 * When this value is set, it overrides the corresponding value on instances of aggregation <code>ganttCharts</code>.
				 */
				enableVerticalLine: {type: "boolean", defaultValue: true},

				/**
				 * Definitions of paint servers used for advanced shape features around SVG fill, stroke, and filter attributes.
				 * 
				 * If this property is provided, the paint server definition of the SVG is rendered. Method <code>getDefString()</code> should be
				 * implemented by all paint server classes that are passed in in this property. It is easier to assign a common paint server definition
				 * in this class instead of in separate instances of <code>sap.gantt.GanttChartBase</code>. Then the definition is 
				 * rendered only once.
				 */
				svgDefs: {type: "sap.gantt.def.SvgDefs", defaultValue: null},

				/**
				 * List of available modes. To apply modes to the toolbar and shapes, further configuration is needed. (specifically, 
				 * in property <code>toolbarSchemes</code>, and properties <code>toolbarSchemes</code> and <code>shapes</code> in 
				 * the <code>GanttChartBase</code> class)If not provided, a default configuration is provided.
				 */
				modes: {type: "array", defaultValue: sap.gantt.config.DEFAULT_MODES},

				/**
				 * List of available toolbar schemes. If not provided, a default configuration is provided.
				 */
				toolbarSchemes: {type: "array", defaultValue: sap.gantt.config.DEFAULT_CONTAINER_TOOLBAR_SCHEMES},

				/**
				 * List of available hierarchies. If not provided, a default configuration is provided.
				 */
				hierarchies: {type: "array", defaultValue: sap.gantt.config.DEFAULT_HIERARCHYS},

				/**
				 * Configuration of container layouts.
				 * 
				 * This configuration affects the data source selection ComboBox in the Container Toolbar. When the selection
				 * changes, the <code>ganttChartChangeRequested</code> event that is triggered includes the corresponding layout key.
				 */
				containerLayouts: {type: "array", defaultValue: sap.gantt.config.DEFAULT_CONTAINER_LAYOUTS},

				/**
				 * Current container layout key.
				 * 
				 * This is a key configured in configuration property <code>containerLayouts</code>.
				 */
				containerLayoutKey: {type: "string", defaultValue: sap.gantt.config.DEFAULT_CONTAINER_SINGLE_LAYOUT_KEY},

				/**
				 * Define the amount of units to change the time zoom slider.
				 *
				 * See {@link sap.m.Slider#setStep}
				 */
				sliderStep: {type: "int", defaultValue: 10}
			},
			aggregations: {
				
				/**
				 * Legend shown when the legend button is clicked.
				 * 
				 * This aggregation is used only when the Legend button is configured to be shown in the container toolbar.
				 */
				legendContainer: {type: "sap.gantt.legend.LegendContainer", multiple: false, visibility: "public"},

				/**
				 * Controls to be placed in the container toolbar.
				 * 
				 * <p>This aggregation is used only when the custom toolbar item group is configured to be shown in the container toolbar.
				 * Different from the built-in buttons that are configured to be shown or hidden, these controls are free controls created 
				 * by the application, but are only placed in the container toolbar by <code>sap.gantt.GanttChartContainer</code>.</p>
				 * 
				 * <p>If the source selection group is enabled and you want your application to use a container layout pre-configured 
				 * for a specific source, you can implement your custom toolbar items in the event handler of event <code>ganttChartChangeRequested</code>.</p>
				 */
				customToolbarItems: {type: "sap.ui.core.Control", multiple: true, visibility: "public",
					singularName: "customToolbarItem", bindable: "bindable"},

				/**
				 * Gantt chart instances.
				 * 
				 * <p>If the source selection group is enabled and you want your application to use a container layout pre-configured 
				 * for a specific source, you can implement your custom toolbar items in the event handler of event <code>ganttChartChangeRequested</code>.</p>
				 * <p>Provide a Gantt chart in compliance with the container layout setting.
				 * GanttChartContainer is designed to support Gantt chart layouts that include multiple views.</p>
				 */
				ganttCharts: {type: "sap.gantt.GanttChartBase", multiple: true, visibility: "public", singularName: "ganttChart", bindable: "bindable"},

				_toolbar: {type: "sap.gantt.control.Toolbar", multiple: false, visibility: "hidden"}
			},
			events: {
				
				/**
				 * Event fired when any change occurs in the toolbar that requests the application to change aggregation <code>ganttCharts</code>. 
				 * 
				 * <p>Possible triggers are:
				 * <ul>
				 * 	<li>The source selection group changes in the container toolbar.</li>
				 * 	<li>The layout group button is clicked in the container toolbar.</li>
				 * 	<li>The source selection group changes in the Gantt chart toolbar.</li>
				 * </ul>
				 * </p>
				 */
				ganttChartChangeRequested: {
					parameters: {
						/**
						 * Action that caused the change.
						 * 
						 * <p>Possible action values are:
						 * <ul>
						 * 	<li><code>'switchGanttChart'</code>: The source selection group of one Gantt chart toolbar is changed.</li>
						 * 	<li><code>'addGanttChart'</code>: The Add Gantt chart dropdown menu is selected.</li>
						 *  <li><code>'lessGanttChart'</code>: The Less Gantt chart dropdown menu is selected.</li>
						 *  <li><code>'switchContainerLayout'</code>: The source selection group of the Container toolbar is changed.</li>
						 * </ul>
						 * </p>
						 */
						action: {type: "string"},
						
						/**
						 * Provided for actions <code>'switchGanttChart'</code> and <code>'lessGanttChart'</code>.
						 */
						ganttChartIndex: {type: "int"},
						
						/**
						 * Provided for actions <code>'switchGanttChart'</code>, <code>'addGanttChart'</code> and <code>'lessGanttChart'</code>.
						 */
						hierarchyKey: {type: "string"},
						
						/**
						 * Provided for action <code>'switchGanttChart'</code>.
						 */
						oldHierarchyKey: {type: "string"},
						
						/**
						 * Provided for action <code>'switchContainerLayout'</code>.
						 */
						containerLayoutKey: {type: "string"}
					}
				},
				
				/**
				 * Event fired when the custom settings are changed.
				 * 
				 * The Custom settings are application-injected settings that can be configured in the Settings dialog box. This event allows the application to handle these settings.
				 * Only check boxes are supported.
				 */
				customSettingChange: {
					parameters: {
						/**
						 * ID of the custom setting
						 */
						id: {type: "string"},
						
						/**
						 * The value of the custom setting
						 */
						value: {type: "boolean"}
					}
				}
			}
		}
	});

	GanttChartContainer.prototype.init = function () {
		jQuery.sap.measure.start("GanttChartContainer Init","GanttPerf:GanttChartContainer Init function");
		
		this._bInitHorizonApplied = false;

		this._oToolbar = new Toolbar({
			type: sap.gantt.control.ToolbarType.Global,
			sourceId: sap.gantt.config.DEFAULT_CONTAINER_SINGLE_LAYOUT_KEY
		});
		this._oToolbar.setSliderStep(this.getSliderStep());
		this.setAggregation("_toolbar", this._oToolbar);
		this._oToolbar.attachSourceChange(this._onToolbarSourceChange, this);
		this._oToolbar.attachLayoutChange(this._onToolbarLayoutChange, this);
		this._oToolbar.attachExpandChartChange(this._onToolbarExpandChartChange, this);
		this._oToolbar.attachZoomRateChange(this._onToolbarZoomRateChange, this);
		this._oToolbar.attachSettingsChange(this._onToolbarSettingsChange, this);
		this._oToolbar.data("holder", this);

		this._oSplitter = new Splitter({
			width: "100%",
			height: "100%",
			orientation: Orientation.Vertical
		});
		
		this._oModesConfigMap = {};
		this._oModesConfigMap[sap.gantt.config.DEFAULT_MODE_KEY] = sap.gantt.config.DEFAULT_MODE;
		
		this._oToolbarSchemeConfigMap = {};
		this._oToolbarSchemeConfigMap[sap.gantt.config.DEFAULT_CONTAINER_TOOLBAR_SCHEME_KEY] = sap.gantt.config.DEFAULT_CONTAINER_TOOLBAR_SCHEME;
		this._oToolbarSchemeConfigMap[sap.gantt.config.DEFAULT_GANTTCHART_TOOLBAR_SCHEME_KEY] = sap.gantt.config.DEFAULT_GANTTCHART_TOOLBAR_SCHEME;
		this._oToolbarSchemeConfigMap[sap.gantt.config.EMPTY_TOOLBAR_SCHEME_KEY] = sap.gantt.config.EMPTY_TOOLBAR_SCHEME;
		
		this._oHierarchyConfigMap = {};
		this._oHierarchyConfigMap[sap.gantt.config.DEFAULT_HIERARCHY_KEY] = sap.gantt.config.DEFAULT_HIERARCHY;
		
		this._oContainerLayoutConfigMap = {};
		this._oContainerLayoutConfigMap[sap.gantt.config.DEFAULT_CONTAINER_SINGLE_LAYOUT_KEY] = sap.gantt.config.DEFAULT_CONTAINER_SINGLE_LAYOUT;
		this._oContainerLayoutConfigMap[sap.gantt.config.DEFAULT_CONTAINER_DUAL_LAYOUT_KEY] = sap.gantt.config.DEFAULT_CONTAINER_DUAL_LAYOUT;
		
		jQuery.sap.measure.end("GanttChartContainer Init");
	};

	GanttChartContainer.prototype.applySettings = function (mSettings, oScope) {
		var retVal = Control.prototype.applySettings.apply(this, arguments);
		if (this.getContainerLayouts() && this.getContainerLayoutKey()) {
			this.switchOrientation(null, true);
		}
		return retVal;
	};
	
	GanttChartContainer.prototype.setModes = function (aModes) {
		this.setProperty("modes", aModes);
		this._oToolbar.setModes(aModes);
		// build a map for easy look up
		this._oModesConfigMap = {};
		if (aModes) {
			for (var i = 0; i < aModes.length; i++) {
				this._oModesConfigMap[aModes[i].getKey()] = aModes[i];
			}
		}
		return this;
	};

	GanttChartContainer.prototype.setSliderStep = function (step) {
		this.setProperty("sliderStep", step);
		this._oToolbar.setSliderStep(step);
		return this;
	};

	GanttChartContainer.prototype.setToolbarSchemes = function (aToolbarSchemes) {
		this.setProperty("toolbarSchemes", aToolbarSchemes);
		this._oToolbar.setToolbarSchemes(aToolbarSchemes);
		// build a map for easy look up
		this._oToolbarSchemeConfigMap = {};
		if (aToolbarSchemes) {
			for (var i = 0; i < aToolbarSchemes.length; i++) {
				this._oToolbarSchemeConfigMap[aToolbarSchemes[i].getKey()] = aToolbarSchemes[i];
			}
		}
		return this;
	};
	
	GanttChartContainer.prototype.setHierarchies = function (aHierarchies) {
		this.setProperty("hierarchies", aHierarchies);
		this._oToolbar.setHierarchies(aHierarchies);
		// build a map for easy look up
		this._oHierarchyConfigMap = {};
		if (aHierarchies) {
			for (var i = 0; i < aHierarchies.length; i++) {
				this._oHierarchyConfigMap[aHierarchies[i].getKey()] = aHierarchies[i];
			}
		}
		return this;
	};
	
	GanttChartContainer.prototype.setContainerLayouts = function (aContainerLayouts) {
		this.setProperty("containerLayouts", aContainerLayouts);
		this._oToolbar.setContainerLayouts(aContainerLayouts);
		// build a map for easy look up
		this._oContainerLayoutConfigMap = {};
		if (aContainerLayouts) {
			for (var i = 0; i < aContainerLayouts.length; i++) {
				this._oContainerLayoutConfigMap[aContainerLayouts[i].getKey()] = aContainerLayouts[i];
			}
		}
		if (this.getContainerLayoutKey()) {
			this.switchOrientation(null, true);
		}
		return this;
	};

	GanttChartContainer.prototype.setEnableCursorLine = function (bEnableCursorLine) {
		this.setProperty("enableCursorLine", bEnableCursorLine);
		var aGanttCharts = this.getGanttCharts();
		for (var i = 0; i < aGanttCharts.length; i++) {
			aGanttCharts[i].setEnableCursorLine(bEnableCursorLine);
		}
		this.getAggregation("_toolbar").setEnableCursorLine(bEnableCursorLine);
		return this;
	};

	GanttChartContainer.prototype.setEnableNowLine = function (bEnableNowLine) {
		this.setProperty("enableNowLine", bEnableNowLine);
		var aGanttCharts = this.getGanttCharts();
		for (var i = 0; i < aGanttCharts.length; i++) {
			aGanttCharts[i].setEnableNowLine(bEnableNowLine);
		}
		this.getAggregation("_toolbar").setEnableNowLine(bEnableNowLine);
		return this;
	};

	GanttChartContainer.prototype.setEnableVerticalLine = function (bEnableVerticalLine) {
		this.setProperty("enableVerticalLine", bEnableVerticalLine);
		var aGanttCharts = this.getGanttCharts();
		for (var i = 0; i < aGanttCharts.length; i++) {
			aGanttCharts[i].setEnableVerticalLine(bEnableVerticalLine);
		}
		this.getAggregation("_toolbar").setEnableVerticalLine(bEnableVerticalLine);
		return this;
	};

	GanttChartContainer.prototype.setEnableTimeScrollSync = function (bEnableTimeScrollSync) {
		this.setProperty("enableTimeScrollSync", bEnableTimeScrollSync);
		var aGanttCharts = this.getGanttCharts();
		for (var i = 0; i < aGanttCharts.length; i++) {
			aGanttCharts[i].detachHorizontalScroll(this._onGanttChartHSBScroll, this);
			if (bEnableTimeScrollSync) {
				aGanttCharts[i].attachHorizontalScroll(this._onGanttChartHSBScroll, this);
			}
		}
		this.getAggregation("_toolbar").setEnableTimeScrollSync(bEnableTimeScrollSync);
		return this;
	};
	

	GanttChartContainer.prototype.setEnableRowScrollSync = function (bEnableRowScrollSync) {
		this.setProperty("enableRowScrollSync", bEnableRowScrollSync);
		var aGanttCharts = this.getGanttCharts();
		for (var i = 0; i < aGanttCharts.length; i++){
			aGanttCharts[i].detachVerticalScroll(this._onGanttChartVSBScroll, this);
			if (bEnableRowScrollSync) {
				aGanttCharts[i].attachVerticalScroll(this._onGanttChartVSBScroll, this);
			}
		}
		this.getAggregation("_toolbar").setEnableRowScrollSync(bEnableRowScrollSync);
		return this;
	};

	GanttChartContainer.prototype.setContainerLayoutKey = function (sContainerLayoutKey) {
		if (this.getProperty("containerLayoutKey") === sContainerLayoutKey) {
			return this;
		}
		this.setProperty("containerLayoutKey", sContainerLayoutKey);
		this._oToolbar.setSourceId(sContainerLayoutKey);
		if (this.getContainerLayouts()) {
			this.switchOrientation(null, true);
		}
		return this;
	};

	GanttChartContainer.prototype.setLegendContainer = function (oLegendContainer) {
		this.setAggregation("legendContainer", oLegendContainer);
		if (oLegendContainer){
			this._oToolbar.setLegend(new AssociateContainer({
				content: oLegendContainer.getId()
			}));
		} 
		return this;
	};

	GanttChartContainer.prototype.addCustomToolbarItem = function (oCustomToolbarItem) {
		this._oToolbar.addCustomToolbarItem(oCustomToolbarItem);
	};

	GanttChartContainer.prototype.insertCustomToolbarItem = function (oCustomToolbarItem, iIndex) {
		this._oToolbar.insertCustomToolbarItem(oCustomToolbarItem, iIndex);
	};

	GanttChartContainer.prototype.removeCustomToolbarItem = function (oCustomToolbarItem) {
		this._oToolbar.removeCustomToolbarItem(oCustomToolbarItem);
	};

	GanttChartContainer.prototype.removeAllCustomToolbarItems = function () {
		this._oToolbar.removeAllCustomToolbarItems();
	};

	GanttChartContainer.prototype.addGanttChart = function (oGanttChart) {
		this.addAggregation("ganttCharts", oGanttChart);
		if (oGanttChart) {
			this._insertGanttChart(oGanttChart);
		}
	};

	GanttChartContainer.prototype.insertGanttChart = function (oGanttChart, iIndex) {
		this.insertAggregation("ganttCharts", oGanttChart, iIndex);
		if (oGanttChart) {
			this._insertGanttChart(oGanttChart, iIndex);
		}
	};

	GanttChartContainer.prototype.removeGanttChart = function (vGanttChart) {
		this._removeGanttChart(vGanttChart);
		this.removeAggregation("ganttCharts", vGanttChart);
	};

	GanttChartContainer.prototype.removeAllGanttCharts = function () {
		var aGanttCharts = this.getGanttCharts();
		for (var i = 0; i < aGanttCharts.length; i++) {
			this._removeGanttChart(aGanttCharts[i]);
		}
		this.removeAllAggregation("ganttCharts");
	};

	GanttChartContainer.prototype._insertGanttChart = function (oGanttChart, iIndex) {
		jQuery.sap.measure.start("GanttChartContainer _insertGanttChart","GanttPerf:GanttChartContainer _insertGanttChart function");
		if (!oGanttChart) {
			return;
		}
		// wrap association container
		var oAssociateContainer = new AssociateContainer({
			content: oGanttChart.getId(),
			layoutData: new SplitterLayoutData({
				size: "auto"
			})
		});
		if (iIndex !== 0 && !iIndex) {
			this._oSplitter.addContentArea(oAssociateContainer);
		} else {
			this._oSplitter.insertContentArea(oAssociateContainer, iIndex);
		}
		
		// pass down properties
		var oContainerLayoutConfig = this._oContainerLayoutConfigMap[this.getContainerLayoutKey()];
		var sSelectionPanelSize = oContainerLayoutConfig.getSelectionPanelSize() ?
			oContainerLayoutConfig.getSelectionPanelSize() : "Auto";
		oGanttChart.setSelectionPanelSize(sSelectionPanelSize);
		
		//oView.setTimeZoomRate(this._oToolbar.getZoomRate());
		// attach events
		if (this.getEnableTimeScrollSync()) {
			oGanttChart.attachHorizontalScroll(this._onGanttChartHSBScroll, this);
		}
		//
		if (this.getEnableRowScrollSync()){
			oGanttChart.attachVerticalScroll(this._onGanttChartVSBScroll, this);
		}

		oGanttChart.attachSplitterResize(this._onViewSplitterResize, this);
		oGanttChart.attachGanttChartSwitchRequested(this._onGanttChartSwitchRequested, this);
		oGanttChart.attachChartDragEnter(this._onChartDragEnter, this);
		oGanttChart.attachChartDragLeave(this._onChartDragLeave, this);
		oGanttChart.attachShapeDragEnd(this._onChartDragEnd, this);
		jQuery.sap.measure.end("GanttChartContainer _insertGanttChart");
	};

	GanttChartContainer.prototype._removeGanttChart = function (vGanttChart) {
		var oGanttChart = vGanttChart;
		if ((typeof vGanttChart) === "number") {
			oGanttChart = this.getGanttCharts()[vGanttChart];	
		}
		if (oGanttChart) {
			// remove associated container
			this._oSplitter.removeContentArea(oGanttChart._oAC);
			// detach events
			oGanttChart.detachHorizontalScroll(this._onGanttChartHSBScroll, this);
			oGanttChart.detachVerticalScroll(this._onGanttChartVSBScroll, this);
			oGanttChart.detachSplitterResize(this._onViewSplitterResize, this);
			oGanttChart.detachGanttChartSwitchRequested(this._onGanttChartSwitchRequested, this);
			oGanttChart.detachChartDragEnter(this._onChartDragEnter, this);
			oGanttChart.detachChartDragLeave(this._onChartDragLeave, this);
			oGanttChart.detachShapeDragEnd(this._onChartDragEnd, this);
		}
	};

	GanttChartContainer.prototype.onBeforeRendering = function () {
		this._detachEvents();
		//View switch will initial global toolbar, need to reset the correct setting status to global toolbar
		this._oToolbar.setEnableTimeScrollSync(this.getEnableTimeScrollSync());
		this._oToolbar.setEnableRowScrollSync(this.getEnableRowScrollSync());
		this._oToolbar.setEnableCursorLine(this.getEnableCursorLine());
		this._oToolbar.setEnableNowLine(this.getEnableNowLine());
		this._oToolbar.setEnableVerticalLine(this.getEnableVerticalLine());
		
		var aGanttCharts = this.getGanttCharts();
		// Views need to respect the setting in Gantt, especially when changing
		// hierarchy layout, which triggered binding updated
		for (var i = 0; i < aGanttCharts.length; i++) {
			var oGanttChart = aGanttCharts[i];
			oGanttChart.setEnableCursorLine(this.getEnableCursorLine());
			oGanttChart.setEnableNowLine(this.getEnableNowLine());
			oGanttChart.setEnableVerticalLine(this.getEnableVerticalLine());
		}
	};

	GanttChartContainer.prototype._detachEvents = function () {};

	GanttChartContainer.prototype.onAfterRendering = function () {
		this._attachEvents();
	};

	
	GanttChartContainer.prototype._attachEvents = function () {
	};
	
	GanttChartContainer.prototype._detachToolbarEvents = function () {
		this._oToolbar.detachSourceChange(this._onToolbarSourceChange, this);
		this._oToolbar.detachLayoutChange(this._onToolbarLayoutChange, this);
		this._oToolbar.detachExpandChartChange(this._onToolbarExpandChartChange, this);
		this._oToolbar.detachZoomRateChange(this._onToolbarZoomRateChange, this);
		this._oToolbar.detachSettingsChange(this._onToolbarSettingsChange, this);
	};
	
	GanttChartContainer.prototype._onGanttChartHSBScroll = function(oEvent){
		var fLeftOffsetRate = oEvent.getParameters().leftOffsetRate;
		var aGanttCharts = this.getGanttCharts();
		for (var i = 0; i < aGanttCharts.length; i++){
			if (oEvent.oSource.getId() === aGanttCharts[i].getId()){
				continue;
			}
			aGanttCharts[i].jumpToPosition(fLeftOffsetRate);
		}
	};
	
	GanttChartContainer.prototype._onGanttChartVSBScroll = function(oEvent){
		var nScrollSteps = oEvent.getParameters().scrollSteps;
		var aGanttCharts = this.getGanttCharts();
		for (var i = 0; i < aGanttCharts.length; i++){
			if (oEvent.oSource.getId() === aGanttCharts[i].getId()){
				continue;
			}
			var oNowGanttChart = aGanttCharts[i]._oTC || aGanttCharts[i]._oTT;
			oNowGanttChart._oVSb.setScrollPosition(nScrollSteps);
		}
	};
	
	GanttChartContainer.prototype._onViewSplitterResize = function (oEvent) {
		if (this._oSplitter.getOrientation() === Orientation.Vertical) {
			this._syncSelectionPanelSizeBetweenViews(oEvent);
			this._oToolbar.setZoomInfo(oEvent.getParameter("zoomInfo"));
		}
	};

	GanttChartContainer.prototype._syncSelectionPanelSizeBetweenViews = function (oEvent) {
		var aGanttCharts = this.getGanttCharts();
		for (var i = 0; i < aGanttCharts.length; i++) {
			if (oEvent.oSource.getId() === aGanttCharts[i].getId()) {
				continue;
			}
			aGanttCharts[i].setSelectionPanelSize(oEvent.getParameter("newSizes")[0] + "px", true);
		}
	};

	GanttChartContainer.prototype._onGanttChartSwitchRequested = function (oEvent) {

		oEvent.getSource().notifySourceChange();

		this.fireGanttChartChangeRequested({
			action: "switchGanttChart",
			hierarchyKey: oEvent.getParameter("hierarchyKey"),
			oldHierarchyKey: oEvent.getParameter("oldHierarchyKey"),
			ganttChartIndex: this.getGanttCharts().indexOf(oEvent.getSource())
		});
	};
	
	GanttChartContainer.prototype._onToolbarLayoutChange = function (oEvent){
		var sEventId = oEvent.getParameter("id");
		var oEventValue = oEvent.getParameter("value");
		switch (sEventId) {
			case "orientation":
				this.switchOrientation(oEventValue);
				break;
			case "add":
				this.fireGanttChartChangeRequested({
					action: "addGanttChart",
					hierarchyKey: oEventValue.hierarchyKey
				});
				this._updateGanttChartSize();
				break;
			case "less":
				this.fireGanttChartChangeRequested({
					action: "lessGanttChart",
					hierarchyKey: oEventValue.hierarchyKey,
					ganttChartIndex: oEventValue.ganttChartIndex
				});
				this._updateGanttChartSize();
				break;
			default:
				break;
		}
	};
	
	GanttChartContainer.prototype._updateGanttChartSize = function() {
		var aContents = this._oSplitter.getContentAreas();
		for (var l = 0; l < aContents.length; l++) {
			if (aContents[l].getLayoutData()) {
				if (aContents[l].getLayoutData().getSize() === "auto") {
					aContents[l].getLayoutData().setSize("100%");
				}
				aContents[l].getLayoutData().setSize("auto");
			}
		}
	};

	GanttChartContainer.prototype._onToolbarSourceChange = function (oEvent) {
		var aGanttCharts = this.getGanttCharts();
		for (var i = 0; i < aGanttCharts.length; i++) {
			aGanttCharts[i].notifySourceChange();
		}

		this.setContainerLayoutKey(oEvent.getParameter("id"));
		this.fireGanttChartChangeRequested({
			action: "switchContainerLayout",
			containerLayoutKey: oEvent.getParameter("id")
		});
	};

	GanttChartContainer.prototype._onToolbarExpandChartChange = function (oEvent) {
		var aGanttCharts = this.getGanttCharts();
		for (var i = 0; i < aGanttCharts.length; i++) {
			aGanttCharts[i].expandChartChange(oEvent);
		}
	};

	GanttChartContainer.prototype._onToolbarZoomRateChange = function (oEvent) {
		var aGanttCharts = this.getGanttCharts();
		var i, oGanttChart;
		for (i = 0; i < aGanttCharts.length; i++) {
			oGanttChart = aGanttCharts[i];
			oGanttChart.setTimeZoomRate(oEvent.getParameter("zoomRate"));
		}
		if (this._bInitHorizonApplied) {
			return;
		}
		this._bInitHorizonApplied = true;
		for (i = 0; i < aGanttCharts.length; i++) {
			oGanttChart = aGanttCharts[i];
			oGanttChart.jumpToPosition();
		}
	};
	
	GanttChartContainer.prototype._onChartDragEnter = function (oEvent) {
		//do the following only when the mouse is still down
		var oSourceEvent = oEvent.getParameter("originEvent");
		var oGanttChart = oEvent.getSource();
		if (oSourceEvent.button == 0 && oSourceEvent.buttons !== 0 && this._oDraggingSource !== undefined) {
			oGanttChart.setDraggingData(this._oDraggingSource);
			this._oDraggingSource = undefined;
		}else {
			this._oDraggingSource = undefined;
			oGanttChart.setDraggingData(this._oDraggingSource);
		}
	};
	
	GanttChartContainer.prototype._onChartDragLeave = function (oEvent) {
		var oParam = oEvent.getParameters();
		if (oParam.draggingSource !== undefined) {
			//drag out of chart
			this._oDraggingSource = oParam.draggingSource;
		}else {
			this._oDraggingSource = undefined;
		}
	};
	
	GanttChartContainer.prototype._onChartDragEnd = function (oEvent) {
		this._oDraggingSource = undefined;
	};
	
	GanttChartContainer.prototype._onToolbarSettingsChange = function(oEvent){
		var oParameters = oEvent.getParameters();
		for (var i = 0; i < oParameters.length; i++) {
			switch (oParameters[i].id)	{
				case sap.gantt.config.SETTING_ITEM_ENABLE_TIME_SCROLL_SYNC_KEY:
					if (this.getEnableTimeScrollSync() !== oParameters[i].value) {
						this.setEnableTimeScrollSync(oParameters[i].value);
					}
					break;
				case sap.gantt.config.SETTING_ITEM_ROW_SCROLL_SYNC_KEY:
					if (this.getEnableRowScrollSync() !== oParameters[i].value) {
						this.setEnableRowScrollSync(oParameters[i].value);
					}
					break;
				case sap.gantt.config.SETTING_ITEM_ENABLE_CURSOR_LINE_KEY:
					if (this.getEnableCursorLine() !== oParameters[i].value) {
						this.setEnableCursorLine(oParameters[i].value);
					}
					break;
				case sap.gantt.config.SETTING_ITEM_ENABLE_NOW_LINE_KEY:
					if (this.getEnableNowLine() !== oParameters[i].value) {
						this.setEnableNowLine(oParameters[i].value);
					}
					break;
				case sap.gantt.config.SETTING_ITEM_ENABLE_VERTICAL_LINE_KEY:
					if (this.getEnableVerticalLine() !== oParameters[i].value) {
						this.setEnableVerticalLine(oParameters[i].value);
					}
					break;
				default:
					this.fireCustomSettingChange(oParameters[i]);
			}
		}
		
	};

	/**
	 * Switches the splitter orientation.
	 * 
	 * @param {string} [vOrientation] Target orientation. If not provided, this method inverts the orientation.
	 * @param {boolean} [bReadConfig] If this value is provided, it overrides the target orientation from the current configuration indicated by property <code>containerLayoutKey</code>.
	 * @returns {object} - <code>this</code>
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.switchOrientation = function (vOrientation, bReadConfig) {
		// init target orientation by switch current orientation
		var sOrientation = this._oSplitter.getOrientation() === Orientation.Horizontal ?
				Orientation.Vertical :
				Orientation.Horizontal;
		// over-write target orientation by input
		sOrientation = vOrientation ? vOrientation : sOrientation;
		
		
		if (bReadConfig) { // if bReadConfig, over-write target orientation by config 
			var sContainerLayoutKey = this.getContainerLayoutKey();
			if (this._oContainerLayoutConfigMap[sContainerLayoutKey]) {
				sOrientation = this._oContainerLayoutConfigMap[sContainerLayoutKey].getOrientation();
			}
		} else { // else, reset view ratio to 'auto'
			this._resetSplitterLayoutData(sOrientation);
		}
		
		this._oSplitter.setOrientation(sOrientation);
		
		return this;
	};

	GanttChartContainer.prototype._resetSplitterLayoutData = function (orientation) {
		var aSplitter;
		var aGanttCharts = this.getGanttCharts();
		var aContents = this._oSplitter.getContentAreas();
		for (var l = 0; l < aContents.length; l++) {
			if (aContents[l].getLayoutData()) {
				// to trigger resize of gantt splitter first
				if (aContents[l].getLayoutData().getSize() === "auto") {
					aContents[l].getLayoutData().setSize("100%");
				}
				aContents[l].getLayoutData().setSize("auto");
			}
		}
		for (var i = 0; i < aGanttCharts.length; i++) {
			aSplitter = aGanttCharts[i]._oSplitter;
			var contents = aSplitter.getContentAreas();
			for (var j = 0;j < contents.length; j++) {
				if (contents[j].getLayoutData()) {
					if (orientation === Orientation.Vertical) {
						if (j == 0 && contents.length > 1) {
							contents[j].getLayoutData().setSize("30%");
						} else {
							contents[j].getLayoutData().setSize("auto");
						}
					} else {
						contents[j].getLayoutData().setSize("auto");
					}			
				}
			}
		}
	};
	
	/**
	 * Returns the current effective toolbar scheme key.
	 * 
	 * @returns {string} - Toolbar scheme key.
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.getToolbarSchemeKey = function () {
		return this._oToolbar.getToolbarSchemeKey();
	};
	
	/**
	 * Selects in-row shapes and returns a success code.
	 * 
	 * @param {int} [iGanttChart] Index of the Gantt chart containing the shapes that you want to select
	 * @param {array} [aIds] L of the shape IDs that you want to select
	 * @param {boolean} [isExclusive] Whether all other selected shapes are to be deselected
	 * @returns {boolean} - If any selection change is applied, returns true.
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.selectShapes = function(iGanttChart, aIds, isExclusive) {
		var aGanttCharts = this.getGanttCharts(),
			bRetVal = false,
			oGanttChart;
		
		if (iGanttChart != undefined && iGanttChart < aGanttCharts.length) {
			oGanttChart = aGanttCharts[iGanttChart];
			bRetVal = oGanttChart.selectShapes(aIds, isExclusive);
		}else {
			for (var i = 0; i < aGanttCharts.length; i++) {
				oGanttChart = aGanttCharts[i];
				if (oGanttChart.selectShapes(aIds, isExclusive)) {
					bRetVal = true;
				}
			}
		}
		return bRetVal;
	};

	/**
	 * Deselects in-row shapes and returns a success code.
	 * 
	 * @param {int} [iGanttChartIndex] Index of the Gantt chart containing the shapes that you want to deselect
	 * @param {array} [aIds] List of the shapes that you want to deselect
	 * @returns {boolean} - If any selection change is applied, returns true.
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.deselectShapes = function(iGanttChartIndex, aIds) {
		var aGanttCharts = this.getGanttCharts(),
			bRetVal = false,
			oGanttChart;
		
		if (iGanttChartIndex != undefined && iGanttChartIndex < this.getGanttCharts().length) {
			oGanttChart = this.getGanttCharts()[iGanttChartIndex];
			bRetVal = oGanttChart.deselectShapes(aIds);
		}else {
			for (var iGanttChart in aGanttCharts) {
				oGanttChart = aGanttCharts[iGanttChart];
				if (oGanttChart.deselectShapes(aIds)) {
					bRetVal = true;
				}
			}
		}
		return bRetVal;
	};

	/**
	 * Selects relationships and returns a success code.
	 * 
	 * @param {int} [iGanttChartIndex] Index of the Gantt chart containing the relationships that you want to select
	 * @param {array} [aIds] List of the relationships that you want to select
	 * @param {boolean} [isExclusive] Whether all other selected relationships are to be deselected
	 * @returns {boolean} - If any selection change is applied, returns true.
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.selectRelationships = function(iGanttChartIndex, aIds, isExclusive) {
		var aGanttCharts = this.getGanttCharts(),
			bRetVal = false,
			oGanttChart;
		
		if (iGanttChartIndex != undefined && iGanttChartIndex < aGanttCharts.length) {
			oGanttChart = aGanttCharts[iGanttChartIndex];
			bRetVal = oGanttChart.selectRelationships(aIds, isExclusive);
		}else {
			for (var i = 0; i < aGanttCharts.length; i++) {
				oGanttChart = aGanttCharts[i];
				if (oGanttChart.selectRelationships(aIds, isExclusive)) {
					bRetVal = true;
				}
			}
		}
		return bRetVal;
	};

	/**
	 * Deselects relationships and returns a success code.
	 * 
	 * @param {int} [iGanttChartIndex] Index of the Gantt chart containing the relationships that you want to deselect
	 * @param {array} [aIds] List of the relationships that you want to deselect
	 * @returns {boolean} - If any selection change is applied, returns true.
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.deselectRelationships = function(iGanttChartIndex, aIds) {
		var aGanttCharts = this.getGanttCharts(),
			bRetVal = false,
			oGanttChart;

		if (iGanttChartIndex != undefined && iGanttChartIndex < aGanttCharts.length) {
			oGanttChart = aGanttCharts[iGanttChartIndex];
			bRetVal = oGanttChart.deselectRelationships(aIds);
		}else {
			for (var i = 0; i < aGanttCharts.length; i++) {
				oGanttChart = aGanttCharts[i];
				if (oGanttChart.deselectRelationships(aIds)) {
					bRetVal = true;
				}
			}
		}

		return bRetVal;
	};

	/**
	 * Selects rows and returns a success code.
	 * 
	 * @param {int} [iGanttChartIndex] Index of the Gantt chart containing the rows that you want to select
	 * @param {array} [aIds] List of the rows that you want to select
	 * @param {boolean} [isExclusive] Whether all other selected rows are to be deselected
	 * @returns {boolean} - If any selection change is applied, returns true.
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.selectRows = function(iGanttChartIndex, aIds, isExclusive) {
		var bRetVal = false,
			aGanttCharts = this.getGanttCharts(),
			oGanttChart;
		
		if (iGanttChartIndex != undefined && iGanttChartIndex < aGanttCharts.length) {
			oGanttChart = aGanttCharts[iGanttChartIndex];
			bRetVal = oGanttChart.selectRows(aIds, isExclusive);
		}else {
			for (var i = 0; i < aGanttCharts.length; i++) {
				oGanttChart = aGanttCharts[i];
				if (oGanttChart.selectRows(aIds, isExclusive)) {
					bRetVal = true;
				}
			}
		}

		return bRetVal;
	};

	/**
	 * Deselects rows and returns a success code.
	 * 
	 * @param {int} [iGanttChartIndex] Index of the Gantt chart containing the rows that you want to deselect
	 * @param {array} [aIds] List of the rows that you want to deselect
	 * @returns {boolean} - If any selection change is applied, returns true.
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.deselectRows = function(iGanttChartIndex, aIds) {
		var bRetVal = false,
			aGanttCharts = this.getGanttCharts(),
			oGanttChart;
		
		if (iGanttChartIndex != undefined && iGanttChartIndex < aGanttCharts.length) {
			oGanttChart = aGanttCharts[iGanttChartIndex];
			bRetVal = oGanttChart.deselectRows(aIds);
		}else {
			for (var i = 0; i < aGanttCharts.length; i++) {
				oGanttChart = aGanttCharts[i];
				if (oGanttChart.deselectRows(aIds)) {
					bRetVal = true;
				}
			}
		}
		return bRetVal;
	};
	
	/**
	 * Selects rows and all shapes contained in these rows.
	 * 
	 * @param {int} [iGanttChartIndex] Index of the Gantt chart containing the rows and shapes that you want to select
	 * @param {array} [aIds] Row UIDs
	 * @param {boolean} [bIsExclusive] Whether reset all other selected rows and shapes are to be reset
	 * @returns {boolean} - If any selection change is applied, returns true.
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.selectRowsAndShapes = function(iGanttChartIndex, aIds, bIsExclusive) {
		var bRetVal = false,
			aGanttCharts = this.getGanttCharts(),
			oGanttChart;
		
		if (iGanttChartIndex != undefined && iGanttChartIndex < aGanttCharts.length) {
			oGanttChart = aGanttCharts[iGanttChartIndex];
			bRetVal = oGanttChart.selectRowsAndShapes(aIds, bIsExclusive);
		}else {
			for (var i = 0; i < aGanttCharts.length; i++) {
				oGanttChart = aGanttCharts[i];
				if (oGanttChart.selectRowsAndShapes(aIds, bIsExclusive)) {
					bRetVal = true;
				}
			}
		}
		return bRetVal;
	};

	/**
	 * Gets the selected in-row shapes.
	 * 
	 * @param {int} [iGanttChartIndex] Index of the Gantt chart containing the selected shapes that you want to get
	 * @return {array} Returns all selected shapes in the chart
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.getSelectedShapes = function(iGanttChartIndex) {
		var aRetVal = [],
			aGanttCharts = this.getGanttCharts(),
			oGanttChart,
			oSelectedShapes;
		
		if (iGanttChartIndex != undefined && iGanttChartIndex < aGanttCharts.length) {
			oGanttChart = aGanttCharts[iGanttChartIndex];
			oSelectedShapes = oGanttChart.getSelectedShapes();
			if (oSelectedShapes !== undefined) {
				aRetVal.push({"ganttChartIndex": iGanttChartIndex, "selectedShapes": oSelectedShapes});
			}
		}else {
			for (var i = 0; i < aGanttCharts.length; i++) {
				oGanttChart = aGanttCharts[i];
				oSelectedShapes = oGanttChart.getSelectedShapes();
				if (oSelectedShapes !== undefined) {
					aRetVal.push({"ganttChartIndex": i, "selectedShapes": oSelectedShapes});
				}
			}
		}
		
		return aRetVal;
	};

	/**
	 * Gets the selected rows.
	 * 
	 * @param {int} [iGanttChartIndex] Index of the Gantt chart containing the selected rows that you want to get
	 * @return {array} Returns all selected rows
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.getSelectedRows = function(iGanttChartIndex) {
		var aRetVal = [],
			aGanttCharts = this.getGanttCharts(),
			oGanttChart, aRows;
		
		if (iGanttChartIndex != undefined && iGanttChartIndex < aGanttCharts.length) {
			oGanttChart = aGanttCharts[iGanttChartIndex];
			aRows = oGanttChart.getSelectedRows();
			if (aRows !== undefined && aRows.length > 0) {
				aRetVal.push({"ganttChartIndex": iGanttChartIndex, "selectedRows": aRows});
			}
		}else {
			for (var i = 0; i < aGanttCharts.length; i++) {
				oGanttChart = aGanttCharts[i];
				aRows = oGanttChart.getSelectedRows();
				if (aRows !== undefined) {
					aRetVal.push({"ganttChartIndex": i, "selectedRows": aRows});
				}
			}
		}
		
		return aRetVal;
	};
	
	/**
	 * Gets the selected relationships.
	 * 
	 * @param {int} [iGanttChartIndex] Index of the Gantt chart containing the selected relationships that you want to get
	 * @return {array} Returns all selected relationships in the chart
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.getSelectedRelationships = function(iGanttChartIndex) {
		var aRetVal = [],
			aGanttCharts = this.getGanttCharts(),
			oGanttChart, aRelationships;

		if (iGanttChartIndex != undefined && iGanttChartIndex < aGanttCharts.length) {
			oGanttChart = aGanttCharts[iGanttChartIndex];
			aRelationships = oGanttChart.getSelectedRelationships();
			if (aRelationships !== undefined) {
				aRetVal.push({"ganttChartIndex": iGanttChartIndex, "selectedRelationships": aRelationships});
			}
		}else {
			for (var i = 0; i < aGanttCharts.length; i++) {
				oGanttChart = aGanttCharts[i];
				aRelationships = oGanttChart.getSelectedRelationships();
				if (aRelationships !== undefined) {
					aRetVal.push({"ganttChartIndex": i, "selectedRelationships": aRelationships});
				}
			}
		}
		
		return aRetVal;
	};
	
	/**
	 * Gets all selected rows and shapes, including relationships.
	 * 
	 * @param {int} [iGanttChartIndex] Index of the Gantt chart containing that you want to get
	 * @return {object} The returned object contains "rows" for all selected rows, "shapes" for all selected shapes, and "relationships" for all selected relationships
	 * @public
	 * @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
	 */
	GanttChartContainer.prototype.getAllSelections = function(iGanttChartIndex) {
		var aRetVal = [],
			aGanttCharts = this.getGanttCharts(),
			oGanttChart, oSelections;
		
		if (iGanttChartIndex != undefined && iGanttChartIndex < aGanttCharts.length) {
			oGanttChart = aGanttCharts[iGanttChartIndex];
			oSelections = oGanttChart.getAllSelections();
			if (oSelections !== undefined) {
				aRetVal.push({"ganttChartIndex": iGanttChartIndex, "allSelection": oSelections});
			}
		}else {
			for (var i = 0; i < aGanttCharts.length; i++) {
				oGanttChart = aGanttCharts[i];
				oSelections = oGanttChart.getAllSelections();
				if (oSelections !== undefined) {
					aRetVal.push({"ganttChartIndex": i, "allSelection": oSelections});
				}
			}
		}
		
		return aRetVal;
	};

	GanttChartContainer.prototype.exit = function () {
		this._detachEvents();
		this._oToolbar.destroy();
		this._oSplitter.destroy();
	};

	return GanttChartContainer;
}, true);
<file_sep>// This file has been generated by the SAPUI5 'AllInOne' Builder
jQuery.sap.declare('sap.suite.ui.microchart.library-all');
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.AreaMicroChartRenderer') ) {
 /*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

jQuery.sap.declare('sap.suite.ui.microchart.AreaMicroChartRenderer'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/AreaMicroChartRenderer",['jquery.sap.global'],
	function() {
	"use strict";

	/**
	 * AreaMicroChartRenderer renderer.
	 * @namespace
	 */
	var AreaMicroChartRenderer = {};

	/**
	 * Renders the HTML for the given control, using the provided
	 * {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm
	 *			the RenderManager that can be used for writing to
	 *			the Render-Output-Buffer
	 * @param {sap.ui.core.Control} oControl
	 *			the control to be rendered
	 */
	AreaMicroChartRenderer.render = function(oRm, oControl) {

		function fnWriteLbl(oLabel, sId, sClass, sType) {
			var sLabel = oLabel ? oLabel.getLabel() : "";
			oRm.write("<div");
			oRm.writeAttribute("id", oControl.getId() + sId);

			if (oLabel) {
				oRm.addClass(oLabel.getColor());
			}

			oRm.addClass("sapSuiteAmcLbl");
			oRm.addClass(sClass);
			oRm.addClass(sType);
			oRm.writeClasses();
			oRm.write(">");
				oRm.writeEscaped(sLabel);
			oRm.write("</div>");
		}

		var sTooltip = oControl.getTooltip_AsString();
		if (typeof sTooltip !== "string") {
			sTooltip = "";
		}

		var sTopLblType = ((oControl.getView() == "Normal" && oControl.getFirstYLabel() && oControl.getFirstYLabel().getLabel()) ? "L" : "")
			+ ((oControl.getMaxLabel() && oControl.getMaxLabel().getLabel()) ? "C" : "")
			+ ((oControl.getView() == "Normal" && oControl.getLastYLabel() && oControl.getLastYLabel().getLabel()) ? "R" : "");

		var sBtmLblType = ((oControl.getView() == "Normal" && oControl.getFirstXLabel() && oControl.getFirstXLabel().getLabel()) ? "L" : "")
			+ ((oControl.getMinLabel() && oControl.getMinLabel().getLabel()) ? "C" : "")
			+ ((oControl.getView() == "Normal" && oControl.getLastXLabel() && oControl.getLastXLabel().getLabel()) ? "R" : "");

		var bLeftLbls, bRightLbls;
		bRightLbls = bLeftLbls = oControl.getView() == "Wide";

		oRm.write("<div");
			oRm.writeControlData(oControl);
			if (sTooltip) {
				oRm.writeAttributeEscaped("title", sTooltip);
			}
			oRm.addStyle("width", oControl.getWidth());
			oRm.addStyle("height", oControl.getHeight());
			oRm.writeStyles();
			oRm.writeAttribute("role", "presentation");
			oRm.writeAttributeEscaped("aria-label", oControl.getAltText().replace(/\s/g, " ") + (sap.ui.Device.browser.firefox ? "" : " " + sTooltip ));
			oRm.addClass("sapSuiteAmc");
			if (oControl.hasListeners("press")) {
				oRm.addClass("sapSuiteUiMicroChartPointer");
				oRm.writeAttribute("tabindex", "0");
			}

			if (sTopLblType) {
				oRm.addClass("topLbls");
			}
			if (sBtmLblType) {
				oRm.addClass("btmLbls");
			}

			oRm.writeClasses();
			oRm.write(">");
				if (sTopLblType) {
					oRm.write("<div");
					oRm.writeAttribute("id", oControl.getId() + "-top-labels");
					oRm.addClass("sapSuiteAmcLabels");
					oRm.addClass("Top");
					oRm.writeClasses();
					oRm.write(">");
						fnWriteLbl(oControl.getFirstYLabel(), "-top-left-lbl", "Left", sTopLblType);
						fnWriteLbl(oControl.getMaxLabel(), "-top-center-lbl", "Center", sTopLblType);
						fnWriteLbl(oControl.getLastYLabel(), "-top-right-lbl", "Right", sTopLblType);
					oRm.write("</div>");
				}

				if (bLeftLbls) {
					oRm.write("<div");
					oRm.writeAttribute("id", oControl.getId() + "-left-labels");
					oRm.addClass("sapSuiteAmcSideLabels");
					oRm.addClass("Left");
					oRm.writeClasses();
					oRm.write(">");
						fnWriteLbl(oControl.getFirstYLabel(), "-top-left-lbl", "Top", "Left");
						fnWriteLbl(oControl.getFirstXLabel(), "-btm-left-lbl", "Btm", "Left");
					oRm.write("</div>");
				}

				oRm.write("<div");
				oRm.writeAttribute("id", oControl.getId() + "-canvas-cont");
				oRm.addClass("sapSuiteAmcCanvas");
				oRm.writeClasses();
				oRm.write(">");
					oRm.write("<canvas");
					oRm.writeAttribute("id", oControl.getId() + "-canvas");
					oRm.addStyle("width", "100%");
					oRm.addStyle("height", "100%");
					oRm.writeStyles();
					oRm.write("></canvas>");
				oRm.write("</div>");

				if (bRightLbls) {
					oRm.write("<div");
					oRm.writeAttribute("id", oControl.getId() + "-right-labels");
					oRm.addClass("sapSuiteAmcSideLabels");
					oRm.addClass("Right");
					oRm.writeClasses();
					oRm.write(">");
						fnWriteLbl(oControl.getLastYLabel(), "-top-right-lbl", "Top", "Right");
						fnWriteLbl(oControl.getLastXLabel(), "-btm-right-lbl", "Btm", "Right");
					oRm.write("</div>");
				}

				if (sBtmLblType) {
					oRm.write("<div");
					oRm.writeAttribute("id", oControl.getId() + "-bottom-labels");
					oRm.addClass("sapSuiteAmcLabels");
					oRm.addClass("Btm");
					oRm.writeClasses();
					oRm.write(">");
						fnWriteLbl(oControl.getFirstXLabel(), "-btm-left-lbl", "Left", sBtmLblType);
						fnWriteLbl(oControl.getMinLabel(), "-btm-center-lbl", "Center", sBtmLblType);
						fnWriteLbl(oControl.getLastXLabel(), "-btm-right-lbl", "Right", sBtmLblType);
					oRm.write("</div>");
				}

				oRm.write("<div");
				oRm.writeAttribute("id", oControl.getId() + "-css-helper");
				oRm.addStyle("display", "none");
				oRm.writeStyles();
				oRm.write("></div>");

		oRm.write("</div>");
	};

	return AreaMicroChartRenderer;

}, /* bExport= */ true);
}; // end of sap/suite/ui/microchart/AreaMicroChartRenderer.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.BulletMicroChartRenderer') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

jQuery.sap.declare('sap.suite.ui.microchart.BulletMicroChartRenderer'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/BulletMicroChartRenderer",['jquery.sap.global'],
	function() {
	"use strict";

	/**
	 * BulletMicroChart renderer.
	 * @namespace
	 */
	var BulletMicroChartRenderer = {};

	/**
	 * Renders the HTML for the given control, using the provided
	 * {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm
	 *            the RenderManager that can be used for writing to
	 *            the Render-Output-Buffer
	 * @param {sap.ui.core.Control} oControl
	 *            the control to be rendered
	 */
	BulletMicroChartRenderer.render = function(oRm, oControl) {
		var oChartData = oControl._calculateChartData();
		var fForecastValuePct = +oChartData.forecastValuePct;
		var sSize = oControl.getSize();
		var sScale = oControl.getScale();
		var bRtl = sap.ui.getCore().getConfiguration().getRTL();
		var sOrientation = bRtl ? "right" : "left";
		var sMode = oControl.getMode();
		var sDeltaValue = (sap.suite.ui.microchart.BulletMicroChartModeType.Delta == sMode) ? oControl._calculateDeltaValue() : 0;
		var bIsActualSet = oControl.getActual() && oControl.getActual()._isValueSet;
		var bShowActualValue = oControl.getShowActualValue() && (sap.m.Size.XS != sSize) && sap.suite.ui.microchart.BulletMicroChartModeType.Actual == sMode;
		var bShowDeltaValue = oControl.getShowDeltaValue() && (sap.m.Size.XS != sSize) && sap.suite.ui.microchart.BulletMicroChartModeType.Delta == sMode;
		var bShowTargetValue = oControl.getShowTargetValue() && (sap.m.Size.XS != sSize);
		var sActualValueLabel = oControl.getActualValueLabel();
		var sDeltaValueLabel = oControl.getDeltaValueLabel();
		var sTargetValueLabel = oControl.getTargetValueLabel();
		var aData = oControl.getThresholds();
		var sTooltip = oControl.getTooltip_AsString();
		if (typeof sTooltip !== "string") {
			sTooltip = "";
		}

		oRm.write("<div");
		oRm.writeControlData(oControl);
		oRm.addClass("sapSuiteBMCContent");
		oRm.addClass(sSize);
		if (oControl.hasListeners("press")) {
			oRm.addClass("sapSuiteUiMicroChartPointer");
			oRm.writeAttribute("tabindex", "0");
		}
		oRm.writeAttribute("role", "presentation");
		oRm.writeAttributeEscaped("aria-label", oControl.getAltText().replace(/\s/g, " ") + (sap.ui.Device.browser.firefox ? "" : " " + sTooltip ));

		oRm.writeClasses();

		if (oControl.getWidth()) {
			oRm.addStyle("width", oControl.getWidth());
			oRm.writeStyles();
		}
		oRm.writeAttribute("id", oControl.getId() + "-bc-content");
		oRm.writeAttributeEscaped("title", sTooltip);
		oRm.write(">");

		oRm.write("<div");
		oRm.addClass("sapSuiteBMCChart");
		oRm.addClass(sSize);
		oRm.writeClasses();
		oRm.writeAttribute("id", oControl.getId() + "-bc-chart");
		oRm.write(">");
		var sValScale = "";
		if (bIsActualSet && bShowActualValue) {
			var sAValToShow = (sActualValueLabel) ? sActualValueLabel : "" + oControl.getActual().getValue();
			sValScale = sAValToShow + sScale;
			oRm.write("<div");
			oRm.addClass("sapSuiteBMCItemValue");
			oRm.addClass(oControl.getActual().getColor());
			oRm.addClass(sSize);
			oRm.writeClasses();
			oRm.writeStyles();
			oRm.writeAttribute("id", oControl.getId() + "-bc-item-value");
			oRm.write(">");
			oRm.writeEscaped(sValScale);
			oRm.write("</div>");
		} else if (bIsActualSet && oControl._isTargetValueSet && bShowDeltaValue) {
			var sDValToShow = (sDeltaValueLabel) ? sDeltaValueLabel : "" + sDeltaValue;
			sValScale = sDValToShow + sScale;
			oRm.write("<div");
			oRm.addClass("sapSuiteBMCItemValue");
			oRm.addClass(oControl.getActual().getColor());
			oRm.addClass(sSize);
			oRm.writeClasses();
			oRm.writeStyles();
			oRm.writeAttribute("id", oControl.getId() + "-bc-item-value");
			oRm.write(">");
			oRm.write("&Delta;");
			oRm.writeEscaped(sValScale);
			oRm.write("</div>");
		}

		for (var i = 0; i < oChartData.thresholdsPct.length; i++) {
			if (aData[i]._isValueSet) {
				this.renderThreshold(oRm,  oControl, oChartData.thresholdsPct[i]);
			}
		}

		oRm.write("<div");
		oRm.writeAttribute("id", oControl.getId() + "-chart-bar");
		oRm.addClass("sapSuiteBMCBar");
		oRm.addClass(sSize);
		oRm.addClass(oControl.getScaleColor());
		oRm.writeClasses();
		oRm.write(">");
		oRm.write("</div>");

		if (oControl._isForecastValueSet && sMode == "Actual") {
			oRm.write("<div");
			oRm.addClass("sapSuiteBMCForecastBarValue");
			oRm.addClass(oControl.getActual().getColor());
			oRm.addClass(sSize);
			oRm.writeClasses();
			oRm.addStyle("width", fForecastValuePct + "%");
			oRm.writeStyles();
			oRm.writeAttribute("id", oControl.getId() + "-forecast-bar-value");
			oRm.write("></div>");
		}

		if (bIsActualSet) {
			oRm.write("<div");
			oRm.addClass("sapSuiteBMCBarValueMarker");
			oRm.addClass(sMode);
			if (!oControl.getShowValueMarker()) {
				oRm.addClass("sapSuiteBMCBarValueMarkerHidden");
			}
			oRm.addClass(oControl.getActual().getColor());
			oRm.addClass(sSize);
			oRm.writeClasses();
			oRm.addStyle(sOrientation, parseFloat(oChartData.actualValuePct) + parseFloat(1) + "%");
			if (sMode == "Delta" && oChartData.actualValuePct <= oChartData.targetValuePct) {
				oRm.addStyle("margin", "0");
			}
			oRm.writeStyles();
			oRm.writeAttribute("id", oControl.getId() + "-bc-bar-value-marker");
			oRm.write("></div>");

			if (sMode == "Actual") {
				oRm.write("<div");
				oRm.addClass("sapSuiteBMCBarValue");
				oRm.addClass(oControl.getActual().getColor());
				oRm.addClass(sSize);
				if (oControl._isForecastValueSet) {
					oRm.addClass("sapSuiteBMCForecast");
				}
				oRm.writeClasses();
				oRm.addStyle("width", oChartData.actualValuePct + "%");
				oRm.writeStyles();
				oRm.writeAttribute("id", oControl.getId() + "-bc-bar-value");
				oRm.write("></div>");
			} else if (oControl._isTargetValueSet && sMode == "Delta") {
				oRm.write("<div");
				oRm.addClass("sapSuiteBMCBarValue");
				oRm.addClass(oControl.getActual().getColor());
				oRm.addClass(sSize);
				oRm.writeClasses();
				oRm.addStyle("width", Math.abs(oChartData.actualValuePct - oChartData.targetValuePct) + "%");
				oRm.addStyle(sOrientation, 1 + Math.min(oChartData.actualValuePct, oChartData.targetValuePct) + "%");
				oRm.writeStyles();
				oRm.writeAttribute("id", oControl.getId() + "-bc-bar-value");
				oRm.write("></div>");
			}
		}

		if (oControl._isTargetValueSet) {
			oRm.write("<div");
			oRm.addClass("sapSuiteBMCTargetBarValue");
			oRm.addClass(sSize);
			oRm.writeClasses();
			oRm.addStyle(sOrientation, parseFloat(oChartData.targetValuePct).toFixed(2) + "%");
			oRm.writeStyles();
			oRm.writeAttribute("id", oControl.getId() + "-bc-target-bar-value");
			oRm.write("></div>");

			if (bShowTargetValue) {
				var sTValToShow = (sTargetValueLabel) ? sTargetValueLabel : "" + oControl.getTargetValue();
				var sTValScale = sTValToShow + sScale;
				oRm.write("<div");
				oRm.addClass("sapSuiteBMCTargetValue");
				oRm.addClass(sSize);
				oRm.writeClasses();
				oRm.writeStyles();
				oRm.writeAttribute("id", oControl.getId() + "-bc-target-value");
				oRm.write(">");
				oRm.writeEscaped(sTValScale);
				oRm.write("</div>");
			}
		}
		oRm.write("</div>");

		oRm.write("<div");
		oRm.writeAttribute("id", oControl.getId() + "-info");
		oRm.writeAttribute("aria-hidden", "true");
		oRm.addStyle("display", "none");
		oRm.writeStyles();
		oRm.write(">");
		oRm.writeEscaped(sTooltip);
		oRm.write("</div>");
		oRm.write("</div>");
	};

	/**
	 * Renders the HTML for the thresholds, using the provided {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the render output buffer
	 * @param {sap.ui.core.Control} oControl an object representation of the control whose thresholds should be rendered
	 * @param {sap.ui.core.Control} oThreshold an object containing threshold values and colors
	 */
	BulletMicroChartRenderer.renderThreshold = function(oRm, oControl, oThreshold) {
		var sOrientation = sap.ui.getCore().getConfiguration().getRTL() ? "right" : "left";
		var fValuePct = 0.98 * oThreshold.valuePct + 1;
		var sColor = oThreshold.color;
		var sSize = oControl.getSize();

		if (sap.m.ValueColor.Error == oThreshold.color) {
			oRm.write("<div");
			oRm.addClass("sapSuiteBMCDiamond");
			oRm.addClass(sSize);
			oRm.addClass(sColor);
			oRm.writeClasses();
			oRm.addStyle(sOrientation, fValuePct + "%");
			oRm.writeStyles();
			oRm.write("></div>");
		}
		oRm.write("<div");
		oRm.addClass("sapSuiteBMCThreshold");
		oRm.addClass(sSize);
		oRm.addClass(sColor);
		oRm.writeClasses();
		oRm.addStyle(sOrientation, fValuePct + "%");
		oRm.writeStyles();
		oRm.write("></div>");
	};

	return BulletMicroChartRenderer;

}, /* bExport= */ true);
}; // end of sap/suite/ui/microchart/BulletMicroChartRenderer.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.ColumnMicroChartRenderer') ) {
 /*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

jQuery.sap.declare('sap.suite.ui.microchart.ColumnMicroChartRenderer'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/ColumnMicroChartRenderer",['jquery.sap.global'],
	function() {
	"use strict";

	/**
	 * ColumnMicroChartRenderer renderer.
	 * @namespace
	 */
	var ColumnMicroChartRenderer = {};

	/**
	 * Renders the HTML for the given control, using the provided
	 * {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm
	 *			the RenderManager that can be used for writing to
	 *			the Render-Output-Buffer
	 * @param {sap.ui.core.Control} oControl
	 *			the control to be rendered
	 */
	ColumnMicroChartRenderer.render = function(oRm, oControl) {
		function fnWriteLbl(oLabel, sId, sClass, bWideBtmLbl) {
			oRm.write("<div");
			oRm.writeAttribute("id", oControl.getId() + sId);
			oRm.addClass("sapSuiteCmcLbl");
			oRm.addClass(sClass);
			oRm.addClass(oLabel.getColor());
			if (bWideBtmLbl) {
				oRm.addClass("W");
			}
			oRm.writeClasses();
			oRm.write(">");
				oRm.writeEscaped(oLabel.getLabel());
			oRm.write("</div>");
		}

		oRm.write("<div");
		oRm.writeControlData(oControl);
		oRm.addClass("sapSuiteCmc");
		oRm.addClass(oControl.getSize());
		var sTooltip = oControl.getTooltip_AsString();

		if (typeof sTooltip !== "string") {
			sTooltip = "";
		}
		oRm.writeAttributeEscaped("title", sTooltip);

		if (oControl.hasListeners("press")) {
			oRm.addClass("sapSuiteUiMicroChartPointer");
			oRm.writeAttribute("tabindex", "0");
		}
		oRm.writeAttribute("role", "presentation");
		oRm.writeAttributeEscaped("aria-label", oControl.getAltText().replace(/\s/g, " ") + (sap.ui.Device.browser.firefox ? "" : " " + sTooltip ));

		oRm.writeClasses();
		oRm.addStyle("width", oControl.getWidth());
		oRm.addStyle("height", oControl.getHeight());
		oRm.writeStyles();
		oRm.write(">");
			var bLeftTopLbl = oControl.getLeftTopLabel() && oControl.getLeftTopLabel().getLabel() != "";
			var bRightTopLbl = oControl.getRightTopLabel() && oControl.getRightTopLabel().getLabel() != "";
			var bLeftBtmLbl = oControl.getLeftBottomLabel() && oControl.getLeftBottomLabel().getLabel() != "";
			var bRightBtmLbl = oControl.getRightBottomLabel() && oControl.getRightBottomLabel().getLabel() != "";

			if (bLeftTopLbl || bRightTopLbl) {
				oRm.write("<div");
				oRm.writeAttribute("id", oControl.getId() + "-top-lbls");
				oRm.addClass("sapSuiteCmcLbls");
				oRm.addClass("T");
				oRm.writeClasses();
				oRm.write(">");
					var bWideTopLbl = bLeftTopLbl ^ bRightTopLbl;
					if (bLeftTopLbl) {
						fnWriteLbl(oControl.getLeftTopLabel(), "-left-top-lbl", "L", bWideTopLbl);
					}

					if (bRightTopLbl) {
						fnWriteLbl(oControl.getRightTopLabel(), "-right-top-lbl", "R", bWideTopLbl);
					}
				oRm.write("</div>");
			}

			oRm.write("<div");
			oRm.writeAttributeEscaped("id", oControl.getId() + "-content");
			oRm.addClass("sapSuiteCmcCnt");
			if (bLeftTopLbl || bRightTopLbl) {
				oRm.addClass("T");
			}
			if (bLeftBtmLbl || bRightBtmLbl) {
				oRm.addClass("B");
			}
			oRm.writeClasses();
			oRm.write(">");
				oRm.write("<div");
				oRm.writeAttributeEscaped("id", oControl.getId() + "-bars");
				oRm.addClass("sapSuiteCmcBars");
				oRm.writeClasses();
				oRm.write(">");
					var iColumnsNum = oControl.getColumns().length;
					for (var i = 0; i < iColumnsNum; i++) {
						var oColumn = oControl.getColumns()[i];
						oRm.write("<div");
						oRm.writeAttribute("id", oControl.getId() + "-bar-" + i);
						oRm.writeAttribute("data-bar-index", i);
						oRm.addClass("sapSuiteCmcBar");
						oRm.addClass(oColumn.getColor());
						if (oColumn.hasListeners("press")) {
							oRm.writeAttribute("tabindex", "0");
							oRm.writeAttribute("role", "presentation");
							var sBarAltText = oControl._getBarAltText(i);
							oRm.writeAttributeEscaped("title", sBarAltText);
							oRm.writeAttributeEscaped("aria-label", sBarAltText);
							oRm.addClass("sapSuiteUiMicroChartPointer");
						}
						oRm.writeClasses();
						oRm.write(">");
						oRm.write("</div>");
					}
				oRm.write("</div>");
			oRm.write("</div>");

			if (bLeftBtmLbl || bRightBtmLbl) {
				oRm.write("<div");
				oRm.writeAttribute("id", oControl.getId() + "-btm-lbls");
				oRm.addClass("sapSuiteCmcLbls");
				oRm.addClass("B");
				oRm.writeClasses();
				oRm.write(">");
					var bWideBtmLbl = bLeftBtmLbl ^ bRightBtmLbl;
					if (bLeftBtmLbl) {
						fnWriteLbl(oControl.getLeftBottomLabel(), "-left-btm-lbl", "L", bWideBtmLbl);
					}

					if (bRightBtmLbl) {
						fnWriteLbl(oControl.getRightBottomLabel(), "-right-btm-lbl", "R", bWideBtmLbl);
					}
				oRm.write("</div>");
			}

			oRm.write("<div");
			oRm.writeAttribute("id", oControl.getId() + "-hidden");
			oRm.writeAttribute("aria-hidden", "true");
			oRm.writeAttribute("tabindex", "0");
			oRm.writeStyles();
			oRm.write(">");
			oRm.write("</div>");
		oRm.write("</div>");
	};

	return ColumnMicroChartRenderer;

}, /* bExport= */ true);
}; // end of sap/suite/ui/microchart/ColumnMicroChartRenderer.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.ComparisonMicroChartRenderer') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

jQuery.sap.declare('sap.suite.ui.microchart.ComparisonMicroChartRenderer'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/ComparisonMicroChartRenderer",['jquery.sap.global'],
	function() {
	"use strict";

	/**
	 * ComparisonMicroChart renderer.
	 * @namespace
	 */
	var ComparisonMicroChartRenderer = {};

	/**
	 * Renders the HTML for the given control, using the provided
	 * {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm
	 *			the RenderManager that can be used for writing to
	 *			the Render-Output-Buffer
	 * @param {sap.ui.core.Control} oControl
	 *			the control to be rendered
	 */
	ComparisonMicroChartRenderer.render = function (oRm, oControl) {
		var sTooltip = oControl.getTooltip_AsString();
		if (typeof sTooltip !== "string") {
			sTooltip = "";
		}

		oRm.write("<div");
		oRm.writeControlData(oControl);
		oRm.addClass("sapSuiteCmpChartContent");
		oRm.addClass(oControl.getSize());
		if (oControl.hasListeners("press")) {
			oRm.writeAttribute("tabindex", "0");
			oRm.addClass("sapSuiteUiMicroChartPointer");
		}
		oRm.writeClasses();

		oRm.writeAttribute("role", "presentation");
		oRm.writeAttributeEscaped("aria-label", oControl.getAltText().replace(/\s/g, " ") + (sap.ui.Device.browser.firefox ? "" : " " + sTooltip ));

		if (oControl.getShrinkable()) {
			oRm.addStyle("min-height", "0px");
		}
		if (oControl.getWidth()) {
			oRm.addStyle("width", oControl.getWidth());
		}
		if (oControl.getHeight()) {
			oRm.addStyle("height", oControl.getHeight());
		}
		oRm.writeStyles();
		oRm.writeAttributeEscaped("title", sTooltip);
		oRm.write(">");
		this._renderInnerContent(oRm, oControl);
			oRm.write("<div");
			oRm.writeAttribute("id", oControl.getId() + "-info");
			oRm.writeAttribute("aria-hidden", "true");
			oRm.addStyle("display", "none");
			oRm.writeStyles();
			oRm.write(">");
				oRm.writeEscaped(sTooltip);
			oRm.write("</div>");

			oRm.write("<div");
			oRm.writeAttribute("id", oControl.getId() + "-hidden");
			oRm.writeAttribute("aria-hidden", "true");
			oRm.writeAttribute("tabindex", "-1");
			oRm.writeStyles();
			oRm.write(">");
			oRm.write("</div>");
		oRm.write("</div>");
	};

	ComparisonMicroChartRenderer._renderInnerContent = function(oRm, oControl) {
		var iCPLength = oControl.getColorPalette().length;
		var iCPIndex = 0;

		var fnNextColor = function() {
			if (iCPLength) {
				if (iCPIndex == iCPLength) {
					iCPIndex = 0;
				}
				return oControl.getColorPalette()[iCPIndex++];
			}
		};

		var aChartData = oControl._calculateChartData();
		for (var i = 0; i < aChartData.length; i++) {
			this._renderChartItem(oRm,  oControl, aChartData[i], i, fnNextColor());
		}
	};

	ComparisonMicroChartRenderer._renderChartItem = function(oRm, oControl, oChartData, iIndex, sColor) {
		oRm.write("<div");
		oRm.writeAttribute("id", oControl.getId() + "-chart-item-" + iIndex);
		oRm.addClass("sapSuiteCmpChartItem");
		oRm.addClass(oControl.getView());
		oRm.addClass(oControl.getSize());
		oRm.writeClasses();
		oRm.write(">");
			this._renderChartHeader(oRm, oControl, iIndex, sColor);
			this._renderChartBar(oRm, oControl, oChartData, iIndex, sColor);
		oRm.write("</div>");
	};

	ComparisonMicroChartRenderer._renderChartBar = function(oRm, oControl, oChartData, iIndex, sColor) {
		var oData = oControl.getData()[iIndex];

		oRm.write("<div");
		oRm.writeAttribute("id", oControl.getId() + "-chart-item-bar-" + iIndex);
		oRm.addClass("sapSuiteCmpChartBar");
		oRm.addClass(oControl.getView());
		oRm.addClass(oControl.getSize());
		if (oControl.getData()[iIndex].hasListeners("press")) {
			oRm.writeAttribute("tabindex", "0");
			oRm.writeAttribute("role", "presentation");
			oRm.writeAttributeEscaped("title", oControl._getBarAltText(iIndex));
			oRm.writeAttributeEscaped("aria-label", oControl._getBarAltText(iIndex));
			oRm.writeAttribute("data-bar-index", iIndex);
			oRm.addClass("sapSuiteUiMicroChartPointer");
		}
		oRm.writeClasses();
		oRm.write(">");

		if (oChartData.negativeNoValue > 0) {
			oRm.write("<div");
			oRm.writeAttribute("data-bar-index", iIndex);
			oRm.addClass("sapSuiteCmpChartBarNegNoValue");
			oRm.writeClasses();
			oRm.addStyle("width", oChartData.negativeNoValue + "%");
			oRm.writeStyles();
			oRm.write("></div>");
		}

		if (oChartData.value > 0) {
			oRm.write("<div");
			oRm.writeAttribute("data-bar-index", iIndex);
			oRm.addClass("sapSuiteCmpChartBarValue");
			oRm.addClass(oData.getColor());
			oRm.writeClasses();
			oRm.addStyle("background-color", sColor);
			oRm.addStyle("width", oChartData.value + "%");
			oRm.writeStyles();
			oRm.write("></div>");
		}

		if (oChartData.positiveNoValue > 0) {
			oRm.write("<div");
			oRm.writeAttribute("data-bar-index", iIndex);
			oRm.addClass("sapSuiteCmpChartBarNoValue");
			oRm.writeClasses();
			oRm.addStyle("width", oChartData.positiveNoValue + "%");
			oRm.writeStyles();
			oRm.write("></div>");
		}

		oRm.write("</div>");
	};

	ComparisonMicroChartRenderer._renderChartHeader = function(oRm, oControl, iIndex, sColor) {
		var oData = oControl.getData()[iIndex];
		var sScale = oControl.getScale();
		var sDisplayValue = oData.getDisplayValue();
		var sAValToShow = sDisplayValue ? sDisplayValue : "" + oData.getValue();
		var sValScale = sAValToShow + sScale;

		oRm.write("<div");
		oRm.writeAttribute("id", oControl.getId() + "-chart-item-" + iIndex + "-header");
		oRm.addClass("sapSuiteCmpChartItemHeader");
		oRm.addClass(oControl.getView());
		oRm.addClass(oControl.getSize());
		oRm.writeClasses();
		oRm.write(">");
			oRm.write("<div");
				oRm.writeAttribute("id", oControl.getId() + "-chart-item-" + iIndex + "-value");
				oRm.addClass("sapSuiteCmpChartItemValue");
				oRm.addClass(oControl.getSize());
				oRm.addClass(oControl.getView());
				if (!sColor) {
					oRm.addClass(oData.getColor());
				}

				if (oData.getTitle()) {
					oRm.addClass("T");
				}
				oRm.writeClasses();
				oRm.write(">");
				if (!isNaN(oData.getValue())) {
					oRm.writeEscaped(sValScale);
				}
			oRm.write("</div>");

			oRm.write("<div");
			oRm.writeAttribute("id", oControl.getId() + "-chart-item-" + iIndex + "-title");
			oRm.addClass("sapSuiteCmpChartItemTitle");
			oRm.writeClasses();
			oRm.write(">");
				oRm.writeEscaped(oData.getTitle());
			oRm.write("</div>");
		oRm.write("</div>");
	};

	return ComparisonMicroChartRenderer;

}, /* bExport= */ true);
}; // end of sap/suite/ui/microchart/ComparisonMicroChartRenderer.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.DeltaMicroChartRenderer') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

jQuery.sap.declare('sap.suite.ui.microchart.DeltaMicroChartRenderer'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/DeltaMicroChartRenderer",['jquery.sap.global'],
	function() {
	"use strict";

	/**
	 * DeltaMicroChart renderer.
	 * @namespace
	 */
	var DeltaMicroChartRenderer = {};

	/**
	 * Renders the HTML for the given control, using the provided
	 * {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm
	 *            the RenderManager that can be used for writing to
	 *            the Render-Output-Buffer
	 * @param {sap.ui.core.Control} oControl
	 *            the control to be rendered
	 */
	DeltaMicroChartRenderer.render = function(oRm, oControl) {

		var sDv1 = oControl.getDisplayValue1();
		var sDv2 = oControl.getDisplayValue2();
		var fVal1 = oControl.getValue1();
		var fVal2 = oControl.getValue2();
		var sDdv = oControl.getDeltaDisplayValue();
		var sAdv1ToShow = sDv1 ? sDv1 : "" + fVal1;
		var sAdv2ToShow = sDv2 ? sDv2 : "" + fVal2;
		var sAddvToShow = sDdv ? sDdv : "" + Math.abs(fVal1 - fVal2).toFixed(Math.max(oControl._digitsAfterDecimalPoint(fVal1), oControl._digitsAfterDecimalPoint(fVal2)));
		var sColor = oControl.getColor();
		var sTooltip = oControl.getTooltip_AsString();
		if (typeof sTooltip !== "string") {
			sTooltip = "";
		}

		var sSize = oControl.getSize();
		var bNoTitles = (!oControl.getTitle1() && !oControl.getTitle2());

		function getDir(bLeft) {
			return bLeft ? "Left" : "Right";
		}

		oRm.write("<div");
		oRm.writeControlData(oControl);
		oRm.addClass("sapSuiteDmc");
			if (oControl.hasListeners("press")) {
			oRm.addClass("sapSuiteUiMicroChartPointer");
			oRm.writeAttribute("tabindex", "0");
		}
		oRm.addClass(sSize);
		oRm.writeAttribute("role", "presentation");
		oRm.writeAttributeEscaped("aria-label", oControl.getAltText().replace(/\s/g, " ") + (sap.ui.Device.browser.firefox ? "" : " " + sTooltip ));
		oRm.writeAttributeEscaped("title", sTooltip);
		oRm.writeClasses();
		if (oControl.getWidth()) {
			oRm.addStyle("width", oControl.getWidth());
			oRm.writeStyles();
		}

		oRm.write(">");
			oRm.write("<div");
			oRm.addClass("sapSuiteDmcCnt");
			oRm.addClass(sSize);
			oRm.writeClasses();
			oRm.write(">");
				oRm.write("<div");
				oRm.writeAttribute("id", oControl.getId() + "-title1");
				oRm.addClass("sapSuiteDmcTitle");
				oRm.addClass("Top");
				oRm.writeClasses();
				oRm.write(">");
					oRm.writeEscaped(oControl.getTitle1());
				oRm.write("</div>");

				oRm.write("<div");
				oRm.addClass("sapSuiteDmcChart");
				oRm.addClass(sSize);
				if (bNoTitles){
					oRm.addClass("NoTitles");
				}
				oRm.writeClasses();
				oRm.writeAttribute("id", oControl.getId() + "-dmc-chart");
				oRm.write(">");
					oRm.write("<div");
					oRm.addClass("sapSuiteDmcBar");
					oRm.addClass("Bar1");
					oRm.addClass(sSize);
					if (oControl._oChartData.delta.isMax) {
						oRm.addClass("MaxDelta");
					}
					if (oControl._oChartData.bar1.isSmaller) {
						oRm.addClass("Smaller");
					}
					oRm.addClass(getDir(oControl._oChartData.bar1.left));
					oRm.writeClasses();
					oRm.addStyle("width", oControl._oChartData.bar1.width + "%");
					oRm.writeStyles();
					oRm.writeAttribute("id", oControl.getId() + "-dmc-bar1");
					oRm.write(">");
						oRm.write("<div");
						oRm.addClass("sapSuiteDmcBarInternal");
						oRm.addClass(getDir(oControl._oChartData.bar2.left));
						oRm.writeClasses();
						oRm.write(">");
						oRm.write("</div>");
					oRm.write("</div>");

					oRm.write("<div");
					oRm.addClass("sapSuiteDmcBar");
					oRm.addClass("Bar2");
					oRm.addClass(sSize);
					if (oControl._oChartData.delta.isMax) {
						oRm.addClass("MaxDelta");
					}
					if (oControl._oChartData.bar2.isSmaller) {
						oRm.addClass("Smaller");
					}
					oRm.addClass(getDir(oControl._oChartData.bar2.left));
					oRm.writeClasses();
					oRm.addStyle("width", oControl._oChartData.bar2.width + "%");
					oRm.writeStyles();
					oRm.writeAttribute("id", oControl.getId() + "-dmc-bar2");
					oRm.write(">");
						oRm.write("<div");
						oRm.addClass("sapSuiteDmcBarInternal");
						oRm.addClass(getDir(oControl._oChartData.bar1.left));
						oRm.writeClasses();
						oRm.write(">");
						oRm.write("</div>");
					oRm.write("</div>");

					oRm.write("<div");
					oRm.addClass("sapSuiteDmcBar");
					oRm.addClass("Delta");
					oRm.addClass(sSize);
					if (!oControl._oChartData.delta.isMax) {
						oRm.addClass("NotMax");
					}
					if (oControl._oChartData.delta.isZero) {
						oRm.addClass("Zero");
					}
					if (oControl._oChartData.delta.isEqual) {
						oRm.addClass("Equal");
					}
					oRm.addClass(getDir(oControl._oChartData.delta.left));
					oRm.writeClasses();
					oRm.addStyle("width", oControl._oChartData.delta.width + "%");
					oRm.writeStyles();
					oRm.writeAttribute("id", oControl.getId() + "-dmc-bar-delta");
					oRm.write(">");
						oRm.write("<div");
						oRm.addClass(sColor);
						oRm.addClass("sapSuiteDmcBarDeltaInt");
						oRm.writeClasses();
						oRm.write(">");
						oRm.write("</div>");

						oRm.write("<div");
						oRm.addClass("sapSuiteDmcBarDeltaStripe");
						oRm.addClass(getDir(true));
						if (oControl._oChartData.delta.isEqual) {
							oRm.addClass("Equal");
						}
						oRm.addClass(oControl._oChartData.delta.isFirstStripeUp ? "Up" : "Down");
						oRm.writeClasses();
						oRm.write(">");
						oRm.write("</div>");

						oRm.write("<div");
						oRm.addClass("sapSuiteDmcBarDeltaStripe");
						oRm.addClass(getDir(false));
						oRm.addClass(oControl._oChartData.delta.isFirstStripeUp ? "Down" : "Up");
						oRm.writeClasses();
						oRm.write(">");
						oRm.write("</div>");
					oRm.write("</div>");

				oRm.write("</div>");

				oRm.write("<div");
				oRm.writeAttribute("id", oControl.getId() + "-title2");
				oRm.addClass("sapSuiteDmcTitle");
				oRm.addClass("Btm");
				oRm.writeClasses();
				oRm.write(">");
					oRm.writeEscaped(oControl.getTitle2());
				oRm.write("</div>");
			oRm.write("</div>");

			oRm.write("<div");
			oRm.addClass("sapSuiteDmcLbls");
			oRm.addClass(sSize);
			oRm.writeClasses();
			oRm.write(">");
				oRm.write("<div");
				oRm.writeAttribute("id", oControl.getId() + "-value1");
				oRm.addClass("sapSuiteDmcValue1");
				oRm.writeClasses();
				oRm.write(">");
					oRm.writeEscaped(sAdv1ToShow);
				oRm.write("</div>");

				oRm.write("<div");
				oRm.writeAttribute("id", oControl.getId() + "-delta");
				oRm.addClass("sapSuiteDmcDelta");
				oRm.addClass(sColor);
				oRm.writeClasses();
				oRm.write(">");
					oRm.writeEscaped(sAddvToShow);
				oRm.write("</div>");

				oRm.write("<div");
				oRm.writeAttribute("id", oControl.getId() + "-value2");
				oRm.addClass("sapSuiteDmcValue2");
				oRm.writeClasses();
				oRm.write(">");
					oRm.writeEscaped(sAdv2ToShow);
				oRm.write("</div>");
			oRm.write("</div>");

			oRm.write("<div");
			oRm.writeAttribute("id", oControl.getId() + "-calc");
			oRm.addClass("sapSuiteDmcCalc");
			oRm.writeClasses();
			oRm.write(">");
				oRm.write("<div");
				oRm.writeAttribute("id", oControl.getId() + "-calc1");
				oRm.addClass("sapSuiteDmcCalc1");
				oRm.writeClasses();
				oRm.write("></div>");
				oRm.write("<div");
				oRm.writeAttribute("id", oControl.getId() + "-calc2");
				oRm.addClass("sapSuiteDmcCalc2");
				oRm.writeClasses();
				oRm.write("></div>");
			oRm.write("</div>");
		oRm.write("</div>");

	};

	return DeltaMicroChartRenderer;

}, /* bExport= */ true);
}; // end of sap/suite/ui/microchart/DeltaMicroChartRenderer.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.HarveyBallMicroChartRenderer') ) {
 /*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

jQuery.sap.declare('sap.suite.ui.microchart.HarveyBallMicroChartRenderer'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
sap.ui.define("sap/suite/ui/microchart/HarveyBallMicroChartRenderer",[],
	function() {
	"use strict";

	/**
	* HarveyBallMicroChartRenderer renderer.
	* @namespace
	*/
	var HarveyBallMicroChartRenderer = {};

	/**
	 * Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the Render - Output - Buffer
	 * @param {sap.ui.core.Control} oControl the control to be rendered
	 */
	HarveyBallMicroChartRenderer.render = function(oRm, oControl) {
		// write the HTML into the render manager

		var bRtl = sap.ui.getCore().getConfiguration().getRTL();
		var sTooltip = oControl.getTooltip_AsString();
		if (typeof sTooltip !== "string") {
			sTooltip = "";
		}
		var sTotalScale = "";
		var sValueLabel = "";
		var sValueScale = "";
		var bFmtLabel = false;
		var fValue = 0;
		var sColor = "";
		var sCpColor = false;
		// support only value from first item
		if (oControl.getItems().length) {
			var oPieItem = oControl.getItems()[0];
			fValue = oPieItem.getFraction();
			sColor = oPieItem.getColor();
			sValueLabel = oPieItem.getFractionLabel() ? oPieItem.getFractionLabel() : sValueLabel + oPieItem.getFraction();
			sValueScale = oPieItem.getFractionScale() ? oPieItem.getFractionScale().substring(0, 3) : sValueScale;
			bFmtLabel = oPieItem.getFormattedLabel();
		}

		if (bFmtLabel) {
			var oFormattedValue = oControl._parseFormattedValue(sValueLabel);

			sValueScale = oFormattedValue.scale.substring(0, 3);
			sValueLabel = oFormattedValue.value;
		}

		var fTotal = oControl.getTotal();
		var sTotalLabel = oControl.getTotalLabel() ? oControl.getTotalLabel() : "" + oControl.getTotal();
		if (oControl.getTotalScale()) {
			sTotalScale = oControl.getTotalScale().substring(0, 3);
		}

		if (oControl.getFormattedLabel()) {
			var oFormattedTotal = oControl._parseFormattedValue(sTotalLabel);
			sTotalScale = oFormattedTotal.scale.substring(0, 3);
			sTotalLabel = oFormattedTotal.value;
		}
		var iTrunc = 5; // truncate values to 5 chars
		if (sValueLabel) {
			sValueLabel = (sValueLabel.length >= iTrunc && (sValueLabel[iTrunc - 1] === "." || sValueLabel[iTrunc - 1] === ","))
					? sValueLabel.substring(0, iTrunc - 1)
					: sValueLabel.substring(0, iTrunc);
		}
		if (sTotalLabel) {
			sTotalLabel = (sTotalLabel.length >= iTrunc && (sTotalLabel[iTrunc - 1] === "." || sTotalLabel[iTrunc - 1] === ","))
					? sTotalLabel.substring(0, iTrunc - 1)
					: sTotalLabel.substring(0, iTrunc);
		}
		if (oControl.getColorPalette().length > 0) {
			sCpColor = oControl.getColorPalette()[0];
		}

		var sSize = oControl.getSize();
		oRm.write("<div");
		oRm.writeControlData(oControl);
		oRm.writeAttributeEscaped("title", sTooltip);
		oRm.addClass("suiteHBMC");
		oRm.addClass(sSize);
		if (oControl.hasListeners("press")) {
			oRm.addClass("sapSuiteUiMicroChartPointer");
			oRm.writeAttribute("tabindex", "0");
		}
		oRm.writeClasses();

		if (oControl.getWidth()) {
			oRm.addStyle("width", oControl.getWidth());
		}
		oRm.writeStyles();

		oRm.write(">");

		oRm.write("<div");
		oRm.addClass("suiteHBMCChartCnt");
		oRm.addClass(sSize);
		oRm.writeClasses();
		oRm.addStyle("display", "inline-block");
		oRm.writeStyles();
		oRm.writeAttribute("role", "presentation");
		oRm.writeAttributeEscaped("aria - label", oControl.getAltText().replace(/\s/g, " ") + (sap.ui.Device.browser.firefox ? "" : " " + sTooltip));

		oRm.write(">");
		oRm.write("<svg");
		oRm.writeAttribute("id", oControl.getId() + "-harvey-ball");
		oRm.writeAttribute("width", oControl._oPath.size);
		oRm.writeAttribute("height", oControl._oPath.size);
		oRm.writeAttribute("focusable", false);
		oRm.write(">");
		oRm.write("<g>");
		oRm.write("<circle");
		oRm.writeAttribute("cx", oControl._oPath.center);
		oRm.writeAttribute("cy", oControl._oPath.center);
		oRm.writeAttribute("r", (sap.ui.getCore().getConfiguration().getTheme() === "sap_hcb")
														? oControl._oPath.center - 1
														: oControl._oPath.center);
		oRm.addClass("suiteHBMCSBall");
		oRm.writeClasses();
		oRm.write("/>");

		if (fValue && fValue >= fTotal) {
			oRm.write("<circle");
			oRm.writeAttribute("cx", oControl._oPath.center);
			oRm.writeAttribute("cy", oControl._oPath.center);
			oRm.writeAttribute("r", oControl._oPath.center - oControl._oPath.border);
			oRm.addClass("suiteHBMCSgmnt");
			oRm.addClass(sColor);
			oRm.writeClasses();

			if (oControl.getColorPalette().length > 0) {
				oRm.addStyle("fill", jQuery.sap.encodeHTML(oControl.getColorPalette()[0]));
				oRm.writeStyles();
			}

			oRm.write("/>");
		} else if (fValue > 0) {
			oRm.write("<path");
			oRm.writeAttribute("id", oControl.getId() + "-segment");
			oRm.addClass("suiteHBMCSgmnt");
			oRm.addClass(sColor);
			oRm.writeClasses();
			oRm.writeAttribute("d", oControl.serializePieChart());

			if (oControl.getColorPalette().length > 0) {
				oRm.addStyle("fill", jQuery.sap.encodeHTML(oControl.getColorPalette()[0]));
				oRm.writeStyles();
			}

			oRm.write("/>");
		}

		oRm.write("</g>");
		oRm.write("</svg>");
		oRm.write("</div>");

		oRm.write("<div");
		oRm.addClass("suiteHBMCValSclCnt");
		oRm.addClass(sSize);
		oRm.addClass(sColor);

		if (sCpColor) {
			oRm.addClass("CP");
		}

		oRm.writeClasses();
		oRm.addStyle("display", oControl.getShowFractions() ? "inline - block" : "none");
		oRm.writeStyles();
		oRm.write(">");
		oRm.write("<p");
		oRm.write(">");
		this.renderLabel(oRm, oControl, [sColor, sSize, "suiteHBMCVal"], sValueLabel, "-fraction");
		this.renderLabel(oRm, oControl, [sColor, sSize, "suiteHBMCValScale"], sValueScale, "-fraction-scale");
		oRm.write("</p>");
		oRm.write("</div>");

		oRm.write("<div");
		oRm.addClass("suiteHBMCTtlSclCnt");
		oRm.addClass(sSize);
		oRm.writeClasses();
		if (bRtl) {
			oRm.addStyle("left", "0");
		} else {
			oRm.addStyle("right", "0");
		}
		oRm.addStyle("display", oControl.getShowTotal() ? "inline-block" : "none");
		oRm.writeStyles();
		oRm.write(">");
		this.renderLabel(oRm, oControl, [sColor, sSize, "suiteHBMCTtl"], sTotalLabel, "-total");
		this.renderLabel(oRm, oControl, [sColor, sSize, "suiteHBMCTtlScale"], sTotalScale, "-total-scale");
		oRm.write("</div>");
		oRm.write("</div>");
	};

	HarveyBallMicroChartRenderer.renderLabel = function(oRm, oControl, aClasses, sLabel, sId) {
		oRm.write("<span");
		oRm.writeAttribute("id", oControl.getId() + sId);
		for (var i = 0; i < aClasses.length; i++) {
			oRm.addClass(aClasses[i]);
		}
		oRm.writeClasses();
		oRm.write(">");
		if (sLabel) {
			oRm.writeEscaped(sLabel);
		}
		oRm.write("</span>");

	};

	return HarveyBallMicroChartRenderer;

}, /* bExport */ true);
}; // end of sap/suite/ui/microchart/HarveyBallMicroChartRenderer.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.RadialMicroChartRenderer') ) {
 /*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

jQuery.sap.declare('sap.suite.ui.microchart.RadialMicroChartRenderer'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/RadialMicroChartRenderer",["jquery.sap.global"],
	function(jQuery) {
	"use strict";

	/**
	* RadialMicroChartRenderer renderer.
	* @namespace
	* @since 1.36.0
	*/
	var RadialMicroChartRenderer = {};

	//Constants
	RadialMicroChartRenderer.FORM_RATIO = 1000; //Form ratio for the control, means the calculation base
	RadialMicroChartRenderer.BACKGROUND_CIRCLE_BORDER_WIDTH = 1;
	RadialMicroChartRenderer.BACKGROUND_CIRCLE_RADIUS = 500; //Calculated by: RadialMicroChartRenderer.FORM_RATIO * 0.5
	RadialMicroChartRenderer.CIRCLE_BORDER_WIDTH = 87.5; //Calculated by: RadialMicroChartRenderer.BACKGROUND_CIRCLE_RADIUS * 0.175<WHEEL_WIDTH_FACTOR>
	RadialMicroChartRenderer.CIRCLE_RADIUS = 441.75; //Calculated by: RadialMicroChartRenderer.BACKGROUND_CIRCLE_RADIUS * (1.0 - 0.029<EXTERNAL_OUTER_BORDER_WIDTH_FACTOR> - 0.175<WHEEL_WIDTH_FACTOR> / 2.0)
	RadialMicroChartRenderer.SVG_VIEWBOX_CENTER_FACTOR = "50%";
	RadialMicroChartRenderer.X_ROTATION = 0;
	RadialMicroChartRenderer.SWEEP_FLAG = 1;
	RadialMicroChartRenderer.NUMBER_FONT_SIZE = 235; //Calculated by: RadialMicroChartRenderer.BACKGROUND_CIRCLE_RADIUS * 0.47<NUMBER_FONT_SIZE_FACTOR>
	RadialMicroChartRenderer.EDGE_CASE_SIZE_ACCESSIBLE_COLOR = 54;
	RadialMicroChartRenderer.EDGE_CASE_SIZE_SHOW_TEXT = 46;
	RadialMicroChartRenderer.EDGE_CASE_SIZE_MICRO_CHART = 24;

	/**
	 * Renders the HTML for the given control, using the provided {@link sap.ui.core.RenderManager}.
	 *
	 * @param {sap.ui.core.RenderManager} oRm the RenderManager that can be used for writing to the Render - Output - Buffer
	 * @param {sap.ui.core.Control} oControl the control to be rendered
	 */
	RadialMicroChartRenderer.render = function(oRm, oControl) {
		// Write the HTML into the render manager
		this._writeDivStartElement(oControl, oRm);
		this._writeSVGStartElement(oRm);
		this._writeBackground(oRm);
		if (this._renderingOfInnerContentIsRequired(oControl)) {
			this._writeBorders(oRm);
			if (this._innerCircleRequired(oControl)) {
				this._writeCircle(oControl, oRm);
			} else {
				this._writeCircleWithPathElements(oControl, oRm);
			}
			this._writeText(oControl, oRm);
		}
		oRm.write("</svg>");
		oRm.write("</div>");
	};

	/* Rendering Write-Helpers */

	/**
	 * Writes the start tag for the surrounding div-element incl. ARIA text and required classes
	 *
	 * @private
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @param {sap.ui.core.RenderManager} oRm the render manager
	 */
	RadialMicroChartRenderer._writeDivStartElement = function(control, oRm) {
		oRm.write("<div");
		oRm.writeControlData(control);
		var sTooltip = control._getTooltipText();
		if (sTooltip) {
			oRm.writeAttributeEscaped("title", sTooltip);
		}
		oRm.writeAttribute("role", "img");
		oRm.writeAttributeEscaped("aria-label", control._getAriaText());
		if (control.hasListeners("press")) {
			oRm.addClass("sapSuiteUiMicroChartPointer");
			oRm.writeAttribute("tabindex", "0");
		}
		oRm.addClass("sapSuiteUiMicroChartRMC");
		oRm.writeClasses();
		oRm.writeStyles();
		oRm.write(">");
	};

	/**
	 * Writes the start tag for the SVG element.
	 *
	 * @private
	 * @param {sap.ui.core.RenderManager} oRm the render manager
	 */
	RadialMicroChartRenderer._writeSVGStartElement = function(oRm) {
		var sPreserveAspectRatio;
		if (!sap.ui.getCore().getConfiguration().getRTL()) {
			sPreserveAspectRatio = "xMaxYMid meet";
		} else {
			sPreserveAspectRatio = "xMinYMid meet";
		}
		oRm.write("<svg width=\"100%\" height=\"100%\" viewBox=\"0 0 " + RadialMicroChartRenderer.FORM_RATIO + ' ' + RadialMicroChartRenderer.FORM_RATIO + "\" preserveAspectRatio=\"" + sPreserveAspectRatio + "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">");
	};

	/**
	 * Writes the background circle.
	 *
	 * @private
	 * @param {sap.ui.core.RenderManager} oRm the render manager
	 */
	RadialMicroChartRenderer._writeBackground = function(oRm) {
		oRm.write("<circle class=\"sapSuiteUiMicroChartRMCCircleBackground\" cx=\"" + RadialMicroChartRenderer.SVG_VIEWBOX_CENTER_FACTOR + "\" cy=\"" + RadialMicroChartRenderer.SVG_VIEWBOX_CENTER_FACTOR + "\" r=\"" + RadialMicroChartRenderer.BACKGROUND_CIRCLE_RADIUS + "\" stroke-width=\"" + this.BACKGROUND_CIRCLE_BORDER_WIDTH + "\" />");
	};

	/**
	 * Writes the Borders, required for HCB.
	 * In case of other themes, they are also available to avoid issues during switching themes.
	 *
	 * @private
	 * @param {sap.ui.core.RenderManager} oRm the render manager
	 */
	RadialMicroChartRenderer._writeBorders = function(oRm) {
		oRm.write("<circle class=\"sapSuiteUiMicroChartRMCHCBIncompleteBorder\" cx=\"" + RadialMicroChartRenderer.SVG_VIEWBOX_CENTER_FACTOR + "\" cy=\"" + RadialMicroChartRenderer.SVG_VIEWBOX_CENTER_FACTOR + "\" r=\"" + (RadialMicroChartRenderer.CIRCLE_RADIUS + RadialMicroChartRenderer.CIRCLE_BORDER_WIDTH / 2.0 - RadialMicroChartRenderer.BACKGROUND_CIRCLE_BORDER_WIDTH ) + "\" stroke-width=\"" + RadialMicroChartRenderer.BACKGROUND_CIRCLE_BORDER_WIDTH + "\" />");
		oRm.write("<circle class=\"sapSuiteUiMicroChartRMCHCBIncompleteBorder\" cx=\"" + RadialMicroChartRenderer.SVG_VIEWBOX_CENTER_FACTOR + "\" cy=\"" + RadialMicroChartRenderer.SVG_VIEWBOX_CENTER_FACTOR + "\" r=\"" + (RadialMicroChartRenderer.CIRCLE_RADIUS - RadialMicroChartRenderer.CIRCLE_BORDER_WIDTH / 2.0 + RadialMicroChartRenderer.BACKGROUND_CIRCLE_BORDER_WIDTH ) + "\" stroke-width=\"" + RadialMicroChartRenderer.BACKGROUND_CIRCLE_BORDER_WIDTH + "\" />");
	};

	/**
	 * Writes the circle element, required for 0% and 100% cases.
	 *
	 * @private
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @param {sap.ui.core.RenderManager} oRm the render manager
	 */
	RadialMicroChartRenderer._writeCircle = function(control, oRm) {
		oRm.write("<circle class=\"" + this._getSVGStringForColor(this._getFullCircleColor(control), control) + "\" cx=\"" + RadialMicroChartRenderer.SVG_VIEWBOX_CENTER_FACTOR + "\" cy=\"" + RadialMicroChartRenderer.SVG_VIEWBOX_CENTER_FACTOR + "\" r=\"" + RadialMicroChartRenderer.CIRCLE_RADIUS + "\" fill=\"transparent\" stroke-width=\"" + RadialMicroChartRenderer.CIRCLE_BORDER_WIDTH + "px\" />");
	};

	/**
	 * Writes the two path elements, required for all cases between 1% and 99%.
	 *
	 * @private
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @param {sap.ui.core.RenderManager} oRm the render manager
	 */
	RadialMicroChartRenderer._writeCircleWithPathElements = function(control, oRm) {
		var iLargeArcFlag = control.getPercentage() > 50 ? 1 : 0;
		var aPathCoordinates = this._calculatePathCoordinates(control);
		this._writePath1(iLargeArcFlag, aPathCoordinates, control, oRm);
		this._writePath2(iLargeArcFlag, aPathCoordinates, control, oRm);
	};

	/**
	 * Writes the first path element for cases between 1% and 99%.
	 *
	 * @private
	 * @param {integer} largeArcFlag for check of smaller or bigger than 180 degrees
	 * @param {float[]} pathCoordinates array containing specific coordinates for the path
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @param {sap.ui.core.RenderManager} oRm the render manager
	 */
	RadialMicroChartRenderer._writePath1 = function(largeArcFlag, pathCoordinates, control, oRm) {
		var sPathData1 = "M" + pathCoordinates[0] + " " + pathCoordinates[1] + " A " + RadialMicroChartRenderer.CIRCLE_RADIUS + " " + RadialMicroChartRenderer.CIRCLE_RADIUS +
		", " + RadialMicroChartRenderer.X_ROTATION + ", " + largeArcFlag + ", " + RadialMicroChartRenderer.SWEEP_FLAG + ", " + pathCoordinates[2] + " " + pathCoordinates[3];

		oRm.write("<path class=\"sapSuiteUiMicroChartRadialMicroChartPath" + this._getSVGStringForColor(this._getPathColor(control), control) + "d=\"" + sPathData1 + "\" fill=\"transparent\" stroke-width=\"" + RadialMicroChartRenderer.CIRCLE_BORDER_WIDTH + "px\" />");
	};

	/**
	 * Writes the second path element for cases between 1% and 99%.
	 *
	 * @private
	 * @param {integer} largeArcFlag for check of smaller or bigger than 180 degrees
	 * @param {float[]} pathCoordinates array containing specific coordinates for the path
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @param {sap.ui.core.RenderManager} oRm the render manager
	 */
	RadialMicroChartRenderer._writePath2 = function(largeArcFlag, pathCoordinates, control, oRm) {
		var sPathData2 = "M" + pathCoordinates[2] + " " + pathCoordinates[3] + " A " + RadialMicroChartRenderer.CIRCLE_RADIUS + " " + RadialMicroChartRenderer.CIRCLE_RADIUS +
		", " + RadialMicroChartRenderer.X_ROTATION + ", " + (1 - largeArcFlag) + ", " + RadialMicroChartRenderer.SWEEP_FLAG + ", " + pathCoordinates[0] + " " + pathCoordinates[1];

		oRm.write("<path class=\"sapSuiteUiMicroChartRadialMicroChartPath sapSuiteUiMicroChartRMCPathIncomplete\" d=\"" + sPathData2 + "\" fill=\"transparent\" stroke-width=\"" + RadialMicroChartRenderer.CIRCLE_BORDER_WIDTH + "px\" />");
	};

	/**
	 * Writes the text content inside the chart.
	 *
	 * @private
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @param {sap.ui.core.RenderManager} oRm the render manager
	 */
	RadialMicroChartRenderer._writeText = function(control, oRm) {
		oRm.write("<text class=\"sapSuiteUiMicroChartRMCFont\" aria-hidden=\"true\" text-anchor=\"middle\" alignment-baseline=\"middle\"" + "\" font-size=\"" + RadialMicroChartRenderer.NUMBER_FONT_SIZE + "\" x=\"" + RadialMicroChartRenderer.SVG_VIEWBOX_CENTER_FACTOR + "\" y=\"" + this._getVerticalViewboxCenterFactorForText() + "\"> " + this._generateTextContent(control) + "</text>");
	};

	/* Helpers */

	/**
	 * Checks if rendering of inner content (circle or path-elements) is required.
	 *
	 * @private
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @returns {boolean} true if rendering is required, false if rendering is not required
	 */
	RadialMicroChartRenderer._renderingOfInnerContentIsRequired = function(control) {
		if (control._getPercentageMode() || (control.getTotal() !== 0)){
			return true;
		} else {
			return false;
		}
	};

	/**
	 * Since the property valueColor can be a CSSColor or ValueColor, we need to add this parameter in different way to the path statement.
	 * For CSSColor, it's added straight to the statement as stroke.
	 * For valueColor it's added as a CSSClass.
	 *
	 * @private
	 * @param {sap.m.ValueColor|sap.ui.core.CSSColor} color of the chart
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @returns {string} value to add to the SVG string
	 */
	RadialMicroChartRenderer._getSVGStringForColor = function(color, control){
		if (control._isValueColorInstanceOfValueColor()) {
			return " " + color + "\"";
		} else if (color === "sapSuiteUiMicroChartRMCPathIncomplete"){
			return " " + color + "\"";
		} else {
			return "\" stroke=\"" + color + "\"";
		}
	};

	/**
	 * Returns the center factor for the text element.
	 * Since browsers interpret the text differently, the constant SVG_VIEWBOX_CENTER_FACTOR can not be used.
	 *
	 * @private
	 * @returns {string} factor for vertical center of text
	 */
	RadialMicroChartRenderer._getVerticalViewboxCenterFactorForText = function() {
		if (sap.ui.Device.browser.msie) {
			return "55%";
		} else if (sap.ui.Device.browser.mozilla) {
			return "56%";
		} else {
			return "51%";
		}
	};

	/**
	 * Checks if the inner circle is required. This is valid for 0% or 100% scenarios.
	 *
	 * @private
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @returns {boolean} true if inner circle has to be rendered, false if inner circle is not required
	 */
	RadialMicroChartRenderer._innerCircleRequired = function(control) {
		if (control.getPercentage() >= 100 || control.getPercentage() <= 0) {
			return true;
		} else {
			return false;
		}
	};

	/**
	 * Generates the coordinates needed for drawing the twho path elements.
	 *
	 * @private
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @returns {float[]} array with calculated coordinates
	 */
	RadialMicroChartRenderer._calculatePathCoordinates = function(control) {
		var fPercentage = this._getPercentageForCircleRendering(control);
		var aCoordinates = [];
		aCoordinates.push(RadialMicroChartRenderer.FORM_RATIO / 2 + RadialMicroChartRenderer.CIRCLE_RADIUS * Math.cos(-Math.PI / 2.0));
		aCoordinates.push(RadialMicroChartRenderer.FORM_RATIO / 2 + RadialMicroChartRenderer.CIRCLE_RADIUS * Math.sin(-Math.PI / 2.0));
		aCoordinates.push(RadialMicroChartRenderer.FORM_RATIO / 2 + RadialMicroChartRenderer.CIRCLE_RADIUS * Math.cos(-Math.PI / 2.0 + fPercentage / 100 * 2 * Math.PI));
		aCoordinates.push(RadialMicroChartRenderer.FORM_RATIO / 2 + RadialMicroChartRenderer.CIRCLE_RADIUS * Math.sin(-Math.PI / 2.0 + fPercentage / 100 * 2 * Math.PI));
		return aCoordinates;
	};

	/**
	 * Generates percentage value for rendering the circle.
	 * For edge cases (99% and 1%) a specific handling is implemented.
	 * For values between 99.0% - 99.9%, 99% will be retrieved to make sure the circle is not completely filled setting thos big values.
	 * For values between 0.1% - 0.9%, 1% will be returned to make sure the circle is not completely empty settings those small values.
	 * This is only used for painting the circle by path elements. For the text area, the value of the percentage property can be used.
	 *
	 * @private
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @returns {float} the calculated percentage value for bar rendering
	 */
	RadialMicroChartRenderer._getPercentageForCircleRendering = function(control) {
		var fPercentage = control.getPercentage();
		var fPercentageForEdgeCases = fPercentage;
		if (fPercentage > 99) {
			fPercentageForEdgeCases = 99;
		}
		if (fPercentage < 1) {
			fPercentageForEdgeCases = 1;
		}
		return fPercentageForEdgeCases;
	};

	/**
	 * Handles the UI specific stuff in onAfterRendering.
	 *
	 * @private
	 * @param {object} control instance of RadialMicroChart
	 */
	RadialMicroChartRenderer._handleOnAfterRendering = function(control) {
		var sParentWidth;
		// Within a Generic Tile max-width was applied instead min-width in Chrome and IE, that's why we forced min-width to be applied in this block.
		if (control.getParent() instanceof sap.m.TileContent) {
			this._adjustToTileContent(control);
		} else {
			//Apply fixed size of parent to make SVG work in all browsers.
			if (control.getParent() !== undefined && control.getParent() !== null &&
					control.getParent().getHeight !== undefined && control.getParent().getHeight !== null) {
				// Two pixels are subtracted from the original value. Otherwise, there's not enough space for the outline and it won't render correctly.
				var sParentHeight = parseFloat(control.getParent().$().height()) - 2;
				control.$().height(sParentHeight); //Required for rendering in page element. Otherwise element is cutted at the top.
				control.$().children("svg").height(sParentHeight);
			}
			if (control.getParent() !== undefined && control.getParent() !== null &&
					control.getParent().getWidth !== undefined && control.getParent().getWidth !== null) {
				// Two pixels are subtracted from the original value. Otherwise, there's not enough space for the outline and it won't render correctly.
				sParentWidth = parseFloat(control.getParent().$().width()) - 2;
				control.$().width(sParentWidth); //Required for rendering in page element. Otherwise element is cutted at the top.
				control.$().children("svg").width(sParentWidth);
			}
		}
		if (parseInt(control.$().children("svg").css("height"), 10) < RadialMicroChartRenderer.EDGE_CASE_SIZE_MICRO_CHART ||
				parseInt(control.$().children("svg").css("width"), 10) < RadialMicroChartRenderer.EDGE_CASE_SIZE_MICRO_CHART) {
			control.$().hide();
			return;
		}
		//Hide text element for small elements (<46px)
		var $text = control.$().find("text");
		if (parseInt(control.$().children("svg").css("height"), 10) <= RadialMicroChartRenderer.EDGE_CASE_SIZE_SHOW_TEXT ||
				parseInt(control.$().children("svg").css("width"), 10) <= RadialMicroChartRenderer.EDGE_CASE_SIZE_SHOW_TEXT) {
			$text.hide();
		} else {
			var sCurrentClass = $text.attr("class"); // Gets all the classes applied to the SVG text element
			if (sCurrentClass) {
				var sTextColorClass = this._getTextColorClass(control); // Gets the correct color
				if (sCurrentClass.indexOf(sTextColorClass) < 0) {
					$text.attr("class", sCurrentClass + " " + sTextColorClass); // Writes a new class attribute with all the other classes and the new correct color
				}
			}
		}
	};
	/**
	 * Performs the necessary adjustments in case of chart located iside of GenericTile.
	 *
	 * @private
	 * @param {object} control instance of RadialMicroChart
	 */
	RadialMicroChartRenderer._adjustToTileContent = function(control) {
		var sParentWidth = control.getParent().$().css("min-width");
		control.getParent().$().width(sParentWidth);
		if (sap.ui.Device.browser.msie || sap.ui.Device.browser.edge) {
			// 16 pixels are removed to compensate the margin and the padding. Needs to be done for IE in case it is rendered only once.
			control.$().width(parseInt(sParentWidth, 10) - 16);
		}
	};
	/**
	 * Returns the text color of the control. Also handles switch for accessibility features.
	 *
	 * @private
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @returns {string} value for CSS Text color class
	 */
	RadialMicroChartRenderer._getTextColorClass = function(control) {
		var iSize = parseInt(jQuery.sap.byId(control.getId()).children("svg").css("height"), 10);
		if (iSize <= RadialMicroChartRenderer.EDGE_CASE_SIZE_ACCESSIBLE_COLOR && (!control._isValueColorInstanceOfValueColor() || control.getValueColor() === sap.m.ValueColor.Neutral)){
			return "sapSuiteUiMicroChartRMCAccessibleTextColor";
		} else {
			switch (control.getValueColor()){
				case sap.m.ValueColor.Good:
					return "sapSuiteUiMicroChartRMCGoodTextColor";
				case sap.m.ValueColor.Error:
					return "sapSuiteUiMicroChartRMCErrorTextColor";
				case sap.m.ValueColor.Critical:
					return "sapSuiteUiMicroChartRMCCriticalTextColor";
				default:
					return "sapSuiteUiMicroChartRMCNeutralTextColor";
			}
		}
	};

	/**
	 * Returns the color for full circles required for 100% or 0% charts.
	 *
	 * @private
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @returns {string} value for full circle CSS color class or css attribute
	 */
	RadialMicroChartRenderer._getFullCircleColor = function(control) {
		if (control.getPercentage() >= 100) {
			return this._getPathColor(control);
		}
		if (control.getPercentage() <= 0) {
			return "sapSuiteUiMicroChartRMCPathIncomplete";
		}
	};

	/**
	 * Gets the CSS class or CSS attribute to apply the right color to the circle path
	 *
	 * @private
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @returns {string} containing the name of the CSS class or the CSS value
	 */
	RadialMicroChartRenderer._getPathColor = function(control) {
		var sValueColor = control.getValueColor();
		if (control._isValueColorInstanceOfValueColor()) {
			switch (sValueColor){
				case sap.m.ValueColor.Good:
					return "sapSuiteUiMicroChartRMCPathGood";
				case sap.m.ValueColor.Error:
					return "sapSuiteUiMicroChartRMCPathError";
				case sap.m.ValueColor.Critical:
					return "sapSuiteUiMicroChartRMCPathCritical";
				default:
					return "sapSuiteUiMicroChartRMCPathNeutral";
			}
		} else {
			return sValueColor;
		}
	};

	/**
	 * Generates the text content of the chart
	 *
	 * @private
	 * @param {sap.suite.ui.microchart.RadialMicroChart} control the current chart control
	 * @returns {string} value for text element in the chart
	 */
	RadialMicroChartRenderer._generateTextContent = function(control) {
		if (control.getPercentage() === 100) {
			return control._rb.getText("RADIALMICROCHART_PERCENTAGE_TEXT", [100]);
		}
		if (control.getPercentage() === 0) {
			return control._rb.getText("RADIALMICROCHART_PERCENTAGE_TEXT", [0]);
		}
		if (control.getPercentage() >= 100) {
			jQuery.sap.log.error("Values over 100%(" + control.getPercentage() + "%) are not supported");
			return control._rb.getText("RADIALMICROCHART_PERCENTAGE_TEXT", [100]);
		}
		if (control.getPercentage() <= 0) {
			jQuery.sap.log.error("Values below 0%(" + control.getPercentage() + "%) are not supported");
			return control._rb.getText("RADIALMICROCHART_PERCENTAGE_TEXT", [0]);
		}
		return control._rb.getText("RADIALMICROCHART_PERCENTAGE_TEXT", [control.getPercentage()]);
	};

	return RadialMicroChartRenderer;
}, /* bExport */ true);
}; // end of sap/suite/ui/microchart/RadialMicroChartRenderer.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.library') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

/**
 * Initialization Code and shared classes of library sap.suite.ui.microchart.
 */
jQuery.sap.declare('sap.suite.ui.microchart.library'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.library'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Core'); // unlisted dependency retained
jQuery.sap.require('sap.m.library'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/library",['jquery.sap.global', 'sap/ui/core/library', 'sap/ui/core/Core', 'sap/m/library'],
	function(jQuery, coreLibrary, Core, mLibrary) {
	"use strict";

	/**
	 * UI5 library: sap.suite.ui.microchart.
	 *
	 * @namespace
	 * @name sap.suite.ui.microchart
	 * @public
	 */

	// delegate further initialization of this library to the Core
	sap.ui.getCore().initLibrary({
		name : "sap.suite.ui.microchart",
		version: "1.36.12",
		// library dependencies
		dependencies : ["sap.ui.core", "sap.m"],
		types: [
			"sap.suite.ui.microchart.AreaMicroChartViewType",
			"sap.suite.ui.microchart.BulletMicroChartModeType",
			"sap.suite.ui.microchart.CommonBackgroundType",
			"sap.suite.ui.microchart.ComparisonMicroChartViewType",
			"sap.suite.ui.microchart.LoadStateType"
		],
		interfaces: [],
		controls: [
			"sap.suite.ui.microchart.AreaMicroChart",
			"sap.suite.ui.microchart.BulletMicroChart",
			"sap.suite.ui.microchart.ColumnMicroChart",
			"sap.suite.ui.microchart.ComparisonMicroChart",
			"sap.suite.ui.microchart.DeltaMicroChart",
			"sap.suite.ui.microchart.HarveyBallMicroChart",
			"sap.suite.ui.microchart.RadialMicroChart"
		],
		elements: [
			"sap.suite.ui.microchart.AreaMicroChartPoint",
			"sap.suite.ui.microchart.AreaMicroChartItem",
			"sap.suite.ui.microchart.AreaMicroChartLabel",
			"sap.suite.ui.microchart.BulletMicroChartData",
			"sap.suite.ui.microchart.ColumnMicroChartData",
			"sap.suite.ui.microchart.ColumnMicroChartLabel",
			"sap.suite.ui.microchart.ComparisonMicroChartData",
			"sap.suite.ui.microchart.HarveyBallMicroChartItem"
		]
	});

	/**
	 * Enum of available views for the area micro chart concerning the position of the labels.
	 *
	 * @enum {string}
	 * @public
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	sap.suite.ui.microchart.AreaMicroChartViewType = {

		/**
		 * The view with labels on the top and bottom.
		 * @public
		 */
		Normal : "Normal",

		/**
		 * The view with labels on the left and right.
		 * @public
		 */
		Wide : "Wide"

	};

	/**
	 * Defines if the horizontal bar represents a current value only or if it represents the delta between a current value and a threshold value.
	 *
	 * @enum {string}
	 * @public
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	sap.suite.ui.microchart.BulletMicroChartModeType = {
		/**
		 * Displays the Actual value.
		 * @public
		 */
		Actual: "Actual",

		/**
		 * Displays delta between the Actual and Threshold values.
		 * @public
		 */
		Delta: "Delta"
	};

	/**
	 * Lists the available theme-specific background colors.
	 *
	 * @enum {string}
	 * @public
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	sap.suite.ui.microchart.CommonBackgroundType = {
		/**
		 * The lightest background color.
		 * @public
		 */
		Lightest: "Lightest",

		/**
		 * Extra light background color.
		 * @public
		 */
		ExtraLight: "ExtraLight",

		/**
		 * Light background color.
		 * @public
		 */
		Light: "Light",

		/**
		 * Medium light background color.
		 * @public
		 */
		MediumLight: "MediumLight",

		/**
		 * Medium background color.
		 * @public
		 */
		Medium: "Medium",

		/**
		 * Dark background color.
		 * @public
		 */
		Dark: "Dark",

		/**
		 * Extra dark background color.
		 * @public
		 */
		ExtraDark: "ExtraDark",

		/**
		 * The darkest background color.
		 * @public
		 */
		Darkest: "Darkest",

		/**
		 * The transparent background color.
		 * @public
		 */
		Transparent: "Transparent"
	};

	/**
	 * Lists the views of the comparison micro chart concerning the position of titles and labels.
	 *
	 * @enum {string}
	 * @public
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	sap.suite.ui.microchart.ComparisonMicroChartViewType = {
		/**
		 * Titles and values are displayed above the bars.
		 * @public
		 */
		Normal: "Normal",

		/**
		 * Titles and values are displayed in the same line with the bars.
		 * @public
		 */
		Wide: "Wide"
	};

	sap.suite.ui.microchart.LoadStateType = {

			/**
			 * LoadableView is loading the control.
			 * @public
			 */
			Loading: "Loading",

			/**
			 * LoadableView has loaded the control.
			 * @public
			 */
			Loaded: "Loaded",

			/**
			 * LoadableView failed to load the control.
			 * @public
			 */
			Failed: "Failed",

			/**
			 * LoadableView disabled to load the control.
			 * @public
			 */
			Disabled: "Disabled"
	};

	return sap.suite.ui.microchart;
});

}; // end of sap/suite/ui/microchart/library.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.AreaMicroChart') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

jQuery.sap.declare('sap.suite.ui.microchart.AreaMicroChart'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Control'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/AreaMicroChart",['jquery.sap.global', './library', 'sap/ui/core/Control'],
	function(jQuery, library, Control) {
	"use strict";

	/**
	 * Constructor for a new AreaMicroChart control.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Chart that displays the history of values and target values as segmented lines and shows thresholds as colored background. This control replaces the deprecated sap.suite.ui.commons.MicroAreaChart.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.AreaMicroChart
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var AreaMicroChart = Control.extend("sap.suite.ui.microchart.AreaMicroChart", /** @lends sap.suite.ui.microchart.AreaMicroChart.prototype */ {
			metadata: {
				library: "sap.suite.ui.microchart",
				properties: {
					/**
					 * The width of the chart.
					 */
					width: {type: "sap.ui.core.CSSSize", group : "Misc", defaultValue : null},

					/**
					 * The height of the chart.
					 */
					height: {type: "sap.ui.core.CSSSize", group : "Misc", defaultValue : null},

					/**
					 * If this property is set it indicates the value X axis ends with.
					 */
					maxXValue: {type: "float", group : "Misc", defaultValue : null},

					/**
					 * If this property is set it indicates the value X axis ends with.
					 */
					minXValue: {type : "float", group : "Misc", defaultValue : null},

					/**
					 * If this property is set it indicates the value X axis ends with.
					 */
					maxYValue: {type: "float", group : "Misc", defaultValue : null},

					/**
					 * If this property is set it indicates the value X axis ends with.
					 */
					minYValue: {type: "float", group : "Misc", defaultValue : null},

					/**
					 * The view of the chart.
					 */
					view: {type: "sap.suite.ui.microchart.AreaMicroChartViewType", group : "Appearance", defaultValue : "Normal"},

					/**
					 * The color palette for the chart. If this property is set,
					 * semantic colors defined in AreaMicroChartItem are ignored.
					 * Colors from the palette are assigned to each line consequentially.
					 * When all the palette colors are used, assignment of the colors begins
					 * from the first palette color.
					 */
					colorPalette: {type: "string[]", group : "Appearance", defaultValue : [] }
				},
				events : {

					/**
					 * The event is fired when the user chooses the micro area chart.
					 */
					press: {}

				},
				aggregations: {
					/**
					 * The configuration of the actual values line.
					 * The color property defines the color of the line.
					 * Points are rendered in the same sequence as in this aggregation.
					 */
					chart: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartItem" },

					/**
					 * The configuration of the max threshold area. The color property defines the color of the area above the max threshold line. Points are rendered in the same sequence as in this aggregation.
					 */
					maxThreshold: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartItem" },

					/**
					 * The configuration of the upper line of the inner threshold area. The color property defines the color of the area between inner thresholds. For rendering of the inner threshold area, both innerMaxThreshold and innerMinThreshold aggregations must be defined. Points are rendered in the same sequence as in this aggregation.
					 */
					innerMaxThreshold: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartItem" },

					/**
					 * The configuration of the bottom line of the inner threshold area. The color property is ignored. For rendering of the inner threshold area, both innerMaxThreshold and innerMinThreshold aggregations must be defined. Points are rendered in the same sequence as in this aggregation.
					 */
					innerMinThreshold: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartItem" },

					/**
					 * The configuration of the min threshold area. The color property defines the color of the area below the min threshold line. Points are rendered in the same sequence as in this aggregation.
					 */
					minThreshold: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartItem" },

					/**
					 * The configuration of the target values line. The color property defines the color of the line. Points are rendered in the same sequence as in this aggregation.
					 */
					target: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartItem" },

					/**
					 * The label on X axis for the first point of the chart.
					 */
					firstXLabel: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartLabel" },

					/**
					 * The label on Y axis for the first point of the chart.
					 */
					firstYLabel: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartLabel" },

					/**
					 * The label on X axis for the last point of the chart.
					 */
					lastXLabel: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartLabel" },

					/**
					 * The label on Y axis for the last point of the chart.
					 */
					lastYLabel: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartLabel" },

					/**
					 * The label for the maximum point of the chart.
					 */
					maxLabel: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartLabel" },

					/**
					 * The label for the minimum point of the chart.
					 */
					minLabel: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartLabel" },

					/**
					 * The set of lines.
					 */
					lines: { multiple: true, type: "sap.suite.ui.microchart.AreaMicroChartItem" }
				}

		}
	});

	AreaMicroChart.prototype.init = function(){
		this._oRb = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.microchart");
		this.setTooltip("{AltText}");
	};

	AreaMicroChart.prototype._getCssValues = function() {
		this._cssHelper.className = Array.prototype.slice.call(arguments).join(" ");
		var oCsses = window.getComputedStyle(this._cssHelper);

		if (oCsses.backgroundColor == undefined) {
			oCsses.backgroundColor = oCsses["background-color"];
		}

		if (oCsses.outlineStyle == undefined) {
			oCsses.outlineStyle = oCsses["outline-style"];
		}

		if (oCsses.outlineWidth == undefined) {
			oCsses.outlineWidth = oCsses["outline-width"];
		}
		return oCsses;
	};

	AreaMicroChart.prototype.__fillThresholdArea = function(c, aPoints1, aPoints2, color) {
		c.beginPath();
		c.moveTo(aPoints1[0].x, aPoints1[0].y);

		for (var i = 1, length = aPoints1.length; i < length; i++) {
			c.lineTo(aPoints1[i].x, aPoints1[i].y);
		}

		for (var j = aPoints2.length - 1; j >= 0 ; j--) {
			c.lineTo(aPoints2[j].x, aPoints2[j].y);
		}

		c.closePath();

		c.fillStyle = "white";
		c.fill();

		c.fillStyle = color;
		c.fill();

		c.lineWidth = 1;
		c.strokeStyle = "white";
		c.stroke();

		c.strokeStyle = color;
		c.stroke();
	};

	AreaMicroChart.prototype._renderDashedLine = function(c, aPoints, d, aDashes) {
		if (c.setLineDash) {
			c.setLineDash(aDashes);
			this._renderLine(c, aPoints, d);
			c.setLineDash([]);
		} else {
			c.beginPath();
			for (var i = 0, length = aPoints.length - 1; i < length; i++) {
				c._dashedLine(aPoints[i].x, aPoints[i].y, aPoints[i + 1].x, aPoints[i + 1].y, aDashes);
			}
			c.stroke();
		}
	};

	AreaMicroChart.prototype._renderLine = function(c, aPoints, d) {
		c.beginPath();
		c.moveTo(aPoints[0].x, aPoints[0].y);

		for (var i = 1, length = aPoints.length; i < length; i++) {
			c.lineTo(aPoints[i].x, aPoints[i].y);
		}

		c.stroke();
	};

	AreaMicroChart.prototype._renderTarget = function(c, d) {
		if (d.target.length > 1) {
			var oCsses = this._getCssValues("sapSuiteAmcTarget", this.getTarget().getColor());
			c.strokeStyle = oCsses.color;
			c.lineWidth = parseFloat(oCsses.width);

			if (oCsses.outlineStyle == "dotted") {
				this._renderDashedLine(c, d.target, d, [parseFloat(oCsses.outlineWidth), 3]);
			} else {
				this._renderLine(c, d.target, d);
			}
		} else if (d.target.length == 1) {
			jQuery.sap.log.warning("Target is not rendered because only 1 point was given");
		}
	};

	AreaMicroChart.prototype._renderThresholdLine = function(c, aPoints, d) {
		if (aPoints && aPoints.length) {
			var oCsses = this._getCssValues("sapSuiteAmcThreshold");

			c.strokeStyle = oCsses.color;
			c.lineWidth = oCsses.width;
			this._renderLine(c, aPoints, d);
		}
	};

	AreaMicroChart.prototype._fillMaxThreshold = function(c, d) {
		if (d.maxThreshold.length > 1) {
			var oCsses = this._getCssValues("sapSuiteAmcThreshold", this.getMaxThreshold().getColor());
			this.__fillThresholdArea(c, d.maxThreshold, [
				{x: d.maxThreshold[0].x, y: d.minY},
				{x: d.maxThreshold[d.maxThreshold.length - 1].x, y: d.minY}
			], oCsses.backgroundColor);
			this._renderThresholdLine(c, d.maxThreshold, d);
		} else if (d.maxThreshold.length == 1) {
			jQuery.sap.log.warning("Max Threshold is not rendered because only 1 point was given");
		}
	};

	AreaMicroChart.prototype._fillMinThreshold = function(c, d) {
		if (d.minThreshold.length > 1) {
			var oCsses = this._getCssValues("sapSuiteAmcThreshold", this.getMinThreshold().getColor());
			this.__fillThresholdArea(c, d.minThreshold, [
				{x: d.minThreshold[0].x, y: d.maxY},
				{x: d.minThreshold[d.minThreshold.length - 1].x, y: d.maxY}
			], oCsses.backgroundColor);
		} else if (d.minThreshold.length == 1) {
			jQuery.sap.log.warning("Min Threshold is not rendered because only 1 point was given");
		}
	};

	AreaMicroChart.prototype._fillThresholdArea = function(c, d) {
		if (d.minThreshold.length > 1 && d.maxThreshold.length > 1) {
			var oCsses = this._getCssValues("sapSuiteAmcThreshold", "Critical");

			this.__fillThresholdArea(c, d.maxThreshold, d.minThreshold, oCsses.backgroundColor);
		}
	};

	AreaMicroChart.prototype._fillInnerThresholdArea = function(c, d) {
		if (d.innerMinThreshold.length > 1 && d.innerMaxThreshold.length > 1) {
			var oCsses = this._getCssValues("sapSuiteAmcThreshold", this.getInnerMaxThreshold().getColor());

			this.__fillThresholdArea(c, d.innerMaxThreshold, d.innerMinThreshold, oCsses.backgroundColor);
		} else if (d.innerMinThreshold.length || d.innerMaxThreshold.length) {
			jQuery.sap.log.warning("Inner threshold area is not rendered because inner min and max threshold were not correctly set");
		}
	};

	AreaMicroChart.prototype._renderChart = function(c, d) {
		if (d.chart.length > 1) {
			var oCsses = this._getCssValues("sapSuiteAmcChart", this.getChart().getColor());
			c.strokeStyle = oCsses.color;
			c.lineWidth = parseFloat(oCsses.width);

			this._renderLine(c, d.chart, d);
		} else if (d.chart.length == 1) {
			jQuery.sap.log.warning("Actual values are not rendered because only 1 point was given");
		}
	};

	AreaMicroChart.prototype._renderLines = function(c, d) {
		var iCpLength = this.getColorPalette().length;
		var iCpIndex = 0;
		var that = this;

		var fnNextColor = function() {
			if (iCpLength) {
				if (iCpIndex == iCpLength) {
					iCpIndex = 0;
				}
				return that.getColorPalette()[iCpIndex++];
			}
		};

		var oCsses = this._getCssValues("sapSuiteAmcLine");
		c.lineWidth = parseFloat(oCsses.width);

		var iLength = d.lines.length;
		for (var i = 0; i < iLength; i++) {
			if (d.lines[i].length > 1) {
				if (iCpLength) {
					c.strokeStyle = fnNextColor();
				} else {
					oCsses = this._getCssValues("sapSuiteAmcLine", this.getLines()[i].getColor());
					c.strokeStyle = oCsses.color;
				}
				this._renderLine(c, d.lines[i], d);
			}
		}
	};

	AreaMicroChart.prototype._renderCanvas = function() {
		this._cssHelper = document.getElementById(this.getId() + "-css-helper");

		var sLabelsWidth = this.$().find(".sapSuiteAmcSideLabels").css("width");
		this.$().find(".sapSuiteAmcCanvas, .sapSuiteAmcLabels").css("right", sLabelsWidth).css("left", sLabelsWidth);

		var canvas = document.getElementById(this.getId() + "-canvas");
		var canvasSettings = window.getComputedStyle(canvas);

		var fWidth = parseFloat(canvasSettings.width);
		canvas.setAttribute("width", fWidth ? fWidth : 360);

		var fHeight = parseFloat(canvasSettings.height);
		canvas.setAttribute("height", fHeight ? fHeight : 242);

		var c = canvas.getContext("2d");

		c.lineJoin = "round";

		c._dashedLine = function(x, y, x2, y2, dashArray) {
			var dashCount = dashArray.length;
			this.moveTo(x, y);
			var dx = (x2 - x), dy = (y2 - y);
			var slope = dx ? dy / dx : 1e15;
			var distRemaining = Math.sqrt(dx * dx + dy * dy);
			var dashIndex = 0, draw = true;
			while (distRemaining >= 0.1) {
				var dashLength = dashArray[dashIndex++ % dashCount];
				if (dashLength > distRemaining) {
					dashLength = distRemaining;
				}
				var xStep = Math.sqrt(dashLength * dashLength / (1 + slope * slope));
				if (dx < 0) {
					xStep = -xStep;
				}
				x += xStep;
				y += slope * xStep;
				this[draw ? 'lineTo' : 'moveTo'](x, y);
				distRemaining -= dashLength;
				draw = !draw;
			}
		};
		var d = this._calculateDimensions(canvas.width, canvas.height);

		this._fillMaxThreshold(c, d);
		this._fillMinThreshold(c, d);
		this._fillThresholdArea(c, d);
		this._renderThresholdLine(c, d.minThreshold, d);
		this._renderThresholdLine(c, d.maxThreshold, d);
		this._fillInnerThresholdArea(c, d);
		this._renderThresholdLine(c, d.innerMinThreshold, d);
		this._renderThresholdLine(c, d.innerMaxThreshold, d);
		this._renderTarget(c, d);
		this._renderChart(c, d);
		this._renderLines(c, d);
	};

	/**
	 *
	 *
	 * @param fWidth
	 * @param fHeight
	 * @returns {object}
	 */
	AreaMicroChart.prototype._calculateDimensions = function(fWidth, fHeight) {
		var maxX, maxY, minX, minY;
		maxX = maxY = minX = minY = undefined;
		var that = this;

		function calculateExtremums() {
			if (!that._isMinXValue || !that._isMaxXValue || !that._isMinYValue || !that._isMaxYValue) {
				var lines = that.getLines();
				if (that.getMaxThreshold()) {
					lines.push(that.getMaxThreshold());
				}

				if (that.getMinThreshold()) {
					lines.push(that.getMinThreshold());
				}

				if (that.getChart()) {
					lines.push(that.getChart());
				}

				if (that.getTarget()) {
					lines.push(that.getTarget());
				}

				if (that.getInnerMaxThreshold()) {
					lines.push(that.getInnerMaxThreshold());
				}

				if (that.getInnerMinThreshold()) {
					lines.push(that.getInnerMinThreshold());
				}

				for (var i = 0, numOfLines = lines.length; i < numOfLines; i++) {
					var aPoints = lines[i].getPoints();

					for (var counter = 0, a = aPoints.length; counter < a; counter++) {
						var tmpVal = aPoints[counter].getXValue();
						if (tmpVal > maxX || maxX === undefined) {
							maxX = tmpVal;
						}
						if (tmpVal < minX || minX === undefined) {
							minX = tmpVal;
						}

						tmpVal = aPoints[counter].getYValue();
						if (tmpVal > maxY || maxY === undefined) {
							maxY = tmpVal;
						}
						if (tmpVal < minY || minY === undefined) {
							minY = tmpVal;
						}
					}
				}
			}
			if (that._isMinXValue) {
				minX = that.getMinXValue();
			}

			if (that._isMaxXValue) {
				maxX = that.getMaxXValue();
			}

			if (that._isMinYValue) {
				minY = that.getMinYValue();
			}

			if (that._isMaxYValue) {
				maxY = that.getMaxYValue();
			}
		}

		calculateExtremums();

		var oResult = {
			minY: 0,
			minX: 0,
			maxY: fHeight,
			maxX: fWidth,
			lines: []
		};

		var kx;
		var fDeltaX = maxX - minX;

		if (fDeltaX > 0) {
			kx = fWidth / fDeltaX;
		} else if (fDeltaX == 0) {
			kx = 0;
			oResult.maxX /= 2;
		} else {
			jQuery.sap.log.warning("Min X is more than max X");
		}

		var ky;
		var fDeltaY = maxY - minY;

		if (fDeltaY > 0) {
			ky = fHeight / (maxY - minY);
		} else if (fDeltaY == 0) {
			ky = 0;
			oResult.maxY /= 2;
		} else {
			jQuery.sap.log.warning("Min Y is more than max Y");
		}

		function calculateCoordinates(line) {
			var bRtl = sap.ui.getCore().getConfiguration().getRTL();

			var fnCalcX = function(fValue) {
				var x = kx * (fValue - minX);

				if (bRtl) {
					x = oResult.maxX - x;
				}
				return x;
			};

			var fnCalcY = function(fValue) {
				return oResult.maxY - ky * (fValue - minY);
			};

			var aResult = [];
			if (line && kx != undefined && ky != undefined) {
				var aPoints = line.getPoints();
				var iLength = aPoints.length;
				var xi, yi, tmpXValue, tmpYValue;

				if (iLength == 1) {
					tmpXValue = aPoints[0].getXValue();
					tmpYValue = aPoints[0].getYValue();

					if (tmpXValue == undefined ^ tmpYValue == undefined) {
						var xn, yn;
						if (tmpXValue == undefined) {
							yn = yi = fnCalcY(tmpYValue);
							xi = oResult.minX;
							xn = oResult.maxX;
						} else {
							xn = xi = fnCalcX(tmpXValue);
							yi = oResult.minY;
							yn = oResult.maxY;
						}

						aResult.push({x: xi, y: yi}, {x: xn, y: yn});
					} else {
						jQuery.sap.log.warning("Point with coordinates [" + tmpXValue + " " + tmpYValue + "] ignored");
					}
				} else {
					for (var i = 0; i < iLength; i++) {
						tmpXValue = aPoints[i].getXValue();
						tmpYValue = aPoints[i].getYValue();

						if (tmpXValue != undefined && tmpYValue != undefined) {
							xi = fnCalcX(tmpXValue);
							yi = fnCalcY(tmpYValue);

							aResult.push({x: xi, y: yi});
						} else {
							jQuery.sap.log.warning("Point with coordinates [" + tmpXValue + " " + tmpYValue + "] ignored");
						}
					}
				}
			}
			return aResult;
		}

		oResult.maxThreshold = calculateCoordinates(that.getMaxThreshold());
		oResult.minThreshold = calculateCoordinates(that.getMinThreshold());
		oResult.chart = calculateCoordinates(that.getChart());
		oResult.target = calculateCoordinates(that.getTarget());
		oResult.innerMaxThreshold = calculateCoordinates(that.getInnerMaxThreshold());
		oResult.innerMinThreshold = calculateCoordinates(that.getInnerMinThreshold());

		var iLength = that.getLines().length;
		for (var i = 0; i < iLength; i++) {
			oResult.lines.push(calculateCoordinates(that.getLines()[i]));
		}
		return oResult;
	};

	/**
	 * Property setter for the Min X value
	 *
	 * @param {int} value - new value Min X
	 * @param {boolean} bSuppressInvalidate - Suppress in validate
	 * @returns {void}
	 * @public
	 */
	AreaMicroChart.prototype.setMinXValue = function(value, bSuppressInvalidate) {
		this._isMinXValue = this._isNumber(value);

		return this.setProperty("minXValue", this._isMinXValue ? value : NaN, bSuppressInvalidate);
	};

	/**
	 * Property setter for the Max X value
	 *
	 * @param {int} value - new value Max X
	 * @param {boolean} bSuppressInvalidate - Suppress in validate
	 * @returns {void}
	 * @public
	 */
	AreaMicroChart.prototype.setMaxXValue = function(value, bSuppressInvalidate) {
		this._isMaxXValue = this._isNumber(value);

		return this.setProperty("maxXValue", this._isMaxXValue ? value : NaN, bSuppressInvalidate);
	};

	/**
	 * Property setter for the Min Y value
	 *
	 * @param {value} value - new value Min Y
	 * @param {boolean} bSuppressInvalidate - Suppress in validate
	 * @returns {void}
	 * @public
	 */
	AreaMicroChart.prototype.setMinYValue = function(value, bSuppressInvalidate) {
		this._isMinYValue = this._isNumber(value);

		return this.setProperty("minYValue", this._isMinYValue ? value : NaN, bSuppressInvalidate);
	};

	/**
	 * Property setter for the Max Y valye
	 *
	 * @param {string} value - new value Max Y
	 * @param {boolean} bSuppressInvalidate - Suppress in validate
	 * @returns {void}
	 * @public
	 */
	AreaMicroChart.prototype.setMaxYValue = function(value, bSuppressInvalidate) {
		this._isMaxYValue = this._isNumber(value);

		return this.setProperty("maxYValue", this._isMaxYValue ? value : NaN, bSuppressInvalidate);
	};

	AreaMicroChart.prototype._isNumber = function(n) {
		return typeof n === 'number' && !isNaN(n) && isFinite(n);
	};

	AreaMicroChart.prototype.onAfterRendering = function() {
		this._renderCanvas();
	};

	AreaMicroChart.prototype.ontap = function(oEvent) {
		if (sap.ui.Device.browser.internet_explorer) {
			this.$().focus();
		}
		this.firePress();
	};

	AreaMicroChart.prototype.onkeydown = function(oEvent) {
		if (oEvent.which == jQuery.sap.KeyCodes.SPACE) {
			oEvent.preventDefault();
		}
	};

	AreaMicroChart.prototype.onkeyup = function(oEvent) {
		if (oEvent.which == jQuery.sap.KeyCodes.ENTER || oEvent.which == jQuery.sap.KeyCodes.SPACE) {
			this.firePress();
			oEvent.preventDefault();
		}
	};

	AreaMicroChart.prototype.attachEvent = function(sEventId, oData, fnFunction, oListener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, sEventId, oData, fnFunction, oListener);

		if (this.hasListeners("press")) {
			this.$().attr("tabindex", 0).addClass("sapSuiteUiMicroChartPointer");
		}

		return this;
	};

	AreaMicroChart.prototype.detachEvent = function(sEventId, fnFunction, oListener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, sEventId, fnFunction, oListener);

		if (!this.hasListeners("press")) {
			this.$().removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	AreaMicroChart.prototype._getLocalizedColorMeaning = function(sColor) {
		return this._oRb.getText(("SEMANTIC_COLOR_" + sColor).toUpperCase());
	};

	AreaMicroChart.prototype.getAltText = function() {
		var sAltText = "";
		var oFirstXLabel = this.getFirstXLabel();
		var oFirstYLabel = this.getFirstYLabel();
		var oLastXLabel = this.getLastXLabel();
		var oLastYLabel = this.getLastYLabel();
		var oMinLabel = this.getMinLabel();
		var oMaxLabel = this.getMaxLabel();
		var oActual = this.getChart();
		var oTarget = this.getTarget();
		var bIsFirst = true;
		if (oFirstXLabel && oFirstXLabel.getLabel() || oFirstYLabel && oFirstYLabel.getLabel()) {
			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("AREAMICROCHART_START")) + ": " + (oFirstXLabel ? oFirstXLabel.getLabel() : "") + " " + (oFirstYLabel ? oFirstYLabel.getLabel()  + " " + this._getLocalizedColorMeaning(oFirstYLabel.getColor()) : "");
			bIsFirst = false;
		}
		if (oLastXLabel && oLastXLabel.getLabel() || oLastYLabel && oLastYLabel.getLabel()) {
			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("AREAMICROCHART_END")) + ": " + (oLastXLabel ? oLastXLabel.getLabel() : "") + " " + (oLastYLabel ? oLastYLabel.getLabel()  + " " + this._getLocalizedColorMeaning(oLastYLabel.getColor()) : "");
			bIsFirst = false;
		}
		if (oMinLabel && oMinLabel.getLabel()) {
			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("AREAMICROCHART_MINIMAL_VALUE")) + ": " + oMinLabel.getLabel() + " " + this._getLocalizedColorMeaning(oMinLabel.getColor());
			bIsFirst = false;
		}
		if (oMaxLabel && oMaxLabel.getLabel()) {
			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("AREAMICROCHART_MAXIMAL_VALUE")) + ": " + oMaxLabel.getLabel() + " " + this._getLocalizedColorMeaning(oMaxLabel.getColor());
			bIsFirst = false;
		}
		if (oActual && oActual.getPoints() && oActual.getPoints().length > 0) {
			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("AREAMICROCHART_ACTUAL_VALUES")) + ":";
			bIsFirst = false;
			var aActual = oActual.getPoints();
			for (var i = 0; i < aActual.length; i++) {
				sAltText += " " + aActual[i].getY();
			}
		}
		if (oTarget && oTarget.getPoints() && oTarget.getPoints().length > 0) {
			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("AREAMICROCHART_TARGET_VALUES")) + ":";
			var aTarget = oTarget.getPoints();
			for (var j = 0; j < aTarget.length; j++) {
				sAltText += " " + aTarget[j].getY();
			}
		}

		for (var k = 0; k < this.getLines().length; k++) {
			var oLine = this.getLines()[k];
			if (oLine.getPoints() && oLine.getPoints().length > 0) {
				sAltText += (bIsFirst ? "" : "\n") + oLine.getTitle() + ":";
				var aLine = oLine.getPoints();
				for (var y = 0; y < aLine.length; y++) {
					sAltText += " " + aLine[y].getY();
				}

				if (this.getColorPalette().length == 0) {
					sAltText += " " + this._getLocalizedColorMeaning(oLine.getColor());
				}
			}
		}
		return sAltText;
	};



	AreaMicroChart.prototype.getTooltip_AsString = function() {
		var oTooltip = this.getTooltip();
		var sTooltip = this.getAltText();

		if (typeof oTooltip === "string" || oTooltip instanceof String) {
			sTooltip = oTooltip.split("{AltText}").join(sTooltip).split("((AltText))").join(sTooltip);
			return sTooltip;
		}
		return oTooltip ? oTooltip : "";
	};

	AreaMicroChart.prototype.clone = function(sIdSuffix, aLocalIds, oOptions) {
		var oClone = sap.ui.core.Control.prototype.clone.apply(this, arguments);
		oClone._isMinXValue = this._isMinXValue;
		oClone._isMaxXValue = this._isMaxXValue;
		oClone._isMinYValue = this._isMinYValue;
		oClone._isMaxYValue = this._isMaxYValue;
		return oClone;
	};
	return AreaMicroChart;

});
}; // end of sap/suite/ui/microchart/AreaMicroChart.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.AreaMicroChartItem') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// This control displays the history of values as a line mini chart or an area mini chart.
jQuery.sap.declare('sap.suite.ui.microchart.AreaMicroChartItem'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Element'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/AreaMicroChartItem",['jquery.sap.global', './library', 'sap/ui/core/Element'],
	function(jQuery, library, Element) {
	"use strict";

	/**
	 * The configuration of the graphic element on the chart.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Graphical representation of the area micro chart regarding the value lines, the thresholds, and the target values.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.AreaMicroChartItem
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var AreaMicroChartItem = Element.extend("sap.suite.ui.microchart.AreaMicroChartItem", /** @lends sap.suite.ui.microchart.AreaMicroChartItem.prototype */ {
			metadata: {
				library: "sap.suite.ui.microchart",
				properties: {
					/**
					 * The graphic element color.
					 */
					color: { group: "Misc", type: "sap.m.ValueColor", defaultValue: "Neutral" },
					
					/**
					 * The line title.
					 */
					title: { type: "string", group: "Misc", defaultValue: null}
				},
				aggregations: {
					
					/**
					 * The set of points for this graphic element.
					 */
					"points": { multiple: true, type: "sap.suite.ui.microchart.AreaMicroChartPoint" }
				}
		}
	});
	
	return AreaMicroChartItem; 
});

}; // end of sap/suite/ui/microchart/AreaMicroChartItem.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.AreaMicroChartLabel') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// This control displays the history of values as a line mini chart or an area mini chart.
jQuery.sap.declare('sap.suite.ui.microchart.AreaMicroChartLabel'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Element'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/AreaMicroChartLabel",['jquery.sap.global', './library', 'sap/ui/core/Element'],
	function(jQuery, library, Element) {
	"use strict";

	/**
	 * Constructor for a new AreaMicroChart control.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Displays or hides the labels for start and end dates, start and end values, and minimum and maximum values.
	 * @extends sap.ui.core.Control
	 *
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.AreaMicroChartLabel
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var AreaMicroChartLabel = Element.extend("sap.suite.ui.microchart.AreaMicroChartLabel", /** @lends sap.suite.ui.microchart.AreaMicroChartLabel.prototype */ {
			metadata : {
				library : "sap.suite.ui.microchart",
				properties : {

					/**
					 * The graphic element color.
					 */
					color: { group: "Misc", type: "sap.m.ValueColor", defaultValue: "Neutral" },

					/**
					 * The line title.
					 */
					label: {type : "string", group : "Misc", defaultValue : "" }
				}
		}
	});
	
	return AreaMicroChartLabel; 
});
}; // end of sap/suite/ui/microchart/AreaMicroChartLabel.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.AreaMicroChartPoint') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// This control displays the history of values as a line mini chart or an area mini chart.
jQuery.sap.declare('sap.suite.ui.microchart.AreaMicroChartPoint'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Element'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/AreaMicroChartPoint",['jquery.sap.global', './library', 'sap/ui/core/Element'],
	function(jQuery, library, Element) {
	"use strict";

	/**
	 * This control contains data for the point.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Contains the data for the point.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.AreaMicroChartPoint
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var AreaMicroChartPoint = Element.extend("sap.suite.ui.microchart.AreaMicroChartPoint", /** @lends sap.suite.ui.microchart.AreaMicroChartPoint.prototype */ {
			metadata : {
				library : "sap.suite.ui.microchart",
				properties : {
					/**
					 * X value for the given point.
					 */
					x: { type : "float", group : "Misc", defaultValue : null },
					
					/**
					 * Y value for the given point.
					 */
					y: { type : "float", group : "Misc", defaultValue : null }
				}
		}
	});

	AreaMicroChartPoint.prototype.setX = function(value, bSuppressInvalidate) {
		this._isXValue = this._isNumber(value);
		
		return this.setProperty("x", this._isXValue ? value : NaN, bSuppressInvalidate);
	};


	AreaMicroChartPoint.prototype.setY = function(value, bSuppressInvalidate) {
		this._isYValue = this._isNumber(value);
		
		return this.setProperty("y", this._isYValue ? value : NaN, bSuppressInvalidate);
	};
	//
	
	/**
	 * Returns the x value. It returns 'undefined', if the x property was not set or an invalid number was set.
	 * 
	 * @public
	 * @returns {string}
	 */
	AreaMicroChartPoint.prototype.getXValue = function() {
		return this._isXValue ? this.getX() : undefined;
	};
	
	/**
	 * Returns the y value. It returns 'undefined', if the y property was not set or an invalid number was set.
	 * 
	 * @public
	 * @returns {float}	
	 */
	AreaMicroChartPoint.prototype.getYValue = function() {
		return this._isYValue ? this.getY() : undefined;
	};
	
	AreaMicroChartPoint.prototype._isNumber = function(n) {
	    return typeof n == 'number' && !isNaN(n) && isFinite(n);
	};

	/**
	 * Overrides Control.clone to clone additional internal state.
	 * 
	 * @param {string} sIdSuffix? a suffix to be appended to the cloned element id
	 * @param {string[]} aLocalIds? an array of local IDs within the cloned hierarchy (internally used)
	 * @param {object} oOptions
	 * @returns {sap.ui.core.Control} reference to the newly created clone
	 */
	AreaMicroChartPoint.prototype.clone = function(sIdSuffix, aLocalIds, oOptions) {
		var oClone = sap.ui.core.Control.prototype.clone.apply(this, arguments);
		oClone._isXValue = this._isXValue;
		oClone._isYValue = this._isYValue;
		return oClone;
	};
	
	return AreaMicroChartPoint; 
});
}; // end of sap/suite/ui/microchart/AreaMicroChartPoint.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.BulletMicroChart') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// Provides control sap.suite.ui.microchart.BulletMicroChart.
jQuery.sap.declare('sap.suite.ui.microchart.BulletMicroChart'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Control'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/BulletMicroChart",['jquery.sap.global', './library', 'sap/ui/core/Control'],
	function(jQuery, library, Control) {
	"use strict";

	/**
	 * Constructor for a new BulletMicroChart control.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Displays a colored horizontal bar representing a current value on top of a background bar representing the compared value. The vertical bars can represent the numeric values, the scaling factors, the thresholds, and the target values.  This control replaces the deprecated sap.suite.ui.commons.BulletChart.
	 * @extends sap.ui.core.Control
	 *
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.BulletMicroChart
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var BulletMicroChart = Control.extend("sap.suite.ui.microchart.BulletMicroChart", /** @lends sap.suite.ui.microchart.BulletMicroChart.prototype */ { metadata : {

		library: "sap.suite.ui.microchart",
		properties: {
			/**
			 * The size of the microchart. If not set, the default size is applied based on the size of the device tile.
			 */
			size: {type: "sap.m.Size", group: "Misc", defaultValue: "Auto"},

			/**
			 * The mode of displaying the actual value itself or the delta between the actual value and the target value. If not set, the actual value is displayed.
			 */
			mode: {type: "sap.suite.ui.microchart.BulletMicroChartModeType", group: "Misc", defaultValue: "Actual"},

			/**
			 * The scaling suffix that is added to the actual and target values.
			 */
			scale: {type: "string", group: "Misc", defaultValue: ""},

			/**
			 * The forecast value that is displayed in Actual  mode only. If set, the forecast value bar appears in the background of the actual value bar.
			 */
			forecastValue: {type: "float", group: "Misc", defaultValue: null},

			/**
			 * The target value that is displayed as a black vertical bar.
			 */
			targetValue: {type: "float", group: "Misc", defaultValue: null},

			/**
			 * The minimum scale value for the bar chart used for defining a fixed size of the scale in different instances of this control.
			 */
			minValue: {type: "float", group: "Misc", defaultValue: null},

			/**
			 * The maximum scale value for the bar chart used for defining a fixed size of the scale in different instances of this control.
			 */
			maxValue: {type: "float", group: "Misc", defaultValue: null},

			/**
			 * If set to true, shows the numeric actual value. This property works in Actual mode only.
			 */
			showActualValue: {type: "boolean", group: "Misc", defaultValue: "true"},

			/**
			 * If set to true, shows the calculated delta value instead of the numeric actual value regardless of the showActualValue setting. This property works in Delta mode only.
			 */
			showDeltaValue: {type: "boolean", group: "Misc", defaultValue: "true"},

			/**
			 * If set to true, shows the numeric target value.
			 */
			showTargetValue: {type: "boolean", group: "Misc", defaultValue: "true"},

			/**
			 * If set to true, shows the value marker.
			 */
			showValueMarker: {type: "boolean", group: "Misc", defaultValue: "false"},

			/**
			 * If set, displays a specified label instead of the numeric actual value.
			 */
			actualValueLabel: {type: "string", group: "Misc", defaultValue: ""},

			/**
			 * If set, displays a specified label instead of the calculated numeric delta value.
			 */
			deltaValueLabel: {type: "string", group: "Misc", defaultValue: ""},

			/**
			 * If set, displays a specified label instead of the numeric target value.
			 */
			targetValueLabel: {type: "string", group: "Misc", defaultValue: ""},

			/**
			 * The width of the chart. If it is not set, the size of the control is defined by the size property.
			 */
			width: {type: "sap.ui.core.CSSSize", group: "Misc"},

			/**
			 * The background color of the scale.
			 */
			scaleColor: {type: "sap.suite.ui.microchart.CommonBackgroundType", group: "Misc", defaultValue: "MediumLight"}
		},
		aggregations: {
			/**
			 * The bullet chart actual data.
			 */
			actual: {type: "sap.suite.ui.microchart.BulletMicroChartData", multiple: false},

			/**
			 * The bullet chart thresholds data.
			 */
			thresholds: {type: "sap.suite.ui.microchart.BulletMicroChartData", multiple: true, singularName: "threshold"}
		},
		events: {
			/**
			 * The event is fired when the user chooses the bullet microchart.
			 */
			press : {}
		}
	}});

	BulletMicroChart.prototype.init = function() {
		this._oRb = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.microchart");
		this.setTooltip("{AltText}");
	};

	/**
	 * Calculates the width in percents of chart elements in accordance with provided chart values.
	 *
	 * @returns {Object} object that contains calculated values for actual value, target value, thresholds and their colors.
	 * @private
	 */
	BulletMicroChart.prototype._calculateChartData = function() {
		var fScaleWidthPct = 98;
		var aData = this.getThresholds();
		var aThresholds = [];
		var fTarget = this.getTargetValue();
		var fForecast = this.getForecastValue();
		var fActual = this.getActual() && this.getActual().getValue() ? this.getActual().getValue() : 0;
		var aValues = [];
		var fLowestValue = 0;
		var fHighestValue = 0;

		if (this.getActual() && this.getActual()._isValueSet) {
			aValues.push(fActual);
		}

		if (this._isForecastValueSet) {
			aValues.push(fForecast);
		}

		if (this._isTargetValueSet) {
			aValues.push(fTarget);
		}

		if (this._isMinValueSet) {
			aValues.push(this.getMinValue());
		}

		if (this._isMaxValueSet) {
			aValues.push(this.getMaxValue());
		}

		for (var iData = 0; iData < aData.length; iData++) {
			aValues.push(aData[iData].getValue());
		}

		var fTotal = 0;

		if (aValues.length > 0) {
			fLowestValue = fHighestValue = aValues[0];
			for (var j = 0; j < aValues.length; j++){
				if (aValues[j] < fLowestValue) {
					fLowestValue = aValues[j];
				}
				if (aValues[j] > fHighestValue) {
					fHighestValue = aValues[j];
				}
			}

			fHighestValue = (fHighestValue < 0 && fHighestValue < 3 * (fLowestValue - fHighestValue)) ? 0 : fHighestValue;
			fLowestValue = (fLowestValue > 0 && fLowestValue > 3 * (fHighestValue - fLowestValue)) ? 0 : fLowestValue;

			fTotal = fHighestValue - fLowestValue;

			for (var iThr = 0; iThr < aData.length; iThr++) {
				aThresholds[iThr] = {color: aData[iThr].getColor(), valuePct: (!aData[iThr]._isValueSet || fTotal == 0) ? 0 : ((aData[iThr].getValue() - fLowestValue) * fScaleWidthPct / fTotal).toFixed(2)};
			}
		}

		return {
			actualValuePct: (!this.getActual() || !this.getActual()._isValueSet || fTotal == 0) ? 0 : (0.05 + (fActual - fLowestValue) * fScaleWidthPct / fTotal).toFixed(2),
			targetValuePct: (!this._isTargetValueSet || fTotal == 0) ? 0 : ((fTarget - fLowestValue) * fScaleWidthPct / fTotal).toFixed(2),
			forecastValuePct: (!this._isForecastValueSet || fTotal == 0) ? 0 : ((fForecast - fLowestValue) * fScaleWidthPct / fTotal).toFixed(2),
			thresholdsPct: aThresholds,
			fScaleWidthPct: fScaleWidthPct
		};
	};

	/**
	 * Calculates the number of digits after the decimal point.
	 *
	 * @param {float} fValue float value
	 * @returns {int} number of digits after the decimal point in fValue.
	 * @private
	 */
	BulletMicroChart.prototype._digitsAfterDecimalPoint = function(fValue) {
		var sAfter = ("" + fValue).match(/[.,](\d+)/g);
		return (sAfter) ? ("" + sAfter).length - 1 : 0;
	};

	/**
	 * Calculates the delta between actual value and threshold.
	 *
	 * @returns {float} value of delta between actual value and threshold.
	 * @private
	 */
	BulletMicroChart.prototype._calculateDeltaValue = function() {
		if (!this.getActual()._isValueSet || !this._isTargetValueSet) {
			return 0;
		} else {
			var fActual = this.getActual().getValue();
			var fTarget = this.getTargetValue();
			return Math.abs(fActual - fTarget).toFixed(Math.max(this._digitsAfterDecimalPoint(fActual), this._digitsAfterDecimalPoint(fTarget)));
		}
	};


	BulletMicroChart.prototype.setMinValue = function(fMinValue, bSuppressInvalidate) {
		this._isMinValueSet = this._fnIsNumber(fMinValue);
		return this.setProperty("minValue", this._isMinValueSet ? fMinValue : NaN, bSuppressInvalidate);
	};


	BulletMicroChart.prototype.setMaxValue = function(fMaxValue, bSuppressInvalidate) {
		this._isMaxValueSet = this._fnIsNumber(fMaxValue);
		return this.setProperty("maxValue", this._isMaxValueSet ? fMaxValue : NaN, bSuppressInvalidate);
	};


	BulletMicroChart.prototype.setTargetValue = function(fTargetValue, bSuppressInvalidate) {
		this._isTargetValueSet = this._fnIsNumber(fTargetValue);
		return this.setProperty("targetValue", this._isTargetValueSet ? fTargetValue : NaN, bSuppressInvalidate);
	};


	BulletMicroChart.prototype.setForecastValue = function(fForecastValue, bSuppressInvalidate) {
		this._isForecastValueSet = this._fnIsNumber(fForecastValue);
		return this.setProperty("forecastValue", this._isForecastValueSet ? fForecastValue : NaN, bSuppressInvalidate);
	};

	BulletMicroChart.prototype.ontap = function(oEvent) {
		if (sap.ui.Device.browser.internet_explorer) {
			this.$().focus();
		}
		this.firePress();
	};

	BulletMicroChart.prototype.onkeydown = function(oEvent) {
		if (oEvent.which == jQuery.sap.KeyCodes.SPACE) {
			oEvent.preventDefault();
		}
	};

	BulletMicroChart.prototype.onkeyup = function(oEvent) {
		if (oEvent.which == jQuery.sap.KeyCodes.ENTER || oEvent.which == jQuery.sap.KeyCodes.SPACE) {
			this.firePress();
			oEvent.preventDefault();
		}
	};

	BulletMicroChart.prototype._fnIsNumber = function(n) {
		return typeof n == 'number' && !isNaN(n) && isFinite(n);
	};

	BulletMicroChart.prototype.attachEvent = function(sEventId, oData, fnFunction, oListener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, sEventId, oData, fnFunction, oListener);
		if (this.hasListeners("press")) {
			this.$().attr("tabindex", 0).addClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	BulletMicroChart.prototype.detachEvent = function(sEventId, fnFunction, oListener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, sEventId, fnFunction, oListener);
		if (!this.hasListeners("press")) {
			this.$().removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	BulletMicroChart.prototype.onAfterRendering = function() {
		if (this._sBarResizeHandlerId) {
			sap.ui.core.ResizeHandler.deregister(this._sBarResizeHandlerId);
		}

		var oHeader = jQuery.sap.domById(this.getId() + "-chart-bar");
		this._sBarResizeHandlerId = sap.ui.core.ResizeHandler.register(oHeader,  jQuery.proxy(this._adjustLabelsPos, this));
		this._adjustLabelsPos();
		if (this.getShowValueMarker()) {
			this._adjustValueToMarker();
		}
	};

	BulletMicroChart.prototype.exit = function() {
		sap.ui.core.ResizeHandler.deregister(this._sBarResizeHandlerId);
	};

	BulletMicroChart.prototype._adjustLabelsPos = function() {
		var bRtl = sap.ui.getCore().getConfiguration().getRTL();
		var oTBarVal = jQuery.sap.byId(this.getId() + "-bc-target-bar-value");
		var oChartBar = jQuery.sap.byId(this.getId() + "-chart-bar");
		var fFullWidth = oChartBar.width();

		if (fFullWidth) {
			var fTValWidth = 0;
			if (oTBarVal && oTBarVal.offset()) {
				fTValWidth = oTBarVal.offset().left - oChartBar.offset().left;
				if (bRtl) {
					fTValWidth = fFullWidth - fTValWidth;
				}
				this._adjustLabelPos(jQuery.sap.byId(this.getId() + "-bc-target-value"), fFullWidth, fTValWidth, bRtl);
			}

			var oValMarker = jQuery.sap.byId(this.getId() + "-bc-bar-value-marker");
			if (oValMarker && oValMarker.offset()) {
				var fAValWidth = oValMarker.offset().left - oChartBar.offset().left;
				if (bRtl) {
					fAValWidth = fFullWidth - fAValWidth;
				}

				if ((sap.suite.ui.microchart.BulletMicroChartModeType.Delta == this.getMode())) {
					fAValWidth = (fAValWidth + fTValWidth) / 2;
				}

				this._adjustLabelPos(jQuery.sap.byId(this.getId() + "-bc-item-value"), fFullWidth, fAValWidth, bRtl);
			}
		}
	};

	BulletMicroChart.prototype._adjustLabelPos = function(oLabel, fFullWidth, fOffset, bRtl) {
		var sOrientation = bRtl ? "right" : "left";
		var fLabelWidth = oLabel.width();
		if (fLabelWidth > fFullWidth) {
			oLabel.css("width", "" + fFullWidth + "px");
			oLabel.css(sOrientation, "0");
		} else {
			var fLabelLeft = fOffset - 0.5 * fLabelWidth;
			if (fLabelLeft < 0) {
				fLabelLeft = 0;
			}

			if (fLabelLeft + fLabelWidth > fFullWidth) {
				fLabelLeft = fFullWidth - fLabelWidth;
			}
			oLabel.css(sOrientation, fLabelLeft);
			oLabel.css("width", "" + (parseInt(fLabelWidth, 10) + 1) + "px");
		}
	};

	BulletMicroChart.prototype._adjustValueToMarker = function() {
		var oValue = jQuery.sap.byId(this.getId() + "-bc-bar-value");
		var oMarker = jQuery.sap.byId(this.getId() + "-bc-bar-value-marker");
		if (oValue.offset() && oMarker.offset()) {
			var fValueWidth = oValue.width();
			var fValueLeft = oValue.offset().left;
			var fMarkerWidth = oMarker.width();
			var fMarkerLeft = oMarker.offset().left;

			if (sap.ui.getCore().getConfiguration().getRTL()) {
				if (fMarkerLeft < fValueLeft) { // browser's subpixel problem fix
					oMarker.css("right", "");
					oMarker.offset({left: fValueLeft});
				}
				if (fMarkerLeft + fMarkerWidth > fValueLeft + fValueWidth) { // bar value is less than marker min-width
					oMarker.css("right", "");
					oMarker.offset({left: fValueLeft + fValueWidth - fMarkerWidth});
				}
			} else {
				if (fMarkerLeft < fValueLeft) { // bar value is less than marker min-width
					oMarker.offset({left: fValueLeft});
				}
				if (fMarkerLeft + fMarkerWidth > fValueLeft + fValueWidth) { // browser's subpixel problem fix
					oValue.width(fMarkerLeft + fMarkerWidth - fValueLeft);
				}
			}
		}
	};

	BulletMicroChart.prototype._getLocalizedColorMeaning = function(sColor) {
		return this._oRb.getText(("SEMANTIC_COLOR_" + sColor).toUpperCase());
	};

	BulletMicroChart.prototype.getAltText = function() {
		var bIsActualSet = this.getActual() && this.getActual()._isValueSet;
		var sScale = this.getScale();
		var sTargetValueLabel = this.getTargetValueLabel();
		var sMeaning = !this.getActual() || !this.getActual().getColor() ? "" : this._getLocalizedColorMeaning(this.getActual().getColor());

		var sAltText = "";

		if (bIsActualSet) {
			var sActualValueLabel = this.getActualValueLabel();
			var sAValToShow = (sActualValueLabel) ? sActualValueLabel : "" + this.getActual().getValue();
			sAltText += this._oRb.getText("BULLETMICROCHART_ACTUAL_TOOLTIP", [sAValToShow + sScale, sMeaning]);
		}
		if (this.getMode() == "Delta") {
			if (this._isTargetValueSet && bIsActualSet) {
				var sDeltaValueLabel = this.getDeltaValueLabel();
				var sDValToShow = (sDeltaValueLabel) ? sDeltaValueLabel : "" + this._calculateDeltaValue();
				sAltText += "\n" + this._oRb.getText("BULLETMICROCHART_DELTA_TOOLTIP", [sDValToShow + sScale, sMeaning]);
			}
		} else {
			if (this._isForecastValueSet) {
				sAltText += (this._isForecastValueSet) ? "\n" + this._oRb.getText("BULLETMICROCHART_FORECAST_TOOLTIP", [this.getForecastValue() + sScale, sMeaning]) : "";
			}
		}

		if (this._isTargetValueSet) {
			var sTValToShow = (sTargetValueLabel) ? sTargetValueLabel : "" + this.getTargetValue();
			sAltText += "\n" + this._oRb.getText("BULLETMICROCHART_TARGET_TOOLTIP", [sTValToShow + sScale]);
		}

		var aThresholds = this.getThresholds().sort(function(oFirst, oSecond) { return oFirst.getValue() - oSecond.getValue(); });

		for (var i = 0; i < aThresholds.length; i++) {
			var oThreshold = aThresholds[i];
			sAltText += "\n" + this._oRb.getText("BULLETMICROCHART_THRESHOLD_TOOLTIP", [oThreshold.getValue() + this.getScale(), this._getLocalizedColorMeaning(oThreshold.getColor())]);
		}

		return sAltText;
	};

	BulletMicroChart.prototype.getTooltip_AsString = function() {
		var oTooltip = this.getTooltip();
		var sTooltip = this.getAltText();

		if (typeof oTooltip === "string" || oTooltip instanceof String) {
			sTooltip = oTooltip.split("{AltText}").join(sTooltip).split("((AltText))").join(sTooltip);
			return sTooltip;
		}
		return oTooltip ? oTooltip : "";
	};

	BulletMicroChart.prototype.clone = function(sIdSuffix, aLocalIds, oOptions) {
		var oClone = sap.ui.core.Control.prototype.clone.apply(this, arguments);
		oClone._isMinValueSet = this._isMinValueSet;
		oClone._isMaxValueSet = this._isMaxValueSet;
		oClone._isForecastValueSet = this._isForecastValueSet;
		oClone._isTargetValueSet = this._isTargetValueSet;
		return oClone;
	};

	return BulletMicroChart;
});

}; // end of sap/suite/ui/microchart/BulletMicroChart.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.BulletMicroChartData') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// Provides control sap.suite.ui.microchart.BulletMicroChartData.
jQuery.sap.declare('sap.suite.ui.microchart.BulletMicroChartData'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Element'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/BulletMicroChartData",['jquery.sap.global', './library', 'sap/ui/core/Element'],
	function(jQuery, library, Element) {
	"use strict";

	/**
	 * Constructor for a new BulletMicroChartData.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Contains the thresholds data.
	 * @extends sap.ui.core.Element
	 *
	 * @version 1.36.12
	 *
	 * @constructor
	 * @public
	 * @alias sap.suite.ui.microchart.BulletMicroChartData
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var BulletMicroChartData = Element.extend("sap.suite.ui.microchart.BulletMicroChartData", /** @lends sap.suite.ui.microchart.BulletMicroChartData.prototype */ { metadata : {
		library: "sap.suite.ui.microchart",
		properties: {
			/**
			 * The actual value.
			 */
			value: {type: "float", group: "Misc", defaultValue: "0"},

			/**
			 * The semantic color of the actual value.
			 */
			color: {type: "sap.m.ValueColor", group: "Misc", defaultValue: "Neutral"}
		}
	}});
	
	
	BulletMicroChartData.prototype.setValue = function(fValue, bSuppressInvalidate) {
		this._isValueSet = this._fnIsNumber(fValue);
		return this.setProperty("value", this._isValueSet ? fValue : NaN, bSuppressInvalidate);
	};
	
	BulletMicroChartData.prototype._fnIsNumber = function(n) {
		return typeof n == 'number' && !isNaN(n) && isFinite(n);
	};
	
	BulletMicroChartData.prototype.clone = function(sIdSuffix, aLocalIds, oOptions) {
		var oClone = sap.ui.core.Control.prototype.clone.apply(this, arguments);
		oClone._isValueSet = this._isValueSet;
		return oClone;
	};
	
	return BulletMicroChartData;

});
}; // end of sap/suite/ui/microchart/BulletMicroChartData.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.ColumnMicroChart') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// Provides control sap.suite.ui.microchart.Example.
jQuery.sap.declare('sap.suite.ui.microchart.ColumnMicroChart'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Control'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/ColumnMicroChart",['jquery.sap.global', './library', 'sap/ui/core/Control'],
	function(jQuery, library, Control) {
	"use strict";

	/**
	 * Constructor for a new ColumnMicroChart control.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Compares different values which are represented as vertical bars. This control replaces the deprecated sap.suite.ui.commons.ColumnMicroChart.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.ColumnMicroChart
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var ColumnMicroChart = Control.extend("sap.suite.ui.microchart.ColumnMicroChart", /** @lends sap.suite.ui.microchart.ColumnMicroChart.prototype */ {
		metadata: {
			library: "sap.suite.ui.microchart",
			properties: {
				/**
				 * Updates the size of the chart. If not set then the default size is applied based on the device tile.
				 */
				size: {group: "Misc", type: "sap.m.Size", defaultValue: "Auto"},

				/**
				 * The width of the chart. If it is not set, the width of the control is defined by the size property.
				 */
				width: {group: "Misc", type: "sap.ui.core.CSSSize"},

				/**
				 * The height of the chart. If it is not set, the height of the control is defined by the size property.
				 */
				height: {group: "Misc", type: "sap.ui.core.CSSSize"}
			},

			events : {

				/**
				 * The event is fired when the user chooses the column chart.
				 */
				press : {}
			},
			aggregations: {

				/**
				 * The column chart data.
				 */
				columns: { multiple: true, type: "sap.suite.ui.microchart.ColumnMicroChartData", defaultValue : null},

				/**
				 * The label on the left top corner of the chart.
				 */
				leftTopLabel: {  multiple: false, type: "sap.suite.ui.microchart.ColumnMicroChartLabel", defaultValue : null},

				/**
				 * The label on the right top corner of the chart.
				 */
				rightTopLabel: { multiple: false, type: "sap.suite.ui.microchart.ColumnMicroChartLabel", defaultValue : null},

				/**
				 * The label on the left bottom corner of the chart.
				 */
				leftBottomLabel: { multiple: false, type: "sap.suite.ui.microchart.ColumnMicroChartLabel", defaultValue: null},

				/**
				 * The label on the right bottom corner of the chart.
				 */
				rightBottomLabel: { multiple: false, type: "sap.suite.ui.microchart.ColumnMicroChartLabel", defaultValue : null}
			}
		}
	});

	ColumnMicroChart.prototype.init = function(){
		this._oRb = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.microchart");
		this.setTooltip("{AltText}");
	};

	ColumnMicroChart.prototype.onAfterRendering = function() {
		if (this._sChartResizeHandlerId) {
			sap.ui.core.ResizeHandler.deregister(this._sChartResizeHandlerId);
		}

	    this._sChartResizeHandlerId = sap.ui.core.ResizeHandler.register(jQuery.sap.domById(this.getId()),  jQuery.proxy(this._calcColumns, this));
		this._fChartWidth = undefined;
		this._fChartHeight = undefined;
		this._aBars = [];

		var iColumnsNum = this.getColumns().length;
		for (var i = 0; i < iColumnsNum; i++) {
			this._aBars.push({});
		}

		this._calcColumns();
	};

	ColumnMicroChart.prototype.exit = function() {
		sap.ui.core.ResizeHandler.deregister(this._sChartResizeHandlerId);
	};

	ColumnMicroChart.prototype._calcColumns = function() {
		var iColumnsNum = this.getColumns().length;
		if (iColumnsNum) {
			var fChartWidth = parseFloat(this.$().css("width"));
			if (fChartWidth != this._fChartWidth) {
				this._fChartWidth = fChartWidth;

				var iColumnMargin = 0;
				var oBar;
				if (iColumnsNum > 1) {
					oBar = jQuery.sap.byId(this.getId() + "-bar-1");
					var bRtl = sap.ui.getCore().getConfiguration().getRTL();
					iColumnMargin = parseInt(oBar.css("margin-" + (bRtl ? "right" : "left")), 10);
				} else {
					oBar = jQuery.sap.byId(this.getId() + "-bar-0");
				}

				var iColumMinWidth = parseInt(oBar.css("min-width"), 10);

				this._calcColumnsWidth(iColumnMargin, iColumMinWidth, fChartWidth, this._aBars);
			}

			var fChartHeight = parseFloat(this.$().css("height"));
			if (fChartHeight != this._fChartHeight) {
				this._fChartHeight = fChartHeight;
				this._calcColumnsHeight(fChartHeight, this._aBars);
			}

			for (var i = 0; i < iColumnsNum; i++) {
				jQuery.sap.byId(this.getId() + "-bar-" + i).css(this._aBars[i]);
			}

			if (this._aBars.overflow) {
				jQuery.sap.log.warning(this.toString() + " Chart overflow",  "Some columns were not rendered");
			}
		}
	};

	ColumnMicroChart.prototype._calcColumnsWidth = function(iColumnMargin, iColumMinWidth, fChartWidth, aBars) {
		var iColumnsNum = this.getColumns().length;
		var iVisibleColumnsNum = Math.floor((fChartWidth + iColumnMargin) / (iColumMinWidth + iColumnMargin));
		var iColumnWidth = Math.floor((fChartWidth + iColumnMargin) / Math.min(iVisibleColumnsNum, iColumnsNum)) - iColumnMargin;

		var sColumnWidth = iColumnWidth + "px";

		for (var i = 0; i < iColumnsNum; i++) {
			if (i < iVisibleColumnsNum) {
				aBars[i].width = sColumnWidth;
				aBars[i].display = "inline-block";
			} else {
				aBars[i].display = "none";
			}
		}

		aBars.overflow = iVisibleColumnsNum != iColumnsNum;
	};

	ColumnMicroChart.prototype._calcColumnsHeight = function(fChartHeight, aBars) {
		var iClmnsNum = this.getColumns().length;

		var fMaxVal, fMinVal, fValue;
		fMaxVal = fMinVal = 0;

		for (var i = 0; i < iClmnsNum; i++) {
			var oClmn = this.getColumns()[i];
			if (fMaxVal < oClmn.getValue()) {
				fMaxVal = oClmn.getValue();
			} else if (fMinVal > oClmn.getValue()) {
				fMinVal = oClmn.getValue();
			}
		}

		var fDelta = fMaxVal - fMinVal;
		var fOnePxVal = fDelta / fChartHeight;

		var fDownShift, fTopShift;
		fDownShift = fTopShift = 0;

		for (var iCl = 0; iCl < iClmnsNum; iCl++) {
			fValue = this.getColumns()[iCl].getValue();

			if (Math.abs(fValue) < fOnePxVal) {
				if (fValue >= 0) {
					if (fValue == fMaxVal) {
						fTopShift = fOnePxVal - fValue;
					}
				} else if (fValue == fMinVal) {
					fDownShift = fOnePxVal + fValue;
				}
			}
		}

		if (fTopShift) {
			fMaxVal += fTopShift;
			fMinVal -= fTopShift;
		}

		if (fDownShift) {
			fMaxVal -= fDownShift;
			fMinVal += fDownShift;
		}

		var fNegativeOnePxVal =  0 - fOnePxVal;

		for (var iClmn = 0; iClmn < iClmnsNum; iClmn++) {
			fValue = this.getColumns()[iClmn].getValue();
			var fCalcVal = fValue;

			if (fValue >= 0) {
				fCalcVal = Math.max(fCalcVal + fTopShift - fDownShift, fOnePxVal);
			} else {
				fCalcVal = Math.min(fCalcVal + fTopShift - fDownShift, fNegativeOnePxVal);
			}

			aBars[iClmn].value = fCalcVal;
		}

		function calcPersent(fValue) {
			return (fValue / fDelta * 100).toFixed(2) + "%";
		}

		var fZeroLine = calcPersent(fMaxVal);

		for (var iCol = 0; iCol < iClmnsNum; iCol++) {
			fValue = aBars[iCol].value;
			aBars[iCol].top = (fValue < 0) ? fZeroLine : calcPersent(fMaxVal - fValue);
			aBars[iCol].height = calcPersent(Math.abs(fValue));
		}
	};

	ColumnMicroChart.prototype.attachEvent = function(sEventId, oData, fnFunction, oListener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, sEventId, oData, fnFunction, oListener);
		if (this.hasListeners("press")) {
			this.$().attr("tabindex", 0).addClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	ColumnMicroChart.prototype.detachEvent = function(sEventId, fnFunction, oListener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, sEventId, fnFunction, oListener);
		if (!this.hasListeners("press")) {
			this.$().removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	ColumnMicroChart.prototype.getLocalizedColorMeaning = function(sColor) {
		if (sColor) {
			return this._oRb.getText(("SEMANTIC_COLOR_" + sColor).toUpperCase());
		}
	};

	ColumnMicroChart.prototype.getAltText = function() {
		var sAltText = "";
		var bIsFirst = true;
		var oLeftTopLabel = this.getLeftTopLabel();
		var oRightTopLabel = this.getRightTopLabel();
		var oLeftBtmLabel = this.getLeftBottomLabel();
		var oRightBtmLabel = this.getRightBottomLabel();

		var sColor;

		if (oLeftTopLabel && oLeftTopLabel.getLabel() || oLeftBtmLabel && oLeftBtmLabel.getLabel()) {
			if (oLeftTopLabel) {
				sColor = oLeftTopLabel.getColor();
			} else if (oLeftBtmLabel){
				sColor = oLeftBtmLabel.getColor();
			} else {
				sColor = "";
			}

			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("COLUMNMICROCHART_START")) + ": " + (oLeftBtmLabel ? oLeftBtmLabel.getLabel() + " " : "")
				+ (oLeftTopLabel ? oLeftTopLabel.getLabel() + " " : "") + this.getLocalizedColorMeaning(sColor);
			bIsFirst = false;
		}

		if (oRightTopLabel && oRightTopLabel.getLabel() || oRightBtmLabel && oRightBtmLabel.getLabel()) {
			if (oRightTopLabel) {
				sColor = oRightTopLabel.getColor();
			} else if (oRightBtmLabel){
				sColor = oRightBtmLabel.getColor();
			} else {
				sColor = "";
			}

			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("COLUMNMICROCHART_END")) + ": " + (oRightBtmLabel ? oRightBtmLabel.getLabel() + " " : "")
				+ (oRightTopLabel ? oRightTopLabel.getLabel() + " " : "") + this.getLocalizedColorMeaning(sColor);
			bIsFirst = false;
		}

		var aColumns = this.getColumns();
		for (var i = 0; i < aColumns.length; i++) {
			var oBar = aColumns[i];
			var sMeaning = this.getLocalizedColorMeaning(oBar.getColor());
			sAltText += ((!bIsFirst || i != 0) ? "\n" : "") + oBar.getLabel() + " " + oBar.getValue() + " " + sMeaning;
		}

		return sAltText;
	};

	ColumnMicroChart.prototype.getTooltip_AsString  = function() {
		var oTooltip = this.getTooltip();
		var sTooltip = this.getAltText();

		if (typeof oTooltip === "string" || oTooltip instanceof String) {
			sTooltip = oTooltip.split("{AltText}").join(sTooltip).split("((AltText))").join(sTooltip);
			return sTooltip;
		}
		return oTooltip ? oTooltip : "";
	};

	ColumnMicroChart.prototype.ontap = function(oEvent) {
		if (sap.ui.Device.browser.edge) {
			this.onclick(oEvent);
		}
	};

	ColumnMicroChart.prototype.onclick = function(oEvent) {
		if (!this.fireBarPress(oEvent)) {
			if (sap.ui.Device.browser.internet_explorer || sap.ui.Device.browser.edge) {
				this.$().focus();
			}
			this.firePress();
	    }
	};

	ColumnMicroChart.prototype.onkeydown = function(oEvent) {
		var iThis, oFocusables;
		switch (oEvent.keyCode) {
			case jQuery.sap.KeyCodes.SPACE:
				oEvent.preventDefault();
				break;

			case jQuery.sap.KeyCodes.ARROW_LEFT:
			case jQuery.sap.KeyCodes.ARROW_UP:
				oFocusables = this.$().find(":focusable"); // all tabstops in the control
				iThis = oFocusables.index(oEvent.target);  // focused element index
				if (oFocusables.length > 0) {
					oFocusables.eq(iThis - 1).get(0).focus();	// previous tab stop element
					oEvent.preventDefault();
					oEvent.stopPropagation();
				}
				break;

			case jQuery.sap.KeyCodes.ARROW_DOWN:
			case jQuery.sap.KeyCodes.ARROW_RIGHT:
				oFocusables = this.$().find(":focusable"); // all tabstops in the control
				iThis = oFocusables.index(oEvent.target);  // focused element index
				if (oFocusables.length > 0) {
					oFocusables.eq((iThis + 1 < oFocusables.length) ? iThis + 1 : 0).get(0).focus(); // next tab stop element
					oEvent.preventDefault();
					oEvent.stopPropagation();
				}
				break;
			default:
		}
	};

	ColumnMicroChart.prototype.onkeyup = function(oEvent) {
	    if (oEvent.which == jQuery.sap.KeyCodes.ENTER || oEvent.which == jQuery.sap.KeyCodes.SPACE) {
	        if (!this.fireBarPress(oEvent)) {
		        this.firePress();
		        oEvent.preventDefault();
		    }
	    }
	};


	ColumnMicroChart.prototype.fireBarPress = function(oEvent) {
		var oBar = jQuery(oEvent.target);
		if (oBar && oBar.attr("data-bar-index")) {
			var iIndex = parseInt(oBar.attr("data-bar-index"), 10);
			var oCmcData = this.getColumns()[iIndex];
			if (oCmcData) {
				oCmcData.firePress();
				oEvent.preventDefault();
				oEvent.stopPropagation();
				if (sap.ui.Device.browser.internet_explorer) {
					oBar.focus();
				}
				return true;
			}
		}
		return false;
	};

	ColumnMicroChart.prototype._getBarAltText = function(iBarIndex) {
		var oBar = this.getColumns()[iBarIndex];
		var sMeaning = this.getLocalizedColorMeaning(oBar.getColor());
		return oBar.getLabel() + " " + oBar.getValue() + " " + sMeaning;
	};

	ColumnMicroChart.prototype.setBarPressable = function(iBarIndex, bPressable) {
		if (bPressable) {
			var sBarAltText = this._getBarAltText(iBarIndex);
			jQuery.sap.byId(this.getId() + "-bar-" + iBarIndex).addClass("sapSuiteUiMicroChartPointer").attr("tabindex", 0).attr("title", sBarAltText).attr("role", "presentation").attr("aria-label", sBarAltText);
		} else {
			jQuery.sap.byId(this.getId() + "-bar-" + iBarIndex).removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer").removeAttr("title").removeAttr("role").removeAttr("aria-label");
		}
	};

	ColumnMicroChart.prototype.onsaptabnext = function(oEvent) {
		var oLast = this.$().find(":focusable").last();  // last tabstop in the control
		if (oLast) {
			this._bIgnoreFocusEvt = true;
			oLast.get(0).focus();
		}
	};

	ColumnMicroChart.prototype.onsaptabprevious = function(oEvent) {
		if (oEvent.target.id != oEvent.currentTarget.id) {
			var oFirst = this.$().find(":focusable").first(); // first tabstop in the control
			if (oFirst) {
				oFirst.get(0).focus();
			}
		}
	};

	ColumnMicroChart.prototype.onfocusin = function(oEvent) {
		if (this._bIgnoreFocusEvt) {
			this._bIgnoreFocusEvt = false;
			return;
		}
		if (this.getId() + "-hidden" == oEvent.target.id) {
			this.$().focus();
			oEvent.preventDefault();
			oEvent.stopPropagation();
		}
	};
	return ColumnMicroChart;

});

}; // end of sap/suite/ui/microchart/ColumnMicroChart.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.ColumnMicroChartData') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// This control displays the history of values as a line mini chart or an area mini chart.
jQuery.sap.declare('sap.suite.ui.microchart.ColumnMicroChartData'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Element'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/ColumnMicroChartData",['jquery.sap.global', './library', 'sap/ui/core/Element'],
	function(jQuery, library, Element) {
	"use strict";

	/**
	 * Constructor for a new ColumnMicroChartData control.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Defines the column chart data.
	 * @extends sap.ui.core.Control
	 *
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.ColumnMicroChartData
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var ColumnMicroChartData = Element.extend("sap.suite.ui.microchart.ColumnMicroChartData", /** @lends sap.suite.ui.microchart.ColumnMicroChartData.prototype */ {
		metadata : {
			library : "sap.suite.ui.microchart",
			properties : {

				/**
				 * The graphic element color.
				 */
				color: { group: "Misc", type: "sap.m.ValueColor", defaultValue: "Neutral" },

				/**
				 * The line title.
				 */
				label: {type : "string", group : "Misc", defaultValue : "" },
				
				/**
				 * The actual value.
				 */
				value: {type: "float", group : "Misc"}
			},
			events: {
				/**
				 * The event is fired when the user chooses the column data.
				 */
				press: {}
			}
		}
	});

	ColumnMicroChartData.prototype.attachEvent = function(sEventId, oData, fnFunction, oListener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, sEventId, oData, fnFunction, oListener);
		if (this.getParent()) {
			this.getParent().setBarPressable(this.getParent().getColumns().indexOf(this), true);
		}
		return this;
	};

	ColumnMicroChartData.prototype.detachEvent = function(sEventId, fnFunction, oListener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, sEventId, fnFunction, oListener);
		if (this.getParent()) {
			this.getParent().setBarPressable(this.getParent().getColumns().indexOf(this), false);
		}
		return this;
	};
	
	return ColumnMicroChartData;

});
}; // end of sap/suite/ui/microchart/ColumnMicroChartData.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.ColumnMicroChartLabel') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// This control displays the history of values as a line mini chart or an area mini chart.
jQuery.sap.declare('sap.suite.ui.microchart.ColumnMicroChartLabel'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Element'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/ColumnMicroChartLabel",['jquery.sap.global', './library', 'sap/ui/core/Element'],
	function(jQuery, library, Element) {
	"use strict";

	/**
	 * Constructor for a new ColumnMicroChartLabel control.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Displays or hides the labels of a column micro chart.
	 * @extends sap.ui.core.Control
	 *
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.ColumnMicroChartLabel
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var ColumnMicroChartLabel = Element.extend("sap.suite.ui.microchart.ColumnMicroChartLabel", /** @lends sap.suite.ui.microchart.ColumnMicroChartLabel.prototype */ {
		metadata : {
			library : "sap.suite.ui.microchart",
			properties : {

				/**
				 * The graphic element color.
				 */
				color: { group: "Misc", type: "sap.m.ValueColor", defaultValue: "Neutral" },

				/**
				 * The line title.
				 */
				label: { type : "string", group : "Misc", defaultValue : "" }
			}
		}
	});
	
	return ColumnMicroChartLabel;

});

}; // end of sap/suite/ui/microchart/ColumnMicroChartLabel.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.ComparisonMicroChart') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// Provides control sap.suite.ui.microchart.ComparisonMicroChart.
jQuery.sap.declare('sap.suite.ui.microchart.ComparisonMicroChart'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Control'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/ComparisonMicroChart",['jquery.sap.global', './library', 'sap/ui/core/Control'],
	function(jQuery, library, Control) {
	"use strict";

	/**
	 * Constructor for a new ComparisonMicroChart control.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Illustrates values as colored bar charts with title, numeric value, and scaling factor in the content area. This control replaces the deprecated sap.suite.ui.commons.ComparisonChart.
	 * @extends sap.ui.core.Control
	 *
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.ComparisonMicroChart
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var ComparisonMicroChart = Control.extend("sap.suite.ui.microchart.ComparisonMicroChart", /** @lends sap.suite.ui.microchart.ComparisonMicroChart.prototype */ { metadata : {

		library: "sap.suite.ui.microchart",
		properties: {
			/**
			 * The size of the microchart. If not set, the default size is applied based on the size of the device tile.
			 */
			size: {type: "sap.m.Size", group: "Misc", defaultValue: "Auto"},

			/**
			 * The scaling suffix that is added to the actual and target values.
			 */
			scale: {type: "string", group: "Misc", defaultValue: ""},

			/**
			 * The width of the chart. If it is not set, the size of the control is defined by the size property.
			 */
			width: {type: "sap.ui.core.CSSSize", group: "Misc"},

			/**
			 * The view of the chart. If not set, the Normal view is used by default.
			 */
			view: {type: "sap.suite.ui.microchart.ComparisonMicroChartViewType", group: "Appearance", defaultValue: "Normal"},

			/**
			 * The color palette for the chart. If this property is set, semantic colors defined in ComparisonData are ignored. Colors from the palette are assigned to each bar consequentially. When all the palette colors are used, assignment of the colors begins from the first palette color.
			 */
			colorPalette: {type: "string[]", group: "Appearance", defaultValue: []},

			/**
			 * If it is set to true, the height of the control is defined by its content.
			 */
			shrinkable: {type: "boolean", group: "Misc", defaultValue: "false"},

			/**
			 * Height of the chart.
			 */
			height: {type: "sap.ui.core.CSSSize", group: "Appearance"}
		},
		aggregations: {
			/**
			 * The comparison chart bar data.
			 */
			data: {type: "sap.suite.ui.microchart.ComparisonMicroChartData", multiple: true}
		},
		events: {
			/**
			 * The event is fired when the user chooses the comparison microchart.
			 */
			press : {}
		}
	}});

	ComparisonMicroChart.prototype.init = function(){
		this._oRb = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.microchart");
		this.setTooltip("{AltText}");
	};

	/**
	 * Calculates the width in percents of chart bars' elements accordingly with provided chart values.
	 *
	 * @returns {Array} array of calculated values for each chart bar.
	 * @private
	 */
	ComparisonMicroChart.prototype._calculateChartData = function() {
		var aResult = [];
		var aData = this.getData();
		var iCount = aData.length;
		var iMaxValue = 0;
		var iMinValue = 0;
		var iTotal;
		var iMaxPercent;
		var iMinPercent;
		var i;

		for (i = 0; i < iCount; i++) {
			var iDataValue = isNaN(aData[i].getValue()) ? 0 : aData[i].getValue();
			iMaxValue = Math.max(iMaxValue, iDataValue);
			iMinValue = Math.min(iMinValue, iDataValue);
		}

		iTotal = iMaxValue - iMinValue;
		iMaxPercent = (iTotal == 0) ? 0 : Math.round(iMaxValue * 100 / iTotal);

		if (iMaxPercent == 0 && iMaxValue != 0) {
			iMaxPercent = 1;
		} else if (iMaxPercent == 100 && iMinValue != 0) {
			iMaxPercent = 99;
		}

		iMinPercent = 100 - iMaxPercent;

		for (i = 0; i < iCount; i++) {
			var oItem = {};
			var iDataVal = isNaN(aData[i].getValue()) ? 0 : aData[i].getValue();

			oItem.value = (iTotal == 0) ? 0 : Math.round(iDataVal * 100 / iTotal);

			if (oItem.value == 0 && iDataVal != 0) {
				oItem.value = (iDataVal > 0) ? 1 : -1;
			} else if (oItem.value == 100) {
				oItem.value = iMaxPercent;
			} else if (oItem.value == -100) {
				oItem.value = -iMinPercent;
			}

			if (oItem.value >= 0) {
				oItem.negativeNoValue = iMinPercent;
				oItem.positiveNoValue = iMaxPercent - oItem.value;
			} else {
				oItem.value = -oItem.value;
				oItem.negativeNoValue = iMinPercent - oItem.value;
				oItem.positiveNoValue = iMaxPercent;
			}

			aResult.push(oItem);
		}

		return aResult;
	};

	ComparisonMicroChart.prototype.attachEvent = function(sEventId, oData, fnFunction, oListener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, sEventId, oData, fnFunction, oListener);
		if (this.hasListeners("press")) {
			this.$().attr("tabindex", 0).addClass("sapSuiteUiMicroChartPointer");
		}

		return this;
	};

	ComparisonMicroChart.prototype.detachEvent = function(sEventId, fnFunction, oListener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, sEventId, fnFunction, oListener);
		if (!this.hasListeners("press")) {
			this.$().removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	ComparisonMicroChart.prototype._getLocalizedColorMeaning = function(sColor) {
		return this._oRb.getText(("SEMANTIC_COLOR_" + sColor).toUpperCase());
	};

	ComparisonMicroChart.prototype.getAltText = function() {
		var sScale = this.getScale();
		var sAltText = "";

		for (var i = 0; i < this.getData().length; i++) {
			var oBar = this.getData()[i];
			var sMeaning = (this.getColorPalette().length) ? "" : this._getLocalizedColorMeaning(oBar.getColor());
			sAltText += ((i == 0) ? "" : "\n") + oBar.getTitle() + " " + (oBar.getDisplayValue() ? oBar.getDisplayValue() : oBar.getValue()) + sScale + " " + sMeaning;
		}

		return sAltText;
	};

	ComparisonMicroChart.prototype.getTooltip_AsString  = function() {
		var oTooltip = this.getTooltip();
		var sTooltip = this.getAltText();

		if (typeof oTooltip === "string" || oTooltip instanceof String) {
			sTooltip = oTooltip.split("{AltText}").join(sTooltip).split("((AltText))").join(sTooltip);
			return sTooltip;
		}
		return oTooltip ? oTooltip : "";
	};

	ComparisonMicroChart.prototype._adjustBars = function() {
		var iHeight = parseFloat(this.$().css("height"));
		var iBarCount = this.getData().length;
		var aBarContainers = this.$().find(".sapSuiteCmpChartItem");
		var iMinH = parseFloat(aBarContainers.css("min-height"));
		var iMaxH = parseFloat(aBarContainers.css("max-height"));
		var iBarContHeight;

		if (iBarCount != 0) {
			iBarContHeight = iHeight / iBarCount;

			if (iBarContHeight > iMaxH) {
				iBarContHeight = iMaxH;
			} else if (iBarContHeight < iMinH) {
				iBarContHeight = iMinH;
			}

			aBarContainers.css("height", iBarContHeight);

			if (this.getView() === "Wide" ) {
				this.$().find(".sapSuiteCmpChartBar>div").css("height", (iBarContHeight * 79 / 42) + "%");

			} else if (this.getView() === "Normal") {
				this.$().find(".sapSuiteCmpChartBar>div").css("height", (iBarContHeight - 19) + "%");
			}

			var iChartsHeightDelta = (iHeight - iBarContHeight * iBarCount) / 2;
			if (iChartsHeightDelta > 0) {
				jQuery(aBarContainers[0]).css("margin-top", iChartsHeightDelta + 7 + "px");
			}
		}
	};

	ComparisonMicroChart.prototype.onAfterRendering = function() {
		if (this.getHeight() != "") {
			var that = this;
			sap.ui.Device.media.attachHandler(function(){
				that._adjustBars();
			});
			this._adjustBars();
		}

	};

	ComparisonMicroChart.prototype._getBarAltText = function(iBarIndex) {
			var sScale = this.getScale();
			var oBar = this.getData()[iBarIndex];
			var sMeaning = (this.getColorPalette().length) ? "" : this._getLocalizedColorMeaning(oBar.getColor());
			return oBar.getTitle() + " " + (oBar.getDisplayValue() ? oBar.getDisplayValue() : oBar.getValue()) + sScale + " " + sMeaning;
	};

	ComparisonMicroChart.prototype.onsaptabnext = function(oEvent) {
		var oLast = this.$().find(":focusable").last();	// last tabstop in the control
		if (oLast) {
			this._bIgnoreFocusEvt = true;
			oLast.get(0).focus();
		}
	};

	ComparisonMicroChart.prototype.onsaptabprevious = function(oEvent) {
		if (oEvent.target.id != oEvent.currentTarget.id) {
			var oFirst = this.$().find(":focusable").first();	// first tabstop in the control
			if (oFirst) {
				oFirst.get(0).focus();
			}
		}
	};

	ComparisonMicroChart.prototype.ontap = function(oEvent) {
		if (sap.ui.Device.browser.edge) {
			this.onclick(oEvent);
		}
	};

	ComparisonMicroChart.prototype.onclick = function(oEvent) {
		if (!this.fireBarPress(oEvent)) {
			if (sap.ui.Device.browser.internet_explorer || sap.ui.Device.browser.edge) {
				this.$().focus();
			}
			this.firePress();
		}
	};

	ComparisonMicroChart.prototype.onkeydown = function(oEvent) {
		switch (oEvent.keyCode) {
			case jQuery.sap.KeyCodes.SPACE:
				oEvent.preventDefault();
				break;

			case jQuery.sap.KeyCodes.ARROW_LEFT:
			case jQuery.sap.KeyCodes.ARROW_UP:
				var oFocusables = this.$().find(":focusable");	// all tabstops in the control
				var iThis = oFocusables.index(oEvent.target);  // focused element index
				if (oFocusables.length > 0) {
					oFocusables.eq(iThis - 1).get(0).focus();	// previous tab stop element
					oEvent.preventDefault();
					oEvent.stopPropagation();
				}
				break;

			case jQuery.sap.KeyCodes.ARROW_DOWN:
			case jQuery.sap.KeyCodes.ARROW_RIGHT:
				var oFocusable = this.$().find(":focusable");	// all tabstops in the control
				var iThisEl = oFocusable.index(oEvent.target);  // focused element index
				if (oFocusable.length > 0) {
					oFocusable.eq((iThisEl + 1 < oFocusable.length) ? iThisEl + 1 : 0).get(0).focus();	// next tab stop element
					oEvent.preventDefault();
					oEvent.stopPropagation();
				}
				break;
			default:
		}
	};

	ComparisonMicroChart.prototype.onkeyup = function(oEvent) {
		if (oEvent.which == jQuery.sap.KeyCodes.ENTER || oEvent.which == jQuery.sap.KeyCodes.SPACE) {
			if (!this.fireBarPress(oEvent)) {
				this.firePress();
				oEvent.preventDefault();
			}
		}
	};

	ComparisonMicroChart.prototype.fireBarPress = function(oEvent) {
		var oBar = jQuery(oEvent.target);
		if (oBar && oBar.attr("data-bar-index")) {
			var iIndex = parseInt(oBar.attr("data-bar-index"), 10);
			var oComparisonData = this.getData()[iIndex];
			if (oComparisonData) {
				oComparisonData.firePress();
				oEvent.preventDefault();
				oEvent.stopPropagation();
				if (sap.ui.Device.browser.internet_explorer) {
					jQuery.sap.byId(this.getId() + "-chart-item-bar-" + iIndex).focus();
				}
				return true;
			}
		}
		return false;
	};


	ComparisonMicroChart.prototype.setBarPressable = function(iBarIndex, bPressable) {
		if (bPressable) {
			var sBarAltText = this._getBarAltText(iBarIndex);
			jQuery.sap.byId(this.getId() + "-chart-item-bar-" + iBarIndex).addClass("sapSuiteUiMicroChartPointer").attr("tabindex", 0).attr("title", sBarAltText).attr("role", "presentation").attr("aria-label", sBarAltText);
		} else {
			jQuery.sap.byId(this.getId() + "-chart-item-bar-" + iBarIndex).removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer").removeAttr("title").removeAttr("role").removeAttr("aria-label");
		}
	};

	ComparisonMicroChart.prototype.onfocusin = function(oEvent) {
		if (this._bIgnoreFocusEvt) {
			this._bIgnoreFocusEvt = false;
			return;
		}
		if (this.getId() + "-hidden" == oEvent.target.id) {
			this.$().focus();
			oEvent.preventDefault();
			oEvent.stopPropagation();
		}
	};

	return ComparisonMicroChart;

});

}; // end of sap/suite/ui/microchart/ComparisonMicroChart.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.ComparisonMicroChartData') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// Provides control sap.suite.ui.microchart.ComparisonMicroChartData.
jQuery.sap.declare('sap.suite.ui.microchart.ComparisonMicroChartData'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Element'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/ComparisonMicroChartData",['jquery.sap.global', './library', 'sap/ui/core/Element'],
	function(jQuery, library, Element) {
	"use strict";

	/**
	 * Constructor for a new ComparisonMicroChartData.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Contains the values of the comparison chart.
	 * @extends sap.ui.core.Element
	 *
	 * @version 1.36.12
	 *
	 * @constructor
	 * @public
	 * @alias sap.suite.ui.microchart.ComparisonMicroChartData
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var ComparisonMicroChartData = Element.extend("sap.suite.ui.microchart.ComparisonMicroChartData", /** @lends sap.suite.ui.microchart.ComparisonMicroChartData.prototype */ {
		metadata : {
			library: "sap.suite.ui.microchart",
			properties: {
				/**
				 * The value for comparison.
				 */
				value: {type: "float", group: "Misc", defaultValue: "0"},
	
				/**
				 * The semantic color of the value.
				 */
				color: {type: "sap.m.ValueColor", group: "Misc", defaultValue: "Neutral"},
	
				/**
				 * The comparison bar title.
				 */
				title: {type: "string", group: "Misc", defaultValue: ""},
	
				/**
				 * If this property is set then it will be displayed instead of value.
				 */
				displayValue: {type: "string", group: "Misc", defaultValue: ""}
			},
			events: {
				/**
				 * The event is fired when the user chooses the comparison chart bar.
				 */
				press : {}
			}
		}
	});

	ComparisonMicroChartData.prototype.setValue = function(fValue, bSuppressInvalidate) {
		this._isValueSet = this._fnIsNumber(fValue);
		return this.setProperty("value", this._isValueSet ? fValue : NaN, bSuppressInvalidate);
	};
	
	ComparisonMicroChartData.prototype._fnIsNumber = function(n) {
		return typeof n == 'number' && !isNaN(n) && isFinite(n);
	};
	
	ComparisonMicroChartData.prototype.clone = function(sIdSuffix, aLocalIds, oOptions) {
		var oClone = sap.ui.core.Control.prototype.clone.apply(this, arguments);
		oClone._isValueSet = this._isValueSet;
		return oClone;
	};
	
	ComparisonMicroChartData.prototype.attachEvent = function(sEventId, oData, fnFunction, oListener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, sEventId, oData, fnFunction, oListener);
		if (this.getParent()) {
			this.getParent().setBarPressable(this.getParent().getData().indexOf(this), true);
		}
			return this;
	};

	ComparisonMicroChartData.prototype.detachEvent = function(sEventId, fnFunction, oListener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, sEventId, fnFunction, oListener);
		if (this.getParent()) {
			this.getParent().setBarPressable(this.getParent().getData().indexOf(this), false);
		}
		return this;
	};

	return ComparisonMicroChartData;

});
}; // end of sap/suite/ui/microchart/ComparisonMicroChartData.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.DeltaMicroChart') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// Provides control sap.suite.ui.microchart.Example.
jQuery.sap.declare('sap.suite.ui.microchart.DeltaMicroChart'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Control'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/DeltaMicroChart",['jquery.sap.global', './library', 'sap/ui/core/Control'],
	function(jQuery, library, Control) {
	"use strict";

	/**
	 * Constructor for a new DeltaMicroChart control.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Represents the delta of two values as a chart. This control replaces the deprecated sap.suite.ui.commons.DeltaMicroChart.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.DeltaMicroChart
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var DeltaMicroChart = Control.extend("sap.suite.ui.microchart.DeltaMicroChart", /** @lends sap.suite.ui.microchart.DeltaMicroChart.prototype */ { metadata: {

		library: "sap.suite.ui.microchart",
		properties: {

			/**
			 * The first value for delta calculation.
			 */
			value1: {type: "float", group: "Misc", defaultValue: null},

			/**
			 * The second value for delta calculation.
			 */
			value2: {type: "float", group: "Misc", defaultValue: null},

			/**
			 * The first value title.
			 */
			title1: {type: "string", group: "Misc", defaultValue: null},

			/**
			 * The second value title.
			 */
			title2: {type: "string", group: "Misc", defaultValue: null},

			/**
			 * If this property is set, it is rendered instead of value1.
			 */
			displayValue1: {type: "string", group: "Misc", defaultValue: null},

			/**
			 * If this property is set, it is rendered instead of value2.
			 */
			displayValue2: {type: "string", group: "Misc", defaultValue: null},

			/**
			 * If this property is set, it is rendered instead of a calculated delta.
			 */
			deltaDisplayValue: {type: "string", group: "Misc", defaultValue: null},

			/**
			 * The semantic color of the delta value.
			 */
			color: {type: "sap.m.ValueColor", group: "Misc", defaultValue: "Neutral"},

			/**
			 * The width of the chart.
			 */
			width: {type: "sap.ui.core.CSSSize", group: "Misc"},

			/**
			 * The size of the chart. If is not set, the default size is applied based on the device type.
			 */
			size: {type: "sap.m.Size", group: "Misc", defaultValue: "Auto"}
		},

		events: {

			/**
			 * The event is fired when the user chooses the delta micro chart.
			 */
			press: {}

		}

	}});

	DeltaMicroChart.prototype.init = function() {
		this._oRb = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.microchart");
		this.setTooltip("{AltText}");
	};

	DeltaMicroChart.prototype._calcChartData = function() {
		var fVal1 = this.getValue1();
		var fVal2 = this.getValue2();

		var fMin = Math.min(fVal1, fVal2, 0);
		var fMax = Math.max(fVal1, fVal2, 0);
		var fTotal = fMax - fMin;

		function calcPercent(fVal) {
			return (fTotal === 0 ?  0 : Math.abs(fVal) / fTotal * 100).toFixed(2);
		}

		var oConf = {};
		var fDelta = fVal1 - fVal2;

		oConf.delta = {
			left: fMax === 0,
			width: calcPercent(fDelta),
			isFirstStripeUp: fVal1 < fVal2,
			isMax: (fVal1 < 0 && fVal2 >= 0) || (fVal1 >= 0 && fVal2 < 0),
			isZero: fVal1 === 0 && fVal2 === 0,
			isEqual: fDelta === 0
		};

		oConf.bar1 = {
			left: fVal2 >= 0,
			width: calcPercent(fVal1),
			isSmaller: Math.abs(fVal1) < Math.abs(fVal2)
		};

		oConf.bar2 = {
			left: fVal1 >= 0,
			width: calcPercent(fVal2),
			isSmaller: Math.abs(fVal2) < Math.abs(fVal1)
		};

		return oConf;
	};

	DeltaMicroChart.prototype._getLocalizedColorMeaning = function(sColor) {
		return this._oRb.getText(("SEMANTIC_COLOR_" + sColor).toUpperCase());
	};

	/**
	 * Calculates the number of digits after the decimal point.
	 *
	 * @param {float} fValue float value
	 * @returns {int} number of digits after the decimal point in fValue.
	 * @private
	 */
	DeltaMicroChart.prototype._digitsAfterDecimalPoint = function(fValue) {
		var sAfter = ("" + fValue).match(/[.,](\d+)/g);
		return (sAfter) ? ("" + sAfter).length - 1 : 0;
	};

	DeltaMicroChart.prototype.getAltText = function() {
	    var sDv1 = this.getDisplayValue1();
	    var sDv2 = this.getDisplayValue2();
	    var sDdv = this.getDeltaDisplayValue();
		var fVal1 = this.getValue1();
		var fVal2 = this.getValue2();
		var sAdv1ToShow = sDv1 ? sDv1 : "" + fVal1;
		var sAdv2ToShow = sDv2 ? sDv2 : "" + fVal2;
		var sAddvToShow = sDdv ? sDdv : "" + Math.abs(fVal1 - fVal2).toFixed(Math.max(this._digitsAfterDecimalPoint(fVal1), this._digitsAfterDecimalPoint(fVal2)));
		var sMeaning = this._getLocalizedColorMeaning(this.getColor());

		return this.getTitle1() + " " + sAdv1ToShow + "\n" + this.getTitle2() + " " + sAdv2ToShow + "\n" +  this._oRb.getText("DELTAMICROCHART_DELTA_TOOLTIP", [sAddvToShow, sMeaning]);
	};

	DeltaMicroChart.prototype.getTooltip_AsString  = function() {
		var oTooltip = this.getTooltip();
		var sTooltip = this.getAltText();

		if (typeof oTooltip === "string" || oTooltip instanceof String) {
			sTooltip = oTooltip.split("{AltText}").join(sTooltip).split("((AltText))").join(sTooltip);
			return sTooltip;
		}
		return oTooltip ? oTooltip : "";
	};

	DeltaMicroChart.prototype._isCalcSupported = function() {
		return jQuery.sap.byId(this.getId() + "-calc").css("max-width") == "11px";
	};

	DeltaMicroChart.prototype._isRoundingSupported = function() {
		return jQuery.sap.byId(this.getId() + "-calc1").width() == 4;
	};

	DeltaMicroChart.prototype.onBeforeRendering = function() {
		this._oChartData = this._calcChartData();
	};

	DeltaMicroChart.prototype.onAfterRendering = function() {
		this._bCalc = this._isCalcSupported();
		this._bRounding = this._isRoundingSupported();

		if (!this._bCalc || !this._bRounding) {
			if (this._sResizeHandlerId) {
				sap.ui.core.ResizeHandler.deregister(this._sResizeHandlerId);
			}

		    var oChart = jQuery.sap.domById(this.getId() + "-dmc-chart");
		    this._sResizeHandlerId = sap.ui.core.ResizeHandler.register(oChart,  jQuery.proxy(this._adjust, this));

		    if (!this._bCalc) {
				this._adjustCalc();
		    }

		    if (!this._bRounding) {
				this._adjustRound();
		    }
		}
	};

	DeltaMicroChart.prototype._adjust = function() {
	    if (!this._bCalc) {
			this._adjustCalc();
	    }

	    if (!this._bRounding) {
			this._adjustRound();
	    }
	};

	DeltaMicroChart.prototype._adjustRound = function() {
		var iChartWidth = jQuery.sap.byId(this.getId() + "-dmc-chart").width();
		var iDeltaWidth = Math.round(iChartWidth * this._oChartData.delta.width / 100);

		jQuery.sap.byId(this.getId() + "-dmc-bar-delta").width(iDeltaWidth);

		if (this._oChartData.bar1.isSmaller && !this._oChartData.delta.isMax) {
			jQuery.sap.byId(this.getId() + "-dmc-bar1").width(iChartWidth - iDeltaWidth);
		}

		if (this._oChartData.bar2.isSmaller && !this._oChartData.delta.isMax) {
			jQuery.sap.byId(this.getId() + "-dmc-bar2").width(iChartWidth - iDeltaWidth);
		}
	};

	DeltaMicroChart.prototype._adjustCalc = function() {
		var iChartWidth = jQuery.sap.byId(this.getId() + "-dmc-chart").width();

		function adjustBar(oBar) {
			oBar.css("max-width", iChartWidth - parseInt(oBar.css("max-width"), 10) + "px");
		}

		adjustBar(jQuery.sap.byId(this.getId() + "-dmc-bar1"));
		adjustBar(jQuery.sap.byId(this.getId() + "-dmc-bar2"));
		adjustBar(jQuery.sap.byId(this.getId() + "-dmc-bar-delta"));
	};

	DeltaMicroChart.prototype.attachEvent = function(sEventId, oData, fnFunction, oListener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, sEventId, oData, fnFunction, oListener);
		if (this.hasListeners("press")) {
			this.$().attr("tabindex", 0).addClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	DeltaMicroChart.prototype.detachEvent = function(sEventId, fnFunction, oListener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, sEventId, fnFunction, oListener);
		if (!this.hasListeners("press")) {
			this.$().removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	DeltaMicroChart.prototype.ontap = function(oEvent) {
	     if (sap.ui.Device.browser.internet_explorer) {
	         this.$().focus();
	     }
	     this.firePress();
	};

	DeltaMicroChart.prototype.onkeydown = function(oEvent) {
	    if (oEvent.which == jQuery.sap.KeyCodes.SPACE) {
	        oEvent.preventDefault();
	    }
	};

	DeltaMicroChart.prototype.onkeyup = function(oEvent) {
	    if (oEvent.which == jQuery.sap.KeyCodes.ENTER || oEvent.which == jQuery.sap.KeyCodes.SPACE) {
	        this.firePress();
	        oEvent.preventDefault();
	    }
	};

	return DeltaMicroChart;
});

}; // end of sap/suite/ui/microchart/DeltaMicroChart.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.HarveyBallMicroChart') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// This file defines behavior for the control.
jQuery.sap.declare('sap.suite.ui.microchart.HarveyBallMicroChart'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Control'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/HarveyBallMicroChart",['jquery.sap.global', './library', 'sap/ui/core/Control'],
	function(jQuery, library, Control) {
	"use strict";

	/**
	 * The configuration of the graphic element on the chart.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Displays parts of a whole as highlighted sectors in a pie chart.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.HarveyBallMicroChart
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var HarveyBallMicroChart = Control.extend("sap.suite.ui.microchart.HarveyBallMicroChart", /** @lends sap.suite.ui.microchart.HarveyBallMicroChart.prototype */ {
		metadata : {
			library: "sap.suite.ui.microchart",
			properties: {

				/**
				 * The total value. This is taken as 360 degrees value on the chart.
				 */
				total: {group:"Misc", type:"float", defaultValue: null},

				/**
				 * The total label. If specified, it is displayed instead of the total value.
				 */
				totalLabel: {group:"Misc", type:"string"},

				/**
				The scaling factor that is displayed next to the total value.
				*/
				totalScale: {group:"Misc", type:"string"},

				/**
				If set to true, the totalLabel parameter is considered as the combination of the total value and its scaling factor. The default value is false. It means that the total value and the scaling factor are defined separately by the total and the totalScale properties accordingly.
				*/
				formattedLabel: {group:"Misc", type:"boolean", defaultValue:false},

				/**
				If it is set to true, the total value is displayed next to the chart. The default setting is true.
				*/
				showTotal: {group:"Misc", type:"boolean", defaultValue:true},

				/**
				If it is set to true, the fraction values are displayed next to the chart. The default setting is true.
				*/
				showFractions: {group:"Misc", type:"boolean", defaultValue:true},

				/**
				The size of the chart. If it is not set, the default size is applied based on the device type.
				*/
				size: {group:"Misc", type:"sap.m.Size", defaultValue:"Auto"},

				/**
				The color palette for the chart. If this property is set, semantic colors defined in HarveyBallMicroChart are ignored. Colors from the palette are assigned to each slice consequentially. When all the palette colors are used, assignment of the colors begins from the first palette color.
				*/
				colorPalette: {type: "string[]", group : "Appearance", defaultValue : [] },

				/**
				The width of the chart. If it is not set, the size of the control is defined by the size property.
				*/
				width: {group:"Misc", type:"sap.ui.core.CSSSize"}
			},
			events: {
				/**
				 * The event is fired when the user chooses the control.
				 */
				press: {}
			},
			aggregations: {

				/**
				 * The set of points for this graphic element.
				 */
				"items": { multiple: true, type: "sap.suite.ui.microchart.HarveyBallMicroChartItem" }
			}
		}
	});

	///**
	// * This file defines behavior for the control,
	// */


	HarveyBallMicroChart.prototype.getAltText = function() {
		var sAltText = "";
		var bIsFirst = true;

		var aItems = this.getItems();
		for (var i = 0; i < aItems.length; i++) {
			var oItem = aItems[i];
			var sColor = (this.getColorPalette().length === 0) ? this._rb.getText(("SEMANTIC_COLOR_" + oItem.getColor()).toUpperCase()) : "";
			var sLabel = oItem.getFractionLabel();
			var sScale = oItem.getFractionScale();
			if (!sLabel && sScale) {
				sLabel = oItem.getFormattedLabel() ? oItem.getFraction() : oItem.getFraction() + oItem.getFractionScale().substring(0,3);
			} else if (!oItem.getFormattedLabel() && oItem.getFractionLabel()) {
				sLabel += oItem.getFractionScale().substring(0,3);
			}

			sAltText += (bIsFirst ? "" : "\n") + sLabel + " " + sColor;
			bIsFirst = false;
		}

		if (this.getTotal()) {
			var sTLabel = this.getTotalLabel();
			if (!sTLabel) {
				sTLabel = this.getFormattedLabel() ? this.getTotal() : this.getTotal() + this.getTotalScale().substring(0,3);
			} else if (!this.getFormattedLabel()) {
				sTLabel += this.getTotalScale().substring(0,3);
			}

			sAltText += (bIsFirst ? "" : "\n") + this._rb.getText("HARVEYBALLMICROCHART_TOTAL_TOOLTIP") + " " + sTLabel;
		}
		return sAltText;
	};

	HarveyBallMicroChart.prototype.getTooltip_AsString = function() {
		var oTooltip = this.getTooltip();
		var sTooltip = this.getAltText();

		if (typeof oTooltip === "string" || oTooltip instanceof String) {
			sTooltip = oTooltip.split("{AltText}").join(sTooltip).split("((AltText))").join(sTooltip);
			return sTooltip;
		}
		return oTooltip ? oTooltip : "";
	};

	HarveyBallMicroChart.prototype.init = function() {
		this._rb = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.microchart");
		this.setTooltip("{AltText}");
		sap.ui.Device.media.attachHandler(this.rerender, this, sap.ui.Device.media.RANGESETS.SAP_STANDARD);
	};

	HarveyBallMicroChart.prototype._calculatePath = function() {
		var oSize = this.getSize();

		var fTot = this.getTotal();
		var fFrac = 0;

		if (this.getItems().length) {
			fFrac = this.getItems()[0].getFraction();
		}

		var bIsPhone = false;

		if (oSize == "Auto") {
			bIsPhone = jQuery("html").hasClass("sapUiMedia-Std-Phone");
		}

		if (oSize == "S" || oSize == "XS") {
			bIsPhone = true;
		}

		var iMeadiaSize = bIsPhone ? 56 : 72;
		var iCenter = iMeadiaSize / 2;
		// var iBorder = bIsPhone? 3 : 4;
		var iBorder = 4;
		this._oPath = {
			initial : {
				x : iCenter,
				y : iCenter,
				x1 : iCenter,
				y1 : iCenter
			},
			lineTo : {
				x : iCenter,
				y : iBorder
			},
			arc : {
				x1 : iCenter - iBorder,
				y1 : iCenter - iBorder,
				xArc : 0,
				largeArc : 0,
				sweep : 1,
				x2 : "",
				y2 : ""
			},
			size : iMeadiaSize,
			border : iBorder,
			center : iCenter
		};

		var fAngle = fFrac / fTot * 360;
		if (fAngle < 10) {
			this._oPath.initial.x -= 1.5;
			this._oPath.initial.x1 += 1.5;
			this._oPath.arc.x2 = this._oPath.initial.x1;
			this._oPath.arc.y2 = this._oPath.lineTo.y;
		} else if (fAngle > 350 && fAngle < 360) {
			this._oPath.initial.x += 1.5;
			this._oPath.initial.x1 -= 1.5;
			this._oPath.arc.x2 = this._oPath.initial.x1;
			this._oPath.arc.y2 = this._oPath.lineTo.y;
		} else {
			var fRad = Math.PI / 180.0;
			var fRadius = this._oPath.center - this._oPath.border;

			var ix = fRadius * Math.cos((fAngle - 90) * fRad) + this._oPath.center;
			var iy = this._oPath.size - (fRadius * Math.sin((fAngle + 90) * fRad) + this._oPath.center);

			this._oPath.arc.x2 = ix.toFixed(2);
			this._oPath.arc.y2 = iy.toFixed(2);
		}

		var iLargeArc = fTot / fFrac < 2 ? 1 : 0;

		this._oPath.arc.largeArc = iLargeArc;
	};

	HarveyBallMicroChart.prototype.onBeforeRendering = function() {
		this._calculatePath();
	};

	HarveyBallMicroChart.prototype.serializePieChart = function() {
		var p = this._oPath;

		return ["M", p.initial.x, ",", p.initial.y, " L", p.initial.x, ",", p.lineTo.y, " A", p.arc.x1, ",", p.arc.y1,
				" ", p.arc.xArc, " ", p.arc.largeArc, ",", p.arc.sweep, " ", p.arc.x2, ",", p.arc.y2, " L", p.initial.x1,
				",", p.initial.y1, " z"].join("");
	};

	HarveyBallMicroChart.prototype._parseFormattedValue = function(
			sValue) {
		return {
			scale: sValue.replace(/.*?([^+-.,\d]*)$/g, "$1").trim(),
			value: sValue.replace(/(.*?)[^+-.,\d]*$/g, "$1").trim()
		};
	};

	HarveyBallMicroChart.prototype.ontap = function(oEvent) {
		if (sap.ui.Device.browser.internet_explorer) {
			this.$().focus();
		}
		this.firePress();
	};

	HarveyBallMicroChart.prototype.onkeydown = function(oEvent) {
		if (oEvent.which == jQuery.sap.KeyCodes.SPACE) {
			oEvent.preventDefault();
		}
	};

	HarveyBallMicroChart.prototype.onkeyup = function(oEvent) {
		if (oEvent.which == jQuery.sap.KeyCodes.ENTER
				|| oEvent.which == jQuery.sap.KeyCodes.SPACE) {
			this.firePress();
			oEvent.preventDefault();
		}
	};

	HarveyBallMicroChart.prototype.attachEvent = function(
			sEventId, oData, fnFunction, oListener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, sEventId, oData,
				fnFunction, oListener);
		if (this.hasListeners("press")) {
			this.$().attr("tabindex", 0).addClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	HarveyBallMicroChart.prototype.detachEvent = function(
			sEventId, fnFunction, oListener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, sEventId, fnFunction,
				oListener);
		if (!this.hasListeners("press")) {
			this.$().removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	HarveyBallMicroChart.prototype.exit = function(oEvent) {
		sap.ui.Device.media.detachHandler(this.rerender, this, sap.ui.Device.media.RANGESETS.SAP_STANDARD);
	};

	return HarveyBallMicroChart;

});

}; // end of sap/suite/ui/microchart/HarveyBallMicroChart.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.HarveyBallMicroChartItem') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// This control displays the history of values as a line mini chart or an area mini chart.
jQuery.sap.declare('sap.suite.ui.microchart.HarveyBallMicroChartItem'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Element'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/HarveyBallMicroChartItem",['jquery.sap.global', './library', 'sap/ui/core/Element'],
	function(jQuery, library, Element) {
	"use strict";

	/**
	 * The configuration of the graphic element on the chart.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Configures the slices of the pie chart.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.HarveyBallMicroChartItem
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var HarveyBallMicroChartItem = Element.extend("sap.suite.ui.microchart.HarveyBallMicroChartItem", /** @lends sap.suite.ui.microchart.HarveyBallMicroChartItem.prototype */ {
		metadata : {
			library: "sap.suite.ui.microchart",
			properties: {
				
				/**
				*The slice color.
				*/
				color: {group:"Misc", type:"sap.m.ValueColor", defaultValue:"Neutral"},
				
				/**
				*The fraction value.
				*/
				fraction: {group:"Misc", type:"float", defaultValue:"0"},
				
				/**
				*The fraction label. If specified, it is displayed instead of the fraction value.
				*/
				fractionLabel: {group:"Misc", type:"string"},
				
				/**
				*The scaling factor that is displayed after the fraction value.
				*/
				fractionScale: {group:"Misc", type:"string"},
				
				/**
				*If set to true, the fractionLabel parameter is considered as the combination of the fraction value and scaling factor. The default value is false. It means that the fraction value and the scaling factor are defined separately by the fraction and the fractionScale properties accordingly.
				*/
				formattedLabel: {group:"Misc", type:"boolean", defaultValue:"false"}
				
			}
		}
	});
	
	return HarveyBallMicroChartItem;

});
}; // end of sap/suite/ui/microchart/HarveyBallMicroChartItem.js
if ( !jQuery.sap.isDeclared('sap.suite.ui.microchart.RadialMicroChart') ) {
/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

// This file defines the behavior for the control.
jQuery.sap.declare('sap.suite.ui.microchart.RadialMicroChart'); // unresolved dependency added by SAPUI5 'AllInOne' Builder
jQuery.sap.require('jquery.sap.global'); // unlisted dependency retained
jQuery.sap.require('sap.ui.core.Control'); // unlisted dependency retained
sap.ui.define("sap/suite/ui/microchart/RadialMicroChart",['jquery.sap.global', './library', 'sap/ui/core/Control', 'sap/suite/ui/microchart/RadialMicroChartRenderer'],
	function(jQuery, library, Control, Renderer) {
	"use strict";

	/**
	 * Describes the configuration of the graphic element on the chart.
	 *
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Displays a ring chart highlighting a current status. The status is displayed with a semantically colored radial bar and a percentage value.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 * @since 1.36.0
	 *
	 * @constructor
	 * @public
	 * @alias sap.suite.ui.microchart.RadialMicroChart
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var RadialMicroChart = Control.extend("sap.suite.ui.microchart.RadialMicroChart", /** @lends sap.suite.ui.microchart.RadialMicroChart.prototype */ {
		constructor : function(sId, mSettings) {
			var bPercentageMode;
			if (mSettings && typeof mSettings.percentage === "number"){
				bPercentageMode = true;
			} else if (sId && typeof sId.percentage === "number") {
				bPercentageMode = true;
			} else {
				bPercentageMode = false;
			}
			try {
				Control.apply(this, arguments);
				this._bPercentageMode = bPercentageMode;
			} catch (e) {
				this.destroy();
				throw e;
			}
		},

		metadata : {
			library: "sap.suite.ui.microchart",
			properties: {
				/**
				 * The total value. This is taken as 360 degrees value on the chart.
				 */
				total: {group:"Data", type:"float", defaultValue: null},

				/**
				 * The fraction of the total value that is displayed.
				 */
				fraction: {group:"Data", type:"float", defaultValue: null},

				/**
				 * The percentage that is displayed.
				 * When a percentage is set, properties total and fraction are not considered.
				 */
				percentage: {group:"Data", type:"float", defaultValue: null},

				/**
				 * The color shown in the completed path.
				 */
				valueColor: {group: "Appearance", type: "sap.m.ValueCSSColor", defaultValue: "Neutral"}
			},
			events: {
				/**
				 * The event is fired when the user chooses the control.
				 */
				press: {}
			}
		}
	});

	/* --- Lifecycle Handling --- */

	/**
	 * Init function for the control
	 */
	RadialMicroChart.prototype.init = function() {
		this._rb = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.microchart");
		this._bPercentageMode; // Flag for tracking if the application is using percentage or fraction and total
	};

	/**
	 * Handler for before rendering
	 */
	RadialMicroChart.prototype.onBeforeRendering = function() {
		if (!this._bPercentageMode) {
			if (this.getTotal() === 0) {
				jQuery.sap.log.error("Total can not be 0, please add a valid total value");
			} else {
				this.setProperty("percentage", Math.round((this.getFraction() * 100 / this.getTotal()) * 10) / 10, true);
			}
		}
	};

	RadialMicroChart.prototype.onAfterRendering = function() {
		Renderer._handleOnAfterRendering(this);
	};

	/* --- Event Handling --- */

	RadialMicroChart.prototype.ontap = function(oEvent) {
		if (sap.ui.Device.browser.internet_explorer) {
			this.$().focus();
		}
		this.firePress();
	};

	RadialMicroChart.prototype.onkeydown = function(oEvent) {
		if (oEvent.which === jQuery.sap.KeyCodes.SPACE) {
			oEvent.preventDefault();
		}
	};

	RadialMicroChart.prototype.onkeyup = function(oEvent) {
		if (oEvent.which === jQuery.sap.KeyCodes.ENTER || oEvent.which === jQuery.sap.KeyCodes.SPACE) {
			this.firePress();
			oEvent.preventDefault();
		}
	};

	RadialMicroChart.prototype.attachEvent = function(eventId, data, functionToCall, listener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, eventId, data, functionToCall, listener);
		if (eventId === "press") {
			this.rerender();
		}
		return this;
	};

	RadialMicroChart.prototype.detachEvent = function(eventId, functionToCall, listener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, eventId, functionToCall, listener);
		if (eventId === "press") {
			this.rerender();
		}
		return this;
	};

	/* --- Getters and Setters --- */

	/**
	 * Getter for internal property _bPercentageMode.
	 * Percentage mode is configured by setting a percentage value on definition of the control.
	 * If Fraction and Total is used, this property is false since percentage gets calculated automatically by the control.
	 *
	 * @private
	 * @returns {boolean} true if chart is in percentage mode, false if not.
	 */
	RadialMicroChart.prototype._getPercentageMode = function() {
		return this._bPercentageMode;
	};

	RadialMicroChart.prototype.setPercentage = function(percentage) {
		if (percentage) {
			if (percentage !== this.getPercentage()) {
				this._bPercentageMode = true;
				this.setProperty("percentage", percentage);
			}
		} else {
			this._bPercentageMode = false;
			this.setProperty("percentage", null);
		}
	};

	/* --- Helpers --- */

	/**
	 * Check if the valueColor property is an instance of sap.m.ValueColor
	 * @returns {boolean} True if valueColor property is an instance of sap.m.ValueColor, false otherwise.
	 * @private
	 */
	RadialMicroChart.prototype._isValueColorInstanceOfValueColor = function() {
		var sValue = this.getValueColor();
		for (var sValueColor in sap.m.ValueColor){
			if (sValueColor === sValue) {
				return true;
			}
		}
		return false;
	};

	/**
	 * Returns the tooltip for the given chart.
	 * If tooltip was set to an empty string (using whitespaces) by the application,
	 * the tooltip will be set to an empty string. If tooltip was not set (null/undefined),
	 * a tooltip gets generated by the control.
	 *
	 * @private
	 * @returns {string} tooltip for the given control
	 */
	RadialMicroChart.prototype._getTooltipText = function() {
		var sTooltip = this.getTooltip_Text();
		if (!sTooltip) { //Tooltip will be set by control
			sTooltip = this._getAriaAndTooltipText();
		} else if (this._isTooltipSuppressed()) {
			sTooltip = null;
		}
		return sTooltip;
	};

	/**
	 * Returns text for ARIA label.
	 * If tooltip was set to an empty string (using whitespaces) by the application or
	 * the tooltip was not set (null/undefined), the ARIA text gets generated by the control.
	 * Otherwise, the given tooltip will also be set as ARIA text.
	 *
	 * @private
	 * @returns {String} ARIA text for the given control
	 */
	RadialMicroChart.prototype._getAriaText = function() {
		var sAriaText = this.getTooltip_Text();
		if (!sAriaText || this._isTooltipSuppressed()) { //ARIA label will be set by control. Otherwise (else), version generated by control will be used. 
			sAriaText = this._getAriaAndTooltipText();
		}
		return sAriaText;
	};

	/**
	 * Returns value that indicates if the tooltip was configured as empty string (e.g. one whitespace).
	 *
	 * @private
	 * @returns {boolean} value that indicates true, if whitespace was set, false in any other case, also null/undefined
	 */
	RadialMicroChart.prototype._isTooltipSuppressed = function() {
		var sTooltip = this.getTooltip_Text();
		if (sTooltip && jQuery.trim(sTooltip).length === 0) {
			return true;
		} else {
			return false;
		}
	};

	/**
	 * Returns the part of the tooltip and ARIA text which is equal.
	 *
	 * @private
	 * @returns {string} value containing the tooltip and ARIA text
	 */
	RadialMicroChart.prototype._getAriaAndTooltipText = function() {
		var sTextValue;
		var fPercentage = this.getPercentage();
		if (fPercentage > 100) {
			fPercentage = 100;
		} else if (fPercentage < 0) {
			fPercentage = 0;
		}
		if (this._isValueColorInstanceOfValueColor()) {
			sTextValue = this._rb.getText("RADIALMICROCHART_ARIA_LABEL", [this.getPercentage(), this._getStatusText()]);
		} else {
			sTextValue = this._rb.getText("RADIALMICROCHART_ARIA_LABEL", [fPercentage, sap.m.ValueColor.Neutral]);
		}
		return sTextValue;
	};

	/**
	 * Returns the status text based on color value (to be available for other languages also)
	 *
	 * @private
	 * @returns {string} value containing the status text
	 */
	RadialMicroChart.prototype._getStatusText = function() {
		var sValueColor = this.getValueColor();
		switch (sValueColor) {
			case sap.m.ValueColor.Error:
				return this._rb.getText("SEMANTIC_COLOR_ERROR");
			case sap.m.ValueColor.Critical:
				return this._rb.getText("SEMANTIC_COLOR_CRITICAL");
			case sap.m.ValueColor.Good:
				return this._rb.getText("SEMANTIC_COLOR_GOOD");
			default:
				return this._rb.getText("SEMANTIC_COLOR_NEUTRAL");
		}
	};

	return RadialMicroChart;
});

}; // end of sap/suite/ui/microchart/RadialMicroChart.js
<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
jQuery.sap.declare("sap.apf.core.messageDefinition");
sap.apf.core.messageDefinition = [ {
	code : "3001",
	severity : "technError",
	text : "Text is not available for the following key: {0}"
}, {
	code : "5001",
	severity : "technError",
	text : "Request {3} to server failed with http status code {0}, http error message {1}, and server response {2}."
}, {
	code : "5002",
	severity : "error",
	description : "Error in OData request; update of analysis step {0} failed.",
	key : "5002"
}, {
	code : "5004",
	severity : "fatal",
	description : "Request with ID {0} does not exist in the analytical content configuration.",
	key : "5004"
}, {
	code : "5005",
	severity : "technError",
	text : "Required property {1} is missing in the filter of the OData request for entity type {0}."
}, {
	code : "5006",
	severity : "technError",
	text : "Inconsistency in data model; non-filterable property {1} is set as required filter for entity type {0}."
}, {
	code : "5015",
	severity : "fatal",
	description : "Service for request {0} is not defined in the analytical content configuration.",
	key : "5015"
}, {
	code : "5016",
	severity : "technError",
	text : "Mandatory parameter key property {0} is missing in filter."
}, {
	code : "5018",
	severity : "fatal",
	description : "Metadata request {0} failed.",
	key : "5018"
}, {
	code : "5019",
	severity : "technError",
	text : "System query option $orderby for property {1} removed from OData request for entity type {0}."
}, {
	code : "5020",
	severity : "fatal",
	description : "Analytical content configuration is not available.",
	key : "5020"
}, {
	code : "5021",
	severity : "error",
	description : "Error during server request; session timeout occurred.",
	key : "5021"
}, {
	code : "5022",
	severity : "fatal",
	description : "Analytical configuration with ID {0} is not available.",
	key : "5022"
}, {
	code : "5023",
	severity : "fatal",
	description : "Texts could not be loaded for Analytical configuration with ID {0}.",
	key : "5023"
}, {
	code : "5024",
	severity : "fatal",
	description : "URL Parameter for Analytical Configuration ID must contain the ID of the application and the ID of the Analytical configuration seperated by a dot.",
	key : "5024"
}, {
	code : "5025",
	severity : "fatal",
	description : "Value for SAP client has not been provided at startup of the application.",
	key : "5025"
}, {
	code : "5026",
	severity : "fatal",
	description : "Logical system cannot be determined for SAP client {0}. ",
	key : "5026"
}, {
	code : "5027",
	severity : "technError",
	text : "Inconsistent parameters; analysis path cannot be saved. Path ID: {0}, path name: {1}, callback function {2}"
}, {
	code : "5028",
	severity : "technError",
	text : "Binding with ID {0} contains a representation without ID."
}, {
	code : "5029",
	severity : "technError",
	text : "Binding with ID {0} contains a duplicated representation ID."
}, {
	code : "5030",
	severity : "technError",
	text : "Constructor property of representation type ID {0} does not contain a module path to a valid function."
}, {
	code : "5031",
	severity : "technError",
	text : "Argument for method 'setApplicationMessageCallback' is not a function."
}, {
	code : "5032",
	severity : "technError",
	text : "System query option {1} unknown in request for entity type {0}."
}, {
	code : "5033",
	severity : "technError",
	text : "Unsupported type {0} in configuration object provided."
}, {
	code : "5034",
	severity : "technError",
	text : "Facet filter configuration attribute 'property' missing."
}, {
	code : "5035",
	severity : "technError",
	text : "Function module path contained in property preselectionFuntion of facet filter ID {0} does not contain a valid function."
}, {
	code : "5036",
	severity : "technError",
	text : "Start paramater step id {0} is not existing."
}, {
	code : "5037",
	severity : "technError",
	text : "Start paramater representation id {0} is not existing."
}, {
	code : "5038",
	severity : "technError",
	text : "Environment for sap.ushell.Container is not existing."
}, {
	code : "5039",
	severity : "technError",
	text : "Error while pushing content to the ushell container"
}, {
	code : "5040",
	severity : "technError",
	text : "Error while fetching content from the ushell container"
}, {
	code : "5100",
	severity : "fatal",
	description : "Unexpected internal error: {0}. Contact SAP.",
	key : "5100"
}, {
	code : "5101",
	severity : "technError",
	text : "Unexpected internal error: {0}. Contact SAP."
}, {
	code : "5102",
	severity : "fatal",
	description : "Wrong definition in analytical content configuration: {0}",
	key : "5102"
}, {
	code : "5103",
	severity : "technError",
	text : "Wrong definition in analytical content configuration: {0}"
}, {
	code : "5104",
	severity : "technError",
	text : "Wrong filter mapping definition in analytical content configuration"
}, {
	code : "5200",
	severity : "technError",
	text : "Server error during processing of path: {0} {1}"
}, {
	code : "5201",
	severity : "error",
	description : "Unknown server error.",
	key : "5201"
}, {
	code : "5202",
	severity : "technError",
	text : "Persistence service call returned '405 - Method not allowed'."
}, {
	code : "5203",
	severity : "technError",
	text : "Bad request; data is structured incorrectly."
}, {
	code : "5204",
	severity : "error",
	description : "Error during server request; maximum number of analysis steps exceeded.",
	key : "5204"
}, {
	code : "5205",
	severity : "error",
	description : "Error during server request; maximum number of analysis paths exceeded.",
	key : "5205"
}, {
	code : "5206",
	severity : "error",
	description : "Access forbidden; insufficient privileges",
	key : "5206"
}, {
	code : "5207",
	severity : "error",
	description : "Inserted value too large; probably maximum length of analysis path name exceeded",
	key : "5207"
}, {
	code : "5208",
	severity : "error",
	description : "Error during path persistence; request to server can not be proceed due to invalid ID.",
	key : "5208"
}, {
	code : "5210",
	severity : "error",
	description : "Error during opening of analysis path; see log.",
	key : "5210"
}, {
	code : "5211",
	severity : "error",
	description : "Server response contains undefined path objects.",
	key : "5211"
}, {
	code : "5212",
	severity : "error",
	description : "Metadata file of application {0} could not be accessed.",
	key : "5212"
}, {
	code : "5213",
	severity : "error",
	description : "Text file of application {0} could not be accessed.",
	key : "5213"
}, {
	code : "5300",
	severity : "fatal",
	description : "You must log out of the application due to a critical error.",
	key : "5300"
}, {
	code : "5301",
	severity : "warning",
	description : "Add or update path filter API method called with unsupported filter; See sap.apf.api documentation",
	key : "5301"
}, {
	code : "6001",
	severity : "fatal",
	description : "Missing {0} in the configuration; contact your administrator.",
	key : "6001"
}, {
	code : "6000",
	severity : "error",
	description : "Data is not available for the {0} step.",
	key : "6000"
}, {
	code : "6002",
	severity : "error",
	description : "Missing {0} for {1} in the configuration; contact your administrator.",
	key : "6002"
}, {
	code : "6003",
	severity : "error",
	description : "Missing {0} in the configuration; contact your administrator.",
	key : "6001"
}, {
	code : "6004",
	severity : "technError",
	text : "Metadata not available for step {0}."
}, {
	code : "6005",
	severity : "error",
	description : "Server request failed. Unable to read paths.",
	key : "6005"
}, {
	code : "6006",
	severity : "error",
	description : "Server request failed. Unable to save path {0}.",
	key : "6006"
}, {
	code : "6007",
	severity : "error",
	description : "Server request failed. Unable to update path {0}.",
	key : "6007"
}, {
	code : "6008",
	severity : "error",
	description : "Server request failed. Unable to open path {0}.",
	key : "6008"
}, {
	code : "6009",
	severity : "error",
	description : "Server request failed. Unable to delete path {0}.",
	key : "6009"
}, {
	code : "6010",
	severity : "technError",
	description : "Data is not available for filter {0}",
	key : "6010"
}, {
	code : "6011",
	severity : "fatal",
	description : "Smart Business service failed.Please try later",
	key : "6011"
}, {
	code : "7000",
	severity : "error",
	description : "Missing {0} in the configuration; contact your administrator.",
	key : "6001"
} ];
<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
jQuery.sap.require('sap.apf.modeler.ui.utils.nullObjectChecker');jQuery.sap.declare('sap.apf.modeler.ui.utils.staticValuesBuilder');(function(){'use strict';sap.apf.modeler.ui.utils.staticValuesBuilder=function(t){sap.apf.modeler.ui.utils.staticValuesBuilder.prototype.getNavTargetTypeData=function(){var a=[t("globalNavTargets"),t("stepSpecific")];return a;};};})();
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2015 SAP SE. All rights reserved
	
 */
sap.ui.define([
	"sap/gantt/shape/Rectangle", "sap/gantt/misc/Utility", "sap/ui/core/Core"
], function(Rectangle, Utility, Core){
	"use strict";

	/**
	 * Creates and initializes a new RowBackgroundRectangle class.
	 * 
	 * @param {string} [sId] ID of the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings of the new control
	 * 
	 * @class 
	 * RowBackgroundRectangle shape class using SVG tag 'rect'. It's used to represent rows' background rectangle in the tree table of a Gantt chart.
	 * 
	 * @extends sap.gantt.shape.Rectangle
	 * 
	 * @author SAP SE
	 * @version 1.36.8
	 * 
	 * @constructor
	 * @public
	 * @alias sap.gantt.shape.ext.RowBackgroundRectangle
	 */
	var RowBackgroundRectangle = Rectangle.extend("sap.gantt.shape.ext.RowBackgroundRectangle", /** @lends sap.gantt.shape.ext.RowBackgroundRectangle.prototype */ {
		metadata: {
			properties: {
				isBulk: {type: "boolean", defaultValue: true},
				enableSelection: {type: "boolean", defaultValue: false}
			}
		}
	});

	/**
	 * Gets the value of property <code>isBulk</code>.
	 * 
	 * <p>
	 * For performance reasons, Gantt charts perform filtering of data using timestamp. For a background rectangle shape which only needs to draw once in visible areas, set this flag to true.
	 * </p>
	 * 
	 * @name sap.gantt.shape.ext.RowBackgroundRectangle.prototype.getIsBulk
	 * @function
	 * 
	 * @param {object} oData Shape data.
	 * @param {object} oRowInfo Information about the row and row data.
	 * @return {boolean} Value of property <code>isBulk</code>.
	 * @public
	 */

	/**
	 * Gets the value of property <code>fill</code>.
	 * 
	 * <p> 
	 * Standard SVG 'fill' attribute.
	 * See {@link http://www.w3.org/TR/SVG/painting.html#FillProperty SVG 1.1 specification for 'fill'}.
	 * <b>Note:</b> You can provide fill with HTML colors and the URL reference to a paint server. Paint server definitions can be retrieved from paint servers rendered by
	 * {@link sap.gantt.GanttChartContainer}, {@link sap.gantt.GanttChartWithTable}, or {@link sap.gantt.GanttChart}.
	 * </p>
	 * 
	 * @param {object} oData Shape data.
	 * @param {object} oRowInfo Information about the row and row data.
	 * @return {string} Value of property <code>fill</code>.
	 * @public
	 */
	RowBackgroundRectangle.prototype.getFill = function(oData, oRowInfo) {
		if (this.mShapeConfig.hasShapeProperty("fill")){
			return this._configFirst("fill", oData);
		}
		
		var oChartSchemeMap = this.mChartInstance._oChartSchemesConfigMap;
		var oChartScheme = (oChartSchemeMap && oChartSchemeMap[oRowInfo.chartScheme]) ? oChartSchemeMap[oRowInfo.chartScheme] : undefined;
		if (oChartScheme && oChartScheme.getBackgroundColor()) {
			return oChartScheme.getBackgroundColor();
		}
		return "none";
	};

	/**
	 * Gets the value of property <code>strokeWidth</code>.
	 * 
	 * <p>
	 * Standard SVG 'stroke-width' attribute.
	 * See {@link http://www.w3.org/TR/SVG/painting.html#StrokeWidthProperty SVG 1.1 specification for 'stroke-width'}.
	 * </p>
	 * <p>The default value is 0.</p>
	 * 
	 * @param {object} oData Shape data.
	 * @param {object} oRowInfo Information about the row and row data.
	 * @return {number} Value of property <code>strokeWidth</code>.
	 * @public
	 */
	RowBackgroundRectangle.prototype.getStrokeWidth = function(oData, oRowInfo) {
		if (this.mShapeConfig.hasShapeProperty("strokeWidth")) {
			return this._configFirst("strokeWidth", oData);
		}

		return 0;
	};

	/**
	 * Gets the value of property <code>x</code>.
	 * 
	 * <p>
	 * x coordinate of the top-left point of a rectangle.
	 * See {@link http://www.w3.org/TR/SVG/shapes.html#RectElementXAttribute SVG 1.1 specification for the 'x' attribute of 'rect'}.
	 * 
	 * Your application should not configure this value. Instead, the getter calculates the value of x by using the initial coordinate 
	 * of the view boundary for visible areas in a Gantt chart.
	 * </p>
	 * 
	 * @param {object} oData Shape data.
	 * @param {object} oRowInfo Information about the row and row data.
	 * @return {number} Value of property <code>x</code>.
	 * @public
	 */
	RowBackgroundRectangle.prototype.getX = function(oData, oRowInfo) {
		if (this.mShapeConfig.hasShapeProperty("x")) {
			return this._configFirst("x", oData);
		}
		
		var aViewRange = this.getShapeViewBoundary();
		if (aViewRange){
			return aViewRange[0];
		}
		return 0;
	};

	/**
	 * Gets the value of property <code>y</code>.
	 * 
	 * <p>
	 * y coordinate of the top-left point of a rectangle.
	 * See {@link http://www.w3.org/TR/SVG/shapes.html#RectElementYAttribute SVG 1.1 specification for the 'y' attribute of 'rect'}.
	 * 
	 * Your application should not configure this value. Instead, the getter calculates the value of y by using parameter <code>oRowInfo</code>.
	 * </p>
	 * <p>The default value is the y coordinate of the row plus 1px, which is the width of the stroke.</p>
	 * 
	 * @param {object} oData Shape data.
	 * @param {object} oRowInfo Information about the row and row data.
	 * @return {number} Value of property <code>y</code>.
	 * @public
	 */
	RowBackgroundRectangle.prototype.getY = function(oData, oRowInfo) {
		if (this.mShapeConfig.hasShapeProperty("y")) {
			return this._configFirst("y", oData);
		}
		
		return oRowInfo.y + 1;
	};

	/**
	 * Gets the value of property <code>width</code>.
	 * 
	 * <p>
	 * Width of a rectangle.
	 * See {@link http://www.w3.org/TR/SVG/shapes.html#RectElementWidthAttribute SVG 1.1 specification for the 'width' attribute of 'rect'}.
	 * 
	 * Your application should not configure this value. Instead, the getter calculates the value of width by using the view boundary for visible areas in a Gantt chart.
	 * If your application overwrites the getter using configuration or code, accurate results cannot be guaranteed.
	 * </p>
	 * 
	 * @param {object} oData Shape data.
	 * @param {object} oRowInfo Information about the row and row data.
	 * @return {number} Value of property <code>width</code>.
	 * @public
	 */
	RowBackgroundRectangle.prototype.getWidth = function(oData, oRowInfo) {
		if (this.mShapeConfig.hasShapeProperty("width")) {
			return this._configFirst("width", oData);
		}
		
		var aViewRange = this.getShapeViewBoundary();
		if (aViewRange){
			return aViewRange[1] - aViewRange[0];
		}
		return 0;
	};

	/**
	 * Gets the value of property <code>height</code>.
	 * 
	 * <p>
	 * Height of a rectangle.
	 * See {@link http://www.w3.org/TR/SVG/shapes.html#RectElementHeightAttribute SVG 1.1 specification for the 'height' attribute of 'rect'}.
	 * </p>
	 * <p>The default value is the height of the row minus 1px, which is the width of stroke.</p>
	 * 
	 * @param {object} oData Shape data.
	 * @param {object} oRowInfo Information about the row and row data.
	 * @return {number} Value of property <code>height</code>.
	 * @public
	 */
	RowBackgroundRectangle.prototype.getHeight = function(oData, oRowInfo) {
		if (this.mShapeConfig.hasShapeProperty("height")) {
			return this._configFirst("height", oData);
		}
		
		return oRowInfo.rowHeight - 1;
	};

	/**
	 * Filter all data in visible areas to get valid rows' data, only these valid rows must have a background rectangle drawn, 
	 * which is filled in a certain color.
	 * 
	 * @param {array} aRowDatas data of all rows in visible areas.
	 * @return {array} data of valid rows that must have a background rectangle drawn.
	 * @public
	 */
	RowBackgroundRectangle.prototype.filterValidData = function(aRowDatas) {
		if (aRowDatas.length > 0){
			var oChart = this.mChartInstance;
			var oChartSchemeMap = oChart._oChartSchemesConfigMap;
			var oObjectTypeMap = oChart._oObjectTypesConfigMap;
			return $.grep(aRowDatas, function(oValue, iIndex) {
				var oChartScheme;
				if (oValue.__group) {
					oChartScheme = (oChartSchemeMap && oChartSchemeMap[oValue.__group]) ? oChartSchemeMap[oValue.__group] : undefined;
				} else {
					var oObjectType = (oObjectTypeMap && oObjectTypeMap[oValue.type]) ? oObjectTypeMap[oValue.type] : undefined;
					if (oObjectType) {
						oChartScheme = (oChartSchemeMap && oChartSchemeMap[oObjectType.getMainChartSchemeKey()]) ? oChartSchemeMap[oObjectType.getMainChartSchemeKey()] : undefined;
					}
				}
				if (oChartScheme && oChartScheme.getBackgroundColor()) {
					return oValue;
				}
			});
		}
		return aRowDatas;
	};
	
	/**
	 * Indicates whether your application must use HtmlClass to decide the color of background.
	 * If the theme is sap_bluecrystal, the application can use custom configuration value for fill property, but if the theme is sap_hcb,
	 * the application must use HtmlClass instead.
	 * 
	 * @param {object} oData Shape data.
	 * @param {object} oRowInfo Information about the row and row data.
	 * @return {boolean} Value indicates whether HtmlClass must be used to decide the color of the background.
	 */
	RowBackgroundRectangle.prototype.getHtmlClass = function(oData, oRowInfo) {
		if (Core.getConfiguration().getTheme() === "sap_hcb") {
			return true;
		}
		return false;
	};

	return RowBackgroundRectangle;
}, true);
<file_sep>/*
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

/**
 * @public
 * @name sap.ui.comp.transport.TransportSelection
 * @author SAP SE
 * @version 1.36.12
 * @since 1.26.0 
 * Helper object to select an ABAP transport for an LREP object. This is not a generic utility to select a transport request, but part
 *        of the SmartVariant control.
 * @param {jquery.sap.global} jQuery a reference to the jQuery implementation.
 * @param {sap.ui.fl.Utils} Utils a reference to the flexibility utilities implementation.
 * @param {sap.ui.fl.Transports} Transports a reference to the transport service implementation.
 * @param {sap.ui.comp.transport.TransportDialog} TransportDialog a reference to the transport dialog implementation.
 * @param {sap.ui.fl.registry.Settings} FlexSettings a reference to the settings implementation
 * @returns {sap.ui.comp.transport.TransportSelection} a new instance of <code>sap.ui.comp.transport.TransportSelection</code>.
 */
sap.ui.define([	"jquery.sap.global", "sap/ui/fl/Utils", "sap/ui/fl/Transports", "sap/ui/comp/transport/TransportDialog", "sap/ui/fl/registry/Settings" ], function(jQuery, Utils, Transports, TransportDialog, FlexSettings) {
	"use strict";
	/**
	 * @public
	 * @constructor
	 */
	var TransportSelection = function() {
		this.oTransports = new sap.ui.fl.Transports();
		this.oUtils = sap.ui.fl.Utils;
	};

	/**
	 * Selects a transport request for a given LREP object.
	 * First checks if the Adaptation Transport Organizer (ATO) is enabled
	 * If ATO is enabled and LREP object is in CUSTOMER layer the request 'ATO_NOTIFICATION' has to be used which in the backend triggers that the change is added to an ATO collection
	 * If ATO is not enabled or LREP object not in CUSTOMER layer:
	 * If the LREP object is already assigned to an open transport request or the LREP object is
	 * assigned to a local ABAP package, no dialog to select a transport is started. Instead the success callback is invoked directly. The transport
	 * dialog is shown if a package or a transport request has still to be selected, so if more than one transport request is available for the
	 * current user and the LREP object is not locked in an open transport request.
	 * 
	 * @param {object} oObjectInfo the LREP object, which has the attributes name, name space, type, layer and package.
	 * @param {function} fOkay call-back to be invoked when a transport request has successfully been selected.
	 * @param {function} fError call-back to be invoked when an error occurred during selection of a transport request.
	 * @param {boolean} bCompactMode flag indicating whether the transport dialog should be opened in compact mode.
	 * @param {object} oControl Control instance
	 * @public
	 */
	TransportSelection.prototype.selectTransport = function(oObjectInfo, fOkay, fError, bCompactMode, oControl) {
		var sComponentName, mPropertyBag;
		var that = this;

		if (oObjectInfo) {
			var sLayerType = Utils.getCurrentLayer(false);
			
			if (oControl) {
				sComponentName = Utils.getComponentClassName(oControl);
				var mPropertyBag = {
				                    appDescriptor: Utils.getAppDescriptor(oControl),
				                    siteId: Utils.getSiteId(oControl)
				};
			}
			// if component name and object layer are known and layer is CUSTOMER
			// check in settings if the adaptation transport organizer (ATO) is enabled
			if (sComponentName && sLayerType && sLayerType === 'CUSTOMER') {
				// retrieve the settings and check if ATO is enabled
				FlexSettings.getInstance(sComponentName, mPropertyBag).then(function(oSettings) {
					// ATO is enabled - signal that change is to be added to an ATO collection
					// instead of a transport
					if (oSettings.isAtoEnabled()) {
						var oTransport = { transportId: "ATO_NOTIFICATION" };
						fOkay(that._createEventObject(oObjectInfo, oTransport));
					// ATO is not enabled - use CTS 
					} else {
						that._selectTransport(oObjectInfo, fOkay, fError, bCompactMode);
					}
				});
			// do not have the required info to check for ATO or not CUSTOMER layer - use CTS
			} else {
				that._selectTransport(oObjectInfo, fOkay, fError, bCompactMode);
			}
		}
	};
	
	/**
	 * Selects a transport request for a given LREP object. If the LREP object is already assigned to an open transport request or the LREP object is
	 * assigned to a local ABAP package, no dialog to select a transport is started. Instead the success callback is invoked directly. The transport
	 * dialog is shown if a package or a transport request has still to be selected, so if more than one transport request is available for the
	 * current user and the LREP object is not locked in an open transport request.
	 * 
	 * @param {object} oObjectInfo the LREP object, which has the attributes name, name space, type, layer and package.
	 * @param {function} fOkay call-back to be invoked when a transport request has successfully been selected.
	 * @param {function} fError call-back to be invoked when an error occurred during selection of a transport request.
	 * @param {boolean} bCompactMode flag indicating whether the transport dialog should be opened in compact mode.
	 * @private
	 */
	TransportSelection.prototype._selectTransport = function(oObjectInfo, fOkay, fError, bCompactMode) {
		var oPromise, that = this;

		if (oObjectInfo) {
			oPromise = this.oTransports.getTransports(oObjectInfo);
			oPromise.then(function(oResult) {
				var oTransport;

				if (that._checkDialog(oResult)) {
					that._openDialog({
						hidePackage: !that.oUtils.doesSharedVariantRequirePackage(),
						pkg: oObjectInfo["package"],
						transports: oResult.transports,
						lrepObject: that._toLREPObject(oObjectInfo)
					}, fOkay, fError, bCompactMode);
				} else {
					oTransport = that._getTransport(oResult);
					fOkay(that._createEventObject(oObjectInfo, oTransport));
				}
			}, function(oResult) {
				fError(oResult);
			});
		}
	};

	/**
	 * Creates an event object similar to the UI5 event object.
	 * 
	 * @param {object} oObjectInfo identifies the LREP object.
	 * @param {object} oTransport the transport request that has been selected.
	 * @return {object} event object.
	 * @private
	 */
	TransportSelection.prototype._createEventObject = function(oObjectInfo, oTransport) {
		return {
			mParameters: {
				selectedTransport: oTransport.transportId,
				selectedPackage: oObjectInfo["package"],
				dialog: false
			},
			getParameters: function() {
				return this.mParameters;
			},
			getParameter: function(sName) {
				return this.mParameters[sName];
			}
		};
	};

	/**
	 * Creates an LREP object description for the transport dialog.
	 * 
	 * @param {object} oObjectInfo identifies the LREP object.
	 * @return {object} LREP object description for the transport dialog.
	 * @private
	 */
	TransportSelection.prototype._toLREPObject = function(oObjectInfo) {
		var oObject = {};

		if (oObjectInfo.namespace) {
			oObject.namespace = oObjectInfo.namespace;
		}

		if (oObjectInfo.name) {
			oObject.name = oObjectInfo.name;
		}

		if (oObjectInfo.type) {
			oObject.type = oObjectInfo.type;
		}

		return oObject;
	};

	/**
	 * Opens the dialog to select a transport request.
	 * 
	 * @param {object} oConfig configuration for the dialog, e.g. package and transports.
	 * @param {function} fOkay call-back to be invoked when a transport request has successfully been selected.
	 * @param {function} fError call-back to be invoked when an error occurred during selection of a transport request.
	 * @param {boolean} bCompactMode flag indicating whether the transport dialog should be opened in compact mode.
	 * @returns {sap.ui.comp.transport.TransportDialog} the dialog.
	 * @private
	 */
	TransportSelection.prototype._openDialog = function(oConfig, fOkay, fError, bCompactMode) {
		var oDialog = new TransportDialog(oConfig);
		oDialog.attachOk(fOkay);
		oDialog.attachCancel(fError);

		// toggle compact style.
		if (bCompactMode) {
			oDialog.addStyleClass("sapUiSizeCompact");
		} else {
			oDialog.removeStyleClass("sapUiSizeCompact");
		}

		oDialog.open();

		return oDialog;
	};

	/**
	 * Returns a transport to assign an LREP object to.
	 * 
	 * @param {object} oTransports the available transports.
	 * @returns {object} a transport to assign an LREP object to, can be <code>null</code>.
	 * @private
	 */
	TransportSelection.prototype._getTransport = function(oTransports) {
		var oTransport;

		if (!oTransports.localonly) {
			oTransport = this._hasLock(oTransports.transports);
		} else {
			oTransport = {
				transportId: ""
			};
		}

		return oTransport;
	};

	/**
	 * Returns whether the dialog to select a transport should be started.
	 * 
	 * @param {object} oTransports the available transports.
	 * @returns {boolean} <code>true</code>, if the LREP object is already locked in one of the transports, <code>false</code> otherwise.
	 * @private
	 */
	TransportSelection.prototype._checkDialog = function(oTransports) {
		if (oTransports) {
			if (oTransports.localonly || this._hasLock(oTransports.transports)) {
				return false;
			}
		}

		return true;
	};

	/**
	 * Returns whether the LREP object is already locked in one of the transports.
	 * 
	 * @param {array} aTransports the available transports.
	 * @returns {object} the transport, if the LREP object is already locked in one of the transports, <code>null</code> otherwise.
	 * @private
	 */
	TransportSelection.prototype._hasLock = function(aTransports) {
		var oTransport, len = aTransports.length;

		while (len--) {
			oTransport = aTransports[len];

			if (oTransport.locked) {
				return oTransport;
			}
		}

		return false;
	};

	return TransportSelection;
}, true);
<file_sep>/* SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP SE. All rights reserved
 */
jQuery.sap.declare("sap.apf.ui.representations.table");
jQuery.sap.require("sap.apf.core.constants");
jQuery.sap.require('sap.apf.ui.utils.formatter');
jQuery.sap.require("sap.apf.ui.representations.BaseUI5ChartRepresentation");
(function() {
	'use strict';
	//select the items in the table which are passed as parameter
	function _selectItemsInTable(aSelectedItems) {
		oTableWithoutHeaders.removeSelections();// remove all the selections , so that older values are not retained
		aSelectedItems.forEach(function(item) {
			oTableWithoutHeaders.setSelectedItem(item);
		});
	}
	//clear the filters from the UI5Charthelper and also from APF filters
	function _clearFilters(oTableInstance) {
		oTableInstance.UI5ChartHelper.filterValues = [];
		oTableInstance.setFilter(oTableInstance.oApi.createFilter());
	}
	//creates the filter values from the filters
	function _getFilterTremsFromTableSelection(oTableInstance) {
		var sRequiredFilterProperty = oTableInstance.getFilter().getInternalFilter().getProperties()[0]; // read the required property in the table
		var aFilterTerms = oTableInstance.getFilter().getInternalFilter().getFilterTermsForProperty(sRequiredFilterProperty); //read the filter terms
		var aFilterValues = aFilterTerms.map(function(term) {
			return term.getValue();
		});
		return aFilterValues;
	}
	//read the filters and select the rows in table. Also read the selected items where selection is enabled, creates the filters from selections
	function _drawSelection(oEvent) {
		var aFilterValues = [], sRequiredFilterProperty;
		var aCurrentSelectedItem = oEvent.getParameters("listItems").listItems; // store the current selected item for which selection event is triggered
		if (this.UI5ChartHelper) { // if the UI5ChartHelper is available , then only filters would be present
			var aInternalFilters = this.getFilter().getInternalFilter().getProperties();
			aFilterValues = aInternalFilters.length > 0 ? _getFilterTremsFromTableSelection(this) : []; // if there are filters then get the filters or it will be an empty array
			sRequiredFilterProperty = aInternalFilters[0]; // read the required property in the table	
			aFilters = aFilterValues; //update the filters for the table , for the selection count. In case of selection coming from charts
		}
		//enable the selection mode in the table based on the required filter availability
		var selectionMode = this.oParameter.requiredFilters.length > 0 ? "MultiSelect" : "None";
		oTableWithoutHeaders.setMode(selectionMode);
		if (oEvent.getId() === "selectionChange") { //if the explicit selection is made on the table, selectionChanged event is triggered
			var isSelectionChanged = true;// boolean to indicate if the selection changed API is triggered just once 
			var newAddedFilters = [];
			sRequiredFilterProperty = aInternalFilters[0] || this.parameter.requiredFilters[0]; //read the required filter from the internal filter or the required filters (when table is created, the internal filter wont be available)  
			var sCurrentRequiredFilter = aCurrentSelectedItem[0].getBindingContext().getProperty(this.parameter.requiredFilters[0]);//required filter from current selected item
			//toggle the selection in table
			if (aCurrentSelectedItem[0].isSelected()) {
				newAddedFilters.push(sCurrentRequiredFilter); // if new item is selected, add it to the new added filter array
			} else {
				var indexOfToggledItem = aFilterValues.indexOf(sCurrentRequiredFilter);
				if (indexOfToggledItem !== -1) { // if item is deselected, find the index of item and remove it from array
					aFilterValues.splice(indexOfToggledItem, 1);
				}
			}
			aFilterValues = aFilterValues.concat(newAddedFilters.filter(function(item) { // merge the unique filters into an array
				return aFilterValues.indexOf(item) < 0;
			}));
			aFilters = aFilterValues;//update the filters for the table , for the selection count. In case of selection event
			if (isSelectionChanged) { // if the selection has changed and selectionChanged event has to be triggered
				_clearFilters(this); // clear the filters first, so that older values are not retained on the UI5ChartHelper filetr values
				this.filter = this.UI5ChartHelper.getFilterFromSelection(aFilterValues);
				this.oApi.getActiveStep().getSelectedRepresentation().UI5ChartHelper.filterValues = this.UI5ChartHelper.filterValues; // assign the filter values from table to the selected representation 
				this.oApi.selectionChanged(); // trigger the selection change event
			} else {
				isSelectionChanged = true;// make the boolean true, so that the selectionChanges API is triggered
			}
		}
		//read the filter directly in case of updateFinished event
		var aAllSelectionInTable = oEvent.getSource().getItems().filter(function(item) { // selection in table which are based on the result filter values
			var reqFilterValue = item.getBindingContext().getProperty(sRequiredFilterProperty);
			return aFilterValues.indexOf(reqFilterValue) !== -1;
		});
		_selectItemsInTable(aAllSelectionInTable);
	}
	//reads the filters and selects the rows in print of table
	function _drawSelectionForPrint(oTableInstance) {
		var aFilterValues = _getFilterTremsFromTableSelection(oTableInstance);
		var sRequiredFilterProperty = oTableInstance.getFilter().getInternalFilter().getProperties()[0]; // read the required property in the table
		var aSelectedListItems = oPrintTable.getItems().filter(function(item) {
			var reqFilterValue = item.getBindingContext().getProperty(sRequiredFilterProperty);
			return aFilterValues.indexOf(reqFilterValue) !== -1;
		});
		var selectionMode = oTableInstance.oParameter.requiredFilters.length > 0 ? "MultiSelect" : "None";
		oPrintTable.setMode(selectionMode);
		return aSelectedListItems;
	}
	var oFormatter, aFilters, tableFields, tableColumns, isAlternateRepresentation, oTableWithoutHeaders, oTableWithHeaders, oPrintTable, aTableData = [];
	var eventsFired, skipAction, skip, topValue, triggerBool;
	var oTableDataModel = new sap.ui.model.json.JSONModel();
	oTableDataModel.setSizeLimit(10000);
	/**
	 * @class table constructor.
	 * @param oApi,oParameters
	 * defines parameters required for chart such as Dimension/Measures.
	 * @returns table object
	 */
	sap.apf.ui.representations.table = function(oApi, oParameters) {
		this.oParameter = oParameters;
		sap.apf.ui.representations.BaseUI5ChartRepresentation.apply(this, [ oApi, oParameters ]);
		isAlternateRepresentation = oParameters.isAlternateRepresentation;
		this.alternateRepresentation = oParameters.defaultListConfigurationTypeID;
		this.type = sap.apf.ui.utils.CONSTANTS.representationTypes.TABLE_REPRESENTATION; //the type is read from step toolbar and step container
		triggerBool = false;
		eventsFired = 0;
		skipAction = 0;
		skip = 0;
		topValue = 10;
		aFilters = [];
		this.aDataResponse = [];// getData in the base class reads the value of data response from this
	};
	sap.apf.ui.representations.table.prototype = Object.create(sap.apf.ui.representations.BaseUI5ChartRepresentation.prototype);
	sap.apf.ui.representations.table.prototype.constructor = sap.apf.ui.representations.table;// Set the "constructor" property to refer to table
	/**
	 * @method setData
	 * @param aDataResponse - Response from oData service
	 * @param metadata - Metadata of the oData service
	 * @description Public API which Fetches the data from oData service and updates the selection if present
	 */
	sap.apf.ui.representations.table.prototype.setData = function(aDataResponse, metadata) {
		var self = this;
		if (skipAction === 0) {
			if (triggerBool) { //if pagination is triggered
				aDataResponse.map(function(dataRow) {
					self.aDataResponse.push(dataRow);// for pagination , append the data to the existing data set
				});
				skipAction++;
			} else { //if the data is being loaded for first time
				skip = 0;
				topValue = 100;//initially 100 records should be fetched
				aTableData = [];
				self.aDataResponse = aDataResponse; // For new table, read only 100 data set
			}
		}
		aTableData = self.aDataResponse || [];
		if (!metadata) {
			this.oMessageObject = this.oApi.createMessageObject({
				code : "6004",
				aParameters : [ this.oApi.getTextNotHtmlEncoded("step") ]
			});
			this.oApi.putMessage(this.oMessageObject);
		} else { //if metadata is available
			this.metadata = metadata; // assign the metadata to be used in the table representation
			oFormatter = new sap.apf.ui.utils.formatter({ // formatter for the value formatting
				getEventCallback : this.oApi.getEventCallback.bind(this.oApi),
				getTextNotHtmlEncoded : this.oApi.getTextNotHtmlEncoded
			}, metadata, aDataResponse);
			this.UI5ChartHelper.metadata = metadata;
		}
	};
	/**
	* @method createDataset
	* @description Intantiates the dataset to be consumed by the table
	* Also formats the column value which has to be displayed in the table
	*/
	sap.apf.ui.representations.table.prototype.createDataset = function() {
		tableFields = [];
		tableColumns = {
			name : [],
			value : []
		};
		tableFields = this.oParameter.dimensions.concat(this.oParameter.measures).length ? this.oParameter.dimensions.concat(this.oParameter.measures) : this.oParameter.properties; // read the table properties if available , else Concatenate dimensions & measures
		aTableData = this.getData();
		if (aTableData.length !== 0) {
			for(var i = 0; i < tableFields.length; i++) {
				tableColumns.value[i] = tableFields[i].fieldName;
				var name = "";
				var defaultLabel = this.metadata.getPropertyMetadata(tableFields[i].fieldName).label || this.metadata.getPropertyMetadata(tableFields[i].fieldName).name;
				var sUnitValue = "";
				if (this.metadata !== undefined && this.metadata.getPropertyMetadata(tableFields[i].fieldName).unit !== undefined) {
					var sUnitReference = this.metadata.getPropertyMetadata(tableFields[i].fieldName).unit;
					sUnitValue = this.getData()[0][sUnitReference]; // take value of unit from firts data set
					name = tableFields[i].fieldDesc === undefined || !this.oApi.getTextNotHtmlEncoded(tableFields[i].fieldDesc).length ? defaultLabel + " (" + sUnitValue + ")" : this.oApi.getTextNotHtmlEncoded(tableFields[i].fieldDesc) + " ("
							+ sUnitValue + ")";
					tableColumns.name[i] = name;
				} else {
					tableColumns.name[i] = tableFields[i].fieldDesc === undefined || !this.oApi.getTextNotHtmlEncoded(tableFields[i].fieldDesc).length ? defaultLabel : this.oApi.getTextNotHtmlEncoded(tableFields[i].fieldDesc);
				}
			}
		}
	};
	/**
	* @method getSelectionFromChart
	* @returns the selected items in the table.
	*/
	sap.apf.ui.representations.table.prototype.getSelectionFromChart = function() {
		var aSelection = oTableWithoutHeaders.getSelectedItems();
		return aSelection;
	};
	/**
	* @method getSelections
	* @description This method helps in determining the selection count, text and id of selected data of a representation
	* @returns the filter selections of the current representation.
	*/
	sap.apf.ui.representations.table.prototype.getSelections = function() {
		var aSelection = [];
		if (aFilters) {
			aFilters.forEach(function(filter) {
				aSelection.push({
					id : filter,
					text : filter
				});
			});
		}
		return aSelection;
	};
	/**
	* @method getRequestOptions
	* @description provide optional filter properties for odata request URL such as pagging, sorting etc
	*/
	sap.apf.ui.representations.table.prototype.getRequestOptions = function() {
		if (!triggerBool) {
			topValue = 100;
			skip = 0;
			skipAction = 0;
		}
		var requestObj = {
			paging : {
				top : topValue,
				skip : skip,
				inlineCount : true
			}
		};
		var orderByArray;
		if (this.sortProperty !== undefined) {
			orderByArray = [ {
				property : this.sortProperty,
				descending : this.sortOrderIsDescending
			} ];
			requestObj.orderby = orderByArray;
		} else {
			if (this.getParameter().orderby && this.getParameter().orderby.length) {
				var aOrderbyProps = this.getParameter().orderby.map(function(oOrderby) {
					return {
						property : oOrderby.property,
						descending : !oOrderby.ascending
					};
				});
				requestObj.orderby = aOrderbyProps;
			}
		}
		return requestObj;
	};
	/**
	 * @method getMainContent
	 * @param oStepTitle - title of the main chart
	 * @param width - width of the main chart
	 * @param height - height of the main chart       
	 * @description draws Main chart into the Chart area
	 */
	sap.apf.ui.representations.table.prototype.getMainContent = function(oStepTitle, height, width) {
		var self = this;
		this.createDataset();
		var oMessageObject;
		if (!oStepTitle) {
			oMessageObject = this.oApi.createMessageObject({
				code : "6002",
				aParameters : [ "title", this.oApi.getTextNotHtmlEncoded("step") ]
			});
			this.oApi.putMessage(oMessageObject);
		}
		if (tableFields.length === 0) {
			oMessageObject = this.oApi.createMessageObject({
				code : "6002",
				aParameters : [ "dimensions", oStepTitle ]
			});
			this.oApi.putMessage(oMessageObject);
		}
		if (!aTableData || aTableData.length === 0) {
			oMessageObject = this.oApi.createMessageObject({
				code : "6000",
				aParameters : [ oStepTitle ]
			});
			this.oApi.putMessage(oMessageObject);
		}
		var chartWidth = (width || 1000) + "px";
		var columnCells = [];
		var indexForColumn;
		var fnCellValue = function(index) {
			return function(columnValue) {
				if (self.metadata === undefined) {
					return columnValue;
				} else {
					var formatedColumnValue;
					if (tableColumns.value[index] && columnValue) {
						formatedColumnValue = oFormatter.getFormattedValue(tableColumns.value[index], columnValue);
					}
					if (formatedColumnValue !== undefined) {
						return formatedColumnValue;
					} else {
						return columnValue;
					}
				}
			};
		};
		var tableCellValues;
		for(indexForColumn = 0; indexForColumn < tableColumns.name.length; indexForColumn++) {
			tableCellValues = new sap.m.Text().bindText(tableColumns.value[indexForColumn], fnCellValue(indexForColumn), sap.ui.model.BindingMode.OneWay);
			columnCells.push(tableCellValues);
		}
		var columnsWithHeaders = [], columnsWithoutHeaders = [];
		var columnNameWithHeaders, columnNameWithoutHeaders;
		var indexTableColumn;
		for(indexTableColumn = 0; indexTableColumn < tableColumns.name.length; indexTableColumn++) {
			columnNameWithHeaders = new sap.m.Column({
				header : new sap.m.Text({
					text : tableColumns.name[indexTableColumn]
				})
			});
			columnsWithHeaders.push(columnNameWithHeaders);
			columnNameWithoutHeaders = new sap.m.Column();
			columnsWithoutHeaders.push(columnNameWithoutHeaders);
		}
		// Table with Headers
		oTableWithHeaders = new sap.m.Table({
			headerText : oStepTitle,
			showNoData : false,
			columns : columnsWithHeaders
		}).addStyleClass("tableWithHeaders");
		// Table without Headers (built to get scroll only on the data part)
		oTableWithoutHeaders = new sap.m.Table({
			columns : columnsWithoutHeaders,
			items : {
				path : "/tableData",
				template : new sap.m.ColumnListItem({
					cells : columnCells
				})
			},
			selectionChange : _drawSelection.bind(self)
		});
		oTableDataModel.setData({
			tableData : aTableData
		});
		oTableWithHeaders.setModel(oTableDataModel);
		oTableWithoutHeaders.setModel(oTableDataModel);
		oTableWithoutHeaders.attachUpdateFinished(_drawSelection.bind(self));
		var handleConfirm = function(oEvent) {
			var param = oEvent.getParameters();
			oTableWithoutHeaders.setBusy(true);
			skipAction = 0;
			self.sortProperty = param.sortItem.getKey();
			self.orderby = self.sortOrderIsDescending = param.sortDescending;
			topValue = 100;
			skip = 0;
			var sorter = [];
			if (param.sortItem) {
				if (isAlternateRepresentation) {
					var oTableBinding = oTableWithoutHeaders.getBinding("items");
					sorter.push(new sap.ui.model.Sorter(self.sortProperty, self.sortOrderIsDescending));
					oTableBinding.sort(sorter);
					oTableWithoutHeaders.setBusy(false);
					return;
				}
				self.oApi.updatePath(function(oStep, bStepChanged) {
					if (oStep === self.oApi.getActiveStep()) {
						oTableDataModel.setData({
							tableData : aTableData
						});
						oTableWithoutHeaders.rerender();
						oTableWithoutHeaders.setBusy(false);
					}
				});
			}
		};
		this.viewSettingsDialog = new sap.m.ViewSettingsDialog({// sort of table using ViewSettingsDialog
			confirm : handleConfirm
		});
		var columnIndex;
		for(columnIndex = 0; columnIndex < oTableWithHeaders.getColumns().length; columnIndex++) {
			var oItem = new sap.m.ViewSettingsItem({
				text : tableColumns.name[columnIndex],
				key : tableColumns.value[columnIndex]
			});
			this.viewSettingsDialog.addSortItem(oItem);
		}
		var sortItemIndex;
		if (this.sortProperty === undefined && this.sortOrderIsDescending === undefined) {// Set default values of radio buttons in view settings dialog
			if (this.getParameter().orderby && this.getParameter().orderby.length) {
				for(sortItemIndex = 0; sortItemIndex < this.viewSettingsDialog.getSortItems().length; sortItemIndex++) {
					if (this.getParameter().orderby[0].property === this.viewSettingsDialog.getSortItems()[sortItemIndex].getKey()) {
						this.viewSettingsDialog.setSelectedSortItem(this.viewSettingsDialog.getSortItems()[sortItemIndex]);
						this.viewSettingsDialog.setSortDescending(!this.getParameter().orderby[0].ascending);
					}
				}
			} else {
				this.viewSettingsDialog.setSelectedSortItem(this.viewSettingsDialog.getSortItems()[0]);// by default set the first value in sort field and sort order
				this.viewSettingsDialog.setSortDescending(false);
			}
		} else {
			for(sortItemIndex = 0; sortItemIndex < this.viewSettingsDialog.getSortItems().length; sortItemIndex++) {
				if (this.sortProperty === this.viewSettingsDialog.getSortItems()[sortItemIndex].getKey()) {
					this.viewSettingsDialog.setSelectedSortItem(this.viewSettingsDialog.getSortItems()[sortItemIndex]);
				}
			}
			this.viewSettingsDialog.setSortDescending(this.sortOrderIsDescending);
			var sorter = [];
			if (isAlternateRepresentation) {
				var oTableBinding = oTableWithoutHeaders.getBinding("items");
				sorter.push(new sap.ui.model.Sorter(this.sortProperty, this.sortOrderIsDescending));
				oTableBinding.sort(sorter);
			}
		}
		var fieldIndex;
		if (this.metadata !== undefined) {// aligning amount fields
			for(fieldIndex = 0; fieldIndex < tableColumns.name.length; fieldIndex++) {
				var oMetadata = this.metadata.getPropertyMetadata(tableColumns.value[fieldIndex]);
				if (oMetadata.unit) {
					var amountCol = oTableWithoutHeaders.getColumns()[fieldIndex];
					amountCol.setHAlign(sap.ui.core.TextAlign.Right);
				}
			}
		}
		var scrollContainer = new sap.m.ScrollContainer({// Scroll container for table without headers(to get vertical scroll on  data part used for pagination
			content : oTableWithoutHeaders,
			height : "480px",
			horizontal : false,
			vertical : true
		}).addStyleClass("tableWithoutHeaders");
		var loadMoreLink = new sap.m.Link({
			text : "More"
		}).addStyleClass("loadMoreLink");
		var scrollContainer1 = new sap.m.ScrollContainer({// Scroll container to hold table with headers and scroll container containing table without headers
			content : [ oTableWithHeaders, scrollContainer ],
			width : chartWidth,
			horizontal : true,
			vertical : false
		}).addStyleClass("scrollContainer");
		oTableDataModel.setSizeLimit(10000); // Set the size of data response to 10000 records
		oTableWithHeaders.addEventDelegate({//Event delegate to bind pagination action
			onAfterRendering : function() {
				jQuery(".scrollContainer > div:first-child").css({// For IE-Full width for alternate representation
					"display" : "table",
					"width" : "inherit"
				});
				var scrollContainerHeight;
				if (this.offsetTop === undefined) {
					this.offsetTop = jQuery(".tableWithoutHeaders").offset().top;
				}
				if (jQuery(".tableWithoutHeaders").offset().top !== this.offsetTop) {// fullscreen
					scrollContainerHeight = ((window.innerHeight - jQuery('.tableWithoutHeaders').offset().top)) + "px";
				} else {
					scrollContainerHeight = ((window.innerHeight - jQuery('.tableWithoutHeaders').offset().top) - (jQuery(".applicationFooter").height()) - 20) + "px";
				}
				document.querySelector('.tableWithoutHeaders').style.cssText += "height : " + scrollContainerHeight;
				var dLoadMoreLink = sap.ui.getCore().getRenderManager().getHTML(loadMoreLink);
				sap.ui.Device.orientation.attachHandler(function() {// TODO for height issue on orientation change
					scrollContainer1.rerender();
				});
				var oActiveStep = self.oApi.getActiveStep();
				if (oActiveStep.getSelectedRepresentation().bIsAlternateView === undefined || oActiveStep.getSelectedRepresentation().bIsAlternateView === false) {// Check if alternate representation else don't paginate
					if (sap.ui.Device.browser.mobile) {
						if (aTableData.length > 0) {// Add More Button for Mobile Device for
							jQuery(jQuery(".tableWithoutHeaders > div:first-child")).append(dLoadMoreLink);
						}
						loadMoreLink.attachPress(function() {
							if (!jQuery(".openToggleImage").length && (aTableData.length > 0)) {
								if (eventsFired === 0) {
									triggerPagination();
									skipAction = 0;
									eventsFired++;
									jQuery(".loadMoreLink").remove();
									jQuery(jQuery(".tableWithoutHeaders > div:first-child")).append(dLoadMoreLink);
								}
							} else {
								jQuery(".loadMoreLink").remove();
							}
						});
					} else {
						jQuery('.tableWithoutHeaders').on("scroll", function() {// Mouse scroll, Mouse Down and Mouse Up Events for desktop
							var self = jQuery(this);
							var scrollTop = self.prop("scrollTop");
							var scrollHeight = self.prop("scrollHeight");
							var offsetHeight = self.prop("offsetHeight");
							var contentHeight = scrollHeight - offsetHeight - 5;
							if ((contentHeight <= scrollTop) && !jQuery(".openToggleImage").length && (aTableData.length > 0)) {
								if (eventsFired === 0) {
									triggerPagination();
									skipAction = 0;
									eventsFired++;
								}
							}
						});
					}
				}
				var triggerPagination = function() {
					oTableWithoutHeaders.setBusy(true);
					sap.ui.getCore().applyChanges();
					var oData = oTableDataModel.getData();
					skip = oData.tableData.length; // already fetched data should be skipped
					topValue = 10;
					triggerBool = true;
					self.oApi.updatePath(function(oStep, bStepChanged) {
						if (oStep === self.oApi.getActiveStep()) {
							oTableDataModel.setData(oData);
							oTableWithoutHeaders.rerender();
							oTableWithoutHeaders.setBusy(false);
							eventsFired = 0;
						}
					});
				};
			}
		});
		return new sap.ui.layout.VerticalLayout({
			content : [ scrollContainer1 ]
		});
	};
	/**
	 * @method getThumbnailContent
	 * @description draws Thumbnail for the current chart and returns to the calling object
	 * @returns thumbnail object for column
	 */
	sap.apf.ui.representations.table.prototype.getThumbnailContent = function() {
		var oThumbnailContent;
		if (this.aDataResponse !== undefined && this.aDataResponse.length !== 0) {
			var image = new sap.ui.core.Icon({
				src : "sap-icon://table-chart",
				size : "70px"
			}).addStyleClass('thumbnailTableImage');
			oThumbnailContent = image;
		} else {
			var noDataText = new sap.m.Text({
				text : this.oApi.getTextNotHtmlEncoded("noDataText")
			}).addStyleClass('noDataText');
			oThumbnailContent = new sap.ui.layout.VerticalLayout({
				content : noDataText
			});
		}
		return oThumbnailContent;
	};
	/**
	 * @method removeAllSelection
	 * @description removes all Selection from Chart
	 */
	sap.apf.ui.representations.table.prototype.removeAllSelection = function() {
		_clearFilters(this);
		aFilters = [];//clear the filters
		oTableWithoutHeaders.removeSelections();
		this.oApi.getActiveStep().getSelectedRepresentation().UI5ChartHelper.filterValues = []; // reset the filter values from table to the selected representation
		this.oApi.selectionChanged();
	};
	/**
	 * @method getPrintContent
	 * @param oStepTitle
	 * title of the step
	 * @description gets the printable content of the representation
	 */
	sap.apf.ui.representations.table.prototype.getPrintContent = function(oStepTitle) {
		var self = this;
		this.createDataset();
		var oPrintTableModel = new sap.ui.model.json.JSONModel();
		oPrintTableModel.setData({
			tableData : aTableData
		});
		var i;
		var columns = [];
		for(i = 0; i < tableColumns.name.length; i++) {
			this.columnName = new sap.m.Column({
				width : "75px",
				header : new sap.m.Label({
					text : tableColumns.name[i]
				})
			});
			columns.push(this.columnName);
		}
		var columnCells = [];
		var fnColumnValue = function(index) {
			return function(columnValue) {
				if (self.metadata === undefined) {
					return columnValue;
				} else {
					var oMetadata = self.metadata.getPropertyMetadata(tableColumns.value[index]);
					if (oMetadata.dataType.type === "Edm.DateTime") {
						if (columnValue === null) {
							return "-";
						}
						var dateFormat = new Date(parseInt(columnValue.slice(6, columnValue.length - 2), 10));
						dateFormat = dateFormat.toLocaleDateString();
						if (dateFormat === "Invalid Date") {
							return "-";
						}
						return dateFormat;
					}
					if (oMetadata.unit) {
						if (columnValue === null) {
							return "-";
						}
						var currencyMetadata = self.metadata.getPropertyMetadata(oMetadata.unit);
						if (currencyMetadata.semantics === "currency-code") {
							var precision = aTableData[0][oMetadata.scale];
							columnValue = parseFloat(columnValue, 10).toFixed(precision).toString();
							var store = columnValue.split(".");
							var amountValue = parseFloat(store[0]).toLocaleString();
							var sample = 0.1;
							sample = sample.toLocaleString();
							if (amountValue.split(sample.substring(1, 2)).length > 1) {
								amountValue = amountValue.split(sample.substring(1, 2))[0];
							}
							amountValue = amountValue.concat(sample.substring(1, 2), store[1]);
							return amountValue;
						}
					} else {
						return columnValue;
					}
				}
			};
		};
		var tableCellValues;
		for(i = 0; i < tableColumns.name.length; i++) {
			tableCellValues = new sap.m.Text().bindText(tableColumns.value[i], fnColumnValue(i), sap.ui.model.BindingMode.OneWay);
			columnCells.push(tableCellValues);
		}
		oPrintTable = new sap.m.Table({
			headerText : oStepTitle,
			headerDesign : sap.m.ListHeaderDesign.Standard,
			columns : columns,
			items : {
				path : "/tableData",
				template : new sap.m.ColumnListItem({
					cells : columnCells
				})
			}
		});
		if (this.metadata !== undefined) {// aligning amount fields
			for(i = 0; i < tableColumns.name.length; i++) {
				var oMetadata = this.metadata.getPropertyMetadata(tableColumns.value[i]);
				if (oMetadata.unit) {
					var amountCol = oPrintTable.getColumns()[i];
					amountCol.setHAlign(sap.ui.core.TextAlign.Right);
				}
			}
		}
		oPrintTable.setModel(oPrintTableModel);
		var aSelectedListItems = _drawSelectionForPrint(this);// set the selections on table
		return {
			oTableForPrint : new sap.ui.layout.VerticalLayout({
				content : [ oPrintTable ]
			}),
			aSelectedListItems : aSelectedListItems
		};
	};
}());<file_sep>/*
 * ! SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

// Provides control sap.ui.comp.navpopover.NavigationPopover.
sap.ui.define([
	'jquery.sap.global', 'sap/m/CustomListItem', 'sap/m/Link', 'sap/m/Popover', 'sap/ui/core/Title', 'sap/ui/layout/form/SimpleForm', 'sap/m/VBox', 'sap/m/PopoverRenderer'
], function(jQuery, CustomListItem, Link, Popover, Title, SimpleForm, VBox, PopoverRenderer) {
	"use strict";

	/**
	 * Constructor for a new navpopover/NavigationPopover.
	 * 
	 * @param {string} [sId] ID for the new control, generated automatically if no ID is given
	 * @param {object} [mSettings] Initial settings for the new control
	 * @class The NavigationPopover allows navigating to different destinations by providing links on a popover.<br>
	 *        The links are fetched using the {@link sap.ushell.services.CrossApplicationNavigation CrossApplicationNavigation} service of the unified
	 *        shell.<br>
	 *        This class gets instantiated by {@link sap.ui.comp.navpopover.SmartLink SmartLink}. It is recommended to use
	 *        {@link sap.ui.comp.navpopover.SmartLink SmartLink} instead of creating NavigationPopover manually.
	 * @extends sap.m.Popover
	 * @constructor
	 * @public
	 * @alias sap.ui.comp.navpopover.NavigationPopover
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var NavigationPopover = Popover.extend("sap.ui.comp.navpopover.NavigationPopover", /** @lends sap.ui.comp.navpopover.NavigationPopover.prototype */
	{
		metadata: {

			library: "sap.ui.comp",
			properties: {

				/**
				 * popover title
				 * 
				 * @since 1.28.0
				 */
				title: {
					type: "string",
					group: "Misc",
					defaultValue: null
				},

				/**
				 * the name of the semantic object
				 * 
				 * @since 1.28.0
				 */
				semanticObjectName: {
					type: "string",
					group: "Misc",
					defaultValue: null
				},

				/**
				 * describes the semantic attributes. The attribute has to be a map
				 * 
				 * @since 1.28.0
				 */
				semanticAttributes: {
					type: "object",
					group: "Misc",
					defaultValue: null
				},

				/**
				 * The application state key passed to retrieve the navigation targets.
				 * 
				 * @since 1.28.0
				 */
				appStateKey: {
					type: "string",
					group: "Misc",
					defaultValue: null
				},

				/**
				 * Sets the visible text for the main navigation. If empty, the navigationPopover will try to get the Id from the given sourceObject.
				 */
				mainNavigationId: {
					type: "string",
					group: "Misc",
					defaultValue: null
				}
			},
			aggregations: {

				/**
				 * A list of available actions shown to the user.
				 * 
				 * @since 1.28.0
				 */
				availableActions: {
					type: "sap.ui.comp.navpopover.LinkData",
					multiple: true,
					singularName: "availableAction"
				},

				/**
				 * The main navigation displayed first on the popover.
				 * 
				 * @since 1.28.0
				 */
				mainNavigation: {
					type: "sap.ui.comp.navpopover.LinkData",
					multiple: false
				},

				/**
				 * The navigation taking the user back to the source application.
				 * 
				 * @since 1.28.0
				 */
				ownNavigation: {
					type: "sap.ui.comp.navpopover.LinkData",
					multiple: false
				}
			},
			associations: {

				/**
				 * Source control for which the popover is displayed.
				 * 
				 * @since 1.28.0
				 */
				source: {
					type: "sap.ui.core.Control",
					multiple: false
				},

				/**
				 * ExtraContent is displayed between the main navigation and the additional available links.
				 * 
				 * @since 1.28.0
				 */
				extraContent: {
					type: "sap.ui.core.Control",
					multiple: false
				},

				/**
				 * The parent component.
				 */
				component: {
					type: "sap.ui.core.Element",
					multiple: false
				}
			},
			events: {

				/**
				 * The navigation targets that are shown.
				 * 
				 * @since 1.28.0
				 */
				targetsObtained: {},

				/**
				 * Event is triggered when a link is pressed.
				 * 
				 * @since 1.28.0
				 */
				navigate: {}
			}
		},
		renderer: PopoverRenderer.render
	});

	NavigationPopover.prototype.init = function() {
		Popover.prototype.init.call(this);

		this.addStyleClass("navigationPopover");

		this.setContentWidth("380px");
		this.setHorizontalScrolling(false);
		this.setPlacement(sap.m.PlacementType.Auto);

		this._oHeaderForm = new SimpleForm({
			maxContainerCols: 1,
			visible: true
		});

		this._oMainNavigationText = new Title();
		this._oMainNavigationLink = new Link();
		this._oMainNavigationLink.attachPress(jQuery.proxy(this._onLinkPress, this));

		this._oHeaderForm.addContent(this._oMainNavigationText);
		this._oHeaderForm.addContent(this._oMainNavigationLink);

		this._oForm = new SimpleForm({
			maxContainerCols: 1,
			visible: false
		});

		this._oNavigationLinkContainer = new VBox();

		this._oForm.addContent(new Title({
			text: sap.ui.getCore().getLibraryResourceBundle("sap.ui.comp").getText("POPOVER_LINKLIST_TEXT")
		}));
		this._oForm.addContent(this._oNavigationLinkContainer);

		this.addContent(this._oHeaderForm);
		this.addContent(this._oForm);
	};

	NavigationPopover.prototype.addAvailableAction = function(oLinkData) {
		this.addAggregation("availableActions", oLinkData);
	};

	NavigationPopover.prototype._getSemanticObjectValue = function() {

		var oSemanticAttributes = this.getSemanticAttributes();
		if (oSemanticAttributes) {
			var sSemanticalObject = this.getSemanticObjectName();
			return oSemanticAttributes[sSemanticalObject];
		}

		return null;
	};

	/**
	 * creates the link controls and sets them into the popover's content
	 * 
	 * @private
	 */
	NavigationPopover.prototype._createLinks = function() {
		var i;
		var oLink;
		var sValue;
		var sHref;
		var oLinkData;
		var oComponent = this._getComponent();
		var oXApplNavigation = this._getNavigationService();

		this._oNavigationLinkContainer.removeAllItems();

		sValue = this.getMainNavigationId();
		if (!sValue) {
			var oSmartLink = this._getSourceControl();
			if (oSmartLink) {
				if (oSmartLink.getSemanticObjectValue) {
					sValue = oSmartLink.getSemanticObjectValue();
				} else {
					sValue = this._getSemanticObjectValue();
				}
			}
		}

		this._oMainNavigationText.setText(sValue);

		var oMainNav = this.getMainNavigation();
		if (oMainNav) {
			sHref = oMainNav.getHref();
			if (sHref) {
				this._oHeaderForm.removeStyleClass("navpopoversmallheader");
				this._oMainNavigationLink.setText(oMainNav.getText());

				if (oXApplNavigation) {
					sHref = oXApplNavigation.hrefForExternal({
						target: {
							shellHash: sHref
						}
					}, oComponent);
				}
				this._oMainNavigationLink.setHref(sHref);
				this._oMainNavigationLink.setTarget(oMainNav.getTarget());
				this._oMainNavigationLink.setVisible(true);
			} else {
				this._oHeaderForm.addStyleClass("navpopoversmallheader");
				this._oMainNavigationLink.setText("");
				this._oMainNavigationLink.setVisible(false);
			}
		}

		var aActions = this.getAvailableActions();
		if (aActions) {
			for (i = 0; i < aActions.length; i++) {
				oLink = new Link();
				oLinkData = aActions[i];

				if (oLinkData) {
					oLink.setText(oLinkData.getText());
					oLink.attachPress(jQuery.proxy(this._onLinkPress, this));

					sHref = oLinkData.getHref();
					if (oXApplNavigation && sHref) {
						sHref = oXApplNavigation.hrefForExternal({
							target: {
								shellHash: sHref
							}
						}, oComponent);
					}
					oLink.setHref(sHref);
					oLink.setTarget(oLinkData.getTarget());
				}

				this._oNavigationLinkContainer.addItem(oLink);
			}
		}

		this._setListVisibility();
	};

	NavigationPopover.prototype.insertAvailableAction = function(oLinkData, iIndex) {
		this.insertAggregation("availableActions", oLinkData, iIndex);
	};

	NavigationPopover.prototype.removeAvailableAction = function(oLinkData) {
		var iIndexOfRemovedItem;

		if (typeof (oLinkData) === "number") { // oLinkData can also be an index to be removed
			iIndexOfRemovedItem = oLinkData;
		} else {
			iIndexOfRemovedItem = this.getAvailableActions().indexOf(oLinkData);
		}

		if (iIndexOfRemovedItem >= 0) {
			this._oNavigationLinkContainer.removeItem(iIndexOfRemovedItem);
		}

		var oReturnValue = this.removeAggregation("availableActions", oLinkData);
		this._setListVisibility();
		return oReturnValue;
	};

	NavigationPopover.prototype.removeAllAvailableActions = function() {
		this._oNavigationLinkContainer.removeAllItems();
		this.removeAllAggregation("availableActions");
		this._setListVisibility();
	};

	/**
	 * sets the visibility of the link list depending on the number of available links (0 = invisible)
	 * 
	 * @private
	 */
	NavigationPopover.prototype._setListVisibility = function() {
		var iAvailableActions = this.getAvailableActions().length;
		this._oForm.setVisible(iAvailableActions > 0);
	};

	/**
	 * EventHandler for all link press on this popover
	 * 
	 * @param {object} oEvent - the event parameters
	 * @private
	 */
	NavigationPopover.prototype._onLinkPress = function(oEvent) {
		var oSource = oEvent.getSource();
		this.fireNavigate({
			text: oSource.getText(),
			href: oSource.getHref()
		});
	};

	NavigationPopover.prototype.setSemanticObjectName = function(sSemanticalObject) {
		this.setProperty("semanticObjectName", sSemanticalObject);

		this.removeAllAvailableActions();
		this.setMainNavigation(null);
	};

	/**
	 * retrieve the navigation service
	 * 
	 * @private
	 * @returns {object} the navigation service
	 */
	NavigationPopover.prototype._getNavigationService = function() {
		return sap.ushell && sap.ushell.Container && sap.ushell.Container.getService("CrossApplicationNavigation");
	};

	/**
	 * retrieve the url service
	 * 
	 * @private
	 * @returns {object} the url service
	 */
	NavigationPopover.prototype._getUrlService = function() {
		return sap.ushell && sap.ushell.Container && sap.ushell.Container.getService("URLParsing");
	};

	/**
	 * determines the potential navigation targets for the semantical object and visualize the popover
	 * 
	 * @public
	 * @param {string} sSemanticalObject name of the semantical object
	 */
	NavigationPopover.prototype.retrieveNavTargets = function() {
		var sSemanticalObject = this.getSemanticObjectName();
		var mSemanticAttributes = this.getSemanticAttributes();
		var sAppStateKey = this.getAppStateKey();
		this._retrieveNavTargets(sSemanticalObject, mSemanticAttributes, sAppStateKey);
	};

	/**
	 * determines the potential navigation targets for the semantical object and visualize the popover
	 * 
	 * @private
	 * @param {string} sSemanticalObject name of the semantical object
	 * @param {map} mSemanticAttributes map of (name, values) pair for to fine-tune the result
	 * @param {string} sAppStateKey Application state key
	 */
	NavigationPopover.prototype._retrieveNavTargets = function(sSemanticalObject, mSemanticAttributes, sAppStateKey) {

		var that = this;

		this.setMainNavigation(null);
		this.removeAllAvailableActions();

		var oXApplNavigation = this._getNavigationService();
		if (!oXApplNavigation) {
			jQuery.sap.log.error("Service 'CrossApplicationNavigation' could not be obtained");

			// still fire targetsObtained event: easier for testing and the eventhandlers still could provide static links
			this.fireTargetsObtained();
			return;
		}

		var bIgnoreFormFactor = false;

		var oComponent = this._getComponent();

		var oPromise = oXApplNavigation.getSemanticObjectLinks(sSemanticalObject, mSemanticAttributes, bIgnoreFormFactor, oComponent, sAppStateKey);
		oPromise.fail(jQuery.proxy(function() {
			// Reset actions
			jQuery.sap.log.error("'getSemanticObjectLinks' failed");
		}, this));

		oPromise.done(jQuery.proxy(function(aLinks) {
			var i, sId, sText;
			var oURLParsing, oShellHash;
			var oLinkData;
			var bHasFactSheet = false;

			if (aLinks && aLinks.length) {
				oURLParsing = that._getUrlService();

				var sCurrentHash = oXApplNavigation.hrefForExternal();
				if (sCurrentHash && sCurrentHash.indexOf("?") !== -1) { // sCurrentHash can contain query string, cut it off!
					sCurrentHash = sCurrentHash.split("?")[0];
				}

				for (i = 0; i < aLinks.length; i++) {
					sId = aLinks[i].intent;

					sText = aLinks[i].text;

					oLinkData = new sap.ui.comp.navpopover.LinkData({
						text: sText,
						href: sId
					});

					if (sId.indexOf(sCurrentHash) === 0) {
						// Prevent current app from being listed
						// NOTE: If the navigation target exists in
						// multiple contexts (~XXXX in hash) they will all be skipped
						this.setOwnNavigation(oLinkData);
						continue;
					}

					// Check if a FactSheet exists for this SemanticObject (to skip the first one found)
					oShellHash = oURLParsing.parseShellHash(sId);
					if (oShellHash.action && (oShellHash.action === 'displayFactSheet') && !bHasFactSheet) {
						// Prevent this first FactSheet from being listed --> TODO why ?
						oLinkData.setText(sap.ui.getCore().getLibraryResourceBundle("sap.ui.comp").getText("POPOVER_FACTSHEET"));
						that.setMainNavigation(oLinkData);
						bHasFactSheet = true;
					} else {
						that.addAvailableAction(oLinkData);
					}
				}
			}

			that.fireTargetsObtained();

		}, this));

	};

	/**
	 * returns the component object
	 * 
	 * @private
	 * @returns {object} the component
	 */
	NavigationPopover.prototype._getComponent = function() {
		var oComponent = this.getComponent();
		if (typeof oComponent === "string") {
			oComponent = sap.ui.getCore().getComponent(oComponent);
		}
		return oComponent;
	};

	/**
	 * displays the popover. This method should be called, once all navigation targets are adapted by the application
	 * 
	 * @public
	 */
	NavigationPopover.prototype.show = function() {

		var oSourceControl = this._getSourceControl();
		if (!oSourceControl) {
			jQuery.sap.log.error("no source assigned");
			return;
		}

		var oMainNav = this.getMainNavigation();
		var aActions = this.getAvailableActions();
		if (!(oMainNav && (oMainNav.getHref())) && !(aActions && (aActions.length > 0))) { // if no fact sheet exists and no actions and no extra
			// content, then do not show popover
			jQuery.sap.log.error("no navigation targets found");

			if (!this.getExtraContent()) {
				jQuery.sap.log.error("NavigationPopover is empty");
				jQuery.sap.require("sap.m.MessageBox");
				var MessageBox = sap.ui.require("sap/m/MessageBox");
				MessageBox.show(sap.ui.getCore().getLibraryResourceBundle("sap.ui.comp").getText("POPOVER_DETAILS_NAV_NOT_POSSIBLE"), {
					icon: MessageBox.Icon.ERROR,
					title: sap.ui.getCore().getLibraryResourceBundle("sap.ui.comp").getText("POPOVER_MSG_NAV_NOT_POSSIBLE"),
					styleClass: (this.$() && this.$().closest(".sapUiSizeCompact").length) ? "sapUiSizeCompact" : ""
				});

				return;
			}
		}

		this._createLinks();

		this.openBy(oSourceControl);
	};

	/**
	 * retrieves the control for which the popover should be displayed
	 * 
	 * @private
	 * @returns { sap.ui.core.Control} returns the source control
	 */
	NavigationPopover.prototype._getSourceControl = function() {
		var oSourceControl = null;
		var sControlId = this.getSource();

		if (sControlId) {
			oSourceControl = sap.ui.getCore().byId(sControlId);
		}

		return oSourceControl;
	};

	NavigationPopover.prototype.setExtraContent = function(oControl) {
		var oOldContent = this.getExtraContent();
		if (oOldContent && oControl && oOldContent === oControl.getId()) {
			return;
		}

		if (oOldContent) {
			var oOldControl = sap.ui.getCore().byId(oOldContent);
			this.removeContent(oOldControl);
		}

		this.setAssociation("extraContent", oControl);

		if (oControl) {
			this.insertContent(oControl, 1);
		}
	};

	return NavigationPopover;

}, /* bExport= */true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */
sap.ui.define(['jquery.sap.global','sap/ui/fl/changeHandler/Base'],function(q,B){"use strict";var R=function(){};R.prototype=q.sap.newObject(B.prototype);R.prototype.applyChange=function(c,f){if(f.getParent){var g=f.getParent();if(g.removeGroupElement){g.removeGroupElement(f);}}else{throw new Error("no GroupElement control provided for removing the field");}};R.prototype.completeChangeContent=function(c,s){var C=c.getDefinition();if(!C.content){C.content={};}};return R;},true);
<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
sap.ui.jsview("sap.apf.ui.reuse.view.messageHandler",{initializeHandler:function(m){this.getController().showMessage(m);},getControllerName:function(){return"sap.apf.ui.reuse.controller.messageHandler";},createContent:function(c){jQuery.sap.require("sap.m.MessageToast");jQuery.sap.require("sap.ca.ui.message.message");}});
<file_sep>/*!
 * SAP APF Analysis Path Framework
 *
 * (c) Copyright 2012-2015 SAP SE. All rights reserved
 */
/*global jQuery, sap */
(function() {
	'use strict';
	jQuery.sap.declare("sap.apf.base.Component");
	jQuery.sap.require("sap.ui.core.UIComponent");
	jQuery.sap.require("sap.apf.api");
	/**
	 * @public
	 * @class Base Component for all APF based applications.
	 * @name sap.apf.base.Component
	 * @extends sap.ui.core.UIComponent
	 * @since SAP UI5 1.30.0.
	 */
	sap.ui.core.UIComponent.extend("sap.apf.base.Component", {
		metadata : {
			"manifest" : "json",
			"publicMethods" : [ "getApi" ]
		},
		oApi : null,
		init : function() {
			var baseManifest;
			var manifest;
			if (!this.oApi) {
				baseManifest = sap.apf.base.Component.prototype.getMetadata().getManifest();
				manifest = jQuery.extend({}, true, this.getMetadata().getManifest());
				this.oApi = new sap.apf.Api(this, undefined, {
					manifest : manifest,
					baseManifest : baseManifest
				});
			} else {
				return;
			}
			sap.ui.core.UIComponent.prototype.init.apply(this, arguments);
		},
		/**
		 * @public
		 * @description Creates the content of the component. A component that extends this component shall call this method.
		 * @function
		 * @name sap.apf.base.Component.prototype.createContent
		 * @returns {sap.ui.core.Control} the content
		 */
		createContent : function() {
			sap.ui.core.UIComponent.prototype.createContent.apply(this, arguments);
			return this.oApi.startApf();
		},
		/**
		 * @public
		 * @description Cleanup the Component instance. The component that extends this component should call this method.
		 * @function
		 * @name sap.apf.base.Component.prototype.exit
		 */
		exit : function() {
			this.oApi.destroy();
		},
		/**
		 * @public
		 * @function
		 * @name sap.apf.base.Component#getApi
		 * @description Returns the instance of the APF API.
		 * @returns {sap.apf.Api}
		 */
		getApi : function() {
			return this.oApi;
		}
	});
}());
<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
jQuery.sap.require("sap.apf.modeler.ui.utils.textPoolHelper");
/**
* @class step
* @memberOf sap.apf.modeler.ui.controller
* @name step
* @description controller for view.step
*/
sap.ui.controller("sap.apf.modeler.ui.controller.step", {
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#onInit
	* @description Called on initialization of the view.
	* Sets the static texts for all controls in UI.
	* Sets the scroll height for the container.
	* Adds style classes to all UI controls.
	* Prepares dependecies.
	* Sets dynamic text for input controls
	* */
	onInit : function() {
		this.getView().addStyleClass("sapUiSizeCompact");//For non touch devices- compact style class increases the information density on the screen by reducing control dimensions
		this.oViewData = this.getView().getViewData();
		this.getText = this.oViewData.getText;
		this.params = this.oViewData.oParams;
		this.oConfigurationHandler = this.oViewData.oConfigurationHandler;
		this.oConfigurationEditor = this.oViewData.oConfigurationEditor;
		this.oTextPool = this.oConfigurationHandler.getTextPool();
		this.getNavigationTargetName = this.oViewData.getNavigationTargetName;
		var self = this;
		if (!this.oConfigurationEditor) {
			this.oConfigurationHandler.loadConfiguration(this.params.arguments.configId, function(configurationEditor) {
				self.oConfigurationEditor = configurationEditor;
			});
		}
		this.oTextPool = this.oConfigurationHandler.getTextPool();
		//this._getDependencies(); //get dependencies from router
		this._setDisplayText();
		this.setDetailData();
		//Set Mandatory Fields
		var mandatoryFields = [];
		mandatoryFields.push(this.byId("idstepTitle"));
		mandatoryFields.push(this.byId("idSourceSelect"));
		mandatoryFields.push(this.byId("idSelectPropCombo"));
		mandatoryFields.push(this.byId("idCategorySelect"));
		mandatoryFields.push(this.byId("idFilterMapEntitySelect")); //filter map entity,select properties and target filter are mandatory when service is selected
		mandatoryFields.push(this.byId("idFilterMapTargetFilterCombo"));
		mandatoryFields.push(this.byId("idCustomRecordValue"));//mandatory custom value in data record for top N
		this._setMandatoryFields(mandatoryFields);
		this._attachEvents();
		if (this.step.getFilterMappingService() === undefined || this.step.getFilterMappingService() === "") { // if the filter mapping field is not available
			this._removeMandatoryFromFilterMap(); //initially filter mapping fields should not be mandatory 
		}
		if (!this.step.getTopN()) { // if the top N is not available
			this.byId("idCustomRecordValue").isMandatory = false; // remove input field from mandatory fields
		}
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_setDisplayText
	* @description Sets static texts in UI
	* */
	_setDisplayText : function() {
		this.byId("idStepBasicData").setTitle(this.getText("stepBasicData"));
		this.byId("idStepTitleLabel").setText(this.getText("stepTitle"));
		this.byId("idStepTitleLabel").setRequired(true);
		this.byId("idstepTitle").setPlaceholder(this.getText("newStep"));
		this.byId("idStepLongTitleLabel").setText(this.getText("stepLongTitle"));
		this.byId("idstepLongTitle").setPlaceholder(this.getText("stepLongTitle"));
		this.byId("idCategoryTitleLabel").setText(this.getText("categoryAssignments"));
		this.byId("idCategoryTitleLabel").setRequired(true);
		this.byId("idGlobalLabel").setText(this.getText("globalNavTargets"));
		this.byId("idStepSpecificLabel").setText(this.getText("stepSpecificNavTargets"));
		this.byId("idSourceSelectLabel").setText(this.getText("source"));
		this.byId("idSourceSelectLabel").setRequired(true);
		this.byId("idEntitySelectLabel").setText(this.getText("entity"));
		this.byId("idEntitySelectLabel").setRequired(true);
		this.byId("idSelectPropComboLabel").setText(this.getText("selectProperties"));
		this.byId("idSelectPropComboLabel").setRequired(true);
		this.byId("idReqFilterSelectLabel").setText(this.getText("requiredFilters"));
		this.byId("idDataRequest").setTitle(this.getText("dataRequest"));
		this.byId("idNavigationTarget").setTitle(this.getText("navigationTargetAssignment"));
		this.byId("idCornerTextLabel").setTitle(this.getText("cornerTextLabel"));
		this.byId("idLeftTop").setPlaceholder(this.getText("leftTop"));
		this.byId("idRightTop").setPlaceholder(this.getText("rightTop"));
		this.byId("idLeftBottom").setPlaceholder(this.getText("leftBottom"));
		this.byId("idRightBottom").setPlaceholder(this.getText("rightBottom"));
		//Data Reduction labels
		this.byId("idDataReduction").setTitle(this.getText("dataReduction"));
		this.byId("idDataReductionLabel").setText(this.getText("dataReductionType"));
		this.byId("idNoDataReduction").setText(this.getText("noDataReduction"));
		this.byId("idTopN").setText(this.getText("topN"));
		this.byId("idDataRecordsLabel").setText(this.getText("recordNumber"));
	},
	/**
	 * @private
	 * @function
	 * @name sap.apf.modeler.ui.controller.step#_addAutoCompleteFeatureOnInputs
	 * @description Adds 'Auto Complete Feature' to the input fields in the view
	 * using sap.apf.modeler.ui.utils.TextPoolHelper.
	 * */
	_addAutoCompleteFeatureOnInputs : function() {
		if (this.oConfigurationHandler) {
			var oTextPoolHelper = new sap.apf.modeler.ui.utils.TextPoolHelper(this.oTextPool);
			var oStepTitleControl = this.byId("idstepTitle");
			var oTranslationFormatForStepTitle = sap.apf.modeler.ui.utils.TranslationFormatMap.STEP_TITLE;
			var oDependenciesForStepTitle = {
				oTranslationFormat : oTranslationFormatForStepTitle,
				type : "text"
			};
			oTextPoolHelper.setAutoCompleteOn(oStepTitleControl, oDependenciesForStepTitle);
			var oStepLongTitleControl = this.byId("idstepLongTitle");
			var oTranslationFormatForStepLongTitle = sap.apf.modeler.ui.utils.TranslationFormatMap.STEP_LONG_TITLE;
			var oDependenciesForStepLongTitle = {
				oTranslationFormat : oTranslationFormatForStepLongTitle,
				type : "text"
			};
			oTextPoolHelper.setAutoCompleteOn(oStepLongTitleControl, oDependenciesForStepLongTitle);
			var oStepLeftTop = this.byId("idLeftTop");
			var oStepRightTop = this.byId("idRightTop");
			var oStepLeftBottom = this.byId("idLeftBottom");
			var oStepRightBottom = this.byId("idRightBottom");
			var oTranslationFormatForStepCornerText = sap.apf.modeler.ui.utils.TranslationFormatMap.STEP_CORNER_TEXT;
			var oDependenciesForStepCornerText = {
				oTranslationFormat : oTranslationFormatForStepCornerText,
				type : "text"
			};
			oTextPoolHelper.setAutoCompleteOn(oStepLeftTop, oDependenciesForStepCornerText);
			oTextPoolHelper.setAutoCompleteOn(oStepRightTop, oDependenciesForStepCornerText);
			oTextPoolHelper.setAutoCompleteOn(oStepLeftBottom, oDependenciesForStepCornerText);
			oTextPoolHelper.setAutoCompleteOn(oStepRightBottom, oDependenciesForStepCornerText);
			//autocomplete for source
			var oDependenciesForService = {
				oConfigurationEditor : this.oConfigurationEditor,
				type : "service"
			};
			var oSource = this.byId("idSourceSelect");
			oTextPoolHelper.setAutoCompleteOn(oSource, oDependenciesForService);
			var oSourceForFilterMapping = this.byId("idFilterMapSourceSelect");
			oTextPoolHelper.setAutoCompleteOn(oSourceForFilterMapping, oDependenciesForService);
		}
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_prepareStepSpecificList
	* @description Prepares the model for step specific targets and sets the step specific targets
	* */
	_prepareStepSpecificList : function() {
		var self = this;
		var aModifiedStepSpecificTargets = [];
		var aAllNavTarget = this.oConfigurationEditor.getNavigationTargets();//Get all the navigation targets in a configuration
		var aStepSpecificNavTargets = this.step.getNavigationTargets();//Get all the navigation targets assigned to the current step
		var aAllStepSpecificNavTargets = aAllNavTarget.filter(function(oNavTarget) {//Filter aAllNavTarget to get only step specific navigation targets
			return oNavTarget.isStepSpecific();
		});
		//If configuration has step specific navigation targets set a busy indicator on the control until texts are read
		if (aAllStepSpecificNavTargets.length !== 0) {
			this.byId("idStepSpecificCombo").setBusy(true);
		}
		aAllStepSpecificNavTargets.forEach(function(oStepSpecificNavTarget) {
			var oNavTarget = {};
			oNavTarget.navTargetKey = oStepSpecificNavTarget.getId();
			self.getNavigationTargetName(oStepSpecificNavTarget.getId()).then(function(value) {
				oNavTarget.navTargetName = value;
				aModifiedStepSpecificTargets.push(oNavTarget);//Push modified step specific target into array
				if (aModifiedStepSpecificTargets.length === aAllStepSpecificNavTargets.length) {
					var stepSpecificModel = new sap.ui.model.json.JSONModel();
					var oStepSpecificData = {
						stepSpecific : aModifiedStepSpecificTargets
					};
					stepSpecificModel.setData(oStepSpecificData);
					self.byId("idStepSpecificCombo").setModel(stepSpecificModel);
					self.byId("idStepSpecificCombo").setSelectedKeys(aStepSpecificNavTargets);//Set navigation targets assigned to the step as selected
					//Remove busy indicator once the model is set on the control
					self.byId("idStepSpecificCombo").setBusy(false);
				}
			});
		});
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_prepareGlobalList
	* @description Prepares the model for global targets and sets the global targets
	* */
	_prepareGlobalList : function() {
		var self = this;
		var aModifiedGlobalTargets = [];
		var aAllNavTarget = this.oConfigurationEditor.getNavigationTargets();//Get all the navigation targets in a configuration
		var aGlobalNavTargets = aAllNavTarget.filter(function(oNavTarget) {//Filter aAllNavTarget to get only global navigation targets
			return oNavTarget.isGlobal();
		});
		//If configuration has global navigation targets set a busy indicator on the control until texts are read
		if (aGlobalNavTargets.length !== 0) {
			this.byId("idGlobalCombo").setBusy(true);
		}
		aGlobalNavTargets = aGlobalNavTargets.map(function(oGlobalNavTarget) {
			return oGlobalNavTarget.getId();
		});
		aGlobalNavTargets.forEach(function(oGlobalTarget) {
			var oGlobalNavTarget = {};
			oGlobalNavTarget.navTargetKey = oGlobalTarget;
			self.getNavigationTargetName(oGlobalTarget).then(function(value) {
				oGlobalNavTarget.navTargetName = value;
				aModifiedGlobalTargets.push(oGlobalNavTarget);//Push modified global target into array
				if (aModifiedGlobalTargets.length === aGlobalNavTargets.length) {
					var globalModel = new sap.ui.model.json.JSONModel();
					var oGlobalData = {
						global : aModifiedGlobalTargets
					};
					globalModel.setData(oGlobalData);
					self.byId("idGlobalCombo").setModel(globalModel);
					self.byId("idGlobalCombo").setSelectedKeys(aGlobalNavTargets);//Set all global targets as selected
					//Remove busy indicator once the model is set on the control
					self.byId("idGlobalCombo").setBusy(false);
				}
			});
		});
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#setDetailData
	* @description Sets dynamic texts for controls
	* */
	setDetailData : function() {
		var self = this;
		if (this.params && this.params.arguments && this.params.arguments.stepId) {
			this.step = this.oConfigurationEditor.getStep(this.params.arguments.stepId);
		}
		var Categories = [];
		this.oTextPool = this.oConfigurationHandler.getTextPool();
		var aAllCategories = this.oConfigurationEditor.getCategories();
		aAllCategories.forEach(function(oCategory) {
			var oCatOb = {};
			oCatOb.CategoryId = oCategory.getId();
			oCatOb.CategoryTitle = self.oTextPool.get(oCategory.labelKey) ? self.oTextPool.get(oCategory.labelKey).TextElementDescription : oCategory.labelKey;
			Categories.push(oCatOb);
		});
		var oData = {
			Categories : Categories
		};
		var oModel = new sap.ui.model.json.JSONModel();
		oModel.setData(oData);
		this.byId("idCategorySelect").setModel(oModel);
		var oProp = {
			propertyKey : this.getText("none"),
			propertyName : this.getText("none")
		};
		var oDataForPropertiesSel = {
			Properties : [ oProp ]
		};
		var oModelForSelectables = new sap.ui.model.json.JSONModel();
		oModelForSelectables.setSizeLimit(500);
		oModelForSelectables.setData(oDataForPropertiesSel);
		this.byId("idReqFilterSelect").setModel(oModelForSelectables);
		var aSelectPropertiesForTargetFilter = [];
		var oSelectedPropertiesForTargetFilter = this.byId("idFilterMapTargetFilterCombo") ? this.byId("idFilterMapTargetFilterCombo").getSelectedKeys() : [];
		oSelectedPropertiesForTargetFilter.forEach(function(property) { //selected properties from the combo box
			var oProp = {};
			oProp.propertyKey = property;
			oProp.propertyName = property;
			aSelectPropertiesForTargetFilter.push(oProp);
		});
		var oModelForTargetFilter = new sap.ui.model.json.JSONModel();
		oModelForTargetFilter.setSizeLimit(500);
		oModelForTargetFilter.setData(aSelectPropertiesForTargetFilter);
		//all the selected properties will be displayed in the target filter property dropdown, none will not be displayed as one property has to be selected
		this.byId("idFilterMapTargetFilterCombo").setModel(oModelForTargetFilter);
		if (this.step) { //for existing step
			var sNone = this.getText("none");
			var noneProperties = [ sNone ];
			//Setting the value for title for a step
			if (this.step.getTitleId && this.step.getTitleId() !== undefined && this.step.getTitleId() !== null && self.oTextPool.get(this.step.getTitleId())) {
				this.byId("idstepTitle").setValue(self.oTextPool.get(this.step.getTitleId()).TextElementDescription);
			} else {
				this.byId("idstepTitle").setValue(this.params.arguments.stepId);
			}
			//Setting the value for long title for a step
			if (this.step.getLongTitleId && this.step.getLongTitleId() !== undefined && this.step.getLongTitleId() !== null && self.oTextPool.get(this.step.getLongTitleId())) {
				this.byId("idstepLongTitle").setValue(self.oTextPool.get(this.step.getLongTitleId()).TextElementDescription);
			} else {
				this.byId("idstepLongTitle").setValue("");
			}
			//Setting the value for data source for a step
			if (this.step.getService && this.step.getService() !== undefined && this.step.getService() !== null) {
				this.byId("idSourceSelect").setValue(this.step.getService());
				var sSource = this.step.getService();
				var aAllEntitySets = [];
				var aAllEntitySetsForControll = [];
				aAllEntitySets = this.oConfigurationEditor.getAllEntitySetsOfService(sSource);
				aAllEntitySets.forEach(function(entiset) {
					var oEntitySet = {};
					oEntitySet.entityKey = entiset;
					oEntitySet.entityName = entiset;
					aAllEntitySetsForControll.push(oEntitySet);
				});
				var oDataForEntitySets = {
					Entities : aAllEntitySetsForControll
				};
				var oModelForEntitySet = new sap.ui.model.json.JSONModel();
				oModelForEntitySet.setSizeLimit(500);
				oModelForEntitySet.setData(oDataForEntitySets);
				this.byId("idEntitySelect").setModel(oModelForEntitySet);
			}
			//Setting the value for entity sets for a step
			if (this.step.getEntitySet && this.step.getEntitySet() !== undefined && this.step.getEntitySet() !== null) {
				this.byId("idEntitySelect").setSelectedKey(this.step.getEntitySet());
				var sEntity = this.step.getEntitySet();
				var sServiceRoot = this.step.getService();
				var aProperties = [], aPropertiesForControl = [];
				if (sServiceRoot && sServiceRoot !== null && sServiceRoot !== "") {
					aProperties = this.oConfigurationEditor.getAllPropertiesOfEntitySet(sServiceRoot, sEntity);
					aProperties.forEach(function(property) {
						var oProp = {};
						oProp.propertyKey = property;
						oProp.propertyName = property;
						aPropertiesForControl.push(oProp);
					});
					var oDataForProperties = {
						Properties : aPropertiesForControl
					};
					var oModelForSelProp = new sap.ui.model.json.JSONModel();
					oModelForSelProp.setSizeLimit(500);
					oModelForSelProp.setData(oDataForProperties);
					this.byId("idSelectPropCombo").setModel(oModelForSelProp);
				}
			}
			//Setting the value for select properties for a step
			if (this.step.getSelectProperties && this.step.getSelectProperties() !== undefined && this.step.getSelectProperties().length !== 0) {
				this.byId("idSelectPropCombo").setSelectedKeys(this.step.getSelectProperties());
				aProperties = noneProperties.concat(this.step.getSelectProperties());
				aPropertiesForControl = [];
				aProperties.forEach(function(property) {
					var oProp = {};
					oProp.propertyKey = property;
					oProp.propertyName = property;
					aPropertiesForControl.push(oProp);
				});
				oDataForPropertiesSel = {
					Properties : aPropertiesForControl
				};
				oModelForSelectables = new sap.ui.model.json.JSONModel();
				oModelForSelectables.setSizeLimit(500);
				oModelForSelectables.setData(oDataForPropertiesSel);
				this.byId("idReqFilterSelect").setModel(oModelForSelectables);
			}
			//Setting the value for required filter for a step
			if (this.step.getFilterProperties && this.step.getFilterProperties() !== undefined && this.step.getFilterProperties().length !== 0) {
				this.byId("idReqFilterSelect").setSelectedKey(this.step.getFilterProperties()[0]);
				this._showFilterMappingField();
			} else {
				this.byId("idReqFilterSelect").setSelectedKey(this.getText("none"));
				this._hideFilterMapField();// Hides filter mapping fields
				this._resetFilterMappingFields();//reset the values from the filter mapping properties and clears the selected keys in control
			}
			this._setTopNValue();//set the top N values 
			//Setting the value for data source for filter mapping of a step
			if (this.step.getFilterMappingService && this.step.getFilterMappingService() !== undefined && this.step.getFilterMappingService().length !== 0) {
				this.byId("idFilterMapSourceSelect").setValue(this.step.getFilterMappingService());
				var sFilterMapSource = this.step.getFilterMappingService();
				var aFilterMapAllEntitySets = [];
				var aFilterMapAllEntitySetsForControl = [];
				var aRequiredProperties = this.step.getFilterProperties();
				aFilterMapAllEntitySets = this.oConfigurationEditor.getAllEntitySetsOfServiceWithGivenProperties(sFilterMapSource, aRequiredProperties);
				aFilterMapAllEntitySets.forEach(function(entity) {
					var oEntitySetFilterMap = {};
					oEntitySetFilterMap.entityKey = entity;
					oEntitySetFilterMap.entityName = entity;
					aFilterMapAllEntitySetsForControl.push(oEntitySetFilterMap);
				});
				var oDataForFilterMapEntitySets = {
					Entities : aFilterMapAllEntitySetsForControl
				};
				var oModelForFilterMapEntitySet = new sap.ui.model.json.JSONModel();
				oModelForFilterMapEntitySet.setSizeLimit(500);
				oModelForFilterMapEntitySet.setData(oDataForFilterMapEntitySets);
				this.byId("idFilterMapEntitySelect").setModel(oModelForFilterMapEntitySet);
				this._addMandatoryfromFilterMap(); //valid service selected, make other fields in filter mapping mandatory
			} else {// if the service was not saved then reset the filter mapping fields
				this._removeMandatoryFromFilterMap(); // removes the mandatory tag 
				this._resetFilterMappingFields();//reset the values from the filter mapping properties and clears the selected keys in control
			}
			//Setting the value for entity sets for filter mapping of a step
			if (this.step.getFilterMappingEntitySet && this.step.getFilterMappingEntitySet() !== undefined && this.step.getFilterMappingEntitySet().length !== 0) {
				this.byId("idFilterMapEntitySelect").setSelectedKey(this.step.getFilterMappingEntitySet());
				var sFilterMapEntity = this.step.getFilterMappingEntitySet();
				var sFilterMapServiceRoot = this.step.getFilterMappingService();
				var aFilterMapProperties = [], aPropertiesForFilterMapControl = [];
				if (sFilterMapServiceRoot && sFilterMapServiceRoot !== null && sFilterMapServiceRoot !== "") {
					aFilterMapProperties = this.oConfigurationEditor.getAllPropertiesOfEntitySet(sFilterMapServiceRoot, sFilterMapEntity);
					aFilterMapProperties.forEach(function(property) {
						var oProp = {};
						oProp.propertyKey = property;
						oProp.propertyName = property;
						aPropertiesForFilterMapControl.push(oProp);
					});
					var oDataForFilterMapProperties = {
						Properties : aPropertiesForFilterMapControl
					};
					var oModelForFilterMapSelProp = new sap.ui.model.json.JSONModel();
					oModelForFilterMapSelProp.setSizeLimit(500);
					oModelForFilterMapSelProp.setData(oDataForFilterMapProperties);
					this.byId("idFilterMapTargetFilterCombo").setModel(oModelForFilterMapSelProp);
				}
			}
			//Setting the value for target property for filter mapping of a step
			if (this.step.getFilterMappingTargetProperties && this.step.getFilterMappingTargetProperties() !== undefined && this.step.getFilterMappingTargetProperties().length !== 0) {
				this.byId("idFilterMapTargetFilterCombo").setSelectedKeys(this.step.getFilterMappingTargetProperties());
			}
			//Setting the value for keep source checkbox for filter mapping of a step
			if (this.step.getFilterMappingKeepSource && this.step.getFilterMappingKeepSource() !== undefined) {
				this.byId("idFilterKeepSourceCheckBox").setSelected(this.step.getFilterMappingKeepSource());
			}
			//Setting the value of categories of a step
			var aSelectedCategories = self.oConfigurationEditor.getCategoriesForStep(this.step.getId());
			if (aSelectedCategories && aSelectedCategories.length !== 0) {
				this.byId("idCategorySelect").setSelectedKeys(aSelectedCategories);
			}
			//Setting the value of left lower corner text of a step
			if (this.step.getLeftLowerCornerTextKey() && self.oTextPool.get(this.step.getLeftLowerCornerTextKey())) {
				this.byId("idLeftBottom").setValue(self.oTextPool.get(this.step.getLeftLowerCornerTextKey()).TextElementDescription);
			} else {
				this.byId("idLeftBottom").setValue(this.step.getLeftLowerCornerTextKey());
			}
			//Setting the value of left upper corner text of a step
			if (this.step.getLeftUpperCornerTextKey() && self.oTextPool.get(this.step.getLeftUpperCornerTextKey())) {
				this.byId("idLeftTop").setValue(self.oTextPool.get(this.step.getLeftUpperCornerTextKey()).TextElementDescription);
			} else {
				this.byId("idLeftTop").setValue(this.step.getLeftUpperCornerTextKey());
			}
			//Setting the value of right upper corner text of a step
			if (this.step.getRightUpperCornerTextKey() && self.oTextPool.get(this.step.getRightUpperCornerTextKey())) {
				this.byId("idRightTop").setValue(self.oTextPool.get(this.step.getRightUpperCornerTextKey()).TextElementDescription);
			} else {
				this.byId("idRightTop").setValue(this.step.getRightUpperCornerTextKey());
			}
			//Setting the value of right lower corner text of a step
			if (this.step.getRightLowerCornerTextKey() && self.oTextPool.get(this.step.getRightLowerCornerTextKey())) {
				this.byId("idRightBottom").setValue(self.oTextPool.get(this.step.getRightLowerCornerTextKey()).TextElementDescription);
			} else {
				this.byId("idRightBottom").setValue(this.step.getRightLowerCornerTextKey());
			}
		} else { //for new step
			this._changeVisibilityDataReductionField(false);// Hide the data reduction as well for new step
			this._changeVisibilityOfTopN(false);//hide the top N fields for new step
			this._hideFilterMapField();//hide the filter mapping fields for new step
			var sCategoryId = this.params.arguments.categoryId;
			var sStepId = self.oConfigurationEditor.createStep(sCategoryId);
			this.step = self.oConfigurationEditor.getStep(sStepId);
			var selectedCategory = [ sCategoryId ];
			this.byId("idCategorySelect").setSelectedKeys(selectedCategory);
			var stepInfo = {
				id : sStepId,
				icon : "sap-icon://BusinessSuiteInAppSymbols/icon-phase"
			};
			this.oViewData.updateSelectedNode(stepInfo);
		}
		this._addAutoCompleteFeatureOnInputs();
		this._prepareGlobalList();
		this._prepareStepSpecificList();
	},
	_setTopNValue : function() {
		//Setting the "Top N" to the step
		this._setSortDataForStep();
		var hasTopNValue; //boolean to check if the Top N settings are available
		if (this.step.getTopN()) { //if the top N is set on the step
			hasTopNValue = true;
			var nDataRecod = this.step.getTopN().top;
			this.byId("idDataReductionRadioGroup").setSelectedButton(this.byId("idDataReductionRadioGroup").getButtons()[1]); //select the "Top N" radio button and show the top N fields
			this.byId("idCustomRecordValue").setValue(nDataRecod); //set the value on the input field
		} else {
			this.byId("idDataReductionRadioGroup").setSelectedButton(this.byId("idDataReductionRadioGroup").getButtons()[0]);
			hasTopNValue = false;
		}
		this._changeVisibilityOfTopN(hasTopNValue); //change the visibility of the Top N fields based on the boolean
	},
	handleChangeDetailValueForTree : function(oEvent) {
		this.oConfigurationEditor.setIsUnsaved();
		var self = this;
		var aStepCategories = this.oConfigurationEditor.getCategoriesForStep(this.step.getId());
		var oTranslationFormat = sap.apf.modeler.ui.utils.TranslationFormatMap.STEP_TITLE;
		var sStepTitle = this.byId("idstepTitle").getValue().trim();
		var sStepTitleId = self.oTextPool.setText(sStepTitle, oTranslationFormat);
		if (sStepTitle !== "" && sStepTitle !== null) {
			this.step.setTitleId(sStepTitleId);
		}
		var stepInfo = {};
		stepInfo.name = sStepTitle;
		stepInfo.id = this.step.getId();
		if (sStepTitle !== "" && sStepTitle !== null) {
			if (aStepCategories.length > 1) {//In case the step is only assigned to one category
				this.oViewData.updateTree();
			} else {//In case the step is assigned to multiple categories, context of step and the list of categories is passed
				this.oViewData.updateSelectedNode(stepInfo);
			}
			var sTitle = this.getText("step") + ": " + sStepTitle;
			this.oViewData.updateTitleAndBreadCrumb(sTitle);
		}
	},
	handleChangeForLongTitle : function() {
		this.oConfigurationEditor.setIsUnsaved();
		var sStepLongTitle = this.byId("idstepLongTitle").getValue().trim();
		var oTranslationFormat = sap.apf.modeler.ui.utils.TranslationFormatMap.STEP_LONG_TITLE;
		var sStepLongTitleId = this.oTextPool.setText(sStepLongTitle, oTranslationFormat);
		this.step.setLongTitleId(sStepLongTitleId);
	},
	/**
	 * @function
	 * @name sap.apf.modeler.ui.controller.step# handleChangeForStepSpecific
	 * @description handler for the step specific navigation target control
	 * Assigns the selected step specific navigation targets to the step
	 * */
	handleChangeForStepSpecific : function() {
		var self = this;
		this.oConfigurationEditor.setIsUnsaved();
		var selectedNavTargets = this.byId("idStepSpecificCombo").getSelectedKeys();
		var prevNavTargets = this.step.getNavigationTargets();
		prevNavTargets.forEach(function(navTargetId) { //Remove the old assigned navigation targets from the step it was assigned to and are unselected now
			if (selectedNavTargets.indexOf(navTargetId) === -1) {
				self.step.removeNavigationTarget(navTargetId);
			}
		});
		selectedNavTargets.forEach(function(navTargetId) {
			if (prevNavTargets.indexOf(navTargetId) === -1) { //Add the selected navigation targets to the step
				self.step.addNavigationTarget(navTargetId);
			}
		});
	},
	_attachEvents : function() {
		var oController = this;
		oController.byId("idSourceSelect").attachEvent("selectService", oController.handleSelectionOfService.bind(oController));
		oController.byId("idFilterMapSourceSelect").attachEvent("selectService", oController.handleSelectionOfService.bind(oController));
	},
	handleShowValueHelpRequest : function(oEvent) {
		var oController = this;
		var oViewData = {
			oTextReader : oController.getView().getViewData().getText,
			parentView : oController.getView(),
			parentControl : oEvent.getSource(),
			getCalatogServiceUri : oController.getView().getViewData().getCalatogServiceUri
		};
		sap.ui.view({
			id : oController.createId("idCatalogServiceView"),
			viewName : "sap.apf.modeler.ui.view.catalogService",
			type : sap.ui.core.mvc.ViewType.XML,
			viewData : oViewData
		});
	},
	handleSelectionOfService : function(oEvent) {
		var selectedService = oEvent.getParameters()[0];
		oEvent.getSource().setValue(selectedService);
		oEvent.getSource().fireEvent("change");
	},
	/**
	 * @function
	 * @name sap.apf.modeler.ui.controller.step# handleChangeForService
	 * @description handler for the "service" property of the step request or filter mapping based on the event
	 * Checks the id of the source control and sets the value for request service or filter mapping service
	 * Reads all the entity set for the given source.
	 * Also , retrieves all the entities based on the required filters from the given source for filter mapping. 
	 * Checks if all the properties (entity, properties etc ) are valid for a given service and empties these properties if the service is invalid.
	 * */
	handleChangeForService : function(oEvent) {
		this.oConfigurationEditor.setIsUnsaved();
		var sSource, aAllEntitySets = [], aAllEntitySetsForControl = [], aProperties = [], aSelectPropertiesForControl = [], aRequiredProperties;
		var sSelectedRequiredFilter = this.byId("idReqFilterSelect").getSelectedKey();
		if (sSelectedRequiredFilter !== this.getText("none")) {
			aRequiredProperties = [ sSelectedRequiredFilter ]; // required filter from the step
		} else {
			aRequiredProperties = this.step.getFilterProperties();
		}
		var sourceControlId = oEvent ? oEvent.getParameter("id") : "";
		var bIsfilterMapControl = sourceControlId.search("FilterMap") !== -1 ? true : false;
		var bServiceRegistered;
		if (bIsfilterMapControl) {
			sSource = this.byId("idFilterMapSourceSelect").getValue().trim();
			bServiceRegistered = this.oConfigurationEditor.registerService(sSource);
			if (bServiceRegistered) {
				this._addMandatoryfromFilterMap(); //valid service selected, make other fields in filter mapping mandatory
				aAllEntitySets = this.oConfigurationEditor.getAllEntitySetsOfServiceWithGivenProperties(sSource, aRequiredProperties);
			} else {
				this._removeMandatoryFromFilterMap(); //remove mandatory tag from the filter mapping fields
			}
		} else {
			this._resetStepRequestProperties();//reset all the request fields when service is changed in case of select source
			if (sSelectedRequiredFilter === this.getText("none") || sSelectedRequiredFilter === "") {//hide the filter mapping field on change of service when required filter is empty or none
				this._hideFilterMapField();// Hide the filter mapping fields
			} else { // reset the filter mapping 
				this._removeMandatoryFromFilterMap(); // removes the mandatory tag 
			}
			this._resetFilterMappingFields();//reset the values from the filter mapping properties and clears the selected keys in control
			sSource = this.byId("idSourceSelect").getValue().trim();
			bServiceRegistered = this.oConfigurationEditor.registerService(sSource);
			aAllEntitySets = this.oConfigurationEditor.getAllEntitySetsOfService(sSource);
		}
		aAllEntitySets.forEach(function(entitySet) {
			var oEntitySet = {};
			oEntitySet.entityKey = entitySet;
			oEntitySet.entityName = entitySet;
			aAllEntitySetsForControl.push(oEntitySet);
		});
		var oEntitySetData = {
			Entities : aAllEntitySetsForControl
		};
		var oEntitySetModel = new sap.ui.model.json.JSONModel();
		oEntitySetModel.setSizeLimit(500);
		oEntitySetModel.setData(oEntitySetData);
		var sEntitySet;
		if (aAllEntitySets.length >= 1) { //set default entity set
			if (bIsfilterMapControl) { //for filter mapping entity set
				if (this.step.getFilterMappingEntitySet()) {
					sEntitySet = this.step.getFilterMappingEntitySet();
					aProperties = this.oConfigurationEditor.getAllPropertiesOfEntitySet(sSource, sEntitySet);
				} else {
					aProperties = this.oConfigurationEditor.getAllPropertiesOfEntitySet(sSource, aAllEntitySets[0]);
				}
				this.step.setFilterMappingEntitySet(aAllEntitySets[0]);
				this.byId("idFilterMapEntitySelect").setSelectedKey(aAllEntitySets[0]);
			} else {
				if (this.step.getEntitySet()) { //for data source entity set
					sEntitySet = this.step.getEntitySet();
					aProperties = this.oConfigurationEditor.getAllPropertiesOfEntitySet(sSource, sEntitySet);
				} else {
					aProperties = this.oConfigurationEditor.getAllPropertiesOfEntitySet(sSource, aAllEntitySets[0]);
				}
				this.step.setEntitySet(aAllEntitySets[0]);
				this.byId("idEntitySelect").setSelectedKey(aAllEntitySets[0]);
			}
			aProperties.forEach(function(property) {
				var oProp = {};
				oProp.propertyKey = property;
				oProp.propertyName = property;
				aSelectPropertiesForControl.push(oProp);
			});
		}
		var oSelectPropertiesData = {
			Properties : aSelectPropertiesForControl
		};
		var oSelectPropertiesModel = new sap.ui.model.json.JSONModel();
		oSelectPropertiesModel.setSizeLimit(500);
		oSelectPropertiesModel.setData(oSelectPropertiesData);
		var aSelectPropertiesForRequiredFilter = [], aSelectPropertiesForTargetFilter = [];
		var oSelectedPropertiesForRequiredFilter = this.byId("idSelectPropCombo").getSelectedKeys();
		oSelectedPropertiesForRequiredFilter.forEach(function(property) { //selected properties from the combo box
			var oProp = {};
			oProp.propertyKey = property;
			oProp.propertyName = property;
			aSelectPropertiesForRequiredFilter.push(oProp);
		});
		var noneTextobj = {
			propertyKey : this.getText("none"),
			propertyName : this.getText("none")
		};
		var aNoneTextObject = [ noneTextobj ];
		aNoneTextObject = aNoneTextObject.concat(aSelectPropertiesForRequiredFilter);
		var oRequiredFilterMapProertyModel = new sap.ui.model.json.JSONModel();
		oRequiredFilterMapProertyModel.setSizeLimit(500);
		var oDataForReqFilter = {
			Properties : aNoneTextObject
		};
		oRequiredFilterMapProertyModel.setData(oDataForReqFilter);
		var oSelectedPropertiesForTargetFilter = this.byId("idFilterMapTargetFilterCombo") ? this.byId("idFilterMapTargetFilterCombo").getSelectedKeys() : [];
		oSelectedPropertiesForTargetFilter.forEach(function(property) { //selected properties from the combo box
			var oProp = {};
			oProp.propertyKey = property;
			oProp.propertyName = property;
			aSelectPropertiesForTargetFilter.push(oProp);
		});
		if (bIsfilterMapControl) {
			this.byId("idFilterMapEntitySelect").setModel(oEntitySetModel);
			this.byId("idFilterMapTargetFilterCombo").setModel(oSelectPropertiesModel);
		} else {
			this.byId("idEntitySelect").setModel(oEntitySetModel);
			this.byId("idSelectPropCombo").setModel(oSelectPropertiesModel);
			this.byId("idReqFilterSelect").setModel(oRequiredFilterMapProertyModel);
		}
		this._checkValidationStateForService("source", sourceControlId);
	},
	/**
	 * @function
	 * @private 
	 * @name sap.apf.modeler.ui.controller.step# _addMandatoryfromFilterMap
	 * @description add the mandatory tags to all the fields in the filter mapping if the service is valid
	 * */
	_addMandatoryfromFilterMap : function() {
		this.byId("idFilterMapEntitySelect").isMandatory = true;
		this.byId("idFilterMapTargetFilterCombo").isMandatory = true;
		this.byId("idFilterMapEntityLabel").setText(this.getText("entity"));
		this.byId("idFilterMapEntityLabel").setRequired(true);
		this.byId("idFilterMapTargetFilterLabel").setText(this.getText("filterMapTarget"));
		this.byId("idFilterMapTargetFilterLabel").setRequired(true);
		this.byId("idFilterMapKeepSourceLabel").setText(this.getText("filterMapKeepSource"));
		this.byId("idFilterMapKeepSourceLabel").setRequired(true);
	},
	/**
	 * @function
	 * @private 
	 * @name sap.apf.modeler.ui.controller.step# _removeMandatoryFromFilterMap
	 * @description removes the mandatory tags to all the fields in the filter mapping if the service is invalid
	 * */
	_removeMandatoryFromFilterMap : function() {
		this.byId("idFilterMapEntitySelect").isMandatory = false;
		this.byId("idFilterMapTargetFilterCombo").isMandatory = false;
		this.byId("idFilterMapEntityLabel").setText(this.getText("entity"));
		this.byId("idFilterMapEntityLabel").setRequired(false);
		this.byId("idFilterMapTargetFilterLabel").setText(this.getText("filterMapTarget"));
		this.byId("idFilterMapTargetFilterLabel").setRequired(false);
		this.byId("idFilterMapKeepSourceLabel").setText(this.getText("filterMapKeepSource"));
		this.byId("idFilterMapKeepSourceLabel").setRequired(false);
	},
	/**
	 * @function
	 * @private 
	 * @name sap.apf.modeler.ui.controller.step# _resetFilterMappingFields
	 * Resets all the values for the filter mapping properties (service, entitySet, select properties, target filter and keep source)
	 * and clears all the data and selected values from the controls
	 * */
	_resetFilterMappingFields : function() {
		var self = this;
		this.step.setFilterMappingService("");
		this.step.setFilterMappingEntitySet(undefined);
		this.step.setFilterMappingKeepSource(undefined);
		var aOldFilterMapTargetProperty = this.step.getFilterMappingTargetProperties();
		aOldFilterMapTargetProperty.forEach(function(property) {
			self.step.removeFilterMappingTargetProperty(property);
		});
		//set an empty model to the controls on the UI
		var oEmptyModelForControlOnReset = new sap.ui.model.json.JSONModel();
		var oEmptyDateSetForControlOnReset = {
			NoData : []
		};
		oEmptyModelForControlOnReset.setData(oEmptyDateSetForControlOnReset);
		this.byId("idFilterMapSourceSelect").setValue("");
		this.byId("idFilterMapEntitySelect").setModel(oEmptyModelForControlOnReset);
		this.byId("idFilterMapEntitySelect").setSelectedKey();
		this.byId("idFilterMapTargetFilterCombo").setModel(oEmptyModelForControlOnReset);
		var aSelectedKeys = this.byId("idFilterMapTargetFilterCombo").getSelectedKeys();
		this.byId("idFilterMapTargetFilterCombo").removeSelectedKeys(aSelectedKeys);
	},
	/**
	 * @function
	 * @name sap.apf.modeler.ui.controller.step# handleChangeForEntity
	 * @description handler for the "entity" property of the step request or filter mapping based on the event
	 * Checks the id of the source control and sets the value for request entity or filter mapping entity
	 * Reads all the properties for the given source and entity and updates the select properties based on entity.
	 * */
	handleChangeForEntity : function(oEvent) {
		this.oConfigurationEditor.setIsUnsaved();
		var sEntity, sService, aProperties = [], aPropertiesForControl = [];
		var sourceControlId = oEvent.getParameter("id");
		var bIsfilterMapControl = sourceControlId.search("FilterMap") !== -1 ? true : false;
		if (bIsfilterMapControl) {
			sEntity = this.byId("idFilterMapEntitySelect").getSelectedKey();
			sService = this.byId("idFilterMapSourceSelect").getValue().trim();
			aProperties = this.oConfigurationEditor.getAllPropertiesOfEntitySet(sService, sEntity);
		} else {
			sEntity = this.byId("idEntitySelect").getSelectedKey();
			sService = this.byId("idSourceSelect").getValue().trim();
			aProperties = this.oConfigurationEditor.getAllPropertiesOfEntitySet(sService, sEntity);
		}
		aProperties.forEach(function(property) {
			var oProp = {};
			oProp.propertyKey = property;
			oProp.propertyName = property;
			aPropertiesForControl.push(oProp);
		});
		var oSelectPropertiesData = {
			Properties : aPropertiesForControl
		};
		var oSelectPropertyModel = new sap.ui.model.json.JSONModel();
		oSelectPropertyModel.setSizeLimit(500);
		oSelectPropertyModel.setData(oSelectPropertiesData);
		var noneTextobj = {
			propertyKey : this.getText("none"),
			propertyName : this.getText("none")
		};
		var aRequiredPropertiesControl = [ noneTextobj ];
		aRequiredPropertiesControl = aRequiredPropertiesControl.concat(aPropertiesForControl);
		var oRequiredFilterMapProertyModel = new sap.ui.model.json.JSONModel();
		oRequiredFilterMapProertyModel.setSizeLimit(500);
		var oDataForReqFilter = {
			Properties : aRequiredPropertiesControl
		};
		oRequiredFilterMapProertyModel.setData(oDataForReqFilter);
		var oTargetFilterMapProertyModel = new sap.ui.model.json.JSONModel();
		oTargetFilterMapProertyModel.setSizeLimit(500);
		oTargetFilterMapProertyModel.setData(aPropertiesForControl);
		if (bIsfilterMapControl) {
			this.byId("idFilterMapTargetFilterCombo").setModel(oSelectPropertyModel);
		} else {
			this.byId("idSelectPropCombo").setModel(oSelectPropertyModel);
			this.byId("idReqFilterSelect").setModel(oRequiredFilterMapProertyModel);
		}
		this._checkValidationStateForService("entitySet", sourceControlId);
		var sRequiredFilter = this.byId("idReqFilterSelect").getSelectedKey();
		if (sRequiredFilter === this.getText("none")) {
			this._hideFilterMapField();// Hides filter mapping fields
			this._resetFilterMappingFields();//reset the values from the filter mapping properties and clears the selected keys in control
		}
	},
	/**
	 * @function
	 * @name sap.apf.modeler.ui.controller.step# handleChangeForSelectProperty
	 * @description handler for the "select property" of the step request or filter mapping based on the event
	 * Checks the id of the source control and sets the value for request select property or filter mapping select property 
	 * Also updates the properties in the required filter list
	 * */
	handleChangeForSelectProperty : function(oEvent) {
		var self = this;
		var bHasSelectProperty;
		this.oConfigurationEditor.setIsUnsaved();
		var aSelectProperty, aSelectPropertiesForControl = [];
		var sourceControlId = oEvent.getParameter("id");
		var aOldSelProp = this.step.getSelectProperties();
		aOldSelProp.forEach(function(property) {
			self.step.removeSelectProperty(property);
		}); // clearing the old properties from core and ui as well
		aSelectProperty = this.byId("idSelectPropCombo").getSelectedKeys();
		if (aSelectProperty.length > 0) { //if there is select property
			aSelectProperty.forEach(function(property) {
				self.step.addSelectProperty(property);
				var oProp = {};
				oProp.propertyKey = property;
				oProp.propertyName = property;
				aSelectPropertiesForControl.push(oProp);
			});
			var noneTextobj = {
				propertyKey : this.getText("none"),
				propertyName : this.getText("none")
			};
			var aRequiredPropertiesControl = [ noneTextobj ];
			aRequiredPropertiesControl = aRequiredPropertiesControl.concat(aSelectPropertiesForControl);
			var oRequiredFilterMapProertyModel = new sap.ui.model.json.JSONModel();
			oRequiredFilterMapProertyModel.setSizeLimit(500);
			var oDataForReqFilter = {
				Properties : aRequiredPropertiesControl
			};
			oRequiredFilterMapProertyModel.setData(oDataForReqFilter);
			var oTargetFilterMapProertyModel = new sap.ui.model.json.JSONModel();
			oTargetFilterMapProertyModel.setSizeLimit(500);
			oTargetFilterMapProertyModel.setData(aSelectPropertiesForControl);
			this.byId("idReqFilterSelect").setModel(oRequiredFilterMapProertyModel);
			this._checkValidationStateForService("selectProperties", sourceControlId);
			var sRequiredFilter = this.step.getFilterProperties() ? this.step.getFilterProperties()[0] : undefined;
			if (sRequiredFilter) {
				var bRequiredFilterPresentInProperties = this.step.getSelectProperties().indexOf(sRequiredFilter) === -1 ? false : true;
				if (bRequiredFilterPresentInProperties) {
					this.byId("idReqFilterSelect").setSelectedKey(sRequiredFilter);
				} else {
					this.byId("idReqFilterSelect").setSelectedKey(this.getText("none"));
				}
			}
			if (this.byId("idReqFilterSelect").getSelectedKey() === this.getText("none")) {
				this._hideFilterMapField();
				this._resetFilterMappingFields();//reset the values from the filter mapping properties and clears the selected keys in control
			}
			this._setSortDataForStep();
			bHasSelectProperty = true;
		} else { // if no select property
			bHasSelectProperty = false;
			this._changeVisibilityOfTopN(bHasSelectProperty);// hide the topN fields
			this.byId("idDataReductionRadioGroup").setSelectedButton(this.byId("idDataReductionRadioGroup").getButtons()[0]);
			this._resetTopNFields(); //reset the Top N when no select property is there
		}
		this._changeVisibilityDataReductionField(bHasSelectProperty);// change the visibility of data reduction field
	},
	_changeVisibilityDataReductionField : function(bHasSelectProperty) {
		this.byId("idDataReduction").setVisible(bHasSelectProperty);
		this.byId("idDataReductionLabel").setVisible(bHasSelectProperty);
		this.byId("idDataReductionRadioButton").setVisible(bHasSelectProperty);
		this.byId("idDataReductionRadioGroup").setVisible(bHasSelectProperty);
	},
	/**
	 * @function
	 * @name sap.apf.modeler.ui.controller.step# handleChangeForRequiredFilter
	 * @description handler for the "Required filter" of the step request
	 * Shows and hides the filter mapping field based on required filter availibility in the step
	 * Updates the entity sets present in the filter mapping based on the required filters
	 * */
	handleChangeForRequiredFilter : function(oEvent) {
		var self = this;
		var sourceControlId = oEvent.getParameter("id");
		this.oConfigurationEditor.setIsUnsaved();
		var aOldSelProp = this.step.getFilterProperties();
		aOldSelProp.forEach(function(property) {
			self.step.removeFilterProperty(property);
		});
		var sRequiredFilter = this.byId("idReqFilterSelect").getSelectedKey();
		if (sRequiredFilter !== this.getText("none")) {
			this.step.addFilterProperty(sRequiredFilter);
			this._showFilterMappingField();//show filter mapping field on UI if there is a required filter
		} else {
			this._hideFilterMapField();//hide filter mapping field from UI if there is no required filter
			this._resetFilterMappingFields();//reset the values from the filter mapping properties and clears the selected keys in control
		}
		this._checkValidationStateForService("requiredFilter", sourceControlId);
	},
	/**
	 * @private
	 * @function
	 * @name sap.apf.modeler.ui.controller.step# _showFilterMappingField
	 * @description shows the filter mapping field from UI if the required filter is available in the step
	 * */
	_showFilterMappingField : function() {
		this.byId("idFilterMapping").setVisible(true);
		this.byId("idFilterMapSourceLabel").setVisible(true);
		this.byId("idFilterMapSourceSelect").setVisible(true);
		this.byId("idFilterMapEntityLabel").setVisible(true);
		this.byId("idFilterMapEntitySelect").setVisible(true);
		this.byId("idFilterMapTargetFilterLabel").setVisible(true);
		this.byId("idFilterMapTargetFilterCombo").setVisible(true);
		this.byId("idFilterMapKeepSourceLabel").setVisible(true);
		this.byId("idFilterKeepSourceCheckBox").setVisible(true);
		this.byId("idFilterMapping").setTitle(this.getText("filterMap"));
		this.byId("idFilterMapSourceLabel").setText(this.getText("source"));
		this.byId("idFilterMapSourceLabel").setRequired(false);
		this.byId("idFilterMapEntityLabel").setText(this.getText("entity"));
		this.byId("idFilterMapEntityLabel").setRequired(false);
		this.byId("idFilterMapTargetFilterLabel").setText(this.getText("filterMapTarget"));
		this.byId("idFilterMapTargetFilterLabel").setRequired(false);
		this.byId("idFilterMapKeepSourceLabel").setText(this.getText("filterMapKeepSource"));
		this.byId("idFilterMapKeepSourceLabel").setRequired(false);
	},
	/**
	 * @private
	 * @function
	 * @name sap.apf.modeler.ui.controller.step# _hideFilterMapField
	 * @description hides the filter mapping field from UI if the required filter is not available in the step
	 * */
	_hideFilterMapField : function() {
		this.byId("idFilterMapping").setVisible(false);
		this.byId("idFilterMapSourceLabel").setVisible(false);
		this.byId("idFilterMapSourceSelect").setVisible(false);
		this.byId("idFilterMapEntityLabel").setVisible(false);
		this.byId("idFilterMapEntitySelect").setVisible(false);
		this.byId("idFilterMapTargetFilterLabel").setVisible(false);
		this.byId("idFilterMapTargetFilterCombo").setVisible(false);
		this.byId("idFilterMapKeepSourceLabel").setVisible(false);
		this.byId("idFilterKeepSourceCheckBox").setVisible(false);
		this._removeMandatoryFromFilterMap(); // removes the mandatory tag 
	},
	/**
	 * @function
	 * @name sap.apf.modeler.ui.controller.step# handleChangeForTargetFilter
	 * @description handler for the "target property" of the filter mapping  
	 * sets the value of target filter on the step object
	 * */
	handleChangeForTargetFilter : function(oEvent) {
		var self = this;
		var sourceControlId = oEvent.getParameter("id");
		this.oConfigurationEditor.setIsUnsaved();
		var aTargetFilterMapProp = this.byId("idFilterMapTargetFilterCombo").getSelectedKeys();
		if (aTargetFilterMapProp.length > 0) { // if any value is selected then clear the previous value and add the new one , else retain the old values
			var aOldTargetProp = this.step.getFilterMappingTargetProperties();
			aOldTargetProp.forEach(function(property) {
				self.step.removeFilterMappingTargetProperty(property);
			});
			aTargetFilterMapProp.forEach(function(property) {
				self.step.addFilterMappingTargetProperty(property);
			});
		}
		this._checkValidationStateForService("targetProperties", sourceControlId);
	},
	/**
	 * @function
	 * @name sap.apf.modeler.ui.controller.step# handleFilterMapKeepSource
	 * @description handler for the "keep source" property of the filter mapping  
	 * sets the boolean value of the property on the step object
	 * */
	handleFilterMapKeepSource : function() {
		var bIsKeepSourceSelected = this.byId("idFilterKeepSourceCheckBox").getSelected();
		this.oConfigurationEditor.setIsUnsaved();
		this.step.setFilterMappingKeepSource(bIsKeepSourceSelected);
	},
	/**
	 * @private
	 * @function
	 * @name sap.apf.modeler.ui.controller.step#_checkValidationStateForService
	 * @param param - to determine which property has to be to validated ( e.g. source, entitySet etc) and based on it the other properties has to be checked and updated
	 * @param sourceControlId  - id of the control to determine if the property are being read from a request or filter mapping 
	 * @description chceks if the filter mapping of the step has all mandatory fields( i.e. entitySet, service, select properties and target filter are available in the step)  
	 * and sets the values on the step object
	 * */
	_checkValidationStateForService : function(param, sourceControlId) {
		var self = this;
		var oValidStep = {
			source : undefined,
			entitySet : undefined,
			selectProperty : undefined,
			requiredFilter : undefined,
			targetFilter : undefined
		};
		var sSource, aRequiredProperties, aAllEntitySets = [], aAllEntitySetsForControll = [];
		var bIsfilterMapControl = sourceControlId.search("FilterMap") !== -1 ? true : false;
		sSource = bIsfilterMapControl ? this.byId("idFilterMapSourceSelect").getValue().trim() : this.byId("idSourceSelect").getValue().trim();
		var bServiceRegistered = this.oConfigurationEditor.registerService(sSource);
		if (bServiceRegistered) {
			oValidStep.source = sSource;
			var sSelectedRequiredFilter = this.byId("idReqFilterSelect").getSelectedKey();
			if (sSelectedRequiredFilter !== this.getText("none")) {
				aRequiredProperties = [ sSelectedRequiredFilter ]; // required filter from the step
			} else {
				aRequiredProperties = this.step.getFilterProperties();
			}
			aAllEntitySets = bIsfilterMapControl ? this.oConfigurationEditor.getAllEntitySetsOfServiceWithGivenProperties(sSource, aRequiredProperties) : this.oConfigurationEditor.getAllEntitySetsOfService(sSource);
			var sSelectedEntity;
			if (param === "entitySet" || param === "selectProperties" || param === "targetProperties" || param === "requiredFilter") {
				sSelectedEntity = bIsfilterMapControl ? this.byId("idFilterMapEntitySelect").getSelectedKey() : this.byId("idEntitySelect").getSelectedKey();
			} else {
				sSelectedEntity = bIsfilterMapControl ? this.step.getFilterMappingEntitySet() : this.step.getEntitySet();
			}
			if (sSelectedEntity) {
				aAllEntitySets.forEach(function(entitySet) {
					if (sSelectedEntity === entitySet) {
						oValidStep.entitySet = sSelectedEntity;
						if (param === "source") {
							if (bIsfilterMapControl) {
								self.byId("idFilterMapEntitySelect").setSelectedKey(sSelectedEntity);
							} else {
								self.byId("idEntitySelect").setSelectedKey(sSelectedEntity);
							}
						}
					}
				});
				var aSelectProperties, aCommonProperty = [];
				if (param === "selectProperties") {
					aSelectProperties = this.byId("idSelectPropCombo").getSelectedKeys();
				} else {
					aSelectProperties = this.step.getSelectProperties();
				}
				var aProperties = this.oConfigurationEditor.getAllPropertiesOfEntitySet(sSource, sSelectedEntity); //TODO check
				var aPropertiesForControl = [];
				aProperties.forEach(function(propertyFromEntity) {
					var oProp = {};
					oProp.propertyKey = propertyFromEntity;
					oProp.propertyName = propertyFromEntity;
					aPropertiesForControl.push(oProp);
				});
				var oDataForProperties = {
					Properties : aPropertiesForControl
				};
				var oModelForSelProp = new sap.ui.model.json.JSONModel();
				oModelForSelProp.setSizeLimit(500);
				oModelForSelProp.setData(oDataForProperties);
				if (!bIsfilterMapControl) {
					this.byId("idSelectPropCombo").setModel(oModelForSelProp);
				} else {
					this.byId("idFilterMapTargetFilterCombo").setModel(oModelForSelProp);
				}
				aProperties.forEach(function(propertyFromEntity) {
					aSelectProperties.forEach(function(propertyFromControl) {
						if (propertyFromControl === propertyFromEntity) {
							aCommonProperty.push(propertyFromControl);
						}
					});
				});
				var aPropertiesMapControl = [];
				var objNoneText = [ {
					propertyKey : this.getText("none"),
					propertyName : this.getText("none")
				} ];
				if (this.step.getFilterMappingTargetProperties().length === 0) {
					this.byId("idFilterMapTargetFilterCombo").setSelectedKeys([]);// if the target filter is not available then clear the selected items from the control
				}
				if (aCommonProperty.length > 0) {
					oValidStep.selectProperty = aCommonProperty;
					if (param !== "selectProperties" && !bIsfilterMapControl) {
						this.byId("idSelectPropCombo").setSelectedKeys(aCommonProperty);
					}
					aCommonProperty.forEach(function(property) {
						var oProp = {};
						oProp.propertyKey = property;
						oProp.propertyName = property;
						aPropertiesMapControl.push(oProp);
					});
				} else { //clear the selected keys from the control if there is no common properties
					var selectedProperties;
					if (!bIsfilterMapControl) {
						selectedProperties = this.byId("idSelectPropCombo").getSelectedKeys();
						this.byId("idSelectPropCombo").removeSelectedKeys(selectedProperties);
						this.byId("idReqFilterSelect").setSelectedKey(this.getText("none"));
					}
				}
				objNoneText = objNoneText.concat(aPropertiesMapControl);
				var oRequiredOrFilterProperties = {
					Properties : objNoneText
				};
				var oRequiredOrFilterPropertyModel = new sap.ui.model.json.JSONModel();
				oRequiredOrFilterPropertyModel.setData(oRequiredOrFilterProperties);
				var aTargetProperties = [], aRequiredFilters = [];
				if (param === "targetProperties") {
					aTargetProperties = this.byId("idFilterMapTargetFilterCombo").getSelectedKeys();
				} else {
					aTargetProperties = this.step.getFilterMappingTargetProperties();
				}
				if (aTargetProperties.length > 0) {
					oValidStep.targetFilter = aTargetProperties;
					this.byId("idFilterMapTargetFilterCombo").setSelectedKeys(aTargetProperties);
				}
				if (param === "requiredFilter") {
					aRequiredFilters.push(this.byId("idReqFilterSelect").getSelectedKey());
				} else {
					aRequiredFilters = this.step.getFilterProperties();
				}
				var aRequiredFilterForValidStep = [];
				aRequiredFilters.forEach(function(requiredFilter) {
					if (requiredFilter !== self.getText("none")) {
						aPropertiesMapControl.forEach(function(oProperty) {
							if (oProperty.propertyKey === requiredFilter) {
								aRequiredFilterForValidStep.push(requiredFilter);
							}
						});
					}
				});
				if (aRequiredFilterForValidStep.length !== 0) {
					oValidStep.requiredFilter = aRequiredFilterForValidStep; //required filters from dropdown - not none text
				} else {
					if (!bIsfilterMapControl) {
						this.byId("idReqFilterSelect").setSelectedKey(this.getText("none"));
					}
				}
				//all the selected properties will be displayed in the target filter property dropdown, none will not be displayed as one property has to be selected
				var oTargetFilterProperties = {
					Properties : aPropertiesMapControl
				};
				var oTargetFilterMapProertyModel = new sap.ui.model.json.JSONModel();
				oTargetFilterMapProertyModel.setSizeLimit(500);
				oTargetFilterMapProertyModel.setData(oTargetFilterProperties);
				if (!bIsfilterMapControl) { //set the model for required filter /target filter
					this.byId("idReqFilterSelect").setModel(oRequiredOrFilterPropertyModel);
				}
			}
			if (bIsfilterMapControl) {
				this._validateStepServiceForFilterMapping(oValidStep);
			} else {
				this._validateStepServiceForDataSource(oValidStep);
			}
		} else { // if service is invalid , reset all the request properties
			if (bIsfilterMapControl) {
				this._resetFilterMappingFields(); //resets the filter mapping target property
			} else {
				this._resetStepRequestProperties();
			}
		}
	},
	/**
	 * @function
	 * @private 
	 * @name sap.apf.modeler.ui.controller.step# _resetStepRequestProperties
	 * Resets all the values for the step request properties (service, entitySet, select properties, required filter)
	 * */
	_resetStepRequestProperties : function() {
		var self = this;
		this.step.setEntitySet(undefined);
		var aOldSelectProperty = this.step.getSelectProperties();
		aOldSelectProperty.forEach(function(property) {
			self.step.removeSelectProperty(property);
		});
		var aOldRequiredFilterProperty = this.step.getFilterProperties();
		aOldRequiredFilterProperty.forEach(function(property) {
			self.step.removeFilterProperty(property);
		});
		this.byId("idEntitySelect").setSelectedKey();
		this.byId("idReqFilterSelect").setSelectedKey();
	},
	/**
	 * @private
	 * @function
	 * @name sap.apf.modeler.ui.controller.step#_validateStepServiceForDataSource
	 * @param {Step}  - step object 
	 * @description chceks if the data source of the step is has all mandatory fields (i.e. entitySet, service, select properties are available in the step)  
	 * and sets the values on the step object
	 * */
	_validateStepServiceForDataSource : function(oValidStep) {
		var self = this;
		if (oValidStep.selectProperty && oValidStep.entitySet && oValidStep.source) {
			this.step.setService(oValidStep.source);
			this.step.setEntitySet(oValidStep.entitySet);
			var aOldSelProp = this.step.getSelectProperties();
			aOldSelProp.forEach(function(property) {
				self.step.removeSelectProperty(property);
			});
			oValidStep.selectProperty.forEach(function(property) {
				self.step.addSelectProperty(property);
			});
			var aOldRequiredProp = this.step.getFilterProperties();
			aOldRequiredProp.forEach(function(property) {
				self.step.removeFilterProperty(property);
			});
			if (oValidStep.requiredFilter) {
				oValidStep.requiredFilter.forEach(function(property) {
					self.step.addFilterProperty(property);
				});
			}
		}
	},
	/**
	 * @private
	 * @function
	 * @name sap.apf.modeler.ui.controller.step#_validateStepServiceForFilterMapping
	 * @param {Step}  - step object 
	 * @description chceks if the filter mapping of the step has all mandatory fields( i.e. entitySet, service, select properties and target filter are available in the step)  
	 * and sets the values on the step object
	 * */
	_validateStepServiceForFilterMapping : function(oValidStep) {
		var self = this;
		if (oValidStep.entitySet && oValidStep.source && oValidStep.targetFilter) {
			this.step.setFilterMappingService(oValidStep.source);
			this.step.setFilterMappingEntitySet(oValidStep.entitySet);
			var aOldFilterMapTargetProp = this.step.getFilterMappingTargetProperties();
			aOldFilterMapTargetProp.forEach(function(property) {
				self.step.removeFilterMappingTargetProperty(property);
			});
			oValidStep.targetFilter.forEach(function(property) {
				self.step.addFilterMappingTargetProperty(property);
			});
		}
	},
	handleChangeForCategory : function() {
		this.oConfigurationEditor.setIsUnsaved();
		var self = this;
		var stepId = self.step.getId();
		var currentCategoryId = this.params.arguments.categoryId;
		var aPreCat = this.oConfigurationEditor.getCategoriesForStep(this.step.getId());
		var sSelCategory = this.byId("idCategorySelect").getSelectedKeys();
		var currentCategoryChange = sSelCategory.indexOf(currentCategoryId);
		var aStepContexts = [];
		var unselectedCategories = [];
		var i, j;
		for(i = 0; i < aPreCat.length; i++) {
			var match = false;
			for(j = 0; j < sSelCategory.length; j++) {
				if (aPreCat[i] === sSelCategory[j]) {
					match = true;
					break;
				}
			}
			if (!match) {
				unselectedCategories.push(aPreCat[i]);
			}
		}
		if (sSelCategory.length !== 0) {
			sSelCategory.forEach(function(category) {
				self.oConfigurationEditor.addCategoryStepAssignment(category, stepId); //Add the step to the categories selected
				var oStepContext = {
					oldContext : {
						name : self.params.name,
						arguments : {
							configId : self.params.arguments.configId,
							categoryId : currentCategoryId,
							stepId : stepId
						}
					},
					newContext : {
						arguments : {
							configId : self.params.arguments.configId,
							categoryId : category
						}
					}
				};
				if (category !== currentCategoryId) {
					aStepContexts.push(oStepContext);
				}
			});
			aPreCat.forEach(function(sCatId) { //Remove the step from all the old categories it was present in
				if (sSelCategory.indexOf(sCatId) === -1) { // ... and that are not selected any more
					self.oConfigurationEditor.removeCategoryStepAssignment(sCatId, self.step.getId());
				}
			});
			if (unselectedCategories.length !== 0) {//Prepare context for unselected categories, to be removed from the model
				var newContext = jQuery.extend(true, {}, self.params);
				unselectedCategories.forEach(function(unselectedCategory) {
					var oStepContext = {
						oldContext : {
							name : self.params.name,
							arguments : {
								configId : self.params.arguments.configId,
								categoryId : currentCategoryId,
								stepId : stepId
							}
						},
						newContext : {
							arguments : {
								configId : self.params.arguments.configId,
								categoryId : unselectedCategory
							}
						},
						removeStep : true
					};
					if (currentCategoryChange === -1 && unselectedCategory === currentCategoryId) {//Prepare context for category change, if the current category is removed from the step
						var categoryChangeContext = {
							arguments : {
								appId : self.params.arguments.appId,
								configId : self.params.arguments.configId,
								categoryId : sSelCategory[0],
								stepId : stepId
							}
						};
						oStepContext.categoryChangeContext = categoryChangeContext;
						oStepContext.changeCategory = true;
					}
					aStepContexts.push(oStepContext);
				});
			}
		}
		if (aStepContexts.length !== 0) {
			this.oViewData.updateConfigTree(aStepContexts);//When the categories in the step is changed
		}
	},
	handleChangeForLeftTop : function() {
		this.oConfigurationEditor.setIsUnsaved();
		var sStepLeftTop = this.byId("idLeftTop").getValue().trim();
		var oTranslationFormat = sap.apf.modeler.ui.utils.TranslationFormatMap.STEP_CORNER_TEXT;
		var sStepLeftTopTextId = this.oTextPool.setText(sStepLeftTop, oTranslationFormat);
		this.step.setLeftUpperCornerTextKey(sStepLeftTopTextId);
	},
	handleChangeForRightTop : function() {
		this.oConfigurationEditor.setIsUnsaved();
		var sStepRightTop = this.byId("idRightTop").getValue().trim();
		var oTranslationFormat = sap.apf.modeler.ui.utils.TranslationFormatMap.STEP_CORNER_TEXT;
		var sStepRightTopTextId = this.oTextPool.setText(sStepRightTop, oTranslationFormat);
		this.step.setRightUpperCornerTextKey(sStepRightTopTextId);
	},
	handleChangeForLeftBottom : function() {
		this.oConfigurationEditor.setIsUnsaved();
		var sStepLeftBottom = this.byId("idLeftBottom").getValue().trim();
		var oTranslationFormat = sap.apf.modeler.ui.utils.TranslationFormatMap.STEP_CORNER_TEXT;
		var sStepLeftBottomTextId = this.oTextPool.setText(sStepLeftBottom, oTranslationFormat);
		this.step.setLeftLowerCornerTextKey(sStepLeftBottomTextId);
	},
	handleChangeForRightBottom : function() {
		this.oConfigurationEditor.setIsUnsaved();
		var sStepRightBottom = this.byId("idRightBottom").getValue().trim();
		var oTranslationFormat = sap.apf.modeler.ui.utils.TranslationFormatMap.STEP_CORNER_TEXT;
		var sStepRightBottomTextId = this.oTextPool.setText(sStepRightBottom, oTranslationFormat);
		this.step.setRightLowerCornerTextKey(sStepRightBottomTextId);
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_setSortDataForStep
	* @description Returns the data set to be bound to sort data layout.
	* Also checks if it is default sorting property, in this case creates the sort row from the first select property
	* creates {Object} Data set for sort data layout of the form:
	* {
	       aSortRows : [
	       		{
	       			 aAllProperties : [
	                      {
	                           sName - Name of the property.
	                      }
	                ],
	                property - Name of the selected sort property.
	                ascending- Translated text for 'ascending' and 'descending'.
	       		}
	       ]
	 * }
	 * Sets the data on the sort layout and also on the sort model
	* */
	_setSortDataForStep : function() {
		var oSelf = this;
		var aSelectProperties = this.step.getSelectProperties().map(function(sProperty) {
			return {
				property : sProperty
			};
		});
		var aSortRows;
		var oTopNSettingsForStep = this.step.getTopN();
		if (oTopNSettingsForStep && oTopNSettingsForStep.orderby) { // if Top N for step exists
			var aSortRowsForStep = oTopNSettingsForStep.orderby.map(function(oSortProperty) {
				var sOrderByProperty = oSortProperty.property;
				var sOrderByDirection = oSortProperty.ascending !== undefined && !oSortProperty.ascending ? oSelf.getText("descending") : oSelf.getText("ascending");
				return {
					property : sOrderByProperty,
					ascending : sOrderByDirection,
					aAllProperties : aSelectProperties
				};
			});
			aSortRows = aSortRowsForStep;
		} else {
			aSortRows = [ {
				property : aSelectProperties[0].property,
				ascending : true,
				aAllProperties : aSelectProperties
			} ];
		}
		var oSortModelForStep = new sap.ui.model.json.JSONModel({
			aSortRows : aSortRows
		});
		this.byId("idStepSortLayout").setModel(oSortModelForStep);
		this._bindSortLayoutDataForStep();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_bindSortLayoutDataForStep
	* @description Binds sap.apf.modeler.ui.controller.step#oSortModelForStep to Sort layout.
	*               Iteratively binds the data to all the controls in Sort Data Layout.
	* */
	_bindSortLayoutDataForStep : function() {
		var oSelf = this;
		var oSortLayout = this.byId("idStepSortLayout");
		var oSortRowTemplate = new sap.ui.layout.Grid({ // add the select box controls to the grid.
			width : "100%"
		});
		var oSortFieldLabel = new sap.m.Label({// "Sort Label" Label
			width : "100%",
			textAlign : "End",
			layoutData : new sap.ui.layout.GridData({
				span : "L3 M3 S3"
			}),
			text : this.getText("sortingField")
		}).addStyleClass("sortFieldLabel");
		oSortRowTemplate.addContent(oSortFieldLabel);
		var oSortPropertySelectBox = new sap.m.Select({// "Sort Fields" Select Box
			width : "100%",
			layoutData : new sap.ui.layout.GridData({
				span : "L2 M3 S3"
			}),
			items : {
				path : "aAllProperties",
				template : new sap.ui.core.ListItem({
					key : "{property}",
					text : "{property}"
				})
			},
			selectedKey : "{property}",
			change : oSelf._handleChangeForSortData.bind(this)
		// the current context should be bound to the event handler
		});
		oSortRowTemplate.addContent(oSortPropertySelectBox);
		var oDirectionLabel = new sap.m.Label({
			layoutData : new sap.ui.layout.GridData({// "Direction" Label
				span : "L2 M2 S2"
			}),
			width : "100%",
			textAlign : "End",
			text : this.getText("direction")
		}).addStyleClass("directionLabel");
		oSortRowTemplate.addContent(oDirectionLabel);
		var oDirectionSelectBox = new sap.m.Select({ // "Direction" Select Box
			width : "100%",
			layoutData : new sap.ui.layout.GridData({
				span : "L2 M2 S2"
			}),
			items : [ {
				key : this.getText("ascending"),
				text : this.getText("ascending")
			}, {
				key : this.getText("descending"),
				text : this.getText("descending")
			} ],
			selectedKey : "{ascending}",
			change : oSelf._handleChangeForSortData.bind(this)
		// the current context should be bound to the event handler
		});
		oSortRowTemplate.addContent(oDirectionSelectBox);// Add Icon
		var oAddIcon = new sap.ui.core.Icon({
			width : "100%",
			src : "sap-icon://add",
			tooltip : this.getText("addButton"),
			visible : true,
			press : oSelf._handleChangeForAddSortRow.bind(this)
		// the current context should be bound to the event handler
		}).addStyleClass("addIconRepresentation");
		var oRemoveIcon = new sap.ui.core.Icon({// Remove Icon
			width : "100%",
			src : "sap-icon://less",
			tooltip : this.getText("deleteButton"),
			visible : {
				path : "/",
				formatter : function() {
					var oBindingContext = this.getBindingContext();
					var nCurrentIndex = parseInt(oBindingContext.getPath().split("/").pop(), 10);
					return !!nCurrentIndex;
				}
			},
			press : oSelf._handleChangeForDeleteSortRow.bind(this)
		// the current context should be bound to the event handler
		}).addStyleClass("lessIconRepresentation");
		var oIconLayout = new sap.m.HBox({// Layout to hold the add/less icons
			layoutData : new sap.ui.layout.GridData({
				span : "L2 M2 S2"
			}),
			items : [ oAddIcon, oRemoveIcon ]
		});
		oSortRowTemplate.addContent(oIconLayout);
		oSortLayout.bindAggregation("items", "/aSortRows", function(sId) {
			return oSortRowTemplate.clone(sId);
		});
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_handleChangeForSortData
	* @description handles the change in the sort property or dort direction and sets the data on the step
	* */
	_handleChangeForSortData : function() {
		this._setSortFieldsFromCurrentDataset();
		this.oConfigurationEditor.setIsUnsaved();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_handleChangeForAddSortRow
	* @param {oAddRowEvent}
	* @description Handler for the "+" icon in the sort property row
	* adds a new sort property row in the representation sort data and also sets the corresponding properties on the step object.          
	* */
	_handleChangeForAddSortRow : function(oAddRowEvent) {
		var oUpdatedSortRow = this._getUpdatedSortRow(oAddRowEvent);
		var oBindingContext = oAddRowEvent.getSource().getBindingContext();
		var oCurrentObjectClone = jQuery.extend(true, {}, oBindingContext.getObject());
		delete oCurrentObjectClone.property;
		delete oCurrentObjectClone.ascending;
		oUpdatedSortRow.aSortRows.splice(oUpdatedSortRow.nCurrentIndex + 1, 0, oCurrentObjectClone);
		this._updateModelForSortData();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_handleChangeForDeleteSortRow
	* @param {oDeleteRowEvent}
	* @description Handler for the "-" icon in the sort property row
	* removes a sort property row from the representation sort data and also sets the corresponding properties on the step object.          
	* */
	_handleChangeForDeleteSortRow : function(oDeleteRowEvent) {
		var oUpdatedSortRow = this._getUpdatedSortRow(oDeleteRowEvent);
		oUpdatedSortRow.aSortRows.splice(oUpdatedSortRow.nCurrentIndex, 1);
		this._updateModelForSortData();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_getUpdatedSortRow
	* @param {oSortRowEvent} - event from the add/delete row in sort data
	* returns the information about the added/deleted row in the sort data
	*      {
	*           nCurrentIndex : nCurrentIndex,
		        aSortRows : aSortRows
	*      }
	*         
	* */
	_getUpdatedSortRow : function(oSortRowEvent) {
		var oBindingContext = oSortRowEvent.getSource().getBindingContext();
		var nCurrentIndex = parseInt(oBindingContext.getPath().split("/").pop(), 10);
		var aSortRows = this.byId("idStepSortLayout").getModel().getData().aSortRows;
		return {
			nCurrentIndex : nCurrentIndex,
			aSortRows : aSortRows
		};
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_updateModelForSortData
	* Updates the model for the sort layout and sets the current properties        
	* */
	_updateModelForSortData : function() {
		this.byId("idStepSortLayout").getModel().updateBindings();
		this._setSortFieldsFromCurrentDataset();
		this.oConfigurationEditor.setIsUnsaved();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_setSortFieldsFromCurrentDataset
	* @description handles every change event related to sort layout
	* Sets new values on the step object based on the current property model.
	* Clears the old values from step object.
	* Sets new values by iterating through the current sort data set.
	* */
	_setSortFieldsFromCurrentDataset : function() {
		var oSelf = this;
		var aSortProperties = [];
		// Loop through current sort model and set orderby properties accordingly.
		this.byId("idStepSortLayout").getModel().getData().aSortRows.forEach(function(oSortRow) {
			var oSortProperty = {};
			oSortProperty.property = oSortRow.property || (oSortRow.aAllProperties.length && oSortRow.aAllProperties[0].property);
			oSortProperty.ascending = !oSortRow.ascending || (oSortRow.ascending === oSelf.getText("ascending"));
			aSortProperties.push(oSortProperty);
		});
		this.step.setTopNSortProperties(aSortProperties);
	},
	/**
	* @function
	* @name sap.apf.modeler.ui.controller.step#handleChangeForDataReduction
	* @description Handler for the data reduction .  Changes the visibility of top N fields based on the selected options.
	* Also restes the top N values in case , "No Data Reduction" is selected       
	* */
	handleChangeForDataReduction : function(oEvent) {
		var bIsTopNVisible; // boolean to check if "Top N" is selected
		if (oEvent.getSource().getSelectedButton().getText() === this.getText("noDataReduction")) {
			bIsTopNVisible = false;
			this._resetTopNFields();
		} else {
			this._setSortDataForStep();
			bIsTopNVisible = true;
		}
		this._changeVisibilityOfTopN(bIsTopNVisible); //change the visibility of the Top N fields based on the boolean
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_resetTopNFields
	* @description resets the Top N fields as well as clears the fields
	* */
	_resetTopNFields : function() {
		this.step.resetTopN();
		var oSortModelForStep = new sap.ui.model.json.JSONModel({
			aSortRows : []
		});
		this.byId("idStepSortLayout").setModel(oSortModelForStep);
		this.byId("idCustomRecordValue").setValue();
	},
	/**
	* @function
	* @name sap.apf.modeler.ui.controller.step#_handleChangeForDataRecordInputValue
	* @description Handler for the data records custom input field
	* Check if the valid value is given in input field, accordingly sets the state of the data record input field   
	* */
	handleChangeForDataRecordInputValue : function(oEvent) {
		var isValidState;
		//value for data record should not be negative, float or greater than 10000 - Otherwise the value state for input is invalid
		if (oEvent.getSource().getValue().trim().indexOf(".") !== -1 || oEvent.getSource().getValue().trim() <= 0 || oEvent.getSource().getValue().trim() > 10000) {
			isValidState = "Error";
		} else {
			isValidState = "None";
		}
		oEvent.getSource().setValueState(isValidState);
		//read the sort properties from the sort layout and set the sort propetues as well on change of data record input
		var aSortProperties = [];
		this.byId("idStepSortLayout").getModel().getData().aSortRows.forEach(function(sortRow) {
			aSortProperties.push({
				property : sortRow.property,
				ascending : sortRow.ascending
			});
		});
		if (aSortProperties) {
			this.step.setTopNValue(oEvent.getSource().getValue());
			this.step.setTopNSortProperties(aSortProperties);
		}
		this.oConfigurationEditor.setIsUnsaved();
	},
	/**
	* @private
	* @function
	* @name sap.apf.modeler.ui.controller.step#_changeVisibilityOfTopN
	* @param bIsTopNVisible - a boolean which is used to change the visibility of the top N fields
	* @description changes the visibility of the the top N fields based on whether top N is set on the step or not
	* Also adds/removes the mandatory tag from the input field for Top N
	* */
	_changeVisibilityOfTopN : function(bIsTopNVisible) {
		this.byId("idCustomRecordValue").isMandatory = bIsTopNVisible;
		this.byId("idDataRecordsLabel").setVisible(bIsTopNVisible);
		this.byId("idDataRecordsLabel").setRequired(bIsTopNVisible);
		this.byId("idCustomRecordValue").setVisible(bIsTopNVisible);
		this.byId("idStepSortLayout").setVisible(bIsTopNVisible);
	},
	/**
	 * @private
	 * @function
	 * @name sap.apf.modeler.ui.controller.step#_setMandatoryFields
	 * @param {Array} fields - Array of form fields
	 * @description Set mandatory fields on the instance level  
	 * */
	_setMandatoryFields : function(fields) {
		this.mandatoryFields = this.mandatoryFields || [];
		for(var i = 0; i < fields.length; i++) {
			fields[i].isMandatory = true;
			this.mandatoryFields.push(fields[i]);
		}
	},
	/**
	 * @private
	 * @function
	 * @name sap.apf.modeler.ui.controller.step#_getMandatoryFields
	 * @param {Object} oEvent - Event instance of the form field 
	 * @description getter for mandatory fields
	 * */
	_getMandatoryFields : function() {
		return this.mandatoryFields;
	},
	/**
	 * @private
	 * @function
	 * @name sap.apf.modeler.ui.controller.step#_setValidationState
	 * @param {Object} oEvent - Event instance of the form field 
	 * @description Set validation state of sub view
	 * */
	_setValidationState : function() {
		var mandatoryFields = this._getMandatoryFields();
		for(var i = 0; i < mandatoryFields.length; i++) {
			if (mandatoryFields[i].isMandatory === true) {
				if (typeof mandatoryFields[i].getSelectedKeys === "function") {
					this.isValidState = (mandatoryFields[i].getSelectedKeys().length >= 1) ? true : false;
				} else if (typeof mandatoryFields[i].getValue === "function") {
					this.isValidState = (mandatoryFields[i].getValue().trim() !== "") ? true : false;
				} else {
					this.isValidState = (mandatoryFields[i].getSelectedKey().length >= 1) ? true : false;
				}
				if (this.isValidState === false) {
					break;
				}
			}
		}
	},
	/**
	 * @private
	 * @function
	 * @name sap.apf.modeler.ui.controller.step#getValidationState
	 * @description Getter for getting the current validation state of sub view
	 * */
	getValidationState : function() {
		this._setValidationState(); //Set the validation state of view
		var isValidState = (this.isValidState !== undefined) ? this.isValidState : true;
		return isValidState;
	}
});<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2014-2016 SAP SE. All rights reserved
 */
sap.ui.define(["jquery.sap.global"],function(q){"use strict";var F=function(){};F.showDialog=function(a,i){};F.closeDialog=function(){};return F;},true);
<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

// Provides control sap.ui.comp.smartfilterbar.SelectOption.
sap.ui.define(['jquery.sap.global', 'sap/ui/comp/library', 'sap/ui/core/Element'],
	function(jQuery, library, Element) {
	"use strict";


	
	/**
	 * Constructor for a new smartfilterbar/SelectOption.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given 
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * A Select Option can be used to specify default filter values for a control configuration of the SmartFilterBar.
	 * @extends sap.ui.core.Element
	 *
	 * @constructor
	 * @public
	 * @alias sap.ui.comp.smartfilterbar.SelectOption
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var SelectOption = Element.extend("sap.ui.comp.smartfilterbar.SelectOption", /** @lends sap.ui.comp.smartfilterbar.SelectOption.prototype */ { metadata : {
	
		library : "sap.ui.comp",
		properties : {
	
			/**
			 * The sign for a Select Option. Possible values are I for include or E for exclude. Constants can be found here: sap.ui.comp.smartfilterbar.SelectOption.SIGN
			 */
			sign : {type : "string", group : "Misc", defaultValue : 'I'},
	
			/**
			 * The operator for a select option. The default value is EQ "for equals". Possible values can be found here: sap.ui.comp.smartfilterbar.SelectOption.OPERATOR.
			 */
			operator : {type : "string", group : "Misc", defaultValue : 'EQ'},
	
			/**
			 * The low value for a select option.
			 */
			low : {type : "string", group : "Misc", defaultValue : null},
	
			/**
			 * The high value for a select option. The high value is only required for a few operators, e.g. BT (between).
			 */
			high : {type : "string", group : "Misc", defaultValue : null}
		}
	}});
	
	SelectOption.SIGN = {
		I: "I",
		include: "I",
		E: "E",
		exclude: "E"
	};
	
	SelectOption.OPERATOR = {
		EQ: "EQ",
		NE: "NE",
		CP: "CP",
		GT: "GT",
		GE: "GE",
		LT: "LT",
		LE: "LE",
		NP: "NP",
		BT: "BT",
		NB: "NB"
	};

	return SelectOption;

}, /* bExport= */ true);
<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
/*global jQuery, sap, OData */
jQuery.sap.declare("sap.apf.core.instance");
jQuery.sap.require('sap.apf.utils.utils');
jQuery.sap.require("sap.apf.core.utils.uriGenerator");
jQuery.sap.require("sap.apf.core.metadata");
jQuery.sap.require("sap.apf.core.metadataFacade");
jQuery.sap.require("sap.apf.core.metadataProperty");
jQuery.sap.require("sap.apf.core.ajax");
jQuery.sap.require("sap.apf.core.odataRequest");
jQuery.sap.require("sap.apf.core.messageHandler");
jQuery.sap.require("sap.apf.core.entityTypeMetadata");
jQuery.sap.require("sap.apf.core.metadataFactory");
jQuery.sap.require("sap.apf.core.textResourceHandler");
jQuery.sap.require("sap.apf.core.configurationFactory");
jQuery.sap.require("sap.apf.core.path");
jQuery.sap.require("sap.apf.core.sessionHandler");
jQuery.sap.require("sap.apf.core.resourcePathHandler");
jQuery.sap.require("sap.apf.core.persistence");
jQuery.sap.require("sap.apf.core.readRequest");
jQuery.sap.require("sap.apf.core.readRequestByRequiredFilter");
jQuery.sap.require("sap.apf.core.utils.fileExists");

(function() {
	'use strict';
	/**
	 * @class Core Component Instance
	 * @name sap.apf.core.Instance
	 * @description Creation of new Core Component Instance
	 */
	sap.apf.core.Instance = function(oApiInject) {

		var that = this;
		var oMessageHandler = oApiInject.messageHandler;
		var oStartParameter = oApiInject.startParameter;
		var sRememberedPath;
		var oInject = {
			messageHandler : oMessageHandler,
			coreApi : that
		};
		var oResourcePathHandler;
		var oMetadataFactory;
		var oTextResourceHandler;
		var oConfigurationFactory;
		var oPath;
		var oSessionHandler;
		var oPersistence;
		var oFileExists;
		this.destroy = function() {
			oPath.destroy();
		};
		/**
		 * @see sap.apf.core.ajax
		 */
		this.ajax = function(oSettings) {
			return sap.apf.core.ajax(oSettings);
		};
		/**
		 * @see sap.apf.core.odataRequestWrapper
		 */
		this.odataRequest = function(oRequest, fnSuccess, fnError, oBatchHandler) {
			sap.apf.core.odataRequestWrapper(oMessageHandler, oRequest, fnSuccess, fnError, oBatchHandler);
		};
		/**
		 * @see sap.apf.utils.startParameter
		 */
		this.getStartParameterFacade = function() {
			return oStartParameter;
		};
		this.getMessageHandler = function() {
			return oMessageHandler;
		};
		/**
		 * @see sap.apf#putMessage for api definition.
		 * @see sap.apf.core.MessageHandler#putMessage for implementation.
		 */
		this.putMessage = function(oMessage) {
			return oMessageHandler.putMessage(oMessage);
		};
		/**
		 * @see sap.apf.core.MessageHandler#check
		 */
		this.check = function(bExpression, sMessage, sCode) {
			return oMessageHandler.check(bExpression, sMessage, sCode);
		};
		/**
		 * @see sap.apf#createMessageObject for api definition.
		 * @see sap.apf.core.MessageHandler#createMessageObject
		 */
		this.createMessageObject = function(oConfig) {
			return oMessageHandler.createMessageObject(oConfig);
		};
		/**
		 * @see sap.apf.core.MessageHandler#activateOnErrorHandling
		 */
		this.activateOnErrorHandling = function(bOnOff) {
			oMessageHandler.activateOnErrorHandling(bOnOff);
		};
		/**
		 * @see sap.apf.core.MessageHandler#setMessageCallback
		 */
		this.setCallbackForMessageHandling = function(fnCallback) {
			oMessageHandler.setMessageCallback(fnCallback);
		};
		/**
		 * @see sap.apf.core.MessageHandler#setApplicationMessageCallback
		 */
		this.setApplicationCallbackForMessageHandling = function(fnCallback) {
			oMessageHandler.setApplicationMessageCallback(fnCallback);
		};
		/**
		 * @see sap.apf.core.MessageHandler#getLogMessages
		 */
		this.getLogMessages = function() {
			return oMessageHandler.getLogMessages();
		};
		/**
		 * @see sap.apf.core.checkForTimeout
		 */
		this.checkForTimeout = function(oServerResponse) {
			var oMessageObject = sap.apf.core.utils.checkForTimeout(oServerResponse);
			// up to now, the error handling was hard coded in checkForTimeout
			if (oMessageObject) {
				oMessageHandler.putMessage(oMessageObject);
			}
			return oMessageObject;
		};
		/**
		 * @description Returns the instance of the UriGenerator. For internal core using only.
		 */
		this.getUriGenerator = function() {
			return sap.apf.core.utils.uriGenerator;
		};
		/**
		 * @see sap.apf.core.MetadataFactory#getMetadata
		 */
		this.getMetadata = function(sAbsolutePathToServiceDocument) {
			return oMetadataFactory.getMetadata(sAbsolutePathToServiceDocument);
		};
		/**
		 * @see sap.apf.core.MetadataFactory#getMetadataFacade
		 */
		this.getMetadataFacade = function() {
			return oMetadataFactory.getMetadataFacade();
		};
		/**
		 * @see sap.apf.core.MetadataFactory#getEntityTypeMetadata
		 */
		this.getEntityTypeMetadata = function(sAbsolutePathToServiceDocument, sEntityType) {
			return oMetadataFactory.getEntityTypeMetadata(sAbsolutePathToServiceDocument, sEntityType);
		};
		/**
		 * @see sap.apf.core.ResourcePathHandler#loadConfigFromFilePath
		 */
		this.loadApplicationConfig = function(sFilePath) {
			oResourcePathHandler.loadConfigFromFilePath(sFilePath);
		};
		/**
		 * @see sap.apf.core.TextResourceHandler#loadTextElements
		 */
		this.loadTextElements = function(textElements) {
			oTextResourceHandler.loadTextElements(textElements);
		};
		/**
		 * @see sap.apf.core.ResourcePathHandler#getConfigurationProperties
		 */
		this.getApplicationConfigProperties = function() {
			return oResourcePathHandler.getConfigurationProperties();
		};
		/**
		 * @see sap.apf.core.ResourcePathHandler#getResourceLocation
		 */
		this.getResourceLocation = function(sResourceIdentifier) {
			return oResourcePathHandler.getResourceLocation(sResourceIdentifier);
		};
		/**
		 * @see sap.apf.core.ResourcePathHandler#getPersistenceConfiguration
		 */
		this.getPersistenceConfiguration = function() {
			return oResourcePathHandler.getPersistenceConfiguration();
		};
		/**
		 * @see sap.apf.core.ResourcePathHandler#getApplicationConfigurationURL
		 */
		this.getApplicationConfigurationURL = function() {
			return oResourcePathHandler.getApplicationConfigurationURL();
		};
		// ConfigurationFactory API
		/**
		 * @see sap.apf.core.ConfigurationFactory#getCategories
		 */
		this.getCategories = function() {
			return oConfigurationFactory.getCategories();
		};
		/**
		 * @see sap.apf.core.ConfigurationFactory#existsConfiguration
		 */
		this.existsConfiguration = function(sId) {
			return oConfigurationFactory.existsConfiguration(sId);
		};
		/**
		 * @see sap.apf.core.ConfigurationFactory#getStepTemplates
		 */
		this.getStepTemplates = function() {
			return oConfigurationFactory.getStepTemplates();
		};
		/**
		 * @see sap.apf.core.ConfigurationFactory#getFacetFilterConfigurations
		 */
		this.getFacetFilterConfigurations = function() {
			return oConfigurationFactory.getFacetFilterConfigurations();
		};
		/**
		 * @see sap.apf.core.ConfigurationFactory#getNavigationTargets
		 */
		this.getNavigationTargets = function() {
			return oConfigurationFactory.getNavigationTargets();
		};
		/**
		 * @description Creates a step object from the configuration object and adds it to the path.
		 * @param {string} sStepId Step id as defined in the analytical configuration.
		 * @param {function} fnStepProcessedCallback Callback function for path update.
		 * @param {string} [sRepresentationId] Parameter, that allows definition of the representation id that shall initially be selected. If omitted the first configured representation will be selected.
		 * @returns {sap.apf.core.Step} oStep Created step.
		 */
		this.createStep = function(sStepId, fnStepProcessedCallback, sRepresentationId) {
			var oStepInstance;
			oMessageHandler.check(sStepId !== undefined && typeof sStepId === "string" && sStepId.length !== 0, "sStepID is  unknown or undefined");
			oStepInstance = oConfigurationFactory.createStep(sStepId, sRepresentationId);
			oPath.addStep(oStepInstance, fnStepProcessedCallback);
			return oStepInstance;
		};
		// Path API
		/**
		 * @see sap.apf.core.Path#getSteps
		 */
		this.getSteps = function() {
			return oPath.getSteps();
		};
		/**
		 * @see sap.apf.core.Path#moveStepToPosition
		 */
		this.moveStepToPosition = function(oStep, nPosition, fnStepProcessedCallback) {
			oPath.moveStepToPosition(oStep, nPosition, fnStepProcessedCallback);
		};
		/**
		 * @function
		 * @name sap.apf.core.Instance#updatePath
		 * @see sap.apf.core.Path#update
		 */
		this.updatePath = function(fnStepProcessedCallback, bContextChanged) {
			oPath.update(fnStepProcessedCallback, bContextChanged);
		};
		/**
		 * @see sap.apf.core.Path#removeStep
		 */
		this.removeStep = function(oStep, fnStepProcessedCallback) {
			oPath.removeStep(oStep, fnStepProcessedCallback);
		};
		/**
		 * @description Creates a new Path instance
		 * @param {boolean} [bRememberActualPath] if true, then the path can be restored
		 *
		 */
		this.resetPath = function(bRememberActualPath) {
			if (bRememberActualPath) {
				sRememberedPath = oPath.serialize();
			}
			if (oPath) {
				oPath.destroy();
			}
			oPath = new sap.apf.core.Path(oInject);
		};
		/**
		 * if resetPath has been called with bRememberActualPath, then the old path
		 * can be restored
		 */
		this.restoreOriginalPath = function() {
			if (sRememberedPath) {
				oPath.destroy();
				oPath = new sap.apf.core.Path(oInject);
				oPath.deserialize(sRememberedPath);
			}
		};
		/**
		 * @see sap.apf.core.Path#stepIsActive
		 */
		this.stepIsActive = function(oStep) {
			return oPath.stepIsActive(oStep);
		};
		/**
		 * @see sap.apf.core.Path#serializePath
		 */
		this.serializePath = function() {
			return oPath.serialize();
		};
		/**
		 * @see sap.apf.core.Path#deserializePath
		 */
		this.deserializePath = function(oSerializedAnalysisPath) {
			oPath.deserialize(oSerializedAnalysisPath);
		};
		// Text Resource Handler API
		/**
		 * @see sap.apf#getTextNotHtmlEncoded
		 * @see sap.apf.core.TextResourceHandler#getTextNotHtmlEncoded
		 */
		this.getTextNotHtmlEncoded = function(oLabel, aParameters) {
			return oTextResourceHandler.getTextNotHtmlEncoded(oLabel, aParameters);
		};
		/**
		 * @see sap.apf#getTextHtmlEncoded
		 * @see sap.apf.core.TextResourceHandler#getTextHtmlEncoded
		 */
		this.getTextHtmlEncoded = function(oLabel, aParameters) {
			return oTextResourceHandler.getTextHtmlEncoded(oLabel, aParameters);
		};
		/**
		 * returns true, if this is the text key for the initial text. Initial text means empty string.
		 */
		this.isInitialTextKey = function(textKey) {
			return (textKey === sap.apf.core.constants.textKeyForInitialText);
		};
		/**
		 * @see sap.apf.core.TextResourceHandler#getMessageText
		 */
		this.getMessageText = function(sCode, aParameters) {
			return oTextResourceHandler.getMessageText(sCode, aParameters);
		};
		/**
		 * @see sap.apf.core.SessionHandler#getXsrfToken
		 */
		this.getXsrfToken = function(sServiceRootPath) {
			return oSessionHandler.getXsrfToken(sServiceRootPath);
		};
		/**
		 * @see sap.apf.core.SessionHandler#setDirtyState
		 */
		this.setDirtyState = function(state) {
		    oSessionHandler.setDirtyState(state);
		};
		/**
		 * @see sap.apf.core.SessionHandler#isDirty
		 */
        this.isDirty = function() {
            return oSessionHandler.isDirty();
        };
        /**
         * @see sap.apf.core.SessionHandler#setPathName
         */
        this.setPathName = function(name) {
            oSessionHandler.setPathName(name);
        };
        /**
         * @see sap.apf.core.SessionHandler#getPathName
         */
        this.getPathName = function() {
            return oSessionHandler.getPathName();
        };		
		/**
		 * @see sap.apf.core.utils.StartFilterHandler#getCumulativeFilter
		 */
		this.getCumulativeFilter = function() {
			return oApiInject.getCumulativeFilter();
		};
		/**
		 * @see sap.apf#createReadRequest
		 * @description Creates an object for performing an Odata Request get operation.
		 * @param {String|Object} sRequestConfigurationId - identifies a request configuration, which is contained in the analytical configuration.
		 *                        or the request configuration is directly passed as an object oRequestConfiguration.
		 * @returns {sap.apf.core.ReadRequest}
		 */
		this.createReadRequest = function(/* sRequestConfigurationId | oRequestConfiguration */requestConfiguration) {
			var oRequest = oConfigurationFactory.createRequest(requestConfiguration);
			var oRequestConfiguration;
			if (typeof requestConfiguration === 'string') {
				oRequestConfiguration = oConfigurationFactory.getConfigurationById(requestConfiguration);
			} else {
				oRequestConfiguration = requestConfiguration;
			}
			return new sap.apf.core.ReadRequest(oInject, oRequest, oRequestConfiguration.service, oRequestConfiguration.entityType);
		};
		/**
		 * @see sap.apf#createReadRequestByRequiredFilter
		 * @description Creates an object for performing an Odata Request get operation with required filter for parameter entity set key properties & required filters.
		 * @param {String|Object} sRequestConfigurationId - identifies a request configuration, which is contained in the analytical configuration.
		 *                        or the request configuration is directly passed as an object oRequestConfiguration.
		 * @returns {sap.apf.core.ReadRequestByRequiredFilter}
		 */
		this.createReadRequestByRequiredFilter = function(/* sRequestConfigurationId | oRequestConfiguration */requestConfiguration) {
			var oRequest = oConfigurationFactory.createRequest(requestConfiguration);
			var oRequestConfiguration;
			if (typeof requestConfiguration === 'string') {
				oRequestConfiguration = oConfigurationFactory.getConfigurationById(requestConfiguration);
			} else {
				oRequestConfiguration = requestConfiguration;
			}
			return new sap.apf.core.ReadRequestByRequiredFilter(oInject, oRequest, oRequestConfiguration.service, oRequestConfiguration.entityType);
		};
		/**
		 * @description Message configurations are loaded.
		 * @see sap.apf.core.MessageHandler#loadConfig
		 */
		this.loadMessageConfiguration = function(aMessages, bResetRegistry) {
			oMessageHandler.loadConfig(aMessages, bResetRegistry);
		};
		/**
		 * @see sap.apf.core.ConfigurationFactory#loadConfig
		 */
		this.loadAnalyticalConfiguration = function(oConfig) {
			oConfigurationFactory.loadConfig(oConfig);
		};
		/**
		 * @see sap.apf.core#savePath for api definition.
		 * @see sap.apf.core.Persistence#createPath
		 */
		this.savePath = function(arg1, arg2, arg3, arg4) {
			var sPathId;
			var sName;
			var fnCallback;
			var oExternalObject;
			if (typeof arg1 === 'string' && typeof arg2 === 'string' && typeof arg3 === 'function') {
				sPathId = arg1;
				sName = arg2;
				fnCallback = arg3;
				oExternalObject = arg4;
				this.setPathName(sName);
				oPersistence.modifyPath(sPathId, sName, fnCallback, oExternalObject);
			} else if (typeof arg1 === 'string' && typeof arg2 === 'function') {
				sName = arg1;
				fnCallback = arg2;
				oExternalObject = arg3;
				this.setPathName(sName);
				oPersistence.createPath(sName, fnCallback, oExternalObject);
			} else {
				oMessageHandler.putMessage(sap.apf.core.createMessageObject({
					code : "5027",
					aParameters : [ arg1, arg2, arg3 ]
				}));
			}
		};
		/**
		 * @see sap.apf.core.Persistence#readPaths
		 */
		this.readPaths = function(fnCallback) {
			oPersistence.readPaths(fnCallback);
		};
		/**
		 * @see sap.apf.core.Persistence#openPath
		 */
		this.openPath = function(sPathId, fnCallback, nActiveStep) {
			function localCallback(oResponse, oEntitiyMetadata, oMessageObject) {
				if (!oMessageObject && sRememberedPath) {
					sRememberedPath = undefined;
				} 
				if (!oMessageObject) {
					that.setPathName(oResponse.path.AnalysisPathName);
				}
				fnCallback(oResponse, oEntitiyMetadata, oMessageObject);
			}
			return oPersistence.openPath(sPathId, localCallback, nActiveStep);
		};
		/**
		 * @see sap.apf.core.Persistence#deletePath
		 */
		this.deletePath = function(sPathId, fnCallback) {
			oPersistence.deletePath(sPathId, fnCallback);
		};
		/**
		 * @see sap.apf#createFilter for api definition
		 * @see sap.apf.utils.Filter
		 */
		this.createFilter = function(oSelectionVariant) {
			return new sap.apf.utils.Filter(oMessageHandler, oSelectionVariant);
		};
		/**
		 * @public
		 * @function
		 * @name sap.apf.core#getActiveStep
		 * @description Returns active step, currently selected step, of analysis path.
		 * @returns {sap.apf.core.Step}
		 */
		this.getActiveStep = function() {
			return oPath.getActiveSteps()[0];
		};
		/**
		 * @public
		 * @function
		 * @name sap.apf.core#getCumulativeFilterUpToActiveStep
		 * @description Returns the cumulative filter up to the active step (included) and the context
		 * @returns {sap.apf.core.utils.Filter} cumulativeFilter
		 */
		this.getCumulativeFilterUpToActiveStep = function() {
			return oPath.getCumulativeFilterUpToActiveStep();
		};
		/**
		 * @public
		 * @function
		 * @name sap.apf.core#setActiveStep
		 * @description Sets handed over step as the active one.
		 * @param {sap.apf.core.Step} oStep The step to be set as active
		 * @returns undefined
		 */
		this.setActiveStep = function(oStep) {
			oPath.makeStepActive(oStep);
			var aActiveSteps = oPath.getActiveSteps();
			var i;
			for(i = 0; i < aActiveSteps.length; ++i) {
				oPath.makeStepInactive(aActiveSteps[i]);
			}
			return oPath.makeStepActive(oStep);
		};
		/**
		 * @public
		 * @function
		 * @name sap.apf.core.Instance#createFirstStep
		 * @description Method to be used APF internally by the binding class to create instances from representation constructors.
		 */
		this.createFirstStep = function(sStepId, sRepId, callback) {
			var isValidStepId = false;
			var stepTemplates;
			stepTemplates = that.getStepTemplates();
			stepTemplates.forEach(function(item) {
				isValidStepId = item.id === sStepId ? true : isValidStepId;
			});
			if (!isValidStepId) {
				oMessageHandler.putMessage(oMessageHandler.createMessageObject({
					code : '5036',
					aParameters : [ sStepId ]
				}));
			} else {
				that.createStep(sStepId, callback, sRepId);
			}
		};
		/**
		 * @private
		 * @function
		 * @name sap.apf.core.Instance#getFunctionCreateRequest
		 * @description Returns function createRequest from sap.apf.core.ConfigurationFactory
		 */
		this.getFunctionCreateRequest = function() {
			return oConfigurationFactory.createRequest;
		};
		// create local singleton instances...
		oTextResourceHandler = new sap.apf.core.TextResourceHandler(oInject);
		oMessageHandler.setTextResourceHandler(oTextResourceHandler);
		if (oApiInject.manifests) {
			oInject.manifests = oApiInject.manifests;
		}
		oFileExists = new sap.apf.core.utils.FileExists();
		oConfigurationFactory = new sap.apf.core.ConfigurationFactory(oInject);
		var oInjectMetadataFactory = {
			entityTypeMetadata : sap.apf.core.EntityTypeMetadata,
			hashtable : sap.apf.utils.Hashtable,
			metadata : sap.apf.core.Metadata,
			metadataFacade : sap.apf.core.MetadataFacade,
			metadataProperty : sap.apf.core.MetadataProperty,
			messageHandler : oInject.messageHandler,
			coreApi : that,
			datajs : OData,
			configurationFactory : oConfigurationFactory,
			fileExists: oFileExists
		};
		oMetadataFactory = new sap.apf.core.MetadataFactory(oInjectMetadataFactory);
		oPath = new sap.apf.core.Path(oInject);
		oSessionHandler = new sap.apf.core.SessionHandler(oInject);
		oPersistence = new sap.apf.core.Persistence(oInject);
		var oInjectRessourcePathHandler = {
				coreApi : that,
				messageHandler : oInject.messageHandler,
				fileExists : oFileExists,
				manifests : oApiInject.manifests
		};
		oResourcePathHandler = new sap.apf.core.ResourcePathHandler(oInjectRessourcePathHandler);
	};
}());<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

sap.ui.define([
	'sap/ui/fl/Utils', 'jquery.sap.global', 'sap/ui/fl/changeHandler/Base'
], function(Utils, jQuery, Base) {
	"use strict";

	/**
	 * Change handler for adding a smart form group.
	 * @constructor
	 * @alias sap.ui.fl.changeHandler.AddGroup
	 * @author SAP SE
	 * @version 1.36.12
	 * @experimental Since 1.27.0
	 */
	var AddGroup = function() {
	};
	AddGroup.prototype = jQuery.sap.newObject(Base.prototype);

	/**
	 * Adds a smart form group.
	 *
	 * @param {sap.ui.fl.Change} oChangeWrapper change wrapper object with instructions to be applied on the control map
	 * @param {sap.ui.comp.smartform.SmartForm} oForm smart form control that matches the change selector for applying the change
	 * @param {object} oControlMap flat list of ids that point to control instances
	 * @public
	 */
	AddGroup.prototype.applyChange = function(oChangeWrapper, oForm) {
		var oChange = oChangeWrapper.getDefinition();
		if (oChange.texts && oChange.texts.groupLabel && oChange.texts.groupLabel.value && oChange.content && oChange.content.group && oChange.content.group.id) {
			jQuery.sap.require("sap.ui.comp.smartform.Group"); //revise in future when concept for accessing controls within change handlers is available
			var oGroup = new sap.ui.comp.smartform.Group(oChange.content.group.id);
			if (oGroup.setLabel) {
				oGroup.setLabel(oChange.texts.groupLabel.value);
			}
			if (oForm && oForm.insertGroup) {
				oForm.insertGroup(oGroup, oChange.content.group.index);
			} else {
				throw new Error("no parent form provided for adding the group");
			}
		} else {
			Utils.log.error("Change does not contain sufficient information to be applied: [" + oChange.layer + "]" + oChange.namespace + "/" + oChange.fileName + "." + oChange.fileType);
			//however subsequent changes should be applied
		}
	};

	/**
	 * Completes the change by adding change handler specific content
	 *
	 * @param {sap.ui.fl.Change} oChangeWrapper change wrapper object to be completed
	 * @param {object} oSpecificChangeInfo with attributes "groupLabel", the group label to be included in the change and "newControlId", the control ID for the control to be added
	 * @public
	 */
	AddGroup.prototype.completeChangeContent = function(oChangeWrapper, oSpecificChangeInfo) {
		var oChange = oChangeWrapper.getDefinition();
		if (oSpecificChangeInfo.groupLabel) {
			this.setTextInChange(oChange, "groupLabel", oSpecificChangeInfo.groupLabel, "XFLD");
		} else {
			throw new Error("oSpecificChangeInfo.groupLabel attribute required");
		}
		if (!oChange.content) {
			oChange.content = {};
		}
		if (!oChange.content.group) {
			oChange.content.group = {};
		}
		if ( oSpecificChangeInfo.newControlId ){
			oChange.content.group.id = oSpecificChangeInfo.newControlId;
		}else {
			throw new Error("oSpecificChangeInfo.newControlId attribute required");
		}
		if (oSpecificChangeInfo.index === undefined) {
			throw new Error("oSpecificChangeInfo.index attribute required");
		} else {
			oChange.content.group.index = oSpecificChangeInfo.index;
		}
	};

	/**
	 * Gets the id from the group to be added.
	 *
	 * @param {object} oChange - addGroup change, which contains the group id within the content
	 * @returns {string} group id
	 * @public
	 */
	AddGroup.prototype.getControlIdFromChangeContent = function(oChange) {
		var sControlId;
		
		if (oChange && oChange._oDefinition) {
			sControlId = oChange._oDefinition.content.group.id;
		}
		
		return sControlId;
	};

	return AddGroup;
},
/* bExport= */true);
<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
/**
 * @class facetFilter
 * @name  facetFilter
 * @description Creates the facet filter
 * @memberOf sap.apf.ui.reuse.view
 * 
 */
(function() {
	'use strict';
	sap.ui.jsview("sap.apf.ui.reuse.view.facetFilter", {
		getControllerName : function() {
			return "sap.apf.ui.reuse.controller.facetFilter";
		},
		createContent : function(oController) {
			var oFacetFilterList;
			var oCoreApi = this.getViewData().oCoreApi;
			var aConfiguredFilters = this.getViewData().aConfiguredFilters;
			var aFacetFilterListControls = [];
			aConfiguredFilters.forEach(function(oConfiguredFilter) {
				oFacetFilterList = new sap.m.FacetFilterList({
					title : oCoreApi.getTextNotHtmlEncoded(oConfiguredFilter.getLabel()),
					multiSelect : oConfiguredFilter.isMultiSelection(),
					key : oConfiguredFilter.getPropertyName(),
					growing : false,
					listClose : oController.onListClose.bind(oController)
				});
				aFacetFilterListControls.push(oFacetFilterList);
			});
			aFacetFilterListControls.forEach(function(oFacetFilterListControl) {
				oFacetFilterListControl.bindItems("/", new sap.m.FacetFilterItem({
					key : '{key}',
					text : '{text}',
					selected : '{selected}'
				}));
				var oModel = new sap.ui.model.json.JSONModel([]);
				oFacetFilterListControl.setModel(oModel);
			});
			var oFacetFilter = new sap.m.FacetFilter(oController.createId("idAPFFacetFilter"), {
				type : "Simple",
				showReset : true,
				showPopoverOKButton : true,
				lists : aFacetFilterListControls,
				reset : oController.onResetPress.bind(oController)
			});
			if (sap.ui.Device.system.desktop) {
				oFacetFilter.addStyleClass("facetfilter");
			}
			return oFacetFilter;
		}
	});
}());<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2016 SAP SE. All rights reserved
	
 */

sap.ui.define(['jquery.sap.global', './library', 'sap/ui/core/Control'],
	function(jQuery, library, Control) {
	"use strict";

	/**
	 * Constructor for a new AreaMicroChart control.
	 *
	 * @param {string} [sId] id for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] initial settings for the new control
	 *
	 * @class
	 * Chart that displays the history of values and target values as segmented lines and shows thresholds as colored background. This control replaces the deprecated sap.suite.ui.commons.MicroAreaChart.
	 * @extends sap.ui.core.Control
	 *
	 * @author SAP SE
	 * @version 1.36.12
	 *
	 * @public
	 * @alias sap.suite.ui.microchart.AreaMicroChart
	 * @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
	 */
	var AreaMicroChart = Control.extend("sap.suite.ui.microchart.AreaMicroChart", /** @lends sap.suite.ui.microchart.AreaMicroChart.prototype */ {
			metadata: {
				library: "sap.suite.ui.microchart",
				properties: {
					/**
					 * The width of the chart.
					 */
					width: {type: "sap.ui.core.CSSSize", group : "Misc", defaultValue : null},

					/**
					 * The height of the chart.
					 */
					height: {type: "sap.ui.core.CSSSize", group : "Misc", defaultValue : null},

					/**
					 * If this property is set it indicates the value X axis ends with.
					 */
					maxXValue: {type: "float", group : "Misc", defaultValue : null},

					/**
					 * If this property is set it indicates the value X axis ends with.
					 */
					minXValue: {type : "float", group : "Misc", defaultValue : null},

					/**
					 * If this property is set it indicates the value X axis ends with.
					 */
					maxYValue: {type: "float", group : "Misc", defaultValue : null},

					/**
					 * If this property is set it indicates the value X axis ends with.
					 */
					minYValue: {type: "float", group : "Misc", defaultValue : null},

					/**
					 * The view of the chart.
					 */
					view: {type: "sap.suite.ui.microchart.AreaMicroChartViewType", group : "Appearance", defaultValue : "Normal"},

					/**
					 * The color palette for the chart. If this property is set,
					 * semantic colors defined in AreaMicroChartItem are ignored.
					 * Colors from the palette are assigned to each line consequentially.
					 * When all the palette colors are used, assignment of the colors begins
					 * from the first palette color.
					 */
					colorPalette: {type: "string[]", group : "Appearance", defaultValue : [] }
				},
				events : {

					/**
					 * The event is fired when the user chooses the micro area chart.
					 */
					press: {}

				},
				aggregations: {
					/**
					 * The configuration of the actual values line.
					 * The color property defines the color of the line.
					 * Points are rendered in the same sequence as in this aggregation.
					 */
					chart: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartItem" },

					/**
					 * The configuration of the max threshold area. The color property defines the color of the area above the max threshold line. Points are rendered in the same sequence as in this aggregation.
					 */
					maxThreshold: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartItem" },

					/**
					 * The configuration of the upper line of the inner threshold area. The color property defines the color of the area between inner thresholds. For rendering of the inner threshold area, both innerMaxThreshold and innerMinThreshold aggregations must be defined. Points are rendered in the same sequence as in this aggregation.
					 */
					innerMaxThreshold: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartItem" },

					/**
					 * The configuration of the bottom line of the inner threshold area. The color property is ignored. For rendering of the inner threshold area, both innerMaxThreshold and innerMinThreshold aggregations must be defined. Points are rendered in the same sequence as in this aggregation.
					 */
					innerMinThreshold: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartItem" },

					/**
					 * The configuration of the min threshold area. The color property defines the color of the area below the min threshold line. Points are rendered in the same sequence as in this aggregation.
					 */
					minThreshold: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartItem" },

					/**
					 * The configuration of the target values line. The color property defines the color of the line. Points are rendered in the same sequence as in this aggregation.
					 */
					target: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartItem" },

					/**
					 * The label on X axis for the first point of the chart.
					 */
					firstXLabel: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartLabel" },

					/**
					 * The label on Y axis for the first point of the chart.
					 */
					firstYLabel: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartLabel" },

					/**
					 * The label on X axis for the last point of the chart.
					 */
					lastXLabel: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartLabel" },

					/**
					 * The label on Y axis for the last point of the chart.
					 */
					lastYLabel: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartLabel" },

					/**
					 * The label for the maximum point of the chart.
					 */
					maxLabel: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartLabel" },

					/**
					 * The label for the minimum point of the chart.
					 */
					minLabel: { multiple: false, type: "sap.suite.ui.microchart.AreaMicroChartLabel" },

					/**
					 * The set of lines.
					 */
					lines: { multiple: true, type: "sap.suite.ui.microchart.AreaMicroChartItem" }
				}

		}
	});

	AreaMicroChart.prototype.init = function(){
		this._oRb = sap.ui.getCore().getLibraryResourceBundle("sap.suite.ui.microchart");
		this.setTooltip("{AltText}");
	};

	AreaMicroChart.prototype._getCssValues = function() {
		this._cssHelper.className = Array.prototype.slice.call(arguments).join(" ");
		var oCsses = window.getComputedStyle(this._cssHelper);

		if (oCsses.backgroundColor == undefined) {
			oCsses.backgroundColor = oCsses["background-color"];
		}

		if (oCsses.outlineStyle == undefined) {
			oCsses.outlineStyle = oCsses["outline-style"];
		}

		if (oCsses.outlineWidth == undefined) {
			oCsses.outlineWidth = oCsses["outline-width"];
		}
		return oCsses;
	};

	AreaMicroChart.prototype.__fillThresholdArea = function(c, aPoints1, aPoints2, color) {
		c.beginPath();
		c.moveTo(aPoints1[0].x, aPoints1[0].y);

		for (var i = 1, length = aPoints1.length; i < length; i++) {
			c.lineTo(aPoints1[i].x, aPoints1[i].y);
		}

		for (var j = aPoints2.length - 1; j >= 0 ; j--) {
			c.lineTo(aPoints2[j].x, aPoints2[j].y);
		}

		c.closePath();

		c.fillStyle = "white";
		c.fill();

		c.fillStyle = color;
		c.fill();

		c.lineWidth = 1;
		c.strokeStyle = "white";
		c.stroke();

		c.strokeStyle = color;
		c.stroke();
	};

	AreaMicroChart.prototype._renderDashedLine = function(c, aPoints, d, aDashes) {
		if (c.setLineDash) {
			c.setLineDash(aDashes);
			this._renderLine(c, aPoints, d);
			c.setLineDash([]);
		} else {
			c.beginPath();
			for (var i = 0, length = aPoints.length - 1; i < length; i++) {
				c._dashedLine(aPoints[i].x, aPoints[i].y, aPoints[i + 1].x, aPoints[i + 1].y, aDashes);
			}
			c.stroke();
		}
	};

	AreaMicroChart.prototype._renderLine = function(c, aPoints, d) {
		c.beginPath();
		c.moveTo(aPoints[0].x, aPoints[0].y);

		for (var i = 1, length = aPoints.length; i < length; i++) {
			c.lineTo(aPoints[i].x, aPoints[i].y);
		}

		c.stroke();
	};

	AreaMicroChart.prototype._renderTarget = function(c, d) {
		if (d.target.length > 1) {
			var oCsses = this._getCssValues("sapSuiteAmcTarget", this.getTarget().getColor());
			c.strokeStyle = oCsses.color;
			c.lineWidth = parseFloat(oCsses.width);

			if (oCsses.outlineStyle == "dotted") {
				this._renderDashedLine(c, d.target, d, [parseFloat(oCsses.outlineWidth), 3]);
			} else {
				this._renderLine(c, d.target, d);
			}
		} else if (d.target.length == 1) {
			jQuery.sap.log.warning("Target is not rendered because only 1 point was given");
		}
	};

	AreaMicroChart.prototype._renderThresholdLine = function(c, aPoints, d) {
		if (aPoints && aPoints.length) {
			var oCsses = this._getCssValues("sapSuiteAmcThreshold");

			c.strokeStyle = oCsses.color;
			c.lineWidth = oCsses.width;
			this._renderLine(c, aPoints, d);
		}
	};

	AreaMicroChart.prototype._fillMaxThreshold = function(c, d) {
		if (d.maxThreshold.length > 1) {
			var oCsses = this._getCssValues("sapSuiteAmcThreshold", this.getMaxThreshold().getColor());
			this.__fillThresholdArea(c, d.maxThreshold, [
				{x: d.maxThreshold[0].x, y: d.minY},
				{x: d.maxThreshold[d.maxThreshold.length - 1].x, y: d.minY}
			], oCsses.backgroundColor);
			this._renderThresholdLine(c, d.maxThreshold, d);
		} else if (d.maxThreshold.length == 1) {
			jQuery.sap.log.warning("Max Threshold is not rendered because only 1 point was given");
		}
	};

	AreaMicroChart.prototype._fillMinThreshold = function(c, d) {
		if (d.minThreshold.length > 1) {
			var oCsses = this._getCssValues("sapSuiteAmcThreshold", this.getMinThreshold().getColor());
			this.__fillThresholdArea(c, d.minThreshold, [
				{x: d.minThreshold[0].x, y: d.maxY},
				{x: d.minThreshold[d.minThreshold.length - 1].x, y: d.maxY}
			], oCsses.backgroundColor);
		} else if (d.minThreshold.length == 1) {
			jQuery.sap.log.warning("Min Threshold is not rendered because only 1 point was given");
		}
	};

	AreaMicroChart.prototype._fillThresholdArea = function(c, d) {
		if (d.minThreshold.length > 1 && d.maxThreshold.length > 1) {
			var oCsses = this._getCssValues("sapSuiteAmcThreshold", "Critical");

			this.__fillThresholdArea(c, d.maxThreshold, d.minThreshold, oCsses.backgroundColor);
		}
	};

	AreaMicroChart.prototype._fillInnerThresholdArea = function(c, d) {
		if (d.innerMinThreshold.length > 1 && d.innerMaxThreshold.length > 1) {
			var oCsses = this._getCssValues("sapSuiteAmcThreshold", this.getInnerMaxThreshold().getColor());

			this.__fillThresholdArea(c, d.innerMaxThreshold, d.innerMinThreshold, oCsses.backgroundColor);
		} else if (d.innerMinThreshold.length || d.innerMaxThreshold.length) {
			jQuery.sap.log.warning("Inner threshold area is not rendered because inner min and max threshold were not correctly set");
		}
	};

	AreaMicroChart.prototype._renderChart = function(c, d) {
		if (d.chart.length > 1) {
			var oCsses = this._getCssValues("sapSuiteAmcChart", this.getChart().getColor());
			c.strokeStyle = oCsses.color;
			c.lineWidth = parseFloat(oCsses.width);

			this._renderLine(c, d.chart, d);
		} else if (d.chart.length == 1) {
			jQuery.sap.log.warning("Actual values are not rendered because only 1 point was given");
		}
	};

	AreaMicroChart.prototype._renderLines = function(c, d) {
		var iCpLength = this.getColorPalette().length;
		var iCpIndex = 0;
		var that = this;

		var fnNextColor = function() {
			if (iCpLength) {
				if (iCpIndex == iCpLength) {
					iCpIndex = 0;
				}
				return that.getColorPalette()[iCpIndex++];
			}
		};

		var oCsses = this._getCssValues("sapSuiteAmcLine");
		c.lineWidth = parseFloat(oCsses.width);

		var iLength = d.lines.length;
		for (var i = 0; i < iLength; i++) {
			if (d.lines[i].length > 1) {
				if (iCpLength) {
					c.strokeStyle = fnNextColor();
				} else {
					oCsses = this._getCssValues("sapSuiteAmcLine", this.getLines()[i].getColor());
					c.strokeStyle = oCsses.color;
				}
				this._renderLine(c, d.lines[i], d);
			}
		}
	};

	AreaMicroChart.prototype._renderCanvas = function() {
		this._cssHelper = document.getElementById(this.getId() + "-css-helper");

		var sLabelsWidth = this.$().find(".sapSuiteAmcSideLabels").css("width");
		this.$().find(".sapSuiteAmcCanvas, .sapSuiteAmcLabels").css("right", sLabelsWidth).css("left", sLabelsWidth);

		var canvas = document.getElementById(this.getId() + "-canvas");
		var canvasSettings = window.getComputedStyle(canvas);

		var fWidth = parseFloat(canvasSettings.width);
		canvas.setAttribute("width", fWidth ? fWidth : 360);

		var fHeight = parseFloat(canvasSettings.height);
		canvas.setAttribute("height", fHeight ? fHeight : 242);

		var c = canvas.getContext("2d");

		c.lineJoin = "round";

		c._dashedLine = function(x, y, x2, y2, dashArray) {
			var dashCount = dashArray.length;
			this.moveTo(x, y);
			var dx = (x2 - x), dy = (y2 - y);
			var slope = dx ? dy / dx : 1e15;
			var distRemaining = Math.sqrt(dx * dx + dy * dy);
			var dashIndex = 0, draw = true;
			while (distRemaining >= 0.1) {
				var dashLength = dashArray[dashIndex++ % dashCount];
				if (dashLength > distRemaining) {
					dashLength = distRemaining;
				}
				var xStep = Math.sqrt(dashLength * dashLength / (1 + slope * slope));
				if (dx < 0) {
					xStep = -xStep;
				}
				x += xStep;
				y += slope * xStep;
				this[draw ? 'lineTo' : 'moveTo'](x, y);
				distRemaining -= dashLength;
				draw = !draw;
			}
		};
		var d = this._calculateDimensions(canvas.width, canvas.height);

		this._fillMaxThreshold(c, d);
		this._fillMinThreshold(c, d);
		this._fillThresholdArea(c, d);
		this._renderThresholdLine(c, d.minThreshold, d);
		this._renderThresholdLine(c, d.maxThreshold, d);
		this._fillInnerThresholdArea(c, d);
		this._renderThresholdLine(c, d.innerMinThreshold, d);
		this._renderThresholdLine(c, d.innerMaxThreshold, d);
		this._renderTarget(c, d);
		this._renderChart(c, d);
		this._renderLines(c, d);
	};

	/**
	 *
	 *
	 * @param fWidth
	 * @param fHeight
	 * @returns {object}
	 */
	AreaMicroChart.prototype._calculateDimensions = function(fWidth, fHeight) {
		var maxX, maxY, minX, minY;
		maxX = maxY = minX = minY = undefined;
		var that = this;

		function calculateExtremums() {
			if (!that._isMinXValue || !that._isMaxXValue || !that._isMinYValue || !that._isMaxYValue) {
				var lines = that.getLines();
				if (that.getMaxThreshold()) {
					lines.push(that.getMaxThreshold());
				}

				if (that.getMinThreshold()) {
					lines.push(that.getMinThreshold());
				}

				if (that.getChart()) {
					lines.push(that.getChart());
				}

				if (that.getTarget()) {
					lines.push(that.getTarget());
				}

				if (that.getInnerMaxThreshold()) {
					lines.push(that.getInnerMaxThreshold());
				}

				if (that.getInnerMinThreshold()) {
					lines.push(that.getInnerMinThreshold());
				}

				for (var i = 0, numOfLines = lines.length; i < numOfLines; i++) {
					var aPoints = lines[i].getPoints();

					for (var counter = 0, a = aPoints.length; counter < a; counter++) {
						var tmpVal = aPoints[counter].getXValue();
						if (tmpVal > maxX || maxX === undefined) {
							maxX = tmpVal;
						}
						if (tmpVal < minX || minX === undefined) {
							minX = tmpVal;
						}

						tmpVal = aPoints[counter].getYValue();
						if (tmpVal > maxY || maxY === undefined) {
							maxY = tmpVal;
						}
						if (tmpVal < minY || minY === undefined) {
							minY = tmpVal;
						}
					}
				}
			}
			if (that._isMinXValue) {
				minX = that.getMinXValue();
			}

			if (that._isMaxXValue) {
				maxX = that.getMaxXValue();
			}

			if (that._isMinYValue) {
				minY = that.getMinYValue();
			}

			if (that._isMaxYValue) {
				maxY = that.getMaxYValue();
			}
		}

		calculateExtremums();

		var oResult = {
			minY: 0,
			minX: 0,
			maxY: fHeight,
			maxX: fWidth,
			lines: []
		};

		var kx;
		var fDeltaX = maxX - minX;

		if (fDeltaX > 0) {
			kx = fWidth / fDeltaX;
		} else if (fDeltaX == 0) {
			kx = 0;
			oResult.maxX /= 2;
		} else {
			jQuery.sap.log.warning("Min X is more than max X");
		}

		var ky;
		var fDeltaY = maxY - minY;

		if (fDeltaY > 0) {
			ky = fHeight / (maxY - minY);
		} else if (fDeltaY == 0) {
			ky = 0;
			oResult.maxY /= 2;
		} else {
			jQuery.sap.log.warning("Min Y is more than max Y");
		}

		function calculateCoordinates(line) {
			var bRtl = sap.ui.getCore().getConfiguration().getRTL();

			var fnCalcX = function(fValue) {
				var x = kx * (fValue - minX);

				if (bRtl) {
					x = oResult.maxX - x;
				}
				return x;
			};

			var fnCalcY = function(fValue) {
				return oResult.maxY - ky * (fValue - minY);
			};

			var aResult = [];
			if (line && kx != undefined && ky != undefined) {
				var aPoints = line.getPoints();
				var iLength = aPoints.length;
				var xi, yi, tmpXValue, tmpYValue;

				if (iLength == 1) {
					tmpXValue = aPoints[0].getXValue();
					tmpYValue = aPoints[0].getYValue();

					if (tmpXValue == undefined ^ tmpYValue == undefined) {
						var xn, yn;
						if (tmpXValue == undefined) {
							yn = yi = fnCalcY(tmpYValue);
							xi = oResult.minX;
							xn = oResult.maxX;
						} else {
							xn = xi = fnCalcX(tmpXValue);
							yi = oResult.minY;
							yn = oResult.maxY;
						}

						aResult.push({x: xi, y: yi}, {x: xn, y: yn});
					} else {
						jQuery.sap.log.warning("Point with coordinates [" + tmpXValue + " " + tmpYValue + "] ignored");
					}
				} else {
					for (var i = 0; i < iLength; i++) {
						tmpXValue = aPoints[i].getXValue();
						tmpYValue = aPoints[i].getYValue();

						if (tmpXValue != undefined && tmpYValue != undefined) {
							xi = fnCalcX(tmpXValue);
							yi = fnCalcY(tmpYValue);

							aResult.push({x: xi, y: yi});
						} else {
							jQuery.sap.log.warning("Point with coordinates [" + tmpXValue + " " + tmpYValue + "] ignored");
						}
					}
				}
			}
			return aResult;
		}

		oResult.maxThreshold = calculateCoordinates(that.getMaxThreshold());
		oResult.minThreshold = calculateCoordinates(that.getMinThreshold());
		oResult.chart = calculateCoordinates(that.getChart());
		oResult.target = calculateCoordinates(that.getTarget());
		oResult.innerMaxThreshold = calculateCoordinates(that.getInnerMaxThreshold());
		oResult.innerMinThreshold = calculateCoordinates(that.getInnerMinThreshold());

		var iLength = that.getLines().length;
		for (var i = 0; i < iLength; i++) {
			oResult.lines.push(calculateCoordinates(that.getLines()[i]));
		}
		return oResult;
	};

	/**
	 * Property setter for the Min X value
	 *
	 * @param {int} value - new value Min X
	 * @param {boolean} bSuppressInvalidate - Suppress in validate
	 * @returns {void}
	 * @public
	 */
	AreaMicroChart.prototype.setMinXValue = function(value, bSuppressInvalidate) {
		this._isMinXValue = this._isNumber(value);

		return this.setProperty("minXValue", this._isMinXValue ? value : NaN, bSuppressInvalidate);
	};

	/**
	 * Property setter for the Max X value
	 *
	 * @param {int} value - new value Max X
	 * @param {boolean} bSuppressInvalidate - Suppress in validate
	 * @returns {void}
	 * @public
	 */
	AreaMicroChart.prototype.setMaxXValue = function(value, bSuppressInvalidate) {
		this._isMaxXValue = this._isNumber(value);

		return this.setProperty("maxXValue", this._isMaxXValue ? value : NaN, bSuppressInvalidate);
	};

	/**
	 * Property setter for the Min Y value
	 *
	 * @param {value} value - new value Min Y
	 * @param {boolean} bSuppressInvalidate - Suppress in validate
	 * @returns {void}
	 * @public
	 */
	AreaMicroChart.prototype.setMinYValue = function(value, bSuppressInvalidate) {
		this._isMinYValue = this._isNumber(value);

		return this.setProperty("minYValue", this._isMinYValue ? value : NaN, bSuppressInvalidate);
	};

	/**
	 * Property setter for the Max Y valye
	 *
	 * @param {string} value - new value Max Y
	 * @param {boolean} bSuppressInvalidate - Suppress in validate
	 * @returns {void}
	 * @public
	 */
	AreaMicroChart.prototype.setMaxYValue = function(value, bSuppressInvalidate) {
		this._isMaxYValue = this._isNumber(value);

		return this.setProperty("maxYValue", this._isMaxYValue ? value : NaN, bSuppressInvalidate);
	};

	AreaMicroChart.prototype._isNumber = function(n) {
		return typeof n === 'number' && !isNaN(n) && isFinite(n);
	};

	AreaMicroChart.prototype.onAfterRendering = function() {
		this._renderCanvas();
	};

	AreaMicroChart.prototype.ontap = function(oEvent) {
		if (sap.ui.Device.browser.internet_explorer) {
			this.$().focus();
		}
		this.firePress();
	};

	AreaMicroChart.prototype.onkeydown = function(oEvent) {
		if (oEvent.which == jQuery.sap.KeyCodes.SPACE) {
			oEvent.preventDefault();
		}
	};

	AreaMicroChart.prototype.onkeyup = function(oEvent) {
		if (oEvent.which == jQuery.sap.KeyCodes.ENTER || oEvent.which == jQuery.sap.KeyCodes.SPACE) {
			this.firePress();
			oEvent.preventDefault();
		}
	};

	AreaMicroChart.prototype.attachEvent = function(sEventId, oData, fnFunction, oListener) {
		sap.ui.core.Control.prototype.attachEvent.call(this, sEventId, oData, fnFunction, oListener);

		if (this.hasListeners("press")) {
			this.$().attr("tabindex", 0).addClass("sapSuiteUiMicroChartPointer");
		}

		return this;
	};

	AreaMicroChart.prototype.detachEvent = function(sEventId, fnFunction, oListener) {
		sap.ui.core.Control.prototype.detachEvent.call(this, sEventId, fnFunction, oListener);

		if (!this.hasListeners("press")) {
			this.$().removeAttr("tabindex").removeClass("sapSuiteUiMicroChartPointer");
		}
		return this;
	};

	AreaMicroChart.prototype._getLocalizedColorMeaning = function(sColor) {
		return this._oRb.getText(("SEMANTIC_COLOR_" + sColor).toUpperCase());
	};

	AreaMicroChart.prototype.getAltText = function() {
		var sAltText = "";
		var oFirstXLabel = this.getFirstXLabel();
		var oFirstYLabel = this.getFirstYLabel();
		var oLastXLabel = this.getLastXLabel();
		var oLastYLabel = this.getLastYLabel();
		var oMinLabel = this.getMinLabel();
		var oMaxLabel = this.getMaxLabel();
		var oActual = this.getChart();
		var oTarget = this.getTarget();
		var bIsFirst = true;
		if (oFirstXLabel && oFirstXLabel.getLabel() || oFirstYLabel && oFirstYLabel.getLabel()) {
			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("AREAMICROCHART_START")) + ": " + (oFirstXLabel ? oFirstXLabel.getLabel() : "") + " " + (oFirstYLabel ? oFirstYLabel.getLabel()  + " " + this._getLocalizedColorMeaning(oFirstYLabel.getColor()) : "");
			bIsFirst = false;
		}
		if (oLastXLabel && oLastXLabel.getLabel() || oLastYLabel && oLastYLabel.getLabel()) {
			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("AREAMICROCHART_END")) + ": " + (oLastXLabel ? oLastXLabel.getLabel() : "") + " " + (oLastYLabel ? oLastYLabel.getLabel()  + " " + this._getLocalizedColorMeaning(oLastYLabel.getColor()) : "");
			bIsFirst = false;
		}
		if (oMinLabel && oMinLabel.getLabel()) {
			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("AREAMICROCHART_MINIMAL_VALUE")) + ": " + oMinLabel.getLabel() + " " + this._getLocalizedColorMeaning(oMinLabel.getColor());
			bIsFirst = false;
		}
		if (oMaxLabel && oMaxLabel.getLabel()) {
			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("AREAMICROCHART_MAXIMAL_VALUE")) + ": " + oMaxLabel.getLabel() + " " + this._getLocalizedColorMeaning(oMaxLabel.getColor());
			bIsFirst = false;
		}
		if (oActual && oActual.getPoints() && oActual.getPoints().length > 0) {
			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("AREAMICROCHART_ACTUAL_VALUES")) + ":";
			bIsFirst = false;
			var aActual = oActual.getPoints();
			for (var i = 0; i < aActual.length; i++) {
				sAltText += " " + aActual[i].getY();
			}
		}
		if (oTarget && oTarget.getPoints() && oTarget.getPoints().length > 0) {
			sAltText += (bIsFirst ? "" : "\n") + this._oRb.getText(("AREAMICROCHART_TARGET_VALUES")) + ":";
			var aTarget = oTarget.getPoints();
			for (var j = 0; j < aTarget.length; j++) {
				sAltText += " " + aTarget[j].getY();
			}
		}

		for (var k = 0; k < this.getLines().length; k++) {
			var oLine = this.getLines()[k];
			if (oLine.getPoints() && oLine.getPoints().length > 0) {
				sAltText += (bIsFirst ? "" : "\n") + oLine.getTitle() + ":";
				var aLine = oLine.getPoints();
				for (var y = 0; y < aLine.length; y++) {
					sAltText += " " + aLine[y].getY();
				}

				if (this.getColorPalette().length == 0) {
					sAltText += " " + this._getLocalizedColorMeaning(oLine.getColor());
				}
			}
		}
		return sAltText;
	};



	AreaMicroChart.prototype.getTooltip_AsString = function() {
		var oTooltip = this.getTooltip();
		var sTooltip = this.getAltText();

		if (typeof oTooltip === "string" || oTooltip instanceof String) {
			sTooltip = oTooltip.split("{AltText}").join(sTooltip).split("((AltText))").join(sTooltip);
			return sTooltip;
		}
		return oTooltip ? oTooltip : "";
	};

	AreaMicroChart.prototype.clone = function(sIdSuffix, aLocalIds, oOptions) {
		var oClone = sap.ui.core.Control.prototype.clone.apply(this, arguments);
		oClone._isMinXValue = this._isMinXValue;
		oClone._isMaxXValue = this._isMaxXValue;
		oClone._isMinYValue = this._isMinYValue;
		oClone._isMaxYValue = this._isMaxYValue;
		return oClone;
	};
	return AreaMicroChart;

});<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

(c) Copyright 2009-2016 SAP SE. All rights reserved
 */

sap.ui.define([
		'jquery.sap.global',
		'sap/ui/fl/registry/ChangeRegistry',
		'sap/ui/fl/registry/SimpleChanges',
		'sap/ui/comp/smartform/flexibility/changes/RemoveField',
		'sap/ui/comp/smartform/flexibility/changes/RemoveGroup',
		'sap/ui/comp/smartform/flexibility/changes/RenameField',
		'sap/ui/comp/smartform/flexibility/changes/RenameGroup',
		'sap/ui/comp/smartform/flexibility/changes/AddField',
		'sap/ui/comp/smartform/flexibility/changes/AddFields',
		'sap/ui/comp/smartform/flexibility/changes/AddGroup',
		'sap/ui/comp/smartform/flexibility/changes/MoveGroups',
		'sap/ui/comp/smartform/flexibility/changes/MoveFields',
		'sap/ui/comp/smartform/flexibility/changes/OrderGroups',
		'sap/ui/comp/smartform/flexibility/changes/OrderFields'
	], function(jQuery, ChangeRegistry, SimpleChanges, RemoveField, RemoveGroup, RenameField, RenameGroup, AddField, AddFields, AddGroup, MoveGroups, MoveFields, OrderGroups, OrderFields) {
		"use strict";

		/**
		 * Change handler for adding a smart form group element (representing a field).
		 * @name sap.ui.comp.smartform.flexibility.Registration
		 * @namespace
		 * @author SAP SE
		 * @version 1.36.12
		 * @experimental Since 1.29.0
		 */
		return {
			registerLibrary: function(){
				var compChanges = {
					orderFields: {
						changeType: "orderFields",
						changeHandler: OrderFields
					},
					orderGroups: {
						changeType: "orderGroups",
						changeHandler: OrderGroups
					},
					removeField: {
						changeType: "removeField",
						changeHandler: RemoveField
					},
					removeGroup: {
						changeType: "removeGroup",
						changeHandler: RemoveGroup
					},
					renameField: {
						changeType: "renameField",
						changeHandler: RenameField
					},
					renameGroup: {
						changeType: "renameGroup",
						changeHandler: RenameGroup
					},
					addField: {
						changeType: "addField",
						changeHandler: AddField
					},
					addFields: {
						changeType: "addFields",
						changeHandler: AddFields
					},
					addGroup: {
						changeType: "addGroup",
						changeHandler: AddGroup
					},
					moveGroups: {
						changeType: "moveGroups",
						changeHandler: MoveGroups
					},
					moveFields: {
						changeType: "moveFields",
						changeHandler: MoveFields
					}
				};

				var oChangeRegistry = ChangeRegistry.getInstance();

				oChangeRegistry.registerControlsForChanges({
					"sap.ui.comp.smartform.SmartForm": [
						compChanges.removeGroup,
						compChanges.addGroup,
						compChanges.moveGroups,
						compChanges.renameField,
						SimpleChanges.propertyChange
					],
					"sap.ui.comp.smartform.Group": [
						SimpleChanges.hideControl,
						SimpleChanges.unhideControl,
						compChanges.renameGroup,
						compChanges.addField,
						compChanges.addFields,
						compChanges.moveFields
					],
					"sap.ui.comp.smartform.GroupElement": [
						SimpleChanges.unhideControl,
						SimpleChanges.hideControl,
						compChanges.renameField
					],
					"sap.ui.comp.smarttable.SmartTable": [
						SimpleChanges.propertyChange
					],
					"sap.ui.comp.smartfilterbar.SmartFilterBar": [
						SimpleChanges.propertyChange
					]
				});

			}
		};
	},
	/* bExport= */true);

<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2015 SAP SE. All rights reserved
	
 */
sap.ui.define([
	"./LegendBase"
], function (LegendBase) {
	"use strict";
	
	var DimensionLegend = LegendBase.extend({
		metadata: {
			properties: {
				shape: {type: "sap.gantt.config.Shape"},
				xDimension: {type: "string"},
				yDimension: {type: "string"},
				xDomain: {type: "array"},
				yDomain: {type: "array"}
			}
		}
	});
	
	return DimensionLegend;
}, true);<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2015 SAP SE. All rights reserved
	
 */
sap.ui.define([
	"./LegendBase", "sap/gantt/drawer/ListLegend", "sap/gantt/drawer/CalendarPattern"
], function (LegendBase, ListLegendDrawer, CalendarPattern) {
	"use strict";
	
	var ListLegend = LegendBase.extend("sap.gantt.legend.ListLegend", {
		metadata: {
			properties: {
				shapes: {type: "array"}
			}
		}
	});
	
	ListLegend.prototype.init = function () {
		LegendBase.prototype.init.apply(this, arguments);
		this._oListLegendDrawer = new ListLegendDrawer();
	};
	
	ListLegend.prototype.onAfterRendering = function () {
		for (var i = 0; i < this._aShapeInstance.length; i++) {
			var oShape = this._aShapeInstance[i];
			
			var aSvg = d3.select("#" + this.getId() + "-svg-" + i);

			this._oListLegendDrawer._drawPerTag(aSvg, oShape);
		}
	};
	
	ListLegend.prototype.setShapes = function (aShapes) {
		if (aShapes && aShapes.length > 0) {
			this._aShapeInstance = this._instantShape(aShapes);
			this.setProperty("shapes", aShapes);
		}
		return this;
	};

	ListLegend.prototype._instantShape = function (aShapes) {
		var aRetVal = [];
		// parse shape instances
		for (var i = 0; i < aShapes.length; i++) {
			if (aShapes[i].getShapeClassName()) {
				// create shape instance
				var oShapeInst = this._instantiateCustomerClass(aShapes[i].getShapeClassName(), i, aShapes[i]);
				
				if (aShapes[i].getClippathAggregation() && aShapes[i].getClippathAggregation() instanceof Array) {
					// create aggregation classes for clip-path
					var aPath = this._instantShape(aShapes[i].getClippathAggregation());
					aRetVal = aRetVal.concat(aPath);
				} else if (aShapes[i].getGroupAggregation() && aShapes[i].getGroupAggregation() instanceof Array) {
					// create aggregation classes for group
					var aAggregation = this._instantShape(aShapes[i].getGroupAggregation());
					for (var k = 0; k < aAggregation.length; k++) {
						oShapeInst.addShape(aAggregation[k]);
					}
				}
				
				if (this._isProperShape(oShapeInst)) {
					aRetVal.push(oShapeInst);
				}
			}
		}

		return aRetVal;
	};
	
	ListLegend.prototype._isProperShape = function (oShapeInst) {
		if (oShapeInst instanceof sap.gantt.shape.cal.Calendar) {
			jQuery.sap.log.warning("Calendar is not proper shape", "key '" + oShapeInst.mShapeConfig.getKey() + "'", "ListLegend");
			return false;
		} else if (oShapeInst.getTag() == "clippath") {
			return false;
		} else {
			return true;
		}
	};

	ListLegend.prototype._instantiateCustomerClass = function (sCustomerClassName, sShapeId, oShapeConfig) {
		var CustomerClass = jQuery.sap.getObject(sCustomerClassName);
		if (!CustomerClass) {
			jQuery.sap.require(sCustomerClassName);
			CustomerClass = jQuery.sap.getObject(sCustomerClassName);
		}
		
		var oCustomerClassInstance = new CustomerClass();

		oCustomerClassInstance.mShapeConfig = oShapeConfig;
		oCustomerClassInstance.mChartInstance = this;

		return oCustomerClassInstance;
	};
	
	return ListLegend;
}, true);<file_sep>/*!
 * SAP UI development toolkit for HTML5 (SAPUI5)

		(c) Copyright 2009-2015 SAP SE. All rights reserved
	
 */
sap.ui.define([
	'jquery.sap.global',
	"sap/gantt/GanttChartBase", "sap/ui/core/Core", "sap/ui/table/TreeTable", "sap/ui/table/Row",
	"sap/gantt/misc/Utility",
	'sap/ui/core/theming/Parameters',
	"sap/gantt/shape/SelectedShape", "sap/gantt/shape/ext/rls/SelectedRelationship",
	"sap/gantt/drawer/ShapeInRow", "sap/gantt/drawer/ShapeCrossRow", "sap/gantt/drawer/CursorLine", "sap/gantt/drawer/NowLine", "sap/gantt/drawer/VerticalLine","sap/gantt/drawer/CalendarPattern",
	"sap/gantt/misc/AxisTime", "sap/gantt/misc/AxisOrdinal", "sap/gantt/misc/Format", "sap/gantt/misc/TreeTableHelper",
	// 3rd party lib
	"sap/ui/thirdparty/d3"
], function (jQuery, GanttChartBase, Core, TreeTable, Row, Utility, Parameters, SelectedShape, SelectedRelationship,
		ShapeInRowDrawer, ShapeCrossRowDrawer, CursorLineDrawer, NowLineDrawer, VerticalLineDrawer, CalendarPattern, AxisTime, AxisOrdinal, Format, TreeTableHelper) {
	"use strict";
	
	/**
	 * Creates and initializes a new Gantt Chart.
	 * 
	 * @param {string} [sId] ID for the new control, generated automatically if no id is given
	 * @param {object} [mSettings] Initial settings for the new control
	 * 
	 * @class 
	 * Gantt Chart control.
	 * 
	 * <p>The Gantt chart has a horizontal axis at the top that represents time and a vertical axis that represents rows.
	 * </p>
	 * 
	 * @extends sap.gantt.GanttChartBase
	 * 
	 * @author SAP SE
	 * @version 1.36.8
	 * 
	 * @constructor
	 * @public
	 * @alias sap.gantt.GanttChart
	 */
	var GanttChart = GanttChartBase.extend("sap.gantt.GanttChart", /** @lends sap.gantt.GanttChart.prototype */ {
		metadata: {
			aggregations: {
				_treeTable: {type: "sap.ui.table.TreeTable", multiple: false, visibility: "hidden"} // to ensure model pass down
			}
		}
	});

	GanttChart.prototype.init = function () {
		jQuery.sap.measure.start("GanttChart init","GanttPerf:GanttChart init function");
		// create tree table
		this._oTT = new TreeTable({
			visibleRowCountMode: "Auto",
			minAutoRowCount: 1,
			selectionBehavior: sap.ui.table.SelectionBehavior.RowOnly,
			selectionMode: sap.ui.table.SelectionMode.Multi,
			columnHeaderVisible: false
		});
		this._oTT.addColumn(new sap.ui.table.Column());
		this.setAggregation("_treeTable", this._oTT);
		// de/attach horizontal scroll bar
		this._oTT._oHSb.detachScroll(this._oTT.onhscroll, this._oTT);
		this._oTT._oHSb.attachScroll(this._onHSbScroll, this);
		// de/attach vertical scroll bar
		this._oTT._oVSb.detachScroll(this._oTT.onvscroll, this._oTT);
		this._oTT._oVSb.attachScroll(this._onVSbScroll, this);
		// sync svg with oTT
		this._oTT.attachEvent("_rowsUpdated", this._onTTRowUpdate.bind(this));
		this._oTT.addEventDelegate({
			onAfterRendering: this._onTTRowUpdate
		}, this);
		
		this._oTT.attachEvent("_rowSelectionChange", this._onRowSelectionChange.bind(this));
		this._oTT.attachRowSelectionChange(this._onRowSelectionChange, this);
		this._oTT.addEventDelegate({
			onAfterRendering: this._updateCSSForDummyRow
		}, this);
		
		// create drawers
		this._oShapeInRowDrawer = new ShapeInRowDrawer();
		this._oShapeCrossRowDrawer = new ShapeCrossRowDrawer();
		this._oCursorLineDrawer = new CursorLineDrawer();
		this._oCalendarPatternDrawer = new CalendarPattern();
		
		// internal private members
		this._oAxisTime = undefined;
		this._oAxisOrdinal = undefined;
		this._aShapeData = undefined; // data to be drawn on svg using registed shape instances
		this._aShapeInstance = undefined;	// array of shape instances
		this._oShapeInstance = undefined;	// map of top shape instances
		this._oZoom = { // zoom info
			base: {}
		};
		this._oDataNamePerType = {};
		this._fLeftOffsetRate = 0.0;
		this._oStatusSet = null;
		this._nLowerRange = 0;
		this._nUpperRange = 0;
		
		this._aSelectedRelationships = undefined;
		this._oSelectedShapes = {};
		this._aSelectedShapeUids = [];
		
		//add for mouse events to support drag shape over views
		this._iMouseDown = 0;
		this._bMouseDown = false;
		this._bDragging = false;
		this._oDraggingData = undefined;
		
		this._lastHoverRowIndex = undefined;
		
		// defualt maps
		this._oChartSchemesConfigMap = {};
		this._oChartSchemesConfigMap[sap.gantt.config.DEFAULT_CHART_SCHEME_KEY] = sap.gantt.config.DEFAULT_CHART_SCHEME;
		this._oObjectTypesConfigMap = {};
		this._oObjectTypesConfigMap[sap.gantt.config.DEFAULT_OBJECT_TYPE_KEY] = sap.gantt.config.DEFAULT_OBJECT_TYPE;
		
		this._fExtendFactor = 0.382;
		
		// create default this._oAxisTime
		this._calZoomFromTimeAxisConfig(sap.gantt.config.DEFAULT_TIME_AXIS);
		this._createAxisTime(sap.gantt.config.DEFAULT_TIME_AXIS);
		
		// performance tuning
		this._mDrawDelayMS = 500;
		this._mTimeouts = {};

		jQuery.sap.measure.end("GanttChart init");
	};
	
	GanttChart.prototype.setTimeAxis = function (oTimeAxis) {
		this.setProperty("timeAxis", oTimeAxis, true); // no need to trigger rerender
		this._calZoomFromTimeAxisConfig(oTimeAxis);
		this._createAxisTime(oTimeAxis);
		this._oStatusSet = null;
		
		this._draw(true); // only _draw is triggered
		
		return this;
	};
	
	GanttChart.prototype.setLocale = function (oLocale) {
		this.setProperty("locale", oLocale, true); // no need to trigger rerender
		this._oAxisTime.setLocale(oLocale);
		
		this._drawShapes();
		this._drawSelectedShapes();
		
		return this;
	};
	
	GanttChart.prototype.setChartSchemes = function (aChartSchemes) {
		this.setProperty("chartSchemes", aChartSchemes, true); // no need to trigger rerender
		// build a map for easy look up
		this._oChartSchemesConfigMap = {};
		if (aChartSchemes) {
			for (var i = 0; i < aChartSchemes.length; i++) {
				this._oChartSchemesConfigMap[aChartSchemes[i].getKey()] = aChartSchemes[i];
			}
		}
		
		this._drawShapes();
		this._drawSelectedShapes();
		
		return this;
	};
	
	GanttChart.prototype.setObjectTypes = function (aObjectTypes) {
		this.setProperty("objectTypes", aObjectTypes, true); // no need to trigger rerender
		// build a map for easy look up
		this._oObjectTypesConfigMap = {};
		if (aObjectTypes) {
			for (var i = 0; i < aObjectTypes.length; i++){
				this._oObjectTypesConfigMap[aObjectTypes[i].getKey()] = aObjectTypes[i];
			}
		}
		
		this._drawShapes();
		this._drawSelectedShapes();
		
		return this;
	};
	
	GanttChart.prototype.setSelectionMode = function (sSelectionMode) {
		this.setProperty("selectionMode", sSelectionMode);
		if (this._oTT) {
			if (sSelectionMode == sap.gantt.SelectionMode.MultiWithKeyboard) {
				this._oTT.setSelectionMode(sap.ui.table.SelectionMode.Multi);
			}else if (sSelectionMode == sap.gantt.SelectionMode.Multiple){
				this._oTT.setSelectionMode(sap.ui.table.SelectionMode.MultiToggle);
			}else if (sSelectionMode == sap.gantt.SelectionMode.Single) {
				this._oTT.setSelectionMode(sap.ui.table.SelectionMode.Single);
			}else {
				this._oTT.setSelectionMode(sap.ui.table.SelectionMode.None);
			}
		}
		return this;
	};

	GanttChart.prototype._calZoomFromTimeAxisConfig = function (oTimeAxis) {
		if (!oTimeAxis) {
			return;
		}
		// init an object on this._oZoom
		this._oZoom.base.sGranularity = oTimeAxis.getGranularity();
		var oGranularity = oTimeAxis.getZoomStrategy()[this._oZoom.base.sGranularity];
		this._oZoom.determinedByConfig = {
			fRate: 1
		};
		// get granularity objects
		var oFinestGranularity = oTimeAxis.getZoomStrategy()[oTimeAxis.getFinestGranularity()];
		var oCoarsestGranularity = oTimeAxis.getZoomStrategy()[oTimeAxis.getCoarsestGranularity()];
		var oStart = d3.time.format("%Y%m%d%H%M%S").parse("20000101000000");
		// calculate base rate scale
		var oBaseDate = jQuery.sap.getObject(oGranularity.innerInterval.unit)
			.offset(oStart, oGranularity.innerInterval.span);
		this._oZoom.base.fScale = this._calZoomScale(oStart, oBaseDate, oGranularity.innerInterval.range);
		// calculate max rate scale
		var oMaxDate = jQuery.sap.getObject(oFinestGranularity.innerInterval.unit)
			.offset(oStart, oFinestGranularity.innerInterval.span);
		var fMaxScale = this._calZoomScale(oStart, oMaxDate, oFinestGranularity.innerInterval.range * 4);
		// calculate min rate scale
		var oMinDate = jQuery.sap.getObject(oCoarsestGranularity.innerInterval.unit)
			.offset(oStart, oCoarsestGranularity.innerInterval.span);
		var fMinScale = this._calZoomScale(oStart, oMinDate, oCoarsestGranularity.innerInterval.range);
		// calculate zoom rates
		this._oZoom.determinedByConfig.fMaxRate = this._oZoom.base.fScale / fMaxScale;
		this._oZoom.determinedByConfig.fMinRate = this._oZoom.base.fScale / fMinScale;
	};

	GanttChart.prototype._calZoomScale = function (oStartDate, oEndDate, iLength) {
		return (oEndDate.valueOf() - oStartDate.valueOf()) / iLength;
	};

	GanttChart.prototype._createAxisTime = function (oConfigTimeAxis) {
		var aStrategy = oConfigTimeAxis.getZoomStrategy();
		var oHorizonStartTime = d3.time.format("%Y%m%d%H%M%S").parse(
			oConfigTimeAxis.getPlanHorizon().getStartTime());
		var oHorizonEndTime = d3.time.format("%Y%m%d%H%M%S").parse(
			oConfigTimeAxis.getPlanHorizon().getEndTime());
		var nHorizonTimeRange = oHorizonEndTime.valueOf() - oHorizonStartTime.valueOf();

		var oGranularity = aStrategy[oConfigTimeAxis.getGranularity()];
		var nUnitTimeRange = jQuery.sap.getObject(oGranularity.innerInterval.unit)
				.offset(oHorizonStartTime, oGranularity.innerInterval.span).valueOf() - oHorizonStartTime.valueOf();

		this._oAxisTime = new AxisTime(
			[oHorizonStartTime, oHorizonEndTime],
			[0, Math.ceil(nHorizonTimeRange * oGranularity.innerInterval.range / nUnitTimeRange)],
			oConfigTimeAxis.getRate(), null, null,
			this.getLocale(), Core.getConfiguration().getRTL(), oConfigTimeAxis.getZoomStrategy());
		this._nLowerRange = this._oAxisTime.getViewRange()[0];
		this._nUpperRange = Math.ceil(this._oAxisTime.getViewRange()[1]);
	};

	GanttChart.prototype.setShapes = function (aShapes) {
		this.setProperty("shapes", aShapes, true); // no need to trigger rerender
		if (aShapes && aShapes.length > 0) {
			this._oShapesConfigMap = {};
			for (var i = 0; i < aShapes.length; i++) {
				this._oShapesConfigMap[aShapes[i].getKey()] = aShapes[i];
			}
			this._parseAndSortShape(this._oShapesConfigMap);
			
			this._drawShapes();
			this._drawSelectedShapes();
		}
		return this;
	};

	GanttChart.prototype._parseAndSortShape = function (oShapeConfig, sTopShapeId) {
		var aRetVal = [];
		// parse shape instances
		var sShapeId, oShapeInst, oSelectedShapeInst, aAggregation, aPath, sSelectedShapeClassName;
		for (var i in oShapeConfig) {
			sShapeId = sTopShapeId ? sTopShapeId : i;
			oShapeInst = {};
			if (oShapeConfig[i].getShapeClassName()) {
				// create shape instance
					oShapeInst = this._instantiateCustomerClass(oShapeConfig[i].getShapeClassName(), i, oShapeConfig[i], sShapeId);
				var category = oShapeInst.getCategory(null, this._oAxisTime, this._oAxisOrdinal);
				// create selected shape instance for top shape only
				if (!sTopShapeId){
					sSelectedShapeClassName = oShapeConfig[i].getSelectedClassName();
					if (!sSelectedShapeClassName) {
						if (category == sap.gantt.shape.ShapeCategory.Relationship) {
							sSelectedShapeClassName = "sap.gantt.shape.ext.rls.SelectedRelationship";
							oSelectedShapeInst = new SelectedRelationship();
						}else {
							sSelectedShapeClassName = "sap.gantt.shape.SelectedShape";
						}
					}
					oSelectedShapeInst = this._instantiateCustomerClass(
							sSelectedShapeClassName, "selected" + i, oShapeConfig[i], sShapeId);
					oShapeInst.setAggregation("selectedShape", oSelectedShapeInst);
				}
				// create aggregations
				if (oShapeConfig[i].getGroupAggregation() && oShapeConfig[i].getGroupAggregation() instanceof Array) {
					// create aggregation classes for group
					aAggregation = this._parseAndSortShape(oShapeConfig[i].getGroupAggregation(), sShapeId);
					for (var k = 0; k < aAggregation.length; k++) {
						oShapeInst.addShape(aAggregation[k]);
					}
				} else if (oShapeConfig[i].getClippathAggregation() && oShapeConfig[i].getClippathAggregation() instanceof Array) {
					// create aggregation classes for clip-path
					aPath = this._parseAndSortShape(oShapeConfig[i].getClippathAggregation(), sShapeId);
					for (var j = 0; j < aPath.length; j++) {
						oShapeInst.addPath(aPath[j]);
					}
				}
			}
			aRetVal.push(oShapeInst);
		}

		// sort top shape instances and create map by shape id
		if (sTopShapeId){
			return aRetVal;
		} else {
			aRetVal.sort(function (oShape1, oShape2) {
				var level1 = jQuery.isNumeric(oShape1.mShapeConfig.getLevel()) ?
						oShape1.mShapeConfig.getLevel() : 99;
				var level2 = jQuery.isNumeric(oShape2.mShapeConfig.getLevel()) ?
						oShape2.mShapeConfig.getLevel() : 99;
				return level2 - level1;
			});
			this._aShapeInstance = aRetVal;

			var oShapeMap = {};
			jQuery.each(this._aShapeInstance, function (iKey, oValue) {
				oShapeMap[oValue.mShapeConfig.getKey()] = oValue;
			});
			this._oShapeInstance = oShapeMap;
		}
	};

	GanttChart.prototype._instantiateCustomerClass = function (sCustomerClassName, sShapeId, oShapeConfig, sTopShapeId) {
		var CustomerClass = jQuery.sap.getObject(sCustomerClassName);
		if (!CustomerClass) {
			jQuery.sap.require(sCustomerClassName);
			CustomerClass = jQuery.sap.getObject(sCustomerClassName);
		}
		
		var oCustomerClassInstance = new CustomerClass();
		var sTShapeId = sTopShapeId;
		if (sTShapeId === undefined) {
			sTShapeId = sShapeId;
		}
		this._storeCustomerClassId(sShapeId, oCustomerClassInstance.getId(), sTopShapeId);
		
		oCustomerClassInstance.mLocaleConfig = this.getLocale();
		oCustomerClassInstance.mShapeConfig = oShapeConfig;
		oCustomerClassInstance.mChartInstance = this;

		return oCustomerClassInstance;
	};
	
	/*
	 * {
	 * 		"activity": "__group0", //sId is the Id of shape class instance and it is randomly generated by UI5 framework
	 * 		"header": "__group1",
	 * 		...
	 * }
	 */
	GanttChart.prototype._storeCustomerClassId = function (sShapeId, sId, sTopShapeId) {
		if (!this._customerClassIds){
			this._customerClassIds = {};
		}
		if (this._oShapesConfigMap[sShapeId]){
			this._customerClassIds[sShapeId] = {
						"classId": sId,
						"topShapeId": sTopShapeId
					};
		}else {
			//non-topShape, when no shapeId in the shapeConfig.groupAggregation
			var sShape = sTopShapeId + "_" + sShapeId;
			this._customerClassIds[sShape] = {
					"classId": sId,
					"topShapeId": sTopShapeId
			};
		}
	};
	
	GanttChart.prototype._getIdByShapeId = function (sShapeId) {
		if (this._customerClassIds && this._customerClassIds[sShapeId]){
			return this._customerClassIds[sShapeId].classId;
		}
		return null;
	};
	
	GanttChart.prototype._getShapeIdById = function (sClassId) {
		if (this._customerClassIds){
			for (var sShapeId in this._customerClassIds) {
				var obj = this._customerClassIds[sShapeId];
				if (obj.classId === sClassId) {
					return {"shapeId": sShapeId, "topShapeId": obj.topShapeId};
				}
			}
		}
		return null;
	};

	GanttChart.prototype._genShapeConfig = function (sShapeId, oProp) {
		var obj = {}, oConfig;
		if (sShapeId !== null && sShapeId !== undefined) {
			obj.shapeId = sShapeId;
		}
		if (oProp.data) {
			obj.data = oProp.data;
		}
		if (oProp.level) {
			obj.level = oProp.level;
		}
		if (oProp.draw){
			oConfig = oProp.draw;
		} else {
			oConfig = oProp;
		}
		for (var item in oConfig) {
			if (item !== "class") {
				obj[item] = oConfig[item];
			}
		}
		return obj;
	};

	GanttChart.prototype.calculateZoomInfoFromChartWidth = function (iChartWidth) {
		var oTimeAxis = this.getTimeAxis();
		var oPlanHorizon = oTimeAxis.getPlanHorizon();
		var oInitHorizon = oTimeAxis.getInitHorizon();
		this._oZoom.determinedByChartWidth = {};
		
		// calculate min zoom rate by time horizon against svg container width
		if (oPlanHorizon) {
			var fMinScale = this._calZoomScale(
				Format.abapTimestampToDate(oPlanHorizon.getStartTime()),
				Format.abapTimestampToDate(oPlanHorizon.getEndTime()),
				iChartWidth);
			this._oZoom.determinedByChartWidth.fMinRate =  this._oZoom.base.fScale / fMinScale;
		}
		// calculate sutible zoom rate by init horizon against svg container width
		if (oInitHorizon && oInitHorizon.getStartTime() && oInitHorizon.getEndTime()) {
			var fSuitableScale = this._calZoomScale(
				Format.abapTimestampToDate(oInitHorizon.getStartTime()),
				Format.abapTimestampToDate(oInitHorizon.getEndTime()),
				iChartWidth);
			this._oZoom.determinedByChartWidth.fSuitableRate = this._oZoom.base.fScale / fSuitableScale;
		}
		this._oZoom.iChartWidth = iChartWidth;
		return this._oZoom;
	};

	GanttChart.prototype.setTimeZoomRate = function (fTimeZoomRate) {
		this.setProperty("timeZoomRate", fTimeZoomRate, true); // no need to trigger rerender
		this._oAxisTime.setZoomRate(fTimeZoomRate);
		this._oAxisTime.setViewOffset(0);
		this._oStatusSet = null;
		this._nLowerRange = this._oAxisTime.getViewRange()[0];
		this._nUpperRange = Math.ceil(this._oAxisTime.getViewRange()[1]);
		this._draw(true); // only _draw is triggered
		return this;
	};

	GanttChart.prototype.getBaseRowHeight = function () {
		if (this._oTT.getRows()[0] && this._oTT.getRows()[0].getDomRef()) {
			return this._oTT.getRows()[0].getDomRef().scrollHeight;
		}
	};
	
	/*
	 * Called by UI5 ManagedObject before and after retrieving data.
	 */
	GanttChart.prototype.updateRelationships = function (sReason) {
		var oBinding = this.getBinding("relationships");
		
		if (oBinding) {
			var aContext = oBinding.getContexts(0, 0);
			
			if (aContext && aContext.length > 0) {
				this._aRelationshipsContexts = aContext;
			}
		}
	};
	
	/*
	 * @see JSDoc generated by SAPUI5 control API generator
	 */
	GanttChart.prototype.addRelationship = function (oRelationship) {
		jQuery.sap.log.error("The control manages the relationships aggregation. The method \"addRelationship\" cannot be used programmatically!");
	};
	/*
	 * @see JSDoc generated by SAPUI5 control API generator
	 */
	GanttChart.prototype.insertRelationship = function (iIndex, oRelationship) {
		jQuery.sap.log.error("The control manages the relationships aggregation. The method \"insertRelationship\" cannot be used programmatically!");
	};
	/*
	 * @see JSDoc generated by SAPUI5 control API generator
	 */
	GanttChart.prototype.removeRelationship = function (oRelationship) {
		jQuery.sap.log.error("The control manages the relationships aggregation. The method \"removeRelationship\" cannot be used programmatically!");
	};
	/*
	 * @see JSDoc generated by SAPUI5 control API generator
	 */
	GanttChart.prototype.getRelationships = function () {
		jQuery.sap.log.error("The control manages the relationships aggregation. The method \"getRelationships\" cannot be used programmatically!");
	};
	/*
	 * @see JSDoc generated by SAPUI5 control API generator
	 */
	GanttChart.prototype.destroyRelationships = function () {
		jQuery.sap.log.error("The control manages the relationships aggregation. The method \"destroyRelationships\" cannot be used programmatically!");
	};
	/*
	 * @see JSDoc generated by SAPUI5 control API generator
	 */
	GanttChart.prototype.indexOfRelationship = function (oRelationship) {
		jQuery.sap.log.error("The control manages the relationships aggregation. The method \"indexOfRelationship\" cannot be used programmatically!");
	};
	/*
	 * @see JSDoc generated by SAPUI5 control API generator
	 */
	GanttChart.prototype.removeAllRelationships = function () {
		jQuery.sap.log.error("The control manages the relationships aggregation. The method \"removeAllRelationships\" cannot be used programmatically!");
	};

	GanttChart.prototype._bindAggregation = function (sName, oBindingInfo) {
		if (sName == "rows" && oBindingInfo){
			var oModel = this.getModel(oBindingInfo.model);
			// resolve the path if view itself is binded
			var oBindingContext = this.getBindingContext(oBindingInfo.model);
			if (oBindingContext && oModel){
				oBindingInfo.path = oModel.resolve(oBindingInfo.path, oBindingContext);
			}
			this._oTT.bindRows(oBindingInfo);
		} else {
			return sap.ui.core.Control.prototype._bindAggregation.apply(this, arguments);
		}
	};

	GanttChart.prototype.onBeforeRendering = function () {
		this._detachEvents();
		this._updateModelForMultiMainRow();
	};

	GanttChart.prototype._updateModelForMultiMainRow = function() {
		var oBinding = this._oTT.getBinding("rows");
		if (!oBinding || oBinding.getLength() === 0) {
			return;
		}
		var aRowContext = oBinding.getContexts(0, oBinding.getLength());
		var oAllShapeData = {}, iRowSpan = 1, sMainChartScheme,
		sType = aRowContext[0].getProperty("type");
		if (sType && this._oObjectTypesConfigMap[sType]) {
			sMainChartScheme = this._oObjectTypesConfigMap[sType].getProperty("mainChartSchemeKey");
			if (sMainChartScheme && this._oChartSchemesConfigMap[sMainChartScheme]) {
				iRowSpan = this._oChartSchemesConfigMap[sMainChartScheme].getProperty("rowSpan");
			}
		}
	
		if (iRowSpan == 1 || iRowSpan == undefined) {
			return;
		}
		for (var i = 0; i < aRowContext.length; i++) {
			var oRowData = aRowContext[i].getProperty();
			if (TreeTableHelper.isDummyRow(this._oTT, i)) {
				continue;
			}
			if (i < aRowContext.length - 1){
				if (TreeTableHelper.isDummyRow(this._oTT, i + 1)) {
					continue;
				}
			}
			oRowData.previousNodeNum = 0;
			oRowData.afterNodeNum = iRowSpan - 1;
			//allShapeData.push(oRowData);
			var oDummyData = {"chartScheme" : sMainChartScheme, "mainRowId" : oRowData.id};
			var aAddData = [];
			for ( var j = 1; j < iRowSpan; j++) {
				var oTempData = jQuery.extend(true, {}, oDummyData);
				oTempData.previousNodeNum = j;
				oTempData.afterNodeNum = iRowSpan - j - 1;
				aAddData.push(oTempData);
			}
			oAllShapeData[i] = aAddData;
		}

		if (!$.isEmptyObject(oAllShapeData)) {
			TreeTableHelper.addDummyData(this._oTT, oAllShapeData, false);
		}
	};

	GanttChart.prototype._detachEvents = function () {
		jQuery("#" + this.getId() + "-svg-ctn").unbind("mousemove", this._onSvgCtnMouseMove);
		jQuery("#" + this.getId() + "-svg-ctn").unbind("mouseleave", this._onSvgCtnMouseLeave);
		jQuery("#" + this.getId() + "-svg-ctn").unbind("mousedown", this._onSvgCtnMouseDown);
		jQuery("#" + this.getId() + "-svg-ctn").unbind("mouseenter", this._onSvgCtnMouseEnter);
		jQuery("#" + this.getId() + "-svg-ctn").unbind("mouseup", this._onSvgCtnMouseUp);
	};

	GanttChart.prototype.onAfterRendering = function () {
		this._attachEvents();
	};

	GanttChart.prototype._attachEvents = function () {

		var $svgCtn = jQuery("#" + this.getId() + "-svg-ctn");	
		$svgCtn.bind("mousemove", this._onSvgCtnMouseMove.bind(this));
		$svgCtn.bind("mouseleave", this._onSvgCtnMouseLeave.bind(this));
		$svgCtn.bind("mousedown", this._onSvgCtnMouseDown.bind(this));
		$svgCtn.bind("mouseenter", this._onSvgCtnMouseEnter.bind(this));
		$svgCtn.bind("mouseup", this._onSvgCtnMouseUp.bind(this));
	};

	GanttChart.prototype.expandChartChange = function (isExpand, aExpandChartSchemes, aExpandedIndices) {
		if (aExpandChartSchemes.length < 0) {
			return;
		}
		jQuery.sap.measure.start("GanttChart expandChartChange","GanttPerf:GanttChart expandChartChange function");
		var aSelectedIndices = (aExpandedIndices && aExpandedIndices.length > 0) ? aExpandedIndices : this._oTT.getSelectedIndices();
		var key;
		if (isExpand) {
			for (key = 0; key < aExpandChartSchemes.length; key++) {
				var sScheme = aExpandChartSchemes[key];
				var sMode;
				if (this._oChartSchemesConfigMap[sScheme] && this._oChartSchemesConfigMap[sScheme].getModeKey()) {
					sMode = this._oChartSchemesConfigMap[sScheme].getModeKey();
				} else {
					sMode = this.getMode();
				}
				var oAllInsertedData = {};
				for (var i = 0; i < aSelectedIndices.length; i++) {
					if (TreeTableHelper.isDummyRow(this._oTT, aSelectedIndices[i])) {
						continue;
					}
					var oSelectedData = TreeTableHelper.getContextObject(this._oTT, aSelectedIndices[i]);
					var oDummyData = {"__group" : aExpandChartSchemes[key], "parentData" : oSelectedData, "parentRefId" : oSelectedData.id};
					//Check whether the current object data has the expanded chart scheme
					if (this._oObjectTypesConfigMap[oSelectedData.type] && this._oObjectTypesConfigMap[oSelectedData.type].getExpandedChartSchemeKeys().length > 0) {
						var aValidSchems = this._oObjectTypesConfigMap[oSelectedData.type].getExpandedChartSchemeKeys();
						if ($.inArray(sScheme, aValidSchems) > -1) {
							var aDrawData, iRowSpan = 1;
							//If the expandedChartScheme is available in current mode, return all valid data names, which can be drawn by shapes of the expandedChartScheme
							var oSchemeInfo = this._collectDataNameForValidChartScheme(sScheme, sMode);
							if (oSchemeInfo) {
								aDrawData = oSchemeInfo.drawData;
								iRowSpan = oSchemeInfo.rowSpan;
								//Calculate how many rows need to be inserted into tree table and adapt number of rows according to rowSpan
								var aAddedData = this._insertExpandedRowsToTT(aSelectedIndices[i], aDrawData, oDummyData, iRowSpan);
								if (aAddedData && aAddedData.length > 0) {
									oAllInsertedData[aSelectedIndices[i]] = aAddedData;
								}
							}
						}
					}
				}
				if (!$.isEmptyObject(oAllInsertedData)) {
					TreeTableHelper.addDummyData(this._oTT, oAllInsertedData, true);
				}
			}
		} else {
			for (key = 0; key < aExpandChartSchemes.length; key++) {
				TreeTableHelper.removeDummyDataFromSelectedIndices(this._oTT, aSelectedIndices, aExpandChartSchemes[key]);
			}
		}
		jQuery.sap.measure.end("GanttChart expandChartChange");
	};

	GanttChart.prototype._collectDataNameForValidChartScheme = function (sScheme, sMode) {
		if (this._oChartSchemesConfigMap[sScheme]) {
			var aDrawData = [], iRowSpan;
			var aShapesForChartScheme = this._oChartSchemesConfigMap[sScheme].getShapeKeys();
			iRowSpan = this._oChartSchemesConfigMap[sScheme].getRowSpan();
			var that = this;
			jQuery.each(aShapesForChartScheme, function (iKey, oVal) {
				if (that._oShapesConfigMap[oVal]) {
					var aModeKeys = that._oShapesConfigMap[oVal].getModeKeys();
					if ((aModeKeys && aModeKeys.length > 0 && $.inArray(sMode, aModeKeys) > -1) || aModeKeys.length == 0 || sMode == sap.gantt.config.DEFAULT_MODE_KEY) {
						aDrawData.push(that._oShapesConfigMap[oVal].getShapeDataName());
					} 
				}
			});
			if (aDrawData.length > 0 && iRowSpan >= 1) {
				return {"drawData" : aDrawData, "rowSpan" : iRowSpan};
			}
		}
	};

	GanttChart.prototype._insertExpandedRowsToTT = function (iSelectedIndice, aDrawData, oDummyData, iRowSpan) {
		var oSelectedData = TreeTableHelper.getContextObject(this._oTT, iSelectedIndice);
		if (aDrawData && aDrawData.length > 0) {
			var iNumberOfRows = 1, bHasData = false;
			$.each(aDrawData, function(ikey, sData) {
				if (oSelectedData[sData] && oSelectedData[sData].length > 0) {
					bHasData = true;
					for (var i = 0; i < oSelectedData[sData].length; i++) {
						if (oSelectedData[sData][i].rowIndex !== undefined && oSelectedData[sData][i].rowIndex > iNumberOfRows) {
							iNumberOfRows = oSelectedData[sData][i].rowIndex;
						}
					}
				}
			});
			if (!bHasData) {
				return [];
			}
			var aAddedData = [], k, oTempData;
			if (iNumberOfRows > 1 && iRowSpan == 1) {
				for (k = 0; k < iNumberOfRows; k++) {
					oTempData = jQuery.extend(true, {}, oDummyData);
					oTempData.index = k + 1;
					aAddedData.push(oTempData);
				}
			} else {
				oDummyData.index = 1;
				for (k = 0; k < iRowSpan; k++) {
					oTempData = jQuery.extend(true, {}, oDummyData);
					aAddedData.push(oTempData);
				}
			}
			return aAddedData;
		}
		return [];
	};

	GanttChart.prototype._composeParameterForClickPosition = function (event) {
		var aSvg = jQuery("#" + this.getId() + "-svg");
		var oSvgPoint = this._getSvgCoodinateByDiv(aSvg[0], event.pageX, event.pageY);
		var x = event.pageX - aSvg.offset().left || event.offsetX;
		var y = event.pageY - aSvg.offset().top || event.offsetY;
		if (!this._oAxisOrdinal) {
			return;
		}
		var oRowInfo, iRowIndex = this._oAxisOrdinal.viewToRowIndex(y, this._oTT.getVisibleRowCount()) + this._oTT.getFirstVisibleRow();
		var oLeadingRowInfo, iLeadingRowNum = iRowIndex;
		if (TreeTableHelper.isMultipleSpanMainRow(this._oTT, iRowIndex)){
			var mainRowGroupIndices = TreeTableHelper.getMultipleSpanMainRowGroupIndices(this._oTT, iRowIndex);
			iLeadingRowNum = mainRowGroupIndices[0];
		}
		if (iLeadingRowNum !== iRowIndex) {
			oLeadingRowInfo = TreeTableHelper.getContextObject(this._oTT, iLeadingRowNum);
		}
		
		var startTime = this._oAxisTime.viewToTime(x);
		oRowInfo = TreeTableHelper.getContextObject(this._oTT, iRowIndex);
		var param = {
			"startTime": startTime,
			"svgPoint": oSvgPoint,
			"leadingRowNum": iLeadingRowNum,
			"leadingRowInfo": oLeadingRowInfo, //if current row is the main row or current GanttChart is not expand chart and not multi row height, the leadingRowInfo = undefined
			"rowIndex": iRowIndex,
			"rowInfo": oRowInfo //if current row is a dummy row, rowInfo = undefined
		};
		return param;
	};
	
	/**
	 * Gets the selected rows, shapes, and relationships
	 * @return {object} The returned object contains "rows" for all selected rows, "shapes" for all selected shapes, and "relationships" for all selected relationships
	 */
	GanttChart.prototype.getAllSelections = function () {
		var selectedRows = this.getSelectedRows();
		var selectedShapes = this.getSelectedShapes();
		var selectedRelationships = this.getSelectedRelationships();
		var currentSelection = {"rows": selectedRows, "shapes": selectedShapes, "relationships": selectedRelationships};
		return currentSelection;
	};
	
	/**
	 * Gets the selected rows
	 * @return {array} Selected rows
	 * @public
	 */
	GanttChart.prototype.getSelectedRows = function () {
		var aSelectedRows = [];
		var iFirstVisibleRow = this._oTT.getFirstVisibleRow();
		var aSelectedIndexs = this._oTT.getSelectedIndices();
		for (var i = 0; i < aSelectedIndexs.length; i++) {
			var iRowIndex = aSelectedIndexs[i] - iFirstVisibleRow;
			if (iRowIndex > -1 && this._aShapeData[iRowIndex] !== undefined) {
				aSelectedRows.push(this._aShapeData[iRowIndex]);
			}
		}
		return aSelectedRows;
	};
	
	/**
	 * Gets the selected shapes
	 * @return {array} selected shapes
	 * @public
	 */
	GanttChart.prototype.getSelectedShapes = function () {
		var aSelectedShapes = this._oSelectedShapes;
		return aSelectedShapes;
	};
	
	/**
	 * Get all the current selected relationships
	 * @return {array} selected relationships
	 * @public
	 */
	GanttChart.prototype.getSelectedRelationships = function () {
		return this._aSelectedRelationships;
	};
	
	/**
	 * Selects shapes, and deselects all shapes when aIds is a null list and bIsExclusive is true
	 * @param {array} [aIds] List of the shapes that you want to select
	 * @param {boolean} [bIsExclusive] Whether all other selected shapes are deselected
	 * @return {boolean} True if the selection change is applied
	 * @public
	 */
	GanttChart.prototype.selectShapes = function(aIds, bIsExclusive) {
		var i, j, aShapeData, oShapeData;
		var bSelectionUpdated = false;
		if (this._aSelectedShapeUids === undefined) {
			this._aSelectedShapeUids = [];
		}
		if (aIds === undefined || aIds.length < 1) {//deselect all
			if (bIsExclusive && this._aSelectedShapeUids.length > 0) {
				this._oSelectedShapes = {};
				this._aSelectedShapeUids = [];
				bSelectionUpdated = true;
			}
		}else if (bIsExclusive) {
			this._oSelectedShapes = {};
			this._aSelectedShapeUids = [];
			for (i = 0; i < aIds.length; i++) {
				aShapeData = this._getShapeDataById(aIds[i], false);
				for (j = 0; j < aShapeData.length; j++) {
					oShapeData = aShapeData[j];
					if (this._judgeEnableSelection(oShapeData)) { // judge whether the uid is existed and whether is enable selection
						var bUpdate = this._selectShape(oShapeData);
						if (bUpdate) {
							bSelectionUpdated = true;
						}
					}
				}
			}
		}else {
			for (i = 0; i < aIds.length; i++) {
				aShapeData = this._getShapeDataById(aIds[i], false);
				for (j = 0; j < aShapeData.length; j++) {
					oShapeData = aShapeData[j];
					if (jQuery.inArray(oShapeData.uid, this._aSelectedShapeUids) > -1) {
						continue;
					}else if (this._judgeEnableSelection(oShapeData) && this._selectShape(oShapeData)) {
						bSelectionUpdated = true;
					}
				}
			}
		}
		
		if (bSelectionUpdated) {
			this._drawSelectedShapes();
		}
		return bSelectionUpdated;
	};

	/**
	 * deselect shapes
	 * @param {array} [aIds] List of the shapes that you want to deselect
	 * @return {boolean} True if the selection change is applied
	 * @public
	 */
	GanttChart.prototype.deselectShapes = function(aIds) {
		var bSelectionUpdated = false;
		for (var i = 0; i < aIds.length; i++) {
			var aShapeData = this._getShapeDataById(aIds[i]);
			var bUpdate;
			for (var j = 0; j < aShapeData.length; j++){
				bUpdate = this._deselectShape(aShapeData[j]);
				if (bUpdate) {
					bSelectionUpdated = true;
				}
			}
		}
		if (bSelectionUpdated) {
			this._drawSelectedShapes();
		}
		return bSelectionUpdated;
	};
	
	/**
	 * Select rows and all shapes contained in those rows
	 * @param {array} [aIds] Row uids
	 * @param {boolean} [bIsExclusive] Wether all other selected rows and shapes are deselected
	 * @return {boolean} True if the selection change is applied
	 * @public
	 */
	GanttChart.prototype.selectRowsAndShapes = function(aIds, bIsExclusive) {
		var bSelectionUpdated = false;
		var bRowSelectionUpdated = this.selectRows(aIds, bIsExclusive);
		if (bIsExclusive) {
			this._oSelectedShapes = {};
			this._aSelectedShapeUids = [];
		}
		if (this._aSelectedShapeUids === undefined) {
			this._aSelectedShapeUids = [];
		}
		for (var id in aIds) {
			var sId = aIds[id];
			var oRowData = this._getRowById(sId);
			if (oRowData !== undefined) {
				for (var sShapeId in oRowData.data) {
					if (oRowData.data[sShapeId] instanceof Array) {
						for ( var i = 0; i < oRowData.data[sShapeId].length; i++) {
							var oShapeData = oRowData.data[sShapeId][i];
							if (jQuery.inArray(oShapeData.uid, this._aSelectedShapeUids) < 0) {
								this._selectShape(oShapeData);
								bSelectionUpdated = true;
							}
						}
					}
				}
			}
		}
		if (bSelectionUpdated) {
			this._drawSelectedShapes();
		}else if (bRowSelectionUpdated) {
			bSelectionUpdated = true;
		}
		
		return bSelectionUpdated;
	};

	/**
	 * Selects relationships, and deselects all other selected relationships if aIds is a null list and bIsExclusive is true
	 * @param {array} [aIds] List of the shapes that you want to select
	 * @param {boolean} [bIsExclusive] Whether all other selected shapes are deselected
	 * @return {boolean} True if the selection change is applied
	 * @public
	 */
	GanttChart.prototype.selectRelationships = function(aIds, bIsExclusive) {
		var i, oRelationship;
		var bSelectionUpdated = false;
		if (this._aSelectedRelationships === undefined) {
			this._aSelectedRelationships = [];
		}
		if (aIds === undefined || aIds.length < 1) {//deselect all
			if (bIsExclusive && this._aSelectedRelationships.length > 0) {
				this._aSelectedRelationships = [];
				bSelectionUpdated = true;
			}
		}else if (bIsExclusive) {
			if (aIds.length == this._aSelectedRelationships.length) {
				//check if any new selecting relationship
				for (i = 0; i < aIds.length; i++) {
					oRelationship = this._getShapeDataById(aIds[i], true)[0];
					if (oRelationship !== undefined && jQuery.inArray(oRelationship, this._aSelectedRelationships) >= 0) {
						continue;
					} else {
						bSelectionUpdated = true;
						break;
					}
				}
			}
			this._aSelectedRelationships = [];
			for (i = 0; i < aIds.length; i++) {
				oRelationship = this._getShapeDataById(aIds[i], true)[0];
				if (oRelationship !== undefined && oRelationship !== null && this._judgeEnableSelection(oRelationship)) {
					this._aSelectedRelationships.push(oRelationship);
					bSelectionUpdated = true;
				}
			}
		}else {
			for (i = 0; i < aIds.length; i++) {
				oRelationship = this._getShapeDataById(aIds[i], true)[0];
				//if the relationship is unavailable or it is already in selection, ignore
				if (oRelationship === undefined || jQuery.inArray(oRelationship, this._aSelectedRelationships) >= 0) {
					continue;
				} else if (this._judgeEnableSelection(oRelationship)) {
					this._aSelectedRelationships.push(oRelationship);
					bSelectionUpdated = true;
				}
			}
		}
		
		if (bSelectionUpdated) {
			this._drawSelectedShapes();
		}
		return bSelectionUpdated;
	};

	/**
	 * Deselects relationships
	 * @param {array} [aIds] List of the relationships that you want to deselect
	 * @return {boolean} True if the selection change is applied
	 * @public
	 */
	GanttChart.prototype.deselectRelationships = function(aIds) {
		var bSelectionUpdated = false;
		var aUids = [];
		if (aIds !== undefined) {
			for (var i = 0; i < aIds.length; i++) {
				var uid = this._getUidById(aIds[i], true)[0];
				if (uid !== undefined) {
					aUids.push(uid);
				}
			}
		}
		for (var j in this._aSelectedRelationships) {
			var oSelectedRLS = this._aSelectedRelationships[j];
			if (jQuery.inArray(oSelectedRLS.uid, aUids) > -1) {
				var iIndex = this._aSelectedRelationships.indexOf(oSelectedRLS);
				this._aSelectedRelationships.splice(iIndex, 1);
				bSelectionUpdated = true;
			}
		}
		if (bSelectionUpdated) {
			this._drawSelectedShapes();
		}
		return bSelectionUpdated;
	};

	/**
	 * Selects rows
	 * @param {array} [aIds] List of the rows that you want to select
	 * @param {boolean} [bIsExclusive] Whether all other selected rows are deselected
	 * @return {boolean} True if the selection change is applied
	 * @public
	 */
	GanttChart.prototype.selectRows = function(aIds, bIsExclusive) {
		var bSelectionUpdated = false;
		var aVisibleRows = this._oTT.getRows();
		//var iFirstRow = this._oTT.getFirstVisibleRow();
		var aSelectedIndexs = this._oTT.getSelectedIndices();
		if (bIsExclusive && aSelectedIndexs.length > 0) {
			this._oTT.clearSelection();
			bSelectionUpdated = true;
		}
		for (var i in aVisibleRows) {
			var oRow = d3.select("#" + aVisibleRows[i].getId());
			//iIndex = iFirstRow + parseInt(oSelectedRow.attr("data-sap-ui-rowindex"), 10);
			var iIndex = parseInt(oRow.attr("data-sap-ui-rowindex"), 10);
			var oRowData = this._aShapeData[iIndex];
			if (oRowData !== undefined && jQuery.inArray(oRowData.data.id, aIds) > -1) {
				if (jQuery.inArray(iIndex, aSelectedIndexs) < 0) {
					//check if the treetable support multiple selection
					var sSelectionMode = this._oTT.getSelectionMode();
					if (sSelectionMode === sap.ui.table.SelectionMode.Multi) {
						this._oTT.addSelectionInterval(iIndex, iIndex);
					}else {
						this._oTT.setSelectedIndex(iIndex);
					}
					bSelectionUpdated = true;
				}
			}
		}
		return bSelectionUpdated;
	};

	/**
	 * Deselects rows
	 * @param {array} [aIds] List of the rows that you want to deselect
	 * @return {boolean} True if the selection change is applied
	 * @public
	 */
	GanttChart.prototype.deselectRows = function(aIds) {
		var bSelectionUpdated = false;
		var aSelectedIndexs = this._oTT.getSelectedIndices();
		var aVisibleRows = this._oTT.getRows();
		for (var i in aSelectedIndexs) {
			var iSelectedIndex = aSelectedIndexs[i];
			var oRow = d3.select("#" + aVisibleRows[iSelectedIndex].getId());
			var iIndex = parseInt(oRow.attr("data-sap-ui-rowindex"), 10);
			var oRowData = this._aShapeData[iIndex];
			if (jQuery.inArray(oRowData.data.id, aIds)) {
				aSelectedIndexs.splice(iSelectedIndex, 1);
				this._oTT.removeSelectionInterval(iSelectedIndex, 1);
				bSelectionUpdated = true;
			}
		}
		return bSelectionUpdated;
	};
	
	//Private method: check if an element is a relationship by its' sShapeUid
	GanttChart.prototype._isRelationship = function (sShapeUid) {
		if (this._getShapeDataNameByUid(sShapeUid) === sap.gantt.shape.ShapeCategory.Relationship) {
			return true;
		}	
		return false;
	};
	
	GanttChart.prototype._onRowSelectionChange = function (oEvent) {

		//below is just a workaround, we may need change these in future
		var aChangedIndices = oEvent.getParameter("rowIndices"),
			aCurrentSelectedIndices = this._oTT.getSelectedIndices(),
			aSelectedIndices = [],
			aDeselectedIndices = [];

		for (var i = 0; i < aChangedIndices.length; i++){
			if (aCurrentSelectedIndices.indexOf(aChangedIndices[i]) === -1){
				aDeselectedIndices.push(aChangedIndices[i]); //deselected indices by user or delegate
			} else {
				aSelectedIndices.push(aChangedIndices[i]); //selected indices by user or delegate
			}
		}
		var oTT = this._oTT;
		var fnUpdateRowSelection = function(aRowIndices, bSelected){
			for (var j = 0; j < aRowIndices.length; j++){
				if (TreeTableHelper.isMultipleSpanMainRow(oTT, aRowIndices[j], true)){
					//indices is actual index in the table
					var aMainRowGroupIndices = TreeTableHelper.getMultipleSpanMainRowGroupIndices(oTT, aRowIndices[j], true);
					var iFirstIndex = aMainRowGroupIndices[0],
						iLastIndex = aMainRowGroupIndices[aMainRowGroupIndices.length - 1];
					
					for (var m = 0; m < aMainRowGroupIndices.length; m++){
						if (bSelected && aCurrentSelectedIndices.indexOf(aMainRowGroupIndices[m]) === -1){
							oTT.addSelectionInterval(iFirstIndex,iLastIndex);
						} else if (!bSelected && aCurrentSelectedIndices.indexOf(aMainRowGroupIndices[m]) !== -1){
							oTT.removeSelectionInterval(iFirstIndex,iLastIndex);
						}
					}
				}
			}
		};

		fnUpdateRowSelection(aSelectedIndices, true);
		fnUpdateRowSelection(aDeselectedIndices, false);

		this.fireRowSelectionChange({
			originEvent: oEvent
		});
	};
	
	//Private method: ShapeSelectionChange, RelationshipSelectionChange
	GanttChart.prototype._selectionChange = function (oShapeData, bCtrl, bShift, origEvent) {
		if (this._aSelectedRelationships == undefined){
			this._aSelectedRelationships = [];
		}
		if (this._aSelectedShapeUids == undefined){
			this._aSelectedShapeUids = [];
		}
		/*
		 * Click on Shapes:	Clear any existing selection of all shape and select current shape.	Clear all rows selection.
		 * Click on Shapes + control key:	Keep existing selection of all shapes and change selection of current shape.	Keep all rows selection. Keep all relationship selection
		 * above 2 same for the relationships
		 * Old: Click on Shape + shift key = Click on Shape
		 */
		var bShapeSelectionChange = false;
		var bRelationshipSelectionChange = false;
		var targetUid = oShapeData.uid;
		var isRelationship = this._isRelationship(targetUid);
		if ((bCtrl && this.getSelectionMode() === sap.gantt.SelectionMode.MultiWithKeyboard) || this.getSelectionMode() === sap.gantt.SelectionMode.Multiple){
			//when ctrl key is pressed or in Fiori multiple selection mode
			if (!isRelationship) {
				//if the shape is already in selectedShapes, deselect it, otherwise select it
				if (this._aSelectedShapeUids !== undefined && jQuery.inArray(targetUid, this._aSelectedShapeUids) > -1){
					if (!this._bDragging) {
						bShapeSelectionChange = this._deselectShape(oShapeData);
					}
				}else {
					bShapeSelectionChange = this._selectShape(oShapeData);
				}
			}else {
				if (jQuery.inArray(oShapeData, this._aSelectedRelationships) < 0){
					this._aSelectedRelationships.push(oShapeData);
				}else {
					var index = this._aSelectedRelationships.indexOf(oShapeData);
					this._aSelectedRelationships.splice(index,1);
				}
				bRelationshipSelectionChange = true;
			}
		}else if (!isRelationship) {
			if ((jQuery.inArray(targetUid, this._aSelectedShapeUids) < 0 || this._aSelectedShapeUids.length > 1) && !this._bDragging) {
				//clear all the Selected Shapes, add the clicking one
				this._oSelectedShapes = {};
				this._aSelectedShapeUids = [];
				bShapeSelectionChange = true;
			}
			if (jQuery.inArray(targetUid, this._aSelectedShapeUids) < 0 ) {
				var bUpdated = this._selectShape(oShapeData);
				if (!bShapeSelectionChange && bUpdated) {
					bShapeSelectionChange = true;
				}
			}
			if (this._aSelectedRelationships.length > 0) {
				this._aSelectedRelationships = [];
				bRelationshipSelectionChange = true;
			}
		}else {//if the current clicking element is a relationship
			if ((jQuery.inArray(oShapeData, this._aSelectedRelationships) < 0) || this._aSelectedRelationships.length > 1){
				//clear all the Selected Shapes, add the clicking one
				this._aSelectedRelationships = [];
				this._aSelectedRelationships.push(oShapeData);
				bRelationshipSelectionChange = true;
			}
			if (this._aSelectedShapeUids !== undefined && this._aSelectedShapeUids.length > 0) {
				this._oSelectedShapes = {};
				this._aSelectedShapeUids = [];
				bShapeSelectionChange = true;
			}
		}
		if (bShapeSelectionChange || bRelationshipSelectionChange) {
			this._drawSelectedShapes();
		}
		return {
			shapeSelectionChange: bShapeSelectionChange,
			relationshipSelectionChange: bRelationshipSelectionChange
		};
	};

	/*
	 * update the selected status back to model data
	 */
	GanttChart.prototype._setSelectedStatusToData = function() {
		for (var sRow in this._aShapeData) {
			var oRowData = this._aShapeData[sRow];
			for (var sShapeDataName in oRowData.data) {
				var aShapes = oRowData.data[sShapeDataName];
				if (aShapes instanceof Array) {
					for ( var iIndex = 0; iIndex < aShapes.length; iIndex++) {
						var oShapeData = aShapes[iIndex];
						if (jQuery.inArray(oShapeData.uid, this._aSelectedShapeUids) > -1) {
							oShapeData.selected = true;
						}else {
							oShapeData.selected = false;
						}
					}
				}
			}
		}
		for (var i in this._aRelationships) {
			this._aRelationships[i].selected = false;
			if (this._aSelectedRelationships !== undefined && this._aSelectedRelationships.length > 0){
				for (var j in this._aSelectedRelationships) {
					if (this._aRelationships[i].uid === this._aSelectedRelationships[j].uid) {
						this._aRelationships[i].selected = true;
					}
				}
			}
		}
	};

	/*
	 * get the selections according to the data from model
	 */
	GanttChart.prototype._setSelectedStatusFromData = function (aShapeDataNames) {
		this._oSelectedShapes = {};
		this._aSelectedShapeUids = [];
		for (var sRow in this._aShapeData) {
			var oRowData = this._aShapeData[sRow];
			for (var sShapeDataName in oRowData.data) {
				var aShapes = oRowData.data[sShapeDataName];
				//only loop the arrays, e.g tasks, activities
				if (aShapes instanceof Array && jQuery.inArray(sShapeDataName, aShapeDataNames) > -1) {
					for ( var i = 0; i < aShapes.length; i++) {
						var oShapeData = aShapes[i];
						if (oShapeData.selected) {
							if (this._oSelectedShapes[sShapeDataName] === undefined) {
								this._oSelectedShapes[sShapeDataName] = [];
							}
							this._oSelectedShapes[sShapeDataName].push({"shapeUid": oShapeData.uid, "shapeData": oShapeData, "objectInfoRef": oRowData});
							this._aSelectedShapeUids.push(oShapeData.uid);
						}
					}
				}
			}
		}
		//loop given relationship data, collect the selected data into the selected relationship collection
		this._aSelectedRelationships = [];
		for (var j in this._aRelationships) {
			if (this._aRelationships[j].selected) {
				this._aSelectedRelationships.push(this._aRelationships[j]);
			}
		}
	};
	/*
	 * Synconize the clicks on empty space of chart with selection of rows in the back table
	 */
	GanttChart.prototype._syncTTSelection = function(event){
		jQuery.sap.measure.start("GanttChart syncTTSelection","GanttPerf:GanttChart syncTTSelection function");
		var x = event.clientX;
		var y = event.clientY;
		var bShift = event.shiftKey;
		var bCtrl = event.ctrlKey;
		var $svg = jQuery("#" + this.getId() + "-svg")[0];
		var oClickPoint = this._getSvgCoodinateByDiv($svg, x, y);

		var iRowIndex = parseInt(this._oAxisOrdinal.viewToBandIndex(oClickPoint.y), 10);
		if (iRowIndex < 0){
			return false;
		}
		var aVisibleRows = this._oTT.getRows();
		var iIndex, oSelectedRow = d3.select("#" + aVisibleRows[iRowIndex].getId());
		if (iRowIndex < aVisibleRows.length && oSelectedRow && oSelectedRow.attr("data-sap-ui-rowindex")){
			iIndex = this._oTT.getFirstVisibleRow() + parseInt(oSelectedRow.attr("data-sap-ui-rowindex"), 10);
		}
		//disable selection for expaned dummy row
		if (TreeTableHelper.isDummyRow(this._oTT, iIndex) && TreeTableHelper.getContextObject(this._oTT, iIndex).__group !== undefined) {
			return false;
		}
		var sSelectionMode = this._oTT.getSelectionMode();
		if (iIndex >= 0 && sSelectionMode !== sap.ui.table.SelectionMode.None) {
			if (sSelectionMode === sap.ui.table.SelectionMode.Single) {
				if (!this._oTT.isIndexSelected(iIndex)) {
					this._oTT.setSelectedIndex(iIndex);
				} else {
					this._oTT.clearSelection();
				}
			} else {
				if (sSelectionMode === sap.ui.table.SelectionMode.Multi && this.getSelectionMode === sap.gantt.SelectionMode.Multiple) {
					bCtrl = true;
				}
				if (bShift) {
					// If no row is selected getSelectedIndex returns -1 - then we simply select the clicked row:
					/* Click on Empty place + shift key: Keep all shape/relationship selection.
					 * sync the row selection with original treetable row selection behavior
					 */
					var iSelectedIndex = this._oTT.getSelectedIndex();
					if (iSelectedIndex >= 0) {
						if (iSelectedIndex < iIndex) {
							this._oTT.addSelectionInterval(iSelectedIndex, iIndex);
						}else {
							this._oTT.addSelectionInterval(iIndex, iSelectedIndex);
						}
					}else {
						this._oTT.setSelectedIndex(iIndex);
					}
				}else if (!this._oTT.isIndexSelected(iIndex)) {
					if (bCtrl) {
						this._oTT.addSelectionInterval(iIndex, iIndex);
					} else {
						this._oTT.clearSelection();
						this._oTT.setSelectedIndex(iIndex);
					}
				}else if (bCtrl) {
					this._oTT.removeSelectionInterval(iIndex, iIndex);
				}else if (this._oTT.getSelectedIndices().length > 1) {
					this._oTT.clearSelection();
					this._oTT.setSelectedIndex(iIndex);
				}
			}
		}
		jQuery.sap.measure.end("GanttChart syncTTSelection");
	};
	
	//Set global variances for svg events
	GanttChart.prototype._setEventStatus = function (sEventName) {
		switch (sEventName) {
			case "dragEnter":
				this._bDragging = true;
				break;
			case "mouseDown":
				this._bMouseDown = true; 
				this._bDragging = false;
				break;
			case "shapeDragging":
				this._bDragging = true;
				break;
			case "mouseUp":
				this._bMouseDown = false;
				break;
			case "shapeDragEnd":
				this._bDragging = false;
				this._oDraggingData = undefined;
				break;
			case "dragLeave":
				this._iMouseDown = 0;
				this._bMouseDown = false;
				this._bDragging = false;
				break;
			default:
				break;
		}
	};
	
	GanttChart.prototype._onShapeDragStart = function (oEvent) {
		var aSvg = jQuery("#" + this.getId() + "-svg");
		//if mouse down on a shape that is dragable
		var oSourceShapeData = d3.select(oEvent.target).data()[0];
		var sClassId = oEvent.target.getAttribute("class").split(" ")[0];
		if (oSourceShapeData !== undefined && jQuery.inArray(oSourceShapeData.uid, this._aSelectedShapeUids) > -1
				&& this._judgeEnableDnD(oSourceShapeData, sClassId)) {
			var rowInfo = this._getRowByShapeUid(oSourceShapeData.uid);
			var x = oEvent.pageX - aSvg.offset().left || oEvent.offsetX;
			var y = oEvent.pageY - aSvg.offset().top || oEvent.offsetY;
			var shapeX, shapeWidth;
			if (oEvent.target.getAttribute("x") && oEvent.target.getAttribute("width")) {
				shapeX = parseInt(oEvent.target.getAttribute("x"), 10);
				shapeWidth = parseInt(oEvent.target.getAttribute("width"), 10);
			}else if (oSourceShapeData.startTime){
				var x1 = this._oAxisTime.timeToView(Format.abapTimestampToDate(oSourceShapeData.startTime));
				var x2 = this._oAxisTime.timeToView(Format.abapTimestampToDate(oSourceShapeData.endTime));
				if (Core.getConfiguration().getRTL()) {
					shapeX = x2;
					shapeWidth = (x1 - x2) > 0 ? (x1 - x2) : 1;
				}else {
					shapeX = x1;
					shapeWidth = (x2 - x1) > 0 ? (x2 - x1) : 1;
				}
			}else {
				shapeX = x;
				shapeWidth = 1;
			}
			var oDragStartPoint = {"x": x, "y": y, "shapeX": shapeX, "shapeWidth": shapeWidth};
			
			var aSourceShapeData = [];
			aSourceShapeData.push({
				"shapeData": oSourceShapeData,
				"objectInfo": rowInfo
			});
			for (var sShapeDataName in this._oSelectedShapes) {
				var aShapeData = this._oSelectedShapes[sShapeDataName];
				if (aShapeData !== undefined) {
					for (var i in aShapeData) {
						if (aShapeData[i].shapeUid !== oSourceShapeData.uid && this._judgeEnableDnD(aShapeData[i].shapeData)) {
							aSourceShapeData.push({
								"shapeData": aShapeData[i].shapeData,
								"objectInfo": aShapeData[i].objectInfoRef
							});
						}
					}
				}
			}
			this._oDraggingData = {
					"sourceShapeData": aSourceShapeData,
					"dragStartPoint": oDragStartPoint,
					"sourceSvgId": this.getId(),
					"targetSvgId": this.getId(),
					"domObject": d3.select(oEvent.target)[0][0]
			};
			
			this._oDraggingData.fDragHandler = this._onShapeDrag.bind(this);
			jQuery(document.body).bind("mousemove", this._oDraggingData.fDragHandler);
			this._oDraggingData.fDragEndHandler = this._onShapeDragEnd.bind(this);
			jQuery(document.body).bind("mouseup", this._oDraggingData.fDragEndHandler);
		}
	};
	
	GanttChart.prototype._onShapeDrag = function (oEvent) {
		if (oEvent.button !== 0 || oEvent.buttons === 0 || oEvent.ctrlKey) {
			return false;
		}
		var aDragDiv = d3.select("#activtityDragDrop");
		var dragDiv = aDragDiv[0];
		if (this._oDraggingData === undefined) {
			if (!aDragDiv.empty()){
				aDragDiv.remove();
			}
		}else {
			var nShapeCount = this._oDraggingData.sourceShapeData.length;
			var iShapeX = this._oDraggingData.dragStartPoint.shapeX;
			var iStartMouseX = this._oDraggingData.dragStartPoint.x;
			if (aDragDiv.empty() || dragDiv === null) {
				dragDiv = d3.select("body").append("div").attr("id", "activtityDragDrop")
				.style("position", "absolute").style("z-index", "999");
				var cloneNode = this._oDraggingData.domObject.cloneNode();
				var width = d3.select(cloneNode).attr("width");
				var height = d3.select(cloneNode).attr("height");
				var fontSize = 12;
				var g = dragDiv.append("svg").attr("id", "activtityDragDropSvg").attr("width", width).attr("height", height)
					.append("g").attr("id", "activtityDragDropSvgGroup");
	
				var shadow = d3.select(this._oDraggingData.domObject.cloneNode())
					.classed("shadow", true)
					.attr("fill-opacity", "0.5")
					.attr("x", 0)
					.attr("y", 0);
	
				g.node().appendChild(shadow.node());
				g.append("text")
					.attr("x", width / 2 - fontSize / 2)
					.attr("y", height - fontSize / 2 + 4)
					.attr("fill", "blue")
					.attr("font-size", 12)
					.text(function () {
						return nShapeCount; 
					});
			}
			var iCurrentX = iShapeX + (oEvent.pageX - iStartMouseX);
			var iCurrentY = oEvent.pageY;//calculate current Y on the align of shape&row
			d3.select("#activtityDragDrop").style("left", iCurrentX + 4 + "px");
			d3.select("#activtityDragDrop").style("top", iCurrentY + 4 + "px");
			jQuery(document.body).addClass("sapGanttDraggingCursor");
			this._setEventStatus("shapeDragging");
			this._iMouseDown = 0;
		}
	};
	
	GanttChart.prototype._onShapeDragEnd = function (oEvent) {
		//console.log("_onShapeDragEnd",oEvent);
		var div = d3.select("#activtityDragDrop");
		if (!div.empty()){
			div.remove();
		}
		if (this._bDragging && this._oDraggingData !== undefined) {
			var sTargetSvgId = this.getId() + "-svg";
			this._collectDraggingShapeData(this._oDraggingData, oEvent);
			this.fireShapeDragEnd({
				originEvent: oEvent,
				sourceSvgId: this._oDraggingData.sourceSvgId,
				targetSvgId: sTargetSvgId,
				sourceShapeData: this._oDraggingData.sourceShapeData,
				targetData: this._oDraggingData.targetData
			});
		}
		if (this._oDraggingData !== undefined) {
			jQuery(document.body).unbind("mousemove", this._oDraggingData.fDragHandler);
			jQuery(document.body).unbind("mouseup", this._oDraggingData.fDragEndHandler);
		}
		jQuery(document.body).removeClass("sapGanttDraggingCursor");
		this._setEventStatus("shapeDragEnd");
	};
	
	GanttChart.prototype._collectDraggingShapeData = function (oDraggingSource, oEvent) {
		var aSvg = jQuery("#" + this.getId() + "-svg");
		var x = oEvent.pageX - aSvg.offset().left || oEvent.offsetX;
		var sStartPointX = oDraggingSource.dragStartPoint.x;
		var iDragDistance = parseInt(x, 10) - parseInt(sStartPointX, 10);
		var sShapeCurrentStartX = parseInt(oDraggingSource.dragStartPoint.shapeX, 10) + iDragDistance;
		var sShapeCurrentEndX = sShapeCurrentStartX + parseInt(oDraggingSource.dragStartPoint.shapeWidth, 10);
		var sNewStartTime, sNewEndTime;
		if (Core.getConfiguration().getRTL() === true) {
			sNewStartTime = Format.dateToAbapTimestamp(this._oAxisTime.viewToTime(sShapeCurrentEndX));
			sNewEndTime = Format.dateToAbapTimestamp(this._oAxisTime.viewToTime(sShapeCurrentStartX));
		} else {
			sNewStartTime = Format.dateToAbapTimestamp(this._oAxisTime.viewToTime(sShapeCurrentStartX));
			sNewEndTime = Format.dateToAbapTimestamp(this._oAxisTime.viewToTime(sShapeCurrentEndX));
		}
		/*
		 * Only Update the clicking shape data with the row object at the current point
		 * keep other shape data as the same as they are in sourceshapedata
		 */
		var param = this._composeParameterForClickPosition(oEvent);
		var rowInfo = param.rowInfo;
		oDraggingSource.targetData = {
			"mouseTimestamp": {startTime: sNewStartTime, endTime: sNewEndTime},
			"mode": this.getMode(),
			"objectInfo": rowInfo
		};
	};
	
	/*
	 * set draggingSource when a drag is from outside of the current chart
	 */
	GanttChart.prototype.setDraggingData = function (oDraggingSource) {
		
		this._oDraggingData = oDraggingSource;
		if (this._oDraggingData !== undefined) {
			this._oDraggingData.targetSvgId = this.getId();
			jQuery(document.body).unbind("mousemove", this._oDraggingData.fDragHandler);
			jQuery(document.body).unbind("mouseup", this._oDraggingData.fDragEndHandler);
			this._oDraggingData.fDragHandler = this._onShapeDrag.bind(this);
			this._oDraggingData.fDragEndHandler = this._onShapeDragEnd.bind(this);
			jQuery(document.body).bind("mousemove", this._oDraggingData.fDragHandler);
			jQuery(document.body).bind("mouseup", this._oDraggingData.fDragEndHandler);
			this._setEventStatus("dragEnter");
		}
	};
	
	GanttChart.prototype._onSvgCtnMouseEnter = function (oEvent) {
		if (oEvent.currentTarget.id === (this.getId() + '-svg-ctn') && oEvent.button === 0 && oEvent.buttons !== 0) {// check if the mouse left key is down
			this.fireChartDragEnter({originEvent: oEvent});
		}
	};

	GanttChart.prototype._onSvgCtnMouseMove = function(oEvent){
		var aSvg = jQuery("#" + this.getId() + "-svg");
		// calculate svg coordinate for hover
		var oSvgPoint = this._getSvgCoodinateByDiv(aSvg[0], oEvent.pageX, oEvent.pageY);

		// draw cursorLine. select svgs of all chart instances to impl synchronized cursorLine
		if (this.getEnableCursorLine()) {
			this._oCursorLineDrawer.drawSvg(
				d3.selectAll(".sapGanttChartSvg"),
				d3.selectAll(".sapGanttChartHeaderSvg"),
				this.getLocale(),
				oSvgPoint);
		}
		//Trigger mouseover event from oSVG to tree table, according to row index
		//if current row is the main row or current GanttChart is not expand chart and not multi row height, the leadingRowInfo = undefined, leadingRowNum = rowIndex
		//if current row is a dummy row, rowInfo = undefined
		var param = this._composeParameterForClickPosition(oEvent);
		//only hover the main row when in expand chart
		var iRowIndex = param ? param.rowIndex : -1; 
		var oShapeData = d3.select(oEvent.target).data()[0];
		if (iRowIndex  > -1 && 
				((oShapeData !== undefined && oShapeData.uid !== this._lastHoverShapeUid)
						|| (oShapeData === undefined && this._lastHoverShapeUid !== undefined) || iRowIndex !== this._lastHoverRowIndex)) {
			this.fireChartMouseOver({
				objectInfo: param.rowInfo,
				leadingRowInfo: param.leadingRowInfo,
				timestamp: param.startTime.getTime(),
				svgId: this.getId() + "-svg",
				svgCoordinate: param.svgPoint, 
				effectingMode: this.getMode(),
				originEvent: oEvent
			});
			if (oShapeData !== undefined) {
				this._lastHoverShapeUid = oShapeData.uid;
			}else {
				this._lastHoverShapeUid = undefined;
			}
		}
		if (iRowIndex > -1 && iRowIndex !== this._lastHoverRowIndex) {
			var oTT = this._oTT;
			var $oTT = jQuery(oTT.getDomRef());
			var aHover = $oTT.find(".sapUiTableRowHvr");
			var oTargetRow = $oTT.find(".sapUiTableTr")[iRowIndex];
			
			if (this._oTT.getRows()[iRowIndex]) {
				var iRowNum = this._oTT.getRows()[iRowIndex].getIndex();
				var oRowContent = TreeTableHelper.getContextObject(this._oTT, iRowNum);
				
				if (aHover.length > 0) {
					for (var i = 0; i < aHover.length; i++) {
						if (jQuery.inArray("sapUiTableTr", aHover[i].classList) > -1) {
							jQuery(aHover[i]).mouseleave();
						}
					}
				}
				//disable hover for expaned dummy row
				if (!TreeTableHelper.isDummyRow(this._oTT, iRowNum) || oRowContent.__group === undefined || oRowContent.__group === null) {
					jQuery(oTargetRow).mouseenter();
					this._lastHoverRowIndex = iRowIndex;
				}
			}
		}
	};

	GanttChart.prototype._onSvgCtnMouseLeave = function (oEvent) {
		if (oEvent.currentTarget.id === (this.getId() + '-svg-ctn') && this._bDragging && this._oDraggingData !== undefined) {
			this._oDraggingData.targetSvgId = undefined;
			//if drag a shape out of a chart(view), then fire an event to Gantt
			this.fireChartDragLeave({
				//eventStatus: this._bDragging, this._mouseup, this.mousedown, or can those status already can be judged by the target(null or not?)
				originEvent: oEvent,
				draggingSource: this._oDraggingData
			});
			this._setEventStatus("dragLeave");
		}
		if (this.getEnableCursorLine()) {
			this._oCursorLineDrawer.destroySvg(
				d3.selectAll(".sapGanttChartSvg"),
				d3.selectAll(".sapGanttChartHeaderSvg"));
		}

		//Trigger mouseout event from oSVG to tree table
		var oTT = this._oTT;
		var $oTT = jQuery(oTT.getDomRef());
		var aHover = $oTT.find(".sapUiTableRowHvr");
		
		if (aHover.length > 0) {
			//to less the times of mouse leave, only trigger the row event
			for (var i = 0; i < aHover.length; i++) {
				if (jQuery.inArray("sapUiTableTr", aHover[i].classList) > -1) {
					jQuery(aHover[i]).mouseleave();
				}
			}
		}
		this._lastHoverShapeUid = undefined;
		this._lastHoverRowIndex = -1;
	};
	
	GanttChart.prototype._onSvgCtnMouseDown = function (oEvent) {
		if (oEvent.button == 0 ) {
			var oShapeData = d3.select(oEvent.target).data()[0];
			var sClassId;
			if (oEvent.target.getAttribute("class")){
				sClassId = oEvent.target.getAttribute("class").split(" ")[0];
			}
			//only when the mousedown is happened to a selectable shape, the shape selection change & dragNdrop are available, but the row selection still works
			if (sClassId && oShapeData && this._judgeEnableSelection(oShapeData, sClassId)) {
				this._oLastSelectedShape = oShapeData;
				this._onShapeDragStart(oEvent);
				//Needed for disabling default drag and drop behaviour in Firefox. This is not harmful to the behaviour in other browsers.
				oEvent.preventDefault();
			}
			this._iMouseDown++;
			this._setEventStatus("mouseDown");
		}
	};
	
	GanttChart.prototype._onSvgCtnMouseUp = function (event) {
		/* check if a dragging is happended, if yes, fireShapeDragEnd
		 * Otherwise check if a single click or a double click should happend
		 */
		if (event.button == 2){
			var param = this._composeParameterForClickPosition(event);
			this.fireChartRightClick({ 
				objectInfo: param.rowInfo,
				leadingRowInfo: param.leadingRowInfo,
				timestamp: param.startTime.getTime(),
				svgId: this.getId() + "-svg",
				svgCoordinate: param.svgPoint, 
				effectingMode: this.getMode(),
				originEvent: event
			});
		}else if (event.button == 0 && !this._bDragging && this._bMouseDown) {
			this._onSvgCtnClick(event);
		}
	};
	
	//event handler for single click on chart
	GanttChart.prototype._onSvgCtnClick = function (oEvent) {
		var oShapeData = d3.select(oEvent.target).data()[0];
		var sClassId;
		if (oEvent.target.getAttribute("class")){
			sClassId = oEvent.target.getAttribute("class").split(" ")[0];
		}
		var bSelectionChange = {};
		if (oShapeData !== undefined && this._judgeEnableSelection(oShapeData, sClassId) && this._oLastSelectedShape !== undefined && this._oLastSelectedShape.uid === oShapeData.uid) {
			bSelectionChange = this._selectionChange(oShapeData, oEvent.ctrlKey, oEvent.shiftKey, oEvent);
		}else if (this.getSelectionMode() === sap.gantt.SelectionMode.MultiWithKeyboard) {
			this._syncTTSelection(oEvent);
			this._oLastSelectedShape = undefined;
		}else {
			if (this._aSelectedShapeUids !== undefined && this._aSelectedShapeUids.length > 0) {
				this._oSelectedShapes = {};
				this._aSelectedShapeUids = [];
				bSelectionChange.shapeSelectionChange = true;
			}
			if (this._aSelectedRelationships.length > 0) {
				this._aSelectedRelationships = [];
				bSelectionChange.relationshipSelectionChange = true;
			}
			if (bSelectionChange.shapeSelectionChange || bSelectionChange.relationshipSelectionChange) {
				this._drawSelectedShapes();
			}
		}
		if (!oEvent.ctrlKey && !oEvent.shiftKey){
			var that = this;
			setTimeout(function () {
				if (that._iMouseDown > 1){
					var param = that._composeParameterForClickPosition(oEvent);
					that.fireChartDoubleClick({
						objectInfo: param.rowInfo,
						leadingRowInfo: param.leadingRowInfo,
						timestamp: param.startTime.getTime(),
						svgId: that.getId() + "-svg",
						svgCoordinate: param.svgPoint,
						effectingMode: that.getMode(),
						originEvent: oEvent
					});	
				}
				that._iMouseDown = 0;
				that._setEventStatus("mouseUp");
				this._oLastSelectedShape = undefined;
			}, 300);
		}else {
			this._iMouseDown = 0;
			this._setEventStatus("mouseUp");
			this._oLastSelectedShape = undefined;
		}
		
		if (bSelectionChange.shapeSelectionChange) {
			this.fireShapeSelectionChange({
				originEvent: oEvent
			});
		}
		if (bSelectionChange.relationshipSelectionChange) {
			this.fireRelationshipSelectionChange({
				originEvent: oEvent
			});
		}
	};

	GanttChart.prototype._onHSbScroll = function (oEvent) {
		var nScrollLeft = this._oTT._oHSb.getScrollPosition();
		this.updateLeftOffsetRate(nScrollLeft);
		this._draw(false);
		this.fireHorizontalScroll({
			scrollSteps: nScrollLeft,
			leftOffsetRate: this._fLeftOffsetRate
		});
	};
	
	GanttChart.prototype._onVSbScroll = function (oEvent) {
		this.fireVerticalScroll({
			scrollSteps: this._oTT._oVSb.getScrollPosition()
		});
		this._oTT.setFirstVisibleRow(this._oTT._oVSb.getScrollPosition() || 0, true);
	};

	GanttChart.prototype._hSbScrollLeft = function (nScrollPosition) {
		var $chartBodySvgCnt = jQuery("#" + this.getId() + "-svg-ctn");
		var $chartHeaderSvgCnt = jQuery("#" + this.getId() + "-header");
		var nScrollLeft;
		if (Core.getConfiguration().getRTL() === true) {
			//Header and Body should have same width. Use header to calculate the scroll position in RTL mode
			nScrollLeft = this._oStatusSet.aViewBoundary[1] - $chartHeaderSvgCnt.width() - nScrollPosition;
			if ( nScrollLeft < 0 ) {
				nScrollLeft = 0;
			}
		} else {
			nScrollLeft = nScrollPosition;
		}

		//scroll divs
		if (Core.getConfiguration().getRTL() === true && sap.ui.Device.browser.name === "ff") {
			$chartBodySvgCnt.scrollLeftRTL(nScrollLeft);
			$chartHeaderSvgCnt.scrollLeftRTL(nScrollLeft);
		} else {
			$chartBodySvgCnt.scrollLeft(nScrollLeft);
			$chartHeaderSvgCnt.scrollLeft(nScrollLeft);
		}

	};
	
	GanttChart.prototype.updateLeftOffsetRate = function(nPosition, nContentWidth) {
		//In RTL mode, treeTable use ui5 scrollbar control which wrap-ups the jQuery scrollLeft. The functions getScrollPosition() and setScrollPosition()
		//act same in 3 browsers: ie, ff, cr. The returned value of getScrollPosition() means the width of hidden DOM element at the right of scroll bar
		//Actually 3 browsers have different logic for scroll bar, UI5 scroll bar control wrap-ups the jQuery and make all act as same in ie.
		//To calculate the _fLeftOffsetRate, need to convert the returned value of getScrollPosition() to the width of hidden DOM element at the left of scroll bar 
		var nScrollWidth = nContentWidth ? nContentWidth : parseInt(this._oTT._oHSb.getContentSize(), 0);
		var nClientWidth = jQuery("#" + this.getId() + "-svg-ctn").width();
		if (nScrollWidth - nClientWidth !== 0) {
			if (Core.getConfiguration().getRTL() === true) {
				this._fLeftOffsetRate = (nScrollWidth - nPosition - nClientWidth) / (nScrollWidth - nClientWidth);
			} else {
				this._fLeftOffsetRate = nPosition / (nScrollWidth - nClientWidth);
			}
			this._fLeftOffsetRate = this._fLeftOffsetRate < 0 ? 0 : this._fLeftOffsetRate;
			this._fLeftOffsetRate = this._fLeftOffsetRate > 1 ? 1 : this._fLeftOffsetRate;
		}
		return this._fLeftOffsetRate;
	};

	GanttChart.prototype.jumpToPosition = function(value) {
		if (!isNaN(value) && !(value instanceof Date)) {
			// when input parameter "value" is float value which means left offset rate
			this._fLeftOffsetRate = value;
			this._draw(false);
			return;
		}
		
		var oDateToJump, nDatePosition;
		var nClientWidth = jQuery("#" + this.getId() + "-svg-ctn").width();
		if (!nClientWidth || nClientWidth <= 0) {
			return;
		}

		if (value instanceof Date) {
			// when value is Date format
			oDateToJump = value;
		} else {
			// when value is null or undefined
			var oTimeAxis = this.getTimeAxis();
			var oInitHorizon = oTimeAxis.getInitHorizon();
			if (!oInitHorizon || !oInitHorizon.getStartTime() || !oInitHorizon.getEndTime()) {
				return;
			}
			oDateToJump = Format.abapTimestampToDate(oInitHorizon.getStartTime());
			// need to adjust zoom rate for jumping to initHorizon
			var fSuitableScale = this._calZoomScale(
				Format.abapTimestampToDate(oInitHorizon.getStartTime()),
				Format.abapTimestampToDate(oInitHorizon.getEndTime()),
				nClientWidth);
			var fSuitableRate = this._oZoom.base.fScale / fSuitableScale;
			this.setTimeZoomRate(fSuitableRate);
		}
		
		var nContentWidth = this._nUpperRange - this._nLowerRange;
		if (!nContentWidth || nContentWidth <= 0) {
			return;
		}
		
		if (Core.getConfiguration().getRTL() === true){
			//Refer to the comments in updateLeftOffsetRate. Convert the the x value to nScrollLeft
			nDatePosition = nContentWidth - this._oAxisTime.timeToView(oDateToJump) - this._oAxisTime.getViewOffset();
			nDatePosition = nDatePosition < 0 ? 0 : nDatePosition;
		} else {
			nDatePosition = this._oAxisTime.timeToView(oDateToJump) + this._oAxisTime.getViewOffset();
		}

		this.updateLeftOffsetRate(nDatePosition, nContentWidth);
		this._draw(false);
	};

	GanttChart.prototype._onTTRowUpdate = function () {
		this._syncSvgHeightWithTT();
		this._syncSvgDataWithTT();
		this._prepareRelationshipDataFromModel();
		this._draw(true);
	};

	GanttChart.prototype._updateDataString = function () {
		var sShapeData = JSON.stringify(this._aShapeData, function(key, value) {
			if (key === "bindingObj" || key === "contextObj") {
				return undefined;
			}
			return value;
		});
		if (this._sShapeData && sShapeData === this._sShapeData) {
			this._sShapeData = sShapeData;
			return false;
		} else {
			this._sShapeData = sShapeData;
			return true;
		}
	};

	GanttChart.prototype._syncSvgHeightWithTT = function () {
		var $svg = this.$().find(".sapGanttChartSvgCtn");
		//var nRowNumber = this._oTT.getVisibleRowCount();
		$svg.height(this.$().find(".sapUiTableCCnt").height());
	};

	GanttChart.prototype._syncSvgDataWithTT = function () {
		var oBinding = this._oTT.getBinding("rows");
		var bJSONTreeBinding = oBinding.getMetadata().getName() === "sap.ui.model.json.JSONTreeBinding";
		
		var iFirstVisibleRow = this._oTT.getFirstVisibleRow();
		var iVisibleRowCount = this._oTT.getVisibleRowCount();
		
		// structured data for drawing by D3
		this._aShapeData = [];
		this._aNonVisibleShapeData = [];
		// temporary variables
		var _aTopNonVisibleShapeData = [];
		var _aBottomNonVisibleShapeData = [];
		// default visible range
		var aVisibleRange = [iFirstVisibleRow, iFirstVisibleRow + iVisibleRowCount - 1];

		if (bJSONTreeBinding) {
			aVisibleRange = this._prepareVerticalDrawingRange();
			
			oBinding.getContexts(0, 0);// get all contexts
			
			if (iFirstVisibleRow > 0) {
				_aTopNonVisibleShapeData = this._getDrawingData([0, iFirstVisibleRow - 1]);
			}
			_aBottomNonVisibleShapeData = this._getDrawingData([iFirstVisibleRow + iVisibleRowCount, oBinding.getLength() - 1]);
			
			oBinding.getContexts(aVisibleRange[0], aVisibleRange[1]);// get contexts of visible area
			
			this._aShapeData = this._getDrawingData(aVisibleRange);
		} else {
			if (this._aRelationshipsContexts && this._aRelationshipsContexts.length > 0){
				// oBinding.getContexts(0, 0) returns all contexts so we have to check whether iFirstVisibleRow is larger than 0
				if (iFirstVisibleRow > 0) {
					_aTopNonVisibleShapeData = this._createShapeDataFromRowContexts(oBinding.getContexts(0, iFirstVisibleRow));
				}
				_aBottomNonVisibleShapeData = this._createShapeDataFromRowContexts(oBinding.getContexts(iFirstVisibleRow + iVisibleRowCount, oBinding.getLength()));
			}
			
			// row contexts of the visible area
			// IMPORTANT: this must be called after getting the row contexts of non visible because Table._aRowIndexMap is refreshed every time when getContexts is called.
			var aRowContext = oBinding.getContexts(iFirstVisibleRow, iVisibleRowCount);
			this._aShapeData = this._createShapeDataFromRowContexts(aRowContext);
		}
		
		// merge _aTopNonVisibleShapeData with _aBottomNonVisibleShapeData
		this._aNonVisibleShapeData = _aTopNonVisibleShapeData.concat(_aBottomNonVisibleShapeData);
		
		// enhance row data
		var aShapeDataNames = this.getShapeDataNames();
		if (aShapeDataNames && aShapeDataNames.length > 0) {
			Utility.generateRowUid(this._aShapeData,this._oObjectTypesConfigMap, aShapeDataNames);	// +uid
			Utility.generateRowUid(this._aNonVisibleShapeData, this._oObjectTypesConfigMap, aShapeDataNames);	// +uid
			this._setSelectedStatusFromData(aShapeDataNames);
		} else {
			jQuery.sap.log.error("Missing configuration for shapeDataNames.");
		}
		var iBaseRowHeight = this.getBaseRowHeight();
		this._oAxisOrdinal = this._createAxisOrdinal(this._aShapeData, iBaseRowHeight,
				(aVisibleRange[0] - iFirstVisibleRow) * iBaseRowHeight);
		
		// this._replaceDataRef(); // replace ref --TODO: move this logic to app
		this._cacheObjectPosition(this._aShapeData, this._oAxisOrdinal);	// +y, +rowHeight
		this._cacheObjectPosition(_aTopNonVisibleShapeData, this._oAxisOrdinal, true);	// +y, +rowHeight
		this._cacheObjectPosition(_aBottomNonVisibleShapeData, this._oAxisOrdinal, false);	// +y, +rowHeight

		if (!this._aVisibleRange || this._aVisibleRange[0] !== aVisibleRange[0] || this._aVisibleRange[1] !== aVisibleRange[1]) {
			this._aVisibleRange = aVisibleRange;
			return true;
		}

		return false;
	};
	
	/*
	 * Creates shape data array for the given row contexts.
	 */
	GanttChart.prototype._createShapeDataFromRowContexts = function (aRowContexts) {
		var aShapeDataNames = this.getShapeDataNames();
		var oBinding = this._oTT.getBinding("rows");
		var oModel = oBinding.getModel();
		
		var aShapeData = [];
		
		for (var i = 0; i < aRowContexts.length; i++) {
			if (aRowContexts[i] != undefined) {
				for (var j = 0; j < aShapeDataNames.length; j++) {
					var sShapeName = aShapeDataNames[j];//e.g. 'Header'
					var aShapeDataPath = aRowContexts[i].getProperty(sShapeName);//e.g. ["HeaderDetail('0%20')","HeaderDetail('48%20')"]
					var oShapeData;
					if (aShapeDataPath) {
						for (var k = 0; k < aShapeDataPath.length; k++) {
							var sShapeDataPath = aShapeDataPath[k];
							oShapeData = oModel.getData("/" + sShapeDataPath);
							aShapeData.push({
								"bindingObj": oBinding,
								"contextObj": aRowContexts[i],
								"data": aRowContexts[i].getObject(),
								"shapeData": [oShapeData],
								"id": oShapeData.id,
								"shapeName": sShapeName,
								"rowIndex": i
							});
						}
					}
				}
			}
		}
		
		return aShapeData;
	};
	
	/*
	 * Calculate [rowHeight] and [y] property for each object based on a given axisY
	 * @param {object[]} objects Shape data array for whose entity we will add y and rowHeight properties to.
	 * @param {object} axisY AxisOrdinal object.
	 * @param {boolean} bAboveOrUnderVisibleArea Optional. Only used for drawing elements in the non visible area.
	 * 		if undefined, means the objects are in the visible area
	 * 		if true, means the objects are above the visible area, then y are -100
	 * 		if false, means the objects are under the visible area, then y are axisY.getViewRange()[1]+100
	 * @return undefined
	 */
	GanttChart.prototype._cacheObjectPosition = function (objects, axisY, bAboveVisibleArea) {
		if (objects && objects.length > 0) {
			if (bAboveVisibleArea === true) {
				for (var i = 0; i < objects.length; i++) {
					objects[i].y = -100;
					objects[i].rowHeight = axisY.getViewBandWidth();
				}
			} else if (bAboveVisibleArea === false) {
				for (var j = 0; j < objects.length; j++) {
					objects[j].y = axisY.getViewRange()[1] + 100;
					objects[j].rowHeight = axisY.getViewBandWidth();
				}
			} else {
				for (var k = 0; k < objects.length; k++) {
					objects[k].y = axisY.elementToView(objects[k].uid);

					if (k > 0) {
						objects[k - 1].rowHeight = objects[k].y - objects[k - 1].y;
					}
				}
				objects[objects.length - 1].rowHeight = axisY.getViewRange()[1] - objects[objects.length - 1].y;
			}
		}
	};
	
	/*
	 * Loop this._aRelationshipsContexts and call getObject method on each entity and then push the value into this._aRelationships
	 */
	GanttChart.prototype._prepareRelationshipDataFromModel = function () {
		this._aRelationships = [];
		if (this._aRelationshipsContexts) {
			for (var i = 0; i < this._aRelationshipsContexts.length; i++) {
				var oRelationship = this._aRelationshipsContexts[i].getObject();
				if (oRelationship !== undefined) {
					this._aRelationships.push(oRelationship);
				}
			}
		}
		Utility.generateUidByShapeDataName(this._aRelationships, "relationship"); // +uid for relationships
	};

	GanttChart.prototype._createAxisOrdinal = function (aShapeData, iBaseRowHeight, fShift) {
		var aRowNames = aShapeData.map(function (oRow) {
			return oRow.uid;
		});
		var aRowHeights = aShapeData.map(function (oRow) {
			if (oRow.rowSpan) {
				return oRow.rowSpan;
			} else {
				//For blank rows in hierarchy, just return 1, since there is no place to specify its rowSpan now...
				return 1;
			}
		});

		return new AxisOrdinal(aRowNames, aRowHeights, iBaseRowHeight, fShift);
	};

	GanttChart.prototype.getShapeData = function(aRange) {
		return this._aShapeData;
	};

	GanttChart.prototype._getDrawingData = function(aRange) {
		var i, j, k, oRow;
		var oBinding = this._oTT.getBinding("rows");
		var aRowList = [];
		for (i = aRange[0]; i <= aRange[1]; i++) {
			oRow = TreeTableHelper.getContextObject(this._oTT, i);
			if (!oRow) {
				continue;
			}
			if (TreeTableHelper.isDummyRow(this._oTT, i)
				&& ((aRowList.length > 0
				&& aRowList[aRowList.length - 1].chartScheme
				&& aRowList[aRowList.length - 1].chartScheme === oRow.__group
				&& aRowList[aRowList.length - 1].index === oRow.index) || oRow.chartScheme)) {
				continue;
			}
			if (oRow.__group) { // expanded row
				var sMode;
				if (this._oChartSchemesConfigMap[oRow.__group] && this._oChartSchemesConfigMap[oRow.__group].getModeKey() && this._oChartSchemesConfigMap[oRow.__group].getModeKey() !== sap.gantt.config.DEFAULT_MODE_KEY) {
					sMode = this._oChartSchemesConfigMap[oRow.__group].getModeKey();
				} else {
					sMode = this.getMode();
				}
				var oSchemeInfo = this._collectDataNameForValidChartScheme(oRow.__group, sMode);
				var oParent = oRow.parentData ? oRow.parentData : null;
				if (oRow.index && oParent && oSchemeInfo && oSchemeInfo.drawData) {
					for (j = 0; j < oSchemeInfo.drawData.length; j++) {
						if (!oParent[oSchemeInfo.drawData[j]]) {
							continue;
						}
						oRow[oSchemeInfo.drawData[j]] = [];
						for (k = 0; k < oParent[oSchemeInfo.drawData[j]].length; k++) {
							if (!oParent[oSchemeInfo.drawData[j]][k].rowIndex ||
								oRow.index === oParent[oSchemeInfo.drawData[j]][k].rowIndex) {
								oRow[oSchemeInfo.drawData[j]].push(oParent[oSchemeInfo.drawData[j]][k]);
							}
						}
					}
				}
				aRowList.push({
					"bindingObj": oBinding,
					"data": oRow,
					"id": oParent.id,
					"rowSpan": oSchemeInfo.rowSpan,
					"chartScheme": oRow.__group,
					"rowIndex": i,
					"index": oRow.index, // > 0
					"icon": this._oChartSchemesConfigMap[oRow.__group].getIcon(),
					"closeIcon": "./image/closeChart.png",
					"name": this._oChartSchemesConfigMap[oRow.__group].getName()
				});
			} else { // main row
				var rowSpan = 1;
				var sChartScheme = this._oObjectTypesConfigMap[oRow.type] ?
					this._oObjectTypesConfigMap[oRow.type].getMainChartSchemeKey() :
					sap.gantt.config.DEFAULT_CHART_SCHEME_KEY;
				if (oRow.type) {
					var oChartScheme = this._oChartSchemesConfigMap[sChartScheme];
					if (oChartScheme) {
						rowSpan = oChartScheme.getRowSpan();
					}
				}
				aRowList.push({
					"bindingObj": oBinding,
					"contextObj": this._oTT.getContextByIndex(i),
					"data": oRow,
					"id": oRow.id,
					"rowSpan": rowSpan,
					"chartScheme": sChartScheme,
					"rowIndex": i,
					"index": 0
				});
			}
		}
		return aRowList;
	};

	GanttChart.prototype._prepareVerticalDrawingRange = function() {
		var nLastBindingRow = this._oTT.getBinding("rows").getLength() - 1;
		if (nLastBindingRow < 0) {
			return [0, -1];
		}
		var nFirstVisibleRow = this._oTT.getFirstVisibleRow();
		var nLastVisibleRow = nFirstVisibleRow + this._oTT.getVisibleRowCount() - 1;
		var nFirstDrawingRow = nFirstVisibleRow;
		var nLastDrawingRow = nLastVisibleRow < nLastBindingRow ? nLastVisibleRow : nLastBindingRow;
		var i, nGroup, nGroupIndex, oRow;
		for (i = nFirstVisibleRow; i >= 0; i--) {
			if (!TreeTableHelper.isDummyRow(this._oTT, i)) {
				break;
			}
			oRow = TreeTableHelper.getContextObject(this._oTT, i);
			if (oRow && oRow.previousNodeNum) {
				nFirstDrawingRow = i - oRow.previousNodeNum;
				continue;
			}
			if (!oRow || !oRow.index || oRow.index < 0) {
				break;
			}			
			if (!nGroupIndex) {
				nGroup = oRow.__group;
				nGroupIndex = oRow.index;
			} else if (nGroup === oRow.__group && nGroupIndex === oRow.index) {
				nFirstDrawingRow = i;
			} else {
				break;
			}
		}
		nGroupIndex = undefined;
		for (i = nLastVisibleRow; i <= nLastBindingRow; i++) {
			oRow = TreeTableHelper.getContextObject(this._oTT, i);
			if (oRow && oRow.afterNodeNum) {
				nLastDrawingRow = i + oRow.afterNodeNum;
				continue;
			}
			if (!TreeTableHelper.isDummyRow(this._oTT, i)) {
				break;
			}			
			if (!oRow || !oRow.index || oRow.index < 0) {
				break;
			}			
			if (!nGroupIndex) {
				nGroup = oRow.__group;
				nGroupIndex = oRow.index;
			} else if (nGroup === oRow.__group && nGroupIndex === oRow.index) {
				nLastDrawingRow = i;
			} else {
				break;
			}
		}
		return [nFirstDrawingRow, nLastDrawingRow];
	};

	GanttChart.prototype._prepareHorizontalDrawingRange = function () {
		//oStatusSet must keep the value of LTR mode because other functions use it
		var nContentWidth = this._nUpperRange - this._nLowerRange;
		var nClientWidth = jQuery("#" + this.getId() + "-svg-ctn").width();

		if (!this._oStatusSet) {
			this._updateScrollWidth();
		}
		
		var nScrollLeft = Math.ceil((this._fLeftOffsetRate ? this._fLeftOffsetRate : 0) * (nContentWidth - nClientWidth));
		if (this._oStatusSet) {
			if ((nClientWidth >= nContentWidth || (this._oStatusSet.aViewBoundary[0] <= nScrollLeft - this._oStatusSet.nOffset &&
				this._oStatusSet.aViewBoundary[1] >= nScrollLeft + nClientWidth - this._oStatusSet.nOffset))) {
				if (!this._mTimeouts._drawSvg) {
					this._scrollSvg();
				}

				return false;
			}
		}

		var nWidth = nClientWidth * (1 + this._fExtendFactor * 2);
		var nOffset = nScrollLeft - nClientWidth * this._fExtendFactor;
		if (nOffset < this._nLowerRange) {
			nWidth += nOffset;
			nOffset = 0;
		}
		if (nOffset + nWidth > this._nUpperRange) {
			nWidth = this._nUpperRange - nOffset;
		}

		this._oAxisTime.setViewOffset(nOffset);
		this._oStatusSet = {
				nWidth: nWidth,
				nOffset: nOffset,
				nScrollLeft: nScrollLeft,
				aViewBoundary: [0, nWidth],
				aTimeBoundary: [this._oAxisTime.viewToTime(0), this._oAxisTime.viewToTime(nWidth)],
				bRTL: Core.getConfiguration().getRTL()
		};

		return true;
	};

	GanttChart.prototype._draw = function (bForced) {
		if (!this._prepareHorizontalDrawingRange() && !bForced) {
			return;
		}
		
		var that = this;
		this._mTimeouts._drawSvg = this._mTimeouts._drawSvg || window.setTimeout(function() {
			that._drawSvg();
			that._mDrawDelayMS = 0;
		}, this._mDrawDelayMS);
	};

	GanttChart.prototype._updateScrollWidth = function () {
		var nMaxScrollWidth = 100000;
		var nContentWidth = this._nUpperRange - this._nLowerRange;
		var nScrollWidth = nContentWidth > nMaxScrollWidth ? nMaxScrollWidth : nContentWidth;
		if (nScrollWidth + "px" !== this._oTT._oHSb.getContentSize()) {
			this._oTT._oHSb.setContentSize(nScrollWidth + "px").bind(this._oTT.getDomRef());
		}
	};

	GanttChart.prototype._updateScrollLeft = function () {
		var nScrollWidth = parseInt(this._oTT._oHSb.getContentSize(), 0);
		var nClientWidth = jQuery("#" + this.getId() + "-svg-ctn").width();
		var nScrollLeft = Math.ceil((this._fLeftOffsetRate ? this._fLeftOffsetRate : 0) * (nScrollWidth - nClientWidth)); 
		if (Core.getConfiguration().getRTL() === true) {
			nScrollLeft = nScrollWidth - nScrollLeft - nClientWidth;
		}
		if (Math.abs(this._oTT._oHSb.getScrollPosition() - nScrollLeft) > 1) {
			this._oTT._oHSb.setScrollPosition(nScrollLeft);
		}
};

	GanttChart.prototype._scrollSvg = function () {
		var $svg = jQuery("#" + this.getId() + "-svg");
		var $header = jQuery("#" + this.getId() + "-header-svg");
		if (this._oStatusSet.nWidth !== $svg.width()) {
			$svg.width(this._oStatusSet.nWidth);
		}
		if (this._oStatusSet.nWidth !== $header.width()) {
			$header.width(this._oStatusSet.nWidth);
		}
		var nContentWidth = this._nUpperRange - this._nLowerRange;
		var nClientWidth = jQuery("#" + this.getId() + "-svg-ctn").width();
		var nScrollLeft = Math.ceil((this._fLeftOffsetRate ? this._fLeftOffsetRate : 0) * (nContentWidth - nClientWidth));
		this._hSbScrollLeft(nScrollLeft - this._oStatusSet.nOffset);
};

	GanttChart.prototype._drawSvg = function () {
		jQuery.sap.measure.start("GanttChart _drawSvg","GanttPerf:GanttChart _drawSvg function");
		
		// before draw
		this._updateScrollLeft();
		this._scrollSvg();
		this._sUiSizeMode = Utility.findSapUiSizeClass(this);
		
		// draw
		this._drawCalendarPattern();
		this._drawHeader();
		this._drawNowLine();
		this._drawVerticalLine();
		this._drawShapes();
		this._drawSelectedShapes();

		// after draw
		this.fireEvent("_shapesUpdated", {aSvg: jQuery("#" + this.getId() + "-svg")});
		this._updateCSSForDummyRow();
		delete this._mTimeouts._drawSvg;
		
		jQuery.sap.measure.end("GanttChart _drawSvg");
	};
	
	GanttChart.prototype._drawHeader = function () {
		var $headerDom = jQuery(this.getDomRef()).find(".sapGanttChartHeader");
		var nSvgHeight = $headerDom.height();

		var oHeaderSvg = d3.select(jQuery(this.getDomRef()).find(".sapGanttChartHeaderSvg").get(0));
		oHeaderSvg.attr("height", nSvgHeight);

		// Split the total SVG height as 5 parts for drawing 
		// label0 (MM YYYY), label1 (DD) and vertical line (|)
		var nfirstRowYOffset = nSvgHeight / 5 * 2;
		var nMiddleLineYOffset = nSvgHeight / 5 * 4;
		var nSecondRowYOffset = nSvgHeight / 5 * 4;

		var aLabelList = this.getAxisTime().getTickTimeIntervalLabel(
				this.getAxisTime().getCurrentTickTimeIntervalKey(), null, [0, this._oStatusSet.nWidth]);

		// append group
		oHeaderSvg.selectAll("g").remove();
		var oGroupSvg = oHeaderSvg.append("g");

		// append text for labels on first row
		oGroupSvg.selectAll("label0")
			.data(aLabelList[0])
			.enter()
			.append("text")
			.classed("sapGanttTimeHeaderSvgText0", true)
			.text(function (d) {
				return d.label;
			}).attr("x", function (d) {
				return d.value;
			}).attr("y", function (d) {
				return nfirstRowYOffset;
			});

		// append text for labels on second row
		oGroupSvg.selectAll("label1")
			.data(aLabelList[1])
			.enter()
			.append("text")
			.classed("sapGanttTimeHeaderSvgText1", true)
			.text(function (d) {
				return d.label;
			}).attr("x", function (d) {
				// 5px spacing for the text
				return d.value + (Core.getConfiguration().getRTL() ? -5 : 5);
			}).attr("y", function (d) {
				return nSecondRowYOffset;
			});

		// append path for scales on both rows
		var sPathData = "";
		for (var i = 0; i < aLabelList[1].length; i++) {
			var oLabel = aLabelList[1][i];
			if (oLabel) {
				sPathData +=
					" M" +
					" " + (oLabel.value - 1 / 2) +
					" " + nMiddleLineYOffset +
					" L" +
					" " + (oLabel.value - 1 / 2 ) +
					" " + nSvgHeight;
			}
		}

		oGroupSvg.append("path").classed("sapGanttTimeHeaderSvgPath", true).attr("d", sPathData);
	};
	
	GanttChart.prototype._drawCalendarPattern = function () {
		var $GanttChartSvg = d3.select("#" + this.getId() + "-svg");
		this._oCalendarPatternDrawer.drawSvg($GanttChartSvg, this.getId(), this.getCalendarDef(), this._oStatusSet, this.getBaseRowHeight());
	};
	
	GanttChart.prototype._drawNowLine = function () {
		this._oNowlineDrawer  = new NowLineDrawer(this._oAxisTime);

		var $GanttChartHeader = d3.select("#" + this.getId() + "-header-svg"),
			$GanttChartSvg = d3.select("#" + this.getId() + "-svg");
		
		if (this.getEnableNowLine()) {
			this._oNowlineDrawer.drawSvg($GanttChartSvg, $GanttChartHeader);
		} else {
			this._oNowlineDrawer.destroySvg($GanttChartSvg, $GanttChartHeader);
		}
	};

	GanttChart.prototype._drawVerticalLine = function() {
		this._oVerticalLineDrawer = new VerticalLineDrawer(this.getAxisTime());
		var $GanttChartSvg = d3.select("#" + this.getId() + "-svg");
		if (this.getEnableVerticalLine()) {
			this._oVerticalLineDrawer.drawSvg($GanttChartSvg);
		} else {
			this._oVerticalLineDrawer.destroySvg($GanttChartSvg);
		}
	};
	
	GanttChart.prototype._drawShapes = function () {
		var aSvg = d3.select("#" + this.getId() + "-svg");
		
		if (!this._oTT || !this._oTT.getRows() || this._oTT.getRows().length <= 0) {
			return;
		}
		
		// draw shape
		if (this._aShapeData && this._aShapeInstance && this._aShapeInstance.length > 0) {

			this._collectDataPerShapeId();
			var relationshipDataSet = [];
			
			for (var i = 0; i < this._aShapeInstance.length; i++) {
				switch (this._aShapeInstance[i].getCategory(null, this._oAxisTime, this._oAxisOrdinal)) {
					case sap.gantt.shape.ShapeCategory.InRowShape:
						this._oShapeInRowDrawer.drawSvg(aSvg, this._aShapeInstance[i],
							this._oAxisTime, this._oAxisOrdinal, this._oStatusSet);
						break;
					case sap.gantt.shape.ShapeCategory.Relationship:
						if (this._judgeDisplayableOfRLS(this._aShapeInstance[i])) {
							relationshipDataSet = this._oShapeCrossRowDrawer.generateRelationshipDataSet(aSvg, this._oShapeInstance, this._aNonVisibleShapeData,
									this.getShapeDataNames(), this._aRelationships, this._oAxisTime, this._oAxisOrdinal);
						}
						this._aShapeInstance[i].dataSet = relationshipDataSet;
						this._oShapeCrossRowDrawer.drawSvg(aSvg, this._aShapeInstance[i],
								this._oAxisTime, this._oAxisOrdinal);
						break;
					default:
						break;
				}
			}
		}
	};
	
	//draw all the selected shapes and relationships
	GanttChart.prototype._drawSelectedShapes = function () {
		if (!this._oTT || !this._oTT.getRows() || this._oTT.getRows().length <= 0) {
			return;
		}
		
		var aSvg = d3.select("#" + this.getId() + "-svg");
		
		//set selected Status for Shapes and relationships
		this._setSelectedStatusToData();
		// draw selected shape
		this._collectSelectedDataPerShapeId();
		for (var sShapeId in this._oShapeInstance) {
			var oSelectedClassIns = this._oShapeInstance[sShapeId].getAggregation("selectedShape");
			var category = oSelectedClassIns.getCategory(null, this._oAxisTime, this._oAxisOrdinal);
			switch (category) {
			case sap.gantt.shape.ShapeCategory.InRowShape:
				this._oShapeInRowDrawer.drawSvg(aSvg, oSelectedClassIns, this._oAxisTime, this._oAxisrdinal, this._oStatusSet);
				break;
			case sap.gantt.shape.ShapeCategory.Relationship:
				var relationshipDataSet = this._oShapeCrossRowDrawer.generateRelationshipDataSet(aSvg, this._oShapeInstance, this._aNonVisibleShapeData,
						this.getShapeDataNames(), this._aSelectedRelationships, this._oAxisTime, this._oAxisOrdinal);
				oSelectedClassIns.dataSet =  relationshipDataSet;
				this._oShapeCrossRowDrawer.drawSvg(aSvg, oSelectedClassIns,
						this._oAxisTime, this._oAxisOrdinal);
				break;
			default:
				break;
			}
		}
	};
	
	/*
	 * This method collect data according to current row's configuration/objectType/shape/chart scheme/mode.
	 * this._aShapeData contains the data for all different shapes so here we need to pick up by sShapeName
	 * once is function finished execution, each instance of shape classes will have 'dataset' attribute
	 * and it is an array of the data picked up from this._aShapeData for drawing that shape.
	 */
	GanttChart.prototype._collectDataPerShapeId = function () {
		var bJSONTreeBinding = (this._oTT.getBinding("rows").getMetadata().getName() === "sap.ui.model.json.JSONTreeBinding");
		var oRowData, oShapeData;
		//this._oShapeInstance is an object which has properties with format as below:
		//property key is the data name for shapes such as 'header'
		//property value is the instance of shape classes such as sap.gantt.shape.Rectangle
		//so the structure of this._oShapeInstance is like
		//{
		//	'header': <instance of sap.gantt.shape.ext.Chevron>
		//	'task': <sap.gantt.shape.Rectangle>
		//}
		for (var sShapeId in this._oShapeInstance) {
			var sShapeName = this._oShapeInstance[sShapeId].mShapeConfig.getShapeDataName();//e.g. Header
			this._oShapeInstance[sShapeId].dataSet = [];

			for (var i = 0; i < this._aShapeData.length; i++) {
				//this._aShapeData contains the data for all different shapes so here we need to pick up by sShapeName
				oRowData = this._aShapeData[i];
				if (oRowData.isBlank) {
					continue;
				}
				//if user doesn't configure the shape with 'shapeDataName', add all row data to the shape
				if (!sShapeName) {
					this._oShapeInstance[sShapeId].dataSet.push({
						"objectInfoRef": oRowData,
						"shapeData": oRowData.data
					});
					continue;
				}

				if (!this._judgeDisplayableByShapeId(oRowData, sShapeId)) {
					continue;
				}
				if (bJSONTreeBinding){
					oShapeData = oRowData.data[sShapeName];
				}else if (sShapeName == oRowData.shapeName) {
						oShapeData = [oRowData.data];
				}else {
					continue;
				}
				if (oShapeData){
					this._oShapeInstance[sShapeId].dataSet.push({
						"objectInfoRef": oRowData,
						"shapeData": oShapeData
					});
				}
			}
		}
	};

	GanttChart.prototype._collectSelectedDataPerShapeId = function () {
		//group the selected shape data into the dataSet of related selectedClass instance
		for (var sShapeId in this._oShapeInstance) {
			var sShapeDataName = this._oShapeInstance[sShapeId].mShapeConfig.getShapeDataName();//e.g. Header
			var oSelectedClassIns = this._oShapeInstance[sShapeId].getAggregation("selectedShape");
			var sCategory = oSelectedClassIns.getCategory(null, this._oAxisTime, this._oAxisOrdinal);
			//collect shape data for every selectedClass instance according to current selection
			oSelectedClassIns.dataSet = [];
			if (sCategory == sap.gantt.shape.ShapeCategory.Relationship) {
				var aShapeData = [];
				for (var j in this._aSelectedRelationships) {
					var oRelationshipData = this._aSelectedRelationships[j];
					//only when the relationship is display, it needs to be drew
					if (this._getShapeDataById(oRelationshipData.id, true) !== undefined) {
						aShapeData.push(oRelationshipData);
					}
				}
				oSelectedClassIns.dataSet.push({
					"shapeData": aShapeData
				});
			}else if (this._oSelectedShapes[sShapeDataName] !== undefined) {
				for (var i in this._oSelectedShapes[sShapeDataName]) {
					var oShape = this._oSelectedShapes[sShapeDataName][i];
					//only when the master shape is displayed, draw the selectedShape
					var oRowData = this._getRowByShapeUid(oShape.shapeUid);
					if (oRowData !== undefined && oRowData !== null && this._judgeDisplayableByShapeId(oRowData, sShapeId)){
						oShape.objectInfoRef = oRowData;
						oSelectedClassIns.dataSet.push({
							"objectInfoRef": oShape.objectInfoRef,
							"shapeData": [oShape.shapeData]
						});
					}
				}
			}
		}
	};
	
	GanttChart.prototype._judgeDisplayableByShapeId = function (oRowData, sShapeId) {
		var  sChartScheme, oChartScheme, aShapeIdsInChartScheme, sMode;
		if (oRowData.data.__group) {
			sChartScheme = oRowData.data.__group;
		} else {
			sChartScheme = this._oObjectTypesConfigMap[oRowData.data.type] ?
					this._oObjectTypesConfigMap[oRowData.data.type].getMainChartSchemeKey() :
					sap.gantt.config.DEFAULT_CHART_SCHEME_KEY;
		}
		oChartScheme = this._oChartSchemesConfigMap[sChartScheme];
		if (oChartScheme == undefined) {
			return false;
		}
		aShapeIdsInChartScheme = oChartScheme.getShapeKeys();
		/*
		 * determin mode. if mode is coded against chart scheme, it over-write current mode in chart
		 */
		sMode = oChartScheme.getModeKey() !== sap.gantt.config.DEFAULT_MODE_KEY ?
				oChartScheme.getModeKey() :
				this.getMode();
		//sMode = oChartScheme.getModeKey() ? oChartScheme.getModeKey() : this.getMode();
		/*
		 * check if shape should appear in current chart scheme and mode
		 */
		if (sChartScheme !== sap.gantt.config.DEFAULT_CHART_SCHEME_KEY &&
				aShapeIdsInChartScheme.indexOf(sShapeId) < 0 ||
				sMode !== sap.gantt.config.DEFAULT_MODE_KEY &&
				this._oShapesConfigMap[sShapeId].getModeKeys() &&
				this._oShapesConfigMap[sShapeId].getModeKeys().length > 0 &&
				this._oShapesConfigMap[sShapeId].getModeKeys().indexOf(sMode) < 0 ||
				!oRowData.data) {
			return false;
		}
		return true;
	};
	
	GanttChart.prototype._judgeDisplayableOfRLS = function (oShape) {

		var aShapeMode = this._oShapesConfigMap[oShape.mShapeConfig.getKey()] ? 
				this._oShapesConfigMap[oShape.mShapeConfig.getKey()].getModeKeys() : [];
		if (jQuery.inArray(this.getMode(), aShapeMode) < 0 && this.getMode() !== sap.gantt.config.DEFAULT_MODE_KEY) {
			return false;
		}
		return true;
	};
	
	//get shapeId by shape uid and related row data uid
	GanttChart.prototype._getShapeDataNameByUid = function (sShapeUid) {
		//var rowData;
		var sShapeDataName;
		if (sShapeUid !== undefined) {
			var str = "|DATA:";
			if (sShapeUid.split(str)[1]) {
				sShapeDataName = sShapeUid.split(str)[1].split("[")[0];
			}else {
				sShapeDataName = sap.gantt.shape.ShapeCategory.Relationship;
			}
		}
		return sShapeDataName;
	};
	
	//get Uid by id
	GanttChart.prototype._getUidById = function (sId, bRelationship) {
		var sUid = [];
		if (bRelationship) {
			for (var i in this._aRelationships) {
				var oRelationship = this._aRelationships[i];
				if (oRelationship.id == sId) {
					sUid.push(oRelationship.uid);
					break;
				}
			}	
		}else {
			jQuery.each(this._aShapeData, function (k, v) {
				var rowInfo = v;
				for (var sShape in rowInfo.data) {
					if (rowInfo.data[sShape] instanceof Array) {
						for (var i in rowInfo.data[sShape]) {
							//a shape can appear in different rows, so one id may have several uids
							if (rowInfo.data[sShape][i].id == sId) {
								sUid.push(rowInfo.data[sShape][i].uid);
							}
						}
					}
				}
			});
		}
		
		return sUid;
	};
	
	//get shapeData by uid
	GanttChart.prototype._getShapeDataByUid = function (sUid, bRelationship) {
		if (bRelationship) {// if it is a relationship
			for (var i in this._aRelationships) {
				var oRelationship = this._aRelationships[i];
				if (oRelationship.uid === sUid) {
					return oRelationship;
				}
			}
		}else {
			var rowInfo = this._getRowByShapeUid(sUid);
			var sShapeDataName = this._getShapeDataNameByUid(sUid);
			if (rowInfo !== undefined && rowInfo.data[sShapeDataName] !== undefined) {
				for ( var j = 0; j < rowInfo.data[sShapeDataName].length; j++) {
					var oShapeData = rowInfo.data[sShapeDataName][j];
					if (oShapeData.uid == sUid) {
						return oShapeData;
					}
				}
			}
		}
		return undefined;
	};
	
	/*
	 * get shapeData by id
	 * @para 
	 * @para
	 * @return an array as there may be multiple uids for a same id, as the shape can appear more than once
	 */
	GanttChart.prototype._getShapeDataById = function (sId, bRelationship) {
		var aShapeData = [];
		var aUids = this._getUidById(sId, bRelationship);
		for (var i in aUids) {
			var oShapeData = this._getShapeDataByUid(aUids[i], bRelationship);
			if (oShapeData !== undefined) {
				aShapeData.push(oShapeData);
			}
		}
		return aShapeData;
	};
	
	//get row obj by shape uid
	//one shape(has an uid as unique key) may appear more then once in different rows, the uid includes row information
	GanttChart.prototype._getRowByShapeUid = function (sShapeUid) {
		var rowData;
		var sShapeDataName = this._getShapeDataNameByUid(sShapeUid);
		var bJSONTreeBinding = (this._oTT.getBinding("rows").getMetadata().getName() === "sap.ui.model.json.JSONTreeBinding");
		jQuery.each(this._aShapeData, function (k, v) {
			var rowInfo = v;
			if (bJSONTreeBinding && rowInfo.data[sShapeDataName]) {
				for ( var i = 0; i < rowInfo.data[sShapeDataName].length; i++) {
					if (rowInfo.data[sShapeDataName][i].uid == sShapeUid) {
						rowData = rowInfo;
						return false;
					}
				}
			}else if (rowInfo.data.uid === sShapeUid) {
				rowData = rowInfo;
				return false;
			}
		});
		return rowData;
	};
	
	//get row by row id
	GanttChart.prototype._getRowById = function (sRowId) {
		var rowData;
		jQuery.each(this._aShapeData, function (k, v) {
			var rowInfo = v;
			if (rowInfo.data.id == sRowId) {
				rowData = rowInfo;
				return false;
			}
		});
		return rowData;
	};
	
	GanttChart.prototype._getSvgCoodinateByDiv = function(oNode, x, y){
		var oClickPoint = oNode.createSVGPoint();
			oClickPoint.x = x;
			oClickPoint.y = y;
			oClickPoint = oClickPoint.matrixTransform(oNode.getScreenCTM().inverse());
			oClickPoint.svgHeight = oNode.height.baseVal.value;
			oClickPoint.svgId = this.getId() + "-svg";
		
		return oClickPoint;
	};
	
	GanttChart.prototype._getTopShapeInstance = function (oShapeData, sClassId) {
		if (sClassId !== undefined) {
			var oShapeId = this._getShapeIdById(sClassId);
			if (oShapeId !== undefined && oShapeId !== null) {
				if (oShapeId.topShapeId !== undefined) {
					return this._oShapeInstance[oShapeId.topShapeId];
				}else {
					return this._oShapeInstance[oShapeId.shapeId];
				}
			}
		}else {
			var sShapeDataName = this._getShapeDataNameByUid(oShapeData.uid);
			for (var sShapeId in this._oShapeInstance) {
				var sShapeName = this._oShapeInstance[sShapeId].mShapeConfig.getShapeDataName();//e.g. Header
				if (sShapeDataName === sShapeName){
					var sTopShapeId = this._customerClassIds[sShapeId].topShapeId;
					if (sTopShapeId !== undefined) {
						return this._oShapeInstance[sTopShapeId];
					}else {
						return this._oShapeInstance[sShapeId];
					}
				}
			}
		}
		return undefined;
	};
	
	//judge if the shape is selectable
	GanttChart.prototype._judgeEnableSelection = function (oShapeData, sClassId) {	
		if (oShapeData === undefined) {
			return false;
		}
		var oTopShapeInstance = this._getTopShapeInstance(oShapeData, sClassId);
		if (oTopShapeInstance !== undefined) {
			return oTopShapeInstance.getEnableSelection(oShapeData);
		}
		return false;
	};
	
	GanttChart.prototype._judgeEnableDnDByUid = function (sShapeUid) {
		if (sShapeUid === undefined || sShapeUid == null) {
			return false;
		}
		var oShapeData;
		if (this._isRelationship(sShapeUid)) {
			oShapeData = this._getShapeDataByUid(sShapeUid, true);
		}else {
			oShapeData = this._getShapeDataByUid(sShapeUid, false);
		}
		return this._judgeEnableDnD(oShapeData);
	};
	
	GanttChart.prototype._judgeEnableDnD = function (oShapeData, sClassId) {
		if (oShapeData === undefined) {
			return false;
		}
		var oTopShapeInstance = this._getTopShapeInstance(oShapeData, sClassId);
		if (oTopShapeInstance !== undefined) {
			return oTopShapeInstance.getEnableDnD(oShapeData);
		}
		return false;
	};
	
	/*select shape by adding current selecting shape into the shape selection
	 * The structure of aSelectedShapes: {"ShapeDataName1": e.g. all selected activities, "ShapeDataName2": e.g. all selected tasks...--- arrays with a struture of {"shapeUid": "shapeData", "objectInfoRef"}
	 */
	GanttChart.prototype._selectShape = function (oShapeData) {
		var oRowInfo = this._getRowByShapeUid(oShapeData.uid);
		if (oRowInfo == undefined) {
			return false;
		}
		if (this._aSelectedShapeUids === undefined) {
			this._aSelectedShapeUids = [];
		}
		var sShapeDataName = this._getShapeDataNameByUid(oShapeData.uid);
		if (this._oSelectedShapes[sShapeDataName] !== undefined && this._oSelectedShapes[sShapeDataName] !== null ) {
			var aShapes = this._oSelectedShapes[sShapeDataName];
			if (jQuery.inArray(oShapeData.uid, this._aSelectedShapeUids) > -1) { //if the shape is already in selection
				return false;
			}else {
				this._aSelectedShapeUids.push(oShapeData.uid);
				aShapes.push({"shapeUid": oShapeData.uid, "shapeData": oShapeData, "objectInfoRef": oRowInfo});
				return true;
			}
		}else {
			this._aSelectedShapeUids.push(oShapeData.uid);
			this._oSelectedShapes[sShapeDataName] = [];
			this._oSelectedShapes[sShapeDataName].push({"shapeUid": oShapeData.uid, "shapeData": oShapeData, "objectInfoRef": oRowInfo});
			return true;
		}
	};

	// deselect current shape by remove it from the collection of selected shapes
	GanttChart.prototype._deselectShape = function (oShapeData) {
		var sShapeDataName = this._getShapeDataNameByUid(oShapeData.uid);
		if (jQuery.inArray(oShapeData.uid, this._aSelectedShapeUids) > -1) {
			var iIndex = this._aSelectedShapeUids.indexOf(oShapeData.uid);
			this._aSelectedShapeUids.splice(iIndex,1);
			var aShapes = this._oSelectedShapes[sShapeDataName];
			for (var i in aShapes) {
				if (aShapes[i].shapeUid === oShapeData.uid) {
					aShapes.splice(i,1);
					break;
				}
			}
			return true;
		}
		
		return false;
	};
	
	GanttChart.prototype._updateCSSForDummyRow = function() {
		var aRows = this._oTT.getRows();
		var aRowHeaders = this._oTT.$().find(".sapUiTableRowHdrScr").children();
		for (var i = 0; i < aRows.length; i++){
			var oRow = aRows[i];
			var index = oRow.getIndex();
			
			if (index !== -1 && TreeTableHelper.isMultipleSpanMainRow(this._oTT, i)){
				var context = TreeTableHelper.getContextObject(this._oTT, index);
				if (context.afterNodeNum > 0){
					aRows[i].$().addClass("sapGanttTrNoBorder");
					$(aRowHeaders[i]).addClass("sapGanttTHeaderNoBorder");
				} else {
					aRows[i].$().removeClass("sapGanttTrNoBorder");
					$(aRowHeaders[i]).removeClass("sapGanttTHeaderNoBorder");
				}
			} else {
				aRows[i].$().removeClass("sapGanttTrNoBorder");
				$(aRowHeaders[i]).removeClass("sapGanttTHeaderNoBorder");
			}
		}
	};
	
	GanttChart.prototype.getAxisOrdinal = function () {
		return this._oAxisOrdinal;
	};
	
	GanttChart.prototype.getAxisTime = function () {
		return this._oAxisTime;
	};
	
	GanttChart.prototype.ondblclick = function (oEvent) {
		return null;
	};
	
	GanttChart.prototype.onclick = function (oEvent) {
		return null;
	};
	
	GanttChart.prototype.getSapUiSizeClass = function () {
		return this._sUiSizeMode;
	};
	
	GanttChart.prototype.exit = function () {
		// TODO: destroy axis time and ordinal after refactor to listener pattern.
		// other children are all strong aggregation relations, no need to destroy.
		this._detachEvents();
	};

	return GanttChart;
}, true);
<file_sep>/*!
 * SAP APF Analysis Path Framework
 * 
 * (c) Copyright 2012-2014 SAP AG. All rights reserved
 */
jQuery.sap.declare("sap.apf.core.sessionHandler");
jQuery.sap.require("sap.apf.core.ajax");
jQuery.sap.require("sap.apf.utils.filter");
jQuery.sap.require("sap.apf.core.constants");

(function() {
	'use strict';
	/**
	 * @class Handles the session of an APF based application. e.g. the XSRF token handling
	 */
	/*global setTimeout*/
	sap.apf.core.SessionHandler = function(oInject) {
		// private vars
		var that = this;
		var dirtyState = false;
		var pathName = '';
		var sXsrfToken = "";
		var sServiceRootPath = "";
		var oHashTableXsrfToken = new sap.apf.utils.Hashtable(oInject.messageHandler);
		var nFetchTryCounter = 0;
		var oCoreApi = oInject.coreApi;
		var oMessageHandler = oInject.messageHandler;

		// private functions
		var onError = function(oJqXHR, sStatus, sErrorThrown) {
			if ((sXsrfToken.length === 0 || sXsrfToken === "unsafe") && nFetchTryCounter < 2) {
				setTimeout(that.fetchXcsrfToken, 500 + Math.random() * 1500);
			} else {
				oMessageHandler.check(false, "No XSRF Token available!", 5101);
			}
		};
		var onFetchXsrfTokenResponse = function(oData, sStatus, oXMLHttpRequest) {
			sXsrfToken = oXMLHttpRequest.getResponseHeader("x-csrf-token");
			/*
			* In case XSRF prevention flag is not set in .xsaccess file for the service, then no "x-csrf-token" field is returned in response header. 
			 * For robustness, XSRF token is set to empty string. Every request triggered by APF contains then a "x-csrf-token" request header field containing an empty string. 
			 */
			if (sXsrfToken === null) {
				sXsrfToken = "";
			} else if ((sXsrfToken.length === 0 || sXsrfToken === "unsafe") && nFetchTryCounter < 2) {
				setTimeout(that.fetchXcsrfToken, 500 + Math.random() * 1500);
			}
		};
		
		// public vars
		/**
		 * @description Returns the type
		 * @returns {String}
		 */
		this.type = "sessionHandler";
		// public function
		/**
		 * @see sap.apf.core.ajax
		 */
		this.ajax = function(oSettings) {
			sap.apf.core.ajax(oSettings);
		};
		/**
		 * @description Returns the XSRF token as string for a given OData service root path
		 * @param {String} serviceRootPath OData service root path
		 * @returns {String}
		 */
		this.getXsrfToken = function(serviceRootPath) {
			sServiceRootPath = serviceRootPath;
			if (oHashTableXsrfToken.hasItem(sServiceRootPath)) {
				return oHashTableXsrfToken.getItem(sServiceRootPath);
			}
			that.fetchXcsrfToken();
			oHashTableXsrfToken.setItem(sServiceRootPath, sXsrfToken);
			return sXsrfToken;
		};

		/**
		 * @description fetches XSRF token from XSE
		 */
		this.fetchXcsrfToken = function() {
			that.ajax({
				url : oCoreApi.getUriGenerator().getAbsolutePath(sServiceRootPath),
				type : "GET",
				beforeSend : function(xhr) {
					xhr.setRequestHeader("x-csrf-token", "Fetch");
				},
				success : onFetchXsrfTokenResponse,
				error : onError,
				async : false
			});
			nFetchTryCounter = nFetchTryCounter + 1;
		};
        /**
         * @private
         * @name sap.apf.core.SessionHandler#setDirtyState
         * @function
         * @description Stores the current state for dirty information
         * @param {boolean} state 
         */ 		
		this.setDirtyState = function(state) {
		    dirtyState = state;
		};
		/**
		 * @private
		 * @name sap.apf.core.SessionHandler#isDirty
		 * @function
		 * @description Returns the last set state for the dirty information
		 * @returns {boolean} true: State of current instance is dirty | false: State of current instance is clean
		 */		
		this.isDirty = function() {
		    return dirtyState;
		};
		/**
		 * @private
		 * @name sap.apf.core.SessionHandler#setPathNamee
		 * @function
		 * @description Set name is stored transiently. For persistent storage the methods of persistence object need to be used.
		 * @param {string} name 
		 */ 		
		this.setPathName = function(name) {
		    if(typeof name != 'string') {
		        pathName = '';
		        return;
		    }
		    pathName = name;
		};
        /**
         * @private
         * @name sap.apf.core.SessionHandler#getPathNamee
         * @function
         * @description Returns the last set path name
         * @returns {string} path name
         */ 		
		this.getPathName = function() {
		    return pathName;
		};
	};
}());