whole_func_string: function(text, options) {
  			// prepare defaults
  			var utils = require('utils');
  			var placeholders = {carets: ''};
  			var marks = [];
  			
  			options = _.extend({}, defaultOptions, options, {
  				tabstop: function(data) {
  					var token = data.token;
  					var ret = '';
  					if (data.placeholder == 'cursor') {
  						marks.push({
  							start: data.start,
  							end: data.start + token.length,
  							group: 'carets',
  							value: ''
  						});
  					} else {
  						// unify placeholder value for single group
  						if ('placeholder' in data)
  							placeholders[data.group] = data.placeholder;
  						
  						if (data.group in placeholders)
  							ret = placeholders[data.group];
  						
  						marks.push({
  							start: data.start,
  							end: data.start + token.length,
  							group: data.group,
  							value: ret
  						});
  					}
  					
  					return token;
  				}
  			});
  			
  			if (options.replaceCarets) {
  				text = text.replace(new RegExp( utils.escapeForRegexp( utils.getCaretPlaceholder() ), 'g'), '${0:cursor}');
  			}
  			
  			// locate tabstops and unify group's placeholders
  			text = this.processText(text, options);
  			
  			// now, replace all tabstops with placeholders
  			var buf = utils.stringBuilder(), lastIx = 0;
  			var tabStops = _.map(marks, function(mark) {
  				buf.append(text.substring(lastIx, mark.start));
  				
  				var pos = buf.length;
  				var ph = placeholders[mark.group] || '';
  				
  				buf.append(ph);
  				lastIx = mark.end;
  				
  				return {
  					group: mark.group,
  					start: pos,
  					end:  pos + ph.length
  				};
  			});
  			
  			buf.append(text.substring(lastIx));
  			
  			return {
  				text: buf.toString(),
  				tabstops: _.sortBy(tabStops, 'start')
  			};
  		}
func_code_string: function(text, options) {
  			// prepare defaults
  			var utils = require('utils');
  			var placeholders = {carets: ''};
  			var marks = [];
  			
  			options = _.extend({}, defaultOptions, options, {
  				tabstop: function(data) {
  					var token = data.token;
  					var ret = '';
  					if (data.placeholder == 'cursor') {
  						marks.push({
  							start: data.start,
  							end: data.start + token.length,
  							group: 'carets',
  							value: ''
  						});
  					} else {
  						// unify placeholder value for single group
  						if ('placeholder' in data)
  							placeholders[data.group] = data.placeholder;
  						
  						if (data.group in placeholders)
  							ret = placeholders[data.group];
  						
  						marks.push({
  							start: data.start,
  							end: data.start + token.length,
  							group: data.group,
  							value: ret
  						});
  					}
  					
  					return token;
  				}
  			});
  			
  			if (options.replaceCarets) {
  				text = text.replace(new RegExp( utils.escapeForRegexp( utils.getCaretPlaceholder() ), 'g'), '${0:cursor}');
  			}
  			
  			// locate tabstops and unify group's placeholders
  			text = this.processText(text, options);
  			
  			// now, replace all tabstops with placeholders
  			var buf = utils.stringBuilder(), lastIx = 0;
  			var tabStops = _.map(marks, function(mark) {
  				buf.append(text.substring(lastIx, mark.start));
  				
  				var pos = buf.length;
  				var ph = placeholders[mark.group] || '';
  				
  				buf.append(ph);
  				lastIx = mark.end;
  				
  				return {
  					group: mark.group,
  					start: pos,
  					end:  pos + ph.length
  				};
  			});
  			
  			buf.append(text.substring(lastIx));
  			
  			return {
  				text: buf.toString(),
  				tabstops: _.sortBy(tabStops, 'start')
  			};
  		}
func_documentation_string: Main function that looks for a tabstops in provided <code>text</code>
  and returns a processed version of <code>text</code> with expanded
  placeholders and list of tabstops found.
  @param {String} text Text to process
  @param {Object} options List of processor options:<br>
  
  <b>replaceCarets</b> : <code>Boolean</code> — replace all default
  caret placeholders (like <i>{%::emmet-caret::%}</i>) with <i>${0:caret}</i><br>
  
  <b>escape</b> : <code>Function</code> — function that handle escaped
  characters (mostly '$'). By default, it returns the character itself
  to be displayed as is in output, but sometimes you will use
  <code>extract</code> method as intermediate solution for further
  processing and want to keep character escaped. Thus, you should override
  <code>escape</code> method to return escaped symbol (e.g. '\\$')<br>
  
  <b>tabstop</b> : <code>Function</code> – a tabstop handler. Receives
  a single argument – an object describing token: its position, number
  group, placeholder and token itself. Should return a replacement
  string that will appear in final output
  
  <b>variable</b> : <code>Function</code> – variable handler. Receives
  a single argument – an object describing token: its position, name
  and original token itself. Should return a replacement
  string that will appear in final output
  
  @returns {Object} Object with processed <code>text</code> property
  and array of <code>tabstops</code> found
  @memberOf tabStops