text:
! Copyright 2005-2017 ECMWF.
!
! This software is licensed under the terms of the Apache Licence Version 2.0
! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
!
! In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
! virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
!
!
!
!  Description: how to get PV values.
!
!
!
program get_pv
  use eccodes
  implicit none
  integer                         :: infile
  integer                         :: igrib
  integer                         :: PVPresent, nb_pv
  real, dimension(:), allocatable :: pv

  call codes_open_file(infile, &
       '../../data/reduced_gaussian_model_level.grib1','r')

  ! A new grib message is loaded from file
  ! igrib is the grib id to be used in subsequent calls
  call codes_grib_new_from_file(infile,igrib)

  ! Get PVPresent to see if the 'pv' array is there
  call codes_get(igrib,'PVPresent',PVPresent)
  print*, "PVPresent = ", PVPresent
  if (PVPresent == 1) then
    call codes_get_size(igrib,'pv',nb_pv)
    print*, "There are ", nb_pv, " PV values"
    allocate(pv(nb_pv))
    call codes_get(igrib,'pv',pv)
    print*, "pv = ", pv
    deallocate(pv)
  else
    print*, "There is no PV values in your GRIB message!"
  end if
  call codes_release(igrib)

  call codes_close_file(infile)

end program get_pv


text:
/**
 * Add an empty master_style to Config object's prototype
 *  the format is { '.className' : 'Description' }
 */

Xinha.Config.prototype.master_style = { };

/**
 * This method loads an external stylesheet and uses it in the ryu_master_styles
 *
 * @param string URL to the stylesheet
 * @param hash Alternate descriptive names for your classes
 *              { '.fooclass': 'Foo Description' }
 * @param bool If set true then @import rules in the stylesheet are skipped,
 *   otherwise they will be incorporated if possible.
 */

// we need some way to get reference back from RYU Dialog
var RYU = RYU || {};
	RYU.RYUMasterStyles = RYU.RYUMasterStyles || {};
Xinha.prototype.ryu_load_master_css = function() {
/***	OLD CONFIRM BOX METHOD	***
	// clear stored data
	for (var k in this.config.master_style) {
		delete this.config.master_style[k];
	}
	var url = prompt(Xinha._lc("Import stylesheet (in /css)","RYUMasterStyles"),RYU.config.importStyles);
  	if (url) {
  		document.getElementById('show_css_file').innerHTML=url;
  		if (url=="thisissue.css") {
  			document.getElementById('edition0').checked;
  		} else {	// port into Output Dialog
  			document.getElementById('edition1').checked=true;
  			document.getElementById('customFile').style.display="table-cell";
  			document.getElementById('editionName').value = url;
  		}
		url = _editor_url + "../../css/"+url
		this.config.ryu_master_stylesLoadStylesheet(url);
		this.addEditorStylesheet(url,1);
		this._fillRYUMasterStyles();
  	}
****	END OLD METHOD ***** */
	RYU.RYUMasterStyles = this;
	RYU.toggleDialog('import_master_styles',1);
		if (RYU.config.xfileman==1) {
			// refresh file list
			document.getElementById('file_list').src="ryuzinewriter/php/scandir.php";
			setTimeout(function(){
				var styles = document.getElementById('file_list').contentWindow.styles;
				var stylebox = '<select id="chooser5">';
				for (var s=0; s < styles.length; s++) {
					stylebox += '<option>'+styles[s]+'</option>';
				}
				stylebox += '</select>';
				document.getElementById('file_chooser5').innerHTML = stylebox;},300);
		}
}

Xinha.prototype.ryu_import_master_css = function() {
	for (var k in this.config.master_style) {
		delete this.config.master_style[k];
	}
	var url = document.getElementById('chooser5').value;
  		document.getElementById('show_css_file').innerHTML=url;
  		if (url=="thisissue.css") {
  			document.getElementById('edition0').checked;
  		} else {	// port into Output Dialog
  			document.getElementById('edition1').checked=true;
  			document.getElementById('customFile').style.display="table-cell";
  			document.getElementById('editionName').value = url;
  		}
		url = _editor_url + "../../css/"+url
		this.config.ryu_master_stylesLoadStylesheet(url);
		this.addEditorStylesheet(url,1);
		this._fillRYUMasterStyles();
}

Xinha.prototype.addEditorStylesheet = function(url,target) {
	if (url==null) { url = "";}
	if (target==null || target==0) { target = 'custom_css';} else { target = 'master_styles'; }
	var ryu_editor = document.getElementById('XinhaIFrame_inputBox').contentWindow.document;
	if (!ryu_editor.getElementById(''+target+'')) {
		var link = document.createElement("link");
			link.setAttribute('rel','stylesheet');
			link.setAttribute('type','text/css');
			link.setAttribute('href',url);
			link.id=''+target+'';
		ryu_editor.getElementsByTagName('head')[0].appendChild(link);
	}
	ryu_editor.getElementById(''+target+'').href=url;
}

Xinha.Config.prototype.ryu_master_stylesLoadStylesheet = function(url, altnames, skip_imports)
{
  console.log('Loading Stylesheet: '+url);

  if(!altnames) altnames = { };
  var newStyles = Xinha.ripMasterStylesFromCSSFile(url, skip_imports);
  for(var i in newStyles)
  {
    if(altnames[i])
    {
      this.master_style[i] = altnames[i];
    }
    else
    {
      this.master_style[i] = newStyles[i];
    }
  }
 /*
  for(var x = 0; x < this.pageStyleSheets.length; x++)
  {
    if(this.pageStyleSheets[x] == url) return;
  }
  this.pageStyleSheets[this.pageStyleSheets.length] = url;
*/
};

/**
 * This method takes raw style definitions and uses them in the ryu_master_styles
 *
 * @param string CSS
 *
 * @param hash Alternate descriptive names for your classes
 *              { '.fooclass': 'Foo Description' }
 *
 * @param bool If set true then @import rules in the stylesheet are skipped,
 *   otherwise they will be incorporated if possible.
 *
 * @param string If skip_imports is false, this string should contain
 *   the "URL" of the stylesheet these styles came from (doesn't matter
 *   if it exists or not), it is used when resolving relative URLs etc.
 *   If not provided, it defaults to Xinha.css in the Xinha root.
 */

Xinha.prototype.updatePanel = function() {
	this.onUpdateToolbar();
}

Xinha.Config.prototype.ryu_master_stylesLoadStyles = function(styles, altnames, skip_imports, imports_relative_to)
{
console.log('Load Styles');
  if(!altnames) altnames = { };
  var newStyles = Xinha.ripStylesFromCSSString(styles, skip_imports);
  for(var i in newStyles)
  {
    if(altnames[i])
    {
      this.master_style[i] = altnames[i];
    }
    else
    {
      this.master_style[i] = newStyles[i];
    }
  }
  this.pageStyle += styles;
};

/**
 * Fill the ryu_master_styles panel with styles that may be applied to the current selection.  Styles
 * are supplied in the master_style property of the Xinha.Config object, which is in the format
 * { '.className' : 'Description' }
 * classes that are defined on a specific tag (eg 'a.email_link') are only shown in the panel
 *    when an element of that type is selected.
 * classes that are defined with selectors/psuedoclasses (eg 'a.email_link:hover') are never
 *    shown (if you have an 'a.email_link' without the pseudoclass it will be shown of course)
 * multiple classes (eg 'a.email_link.staff_member') are shown as a single class, and applied
 *    to the element as multiple classes (class="email_link staff_member")
 * you may click a class name in the ryu_master_styles panel to add it, and click again to remove it
 * you may add multiple classes to any element
 * spans will be added where no single _and_entire_ element is selected
 */
Xinha.prototype._fillRYUMasterStyles = function()
{
console.log('fill RYU Master Styles');
  if(!this.plugins.RYUMasterStyles.instance.dialog) return false;
  var main = this.plugins.RYUMasterStyles.instance.dialog.main.getElementsByTagName('div')[0];
  main.innerHTML = '';
  var ulist = document.createElement('ul');
//  var ulist = main.getElementsByTagName('ul')[0];
//  var items = ulist.getElementsByTagName('li');
  var may_apply = true;
  var sel       = this._getSelection();

console.log('sel='+sel);
  // What is applied
//   var applied = this._getAncestorsClassNames(this._getSelection());

  // Get an active element
  var active_elem = this._activeElement(sel);

  for(var x in this.config.master_style)
  {
    var tag   = null;
    var className = x.trim();
    var applicable = true;
    var apply_to   = active_elem;

    if(applicable && /[^a-zA-Z0-9_.-]/.test(className))
    {
      applicable = false; // Only basic classes are accepted, no selectors, etc.. presumed
                          // that if you have a.foo:visited you'll also have a.foo
      // alert('complex');
    }

    if(className.indexOf('.') < 0)
    {
      // No class name, just redefines a tag
      applicable = false;
    }

    if(applicable && (className.indexOf('.') > 0))
    {
      // requires specific html tag
      tag = className.substring(0, className.indexOf('.')).toLowerCase();
      className = className.substring(className.indexOf('.'), className.length);

      // To apply we must have an ancestor tag that is the right type
      if(active_elem != null && active_elem.tagName.toLowerCase() == tag)
      {
        applicable = true;
        apply_to = active_elem;
      }
      else
      {
        if(this._getFirstAncestor(this._getSelection(), [tag]) != null)
        {
          applicable = true;
          apply_to = this._getFirstAncestor(this._getSelection(), [tag]);
        }
        else
        {
          // alert (this._getFirstAncestor(this._getSelection(), tag));
          // If we don't have an ancestor, but it's a div/span/p/hx stle, we can make one
          if(( tag == 'div' || tag == 'span' || tag == 'p'
              || (tag.substr(0,1) == 'h' && tag.length == 2 && tag != 'hr')))
          {
            if(!this._selectionEmpty(this._getSelection()))
            {
              applicable = true;
              apply_to = 'new';
            }
            else
            {
              // See if we can get a paragraph or header that can be converted
              apply_to = this._getFirstAncestor(sel, ['p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7']);
              if(apply_to != null)
              {
                applicable = true;
              }
              else
              {
                applicable = false;
              }
            }
          }
          else
          {
            applicable = false;
          }
        }
      }
    }

    if(applicable)
    {
      // Remove the first .
      className = className.substring(className.indexOf('.'), className.length);

      // Replace any futher ones with spaces (for multiple class definitions)
      className = className.replace('.', ' ');

      if(apply_to == null)
      {
        if(this._selectionEmpty(this._getSelection()))
        {
          // Get the previous element and apply to that
          apply_to = this._getFirstAncestor(this._getSelection(), null);
        }
        else
        {
          apply_to = 'new';
          tag      = 'span';
        }
      }
    }

    var applied    = (this._ancestorsWithClasses(sel, tag, className).length > 0 ? true : false);
    var applied_to = this._ancestorsWithClasses(sel, tag, className);
/*
	for(var q=0; q < items.length; q++) {	// only add to list if not already there
		if (items[q].innerHTML == ''+this.config.master_style[x]+'') {
			applicable=false;
		}
	}
*/
			if(applicable)
			{
			  var anch = document.createElement('li');
			  anch.onfocus = function () { this.blur() } // prevent dotted line around link that causes horizontal scrollbar
			  anch._ryu_master_styles_className = className.trim();
			  anch._ryu_master_styles_applied   = applied;
			  anch._ryu_master_styles_appliedTo = applied_to;
			  anch._ryu_master_styles_applyTo = apply_to;
			  anch._ryu_master_styles_applyTag = tag;

			  anch.innerHTML = ''+this.config.master_style[x]+'';
		//    anch.href = 'javascript:void(0)';
			  var editor = this;
			  anch.ondblclick = function()
			  {
				if(this._ryu_master_styles_applied == true)
				{
				  editor._ryu_master_stylesRemoveClasses(this._ryu_master_styles_className, this._ryu_master_styles_appliedTo);
				}
				else
				{
				  editor._ryu_master_stylesAddClasses(this._ryu_master_styles_applyTo, this._ryu_master_styles_applyTag, this._ryu_master_styles_className);
				}
				return false;
			  }

		/*
			(Let us handle this in css like we are supposed to)
			  anch.style.display = 'block';
			  anch.style.paddingLeft = '3px';
			  anch.style.paddingTop = '1px';
			  anch.style.paddingBottom = '1px';
			  anch.style.textDecoration = 'none';
		*/
			  if(applied)
			  {
		//        anch.style.background = 'Highlight';
		//        anch.style.color = 'HighlightText';
				  anch.className="selected";
			  }
		//      anch.style.position = 'relative';
				ulist.appendChild(anch);
			}

  }

  main.appendChild(ulist);

};

/**
 * Add the given classes (space seperated list) to the currently selected element
 * (will add a span if none selected)
 */
Xinha.prototype._ryu_master_stylesAddClasses = function(el, tag, classes)
  {
  console.log('element: '+el);
  console.log('tag: '+tag);
  console.log('classes: '+classes);
    if(el == 'new')
    {
      this.insertHTML('<' + tag + ' class="' + classes + '">' + this.getSelectedHTML() + '</' + tag + '>');
    }
    else
    {
      if(tag != null && el.tagName.toLowerCase() != tag)
      {
        // Have to change the tag!
        var new_el = this.switchElementTag(el, tag);

        if(typeof el._ryu_master_styles_usedToBe != 'undefined')
        {
          new_el._ryu_master_styles_usedToBe = el._ryu_master_styles_usedToBe;
          new_el._ryu_master_styles_usedToBe[new_el._ryu_master_styles_usedToBe.length] = {'tagName' : el.tagName, 'className' : el.getAttribute('class')};
        }
        else
        {
          new_el._ryu_master_styles_usedToBe = [{'tagName' : el.tagName, 'className' : el.getAttribute('class')}];
        }

        Xinha.addClasses(new_el, classes);
      }
      else
      {
        Xinha._addClasses(el, classes);
      }
    }
    this.focusEditor();
    this.updateToolbar();
  };

/**
 * Remove the given classes (space seperated list) from the given elements (array of elements)
 */
Xinha.prototype._ryu_master_stylesRemoveClasses = function(classes, from)
  {
    for(var x = 0; x < from.length; x++)
    {
      this._ryu_master_stylesRemoveClassesFull(from[x], classes);
    }
    this.focusEditor();
    this.updateToolbar();
  };

Xinha.prototype._ryu_master_stylesRemoveClassesFull = function(el, classes)
{
  if(el != null)
  {
    var thiers = el.className.trim().split(' ');
    var new_thiers = [ ];
    var ours   = classes.split(' ');
    for(var x = 0; x < thiers.length; x++)
    {
      var exists = false;
      for(var i = 0; exists == false && i < ours.length; i++)
      {
        if(ours[i] == thiers[x])
        {
          exists = true;
        }
      }
      if(exists == false)
      {
        new_thiers[new_thiers.length] = thiers[x];
      }
    }

    if(new_thiers.length == 0 && el._ryu_master_styles_usedToBe && el._ryu_master_styles_usedToBe.length > 0 && el._ryu_master_styles_usedToBe[el._ryu_master_styles_usedToBe.length - 1].className != null)
    {
      // Revert back to what we were IF the classes are identical
      var last_el = el._ryu_master_styles_usedToBe[el._ryu_master_styles_usedToBe.length - 1];
      var last_classes = Xinha.arrayFilter(last_el.className.trim().split(' '), function(c) { if (c == null || c.trim() == '') { return false;} return true; });

      if(
        (new_thiers.length == 0)
        ||
        (
        Xinha.arrayContainsArray(new_thiers, last_classes)
        && Xinha.arrayContainsArray(last_classes, new_thiers)
        )
      )
      {
        el = this.switchElementTag(el, last_el.tagName);
        new_thiers = last_classes;
      }
      else
      {
        // We can't rely on the remembered tags any more
        el._ryu_master_styles_usedToBe = [ ];
      }
    }

    if(     new_thiers.length > 0
        ||  el.tagName.toLowerCase() != 'span'
        || (el.id && el.id != '')
      )
    {
      el.className = new_thiers.join(' ').trim();
    }
    else
    {
      // Must be a span with no classes and no id, so we can splice it out
      var prnt = el.parentNode;
      var tmp;
      while (el.hasChildNodes())
      {
        if (el.firstChild.nodeType == 1)
        {
          // if el.firstChild is an element, we've got to recurse to make sure classes are
          // removed from it and and any of its children.
          this._ryu_master_stylesRemoveClassesFull(el.firstChild, classes);
        }
        tmp = el.removeChild(el.firstChild);
        prnt.insertBefore(tmp, el);
      }
      prnt.removeChild(el);
    }
  }
};

/**
 * Change the tag of an element
 */
Xinha.prototype.switchElementTag = function(el, tag)
{
  var prnt = el.parentNode;
  var new_el = this._doc.createElement(tag);

  if(Xinha.is_ie || el.hasAttribute('id'))    new_el.setAttribute('id', el.getAttribute('id'));
  if(Xinha.is_ie || el.hasAttribute('style')) new_el.setAttribute('style', el.getAttribute('style'));

  var childs = el.childNodes;
  for(var x = 0; x < childs.length; x++)
  {
    new_el.appendChild(childs[x].cloneNode(true));
  }

  prnt.insertBefore(new_el, el);
  new_el._ryu_master_styles_usedToBe = [el.tagName];
  prnt.removeChild(el);
  this.selectNodeContents(new_el);
  return new_el;
};

Xinha.prototype._getAncestorsClassNames = function(sel)
{
  // Scan upwards to find a block level element that we can change or apply to
  var prnt = this._activeElement(sel);
  if(prnt == null)
  {
    prnt = (Xinha.is_ie ? this._createRange(sel).parentElement() : this._createRange(sel).commonAncestorContainer);
  }

  var classNames = [ ];
  while(prnt)
  {
    if(prnt.nodeType == 1)
    {
      var classes = prnt.className.trim().split(' ');
      for(var x = 0; x < classes.length; x++)
      {
        classNames[classNames.length] = classes[x];
      }

      if(prnt.tagName.toLowerCase() == 'body') break;
      if(prnt.tagName.toLowerCase() == 'table'  ) break;
    }
      prnt = prnt.parentNode;
  }

  return classNames;
};

Xinha.prototype._ancestorsWithClasses = function(sel, tag, classes)
{
  var ancestors = [ ];
  var prnt = this._activeElement(sel);
  if(prnt == null)
  {
    try
    {
      prnt = (Xinha.is_ie ? this._createRange(sel).parentElement() : this._createRange(sel).commonAncestorContainer);
    }
    catch(e)
    {
      return ancestors;
    }
  }
  var search_classes = classes.trim().split(' ');

  while(prnt)
  {
    if(prnt.nodeType == 1 && prnt.className)
    {
      if(tag == null || prnt.tagName.toLowerCase() == tag)
      {
        var classes = prnt.className.trim().split(' ');
        var found_all = true;
        for(var i = 0; i < search_classes.length; i++)
        {
          var found_class = false;
          for(var x = 0; x < classes.length; x++)
          {
            if(search_classes[i] == classes[x])
            {
              found_class = true;
              break;
            }
          }

          if(!found_class)
          {
            found_all = false;
            break;
          }
        }

        if(found_all) ancestors[ancestors.length] = prnt;
      }
      if(prnt.tagName.toLowerCase() == 'body')    break;
      if(prnt.tagName.toLowerCase() == 'table'  ) break;
    }
    prnt = prnt.parentNode;
  }
  return ancestors;
};

Xinha.ripMasterStylesFromCSSFile = function(URL, skip_imports)
{
  console.log('ripMasterStylesFromCSSFile');
  var css = Xinha._geturlcontent(URL);

  return Xinha.ripMasterStylesFromCSSString(css, skip_imports, URL);
};

Xinha.ripMasterStylesFromCSSString = function(css, skip_imports, imports_relative_to)
{
  console.log('ripMasterStylesFromCSSString');
  if(!skip_imports)
  {
    if(!imports_relative_to)
    {
      imports_relative_to = _editor_url + 'Xinha.css'
    }

    var seen = { };

    function resolve_imports(css, url)
    {
      seen[url] = true; // protects against infinite recursion

      var RE_atimport = '@import\\s*(url\\()?["\'](.*)["\'].*';
      var imports = css.match(new RegExp(RE_atimport,'ig'));
      var m, file, re = new RegExp(RE_atimport,'i');

      if (imports)
      {
        var path = url.replace(/\?.*$/,'').split("/");
        path.pop();
        path = path.join('/');
        for (var i=0;i<imports.length;i++)
        {
          m = imports[i].match(re);
          file = m[2];
          if (!file.match(/^([^:]+\:)?\//))
          {
            file = Xinha._resolveRelativeUrl(path,file);
          }

          if(seen[file]) continue;

          css += resolve_imports(Xinha._geturlcontent(file), file);
        }
      }

      return css;
    }

    css = resolve_imports(css, imports_relative_to);
  }

  // We are only interested in the selectors, the rules are not important
  //  so we'll drop out all coments and rules
  var RE_comment = /\/\*(.|\r|\n)*?\*\//g;
  var RE_rule    = /\{(.|\r|\n)*?\}/g;

  css = css.replace(RE_rule, ',');
  css = css.replace(RE_comment, '');

  // And split on commas
  css = css.split(',');

  // And add those into our structure
  var selectors = { };
  for(var x = 0; x < css.length; x++)
  {
    if(css[x].trim())
    {
      selectors[css[x].trim()] = css[x].trim();
    }
  }

  return selectors;
};

// Make our right side panel and insert appropriatly
function RYUMasterStyles(editor, args)
{
  this.editor = editor;

  var ryu_master_styles = this;

}

RYUMasterStyles._pluginInfo =
{
  name     : "RYUMasterStyles",
  version  : "1.0",
/*
  Adapted from Stylist plugin to be consistent
  with other Ryuzine Writer webapp plugins.

  Modified so as not to conflict if the original
  plugin is also activated.  Targets left-panel
  instead of right, panel title changed.

  Original Developer Info
  developer: "James Sleeman",
  developer_url: "http://www.gogo.co.nz/",
  c_owner      : "Gogo Internet Services",
  license      : "HTMLArea",
  sponsor      : "Gogo Internet Services",
  sponsor_url  : "http://www.gogo.co.nz/"
*/
};

RYUMasterStyles.prototype.onGenerateOnce = function()
{
  var cfg = this.editor.config;
  if(typeof cfg.master_style != 'undefined' && Xinha.objectProperties(cfg.master_style).length != 0)
  {
    this._prepareDialog();
  }

};
RYUMasterStyles.prototype._prepareDialog = function()
{
  var editor = this.editor;
  var ryu_master_styles = this;

  var html = '
<l10n>Master Styles</l10n>
';

  this.dialog = new Xinha.Dialog(editor, html, 'RYUMasterStyles',{width:200},{modal:false,closable:false});
	Xinha._addClass( this.dialog.rootElem, 'RYUMasterStyles' );
	this.dialog.attachToPanel('right');
  this.dialog.show();

	var dialog = this.dialog;
	var main = this.dialog.main;
	var caption = this.dialog.captionBar;

  main.style.overflow = "auto";
  main.setAttribute('id','ryu_master_styles_list');
  main.className="main";
//main.style.height = this.editor._framework.ed_cell.offsetHeight - caption.offsetHeight + 'px';
  main.style.height = "";

	var adj = document.createElement('div');
		adj.className="adjustable";
	main.appendChild(adj);

  	var ctrls = document.createElement('div');
  		ctrls.className="panel_controls";
//  var ulist = document.createElement('ul');
//  main.appendChild(ulist);

	var loadCSS = document.createElement('div');
		loadCSS.className='panel_button left openfile';
		loadCSS.id = 'load_master_styles_button';
		loadCSS.title=Xinha._lc("Load Stylesheet","RYUMasterStyles");
		loadCSS.onclick=function(){
			editor.ryu_load_master_css();
		}
	ctrls.appendChild(loadCSS);
	var showFile = document.createElement('p');
		showFile.innerHTML = '';
	ctrls.appendChild(showFile);

	main.appendChild(ctrls);

  editor.notifyOn('modechange',
  function(e,args)
  {
    if (!dialog.attached)
    {
      return;
    }
    switch(args.mode)
    {
      case 'text':
      {
        dialog.hide();
        break;
      }
      case 'wysiwyg':
      {
        dialog.show();
        break;
      }
    }
  }
  );
  editor.notifyOn('panel_change',
  function(e,args)
  {
    if (!dialog.attached)
    {
      return;
    }
    switch (args.action)
    {
      case 'show':
      var newHeight = main.offsetHeight - args.panel.offsetHeight;
      main.style.height = ((newHeight > 0) ?  main.offsetHeight - args.panel.offsetHeight : 0) + 'px';
      dialog.rootElem.style.height = caption.offsetHeight + "px";
      editor.sizeEditor();
      break;
      case 'hide':
      ryu_master_styles.resize();
      break;
    }
  }
  );
  editor.notifyOn('before_resize',
  function()
  {
    if (!dialog.attached)
    {
      return;
    }
    dialog.rootElem.style.height = caption.offsetHeight + "px";
  }
  );
  editor.notifyOn('resize',
  function()
  {
    if (!dialog.attached)
    {
      return;
    }
    ryu_master_styles.resize();
  }
  );
}
RYUMasterStyles.prototype.resize = function()
{
  var editor = this.editor;
  EDITOR = editor;	// global reference (sux but what else can I do?)
  var rootElem = this.dialog.rootElem;

  if (rootElem.style.display == 'none') return;

  var panelContainer = rootElem.parentNode;

  var newSize = panelContainer.offsetHeight;
  for (var i=0; i < panelContainer.childNodes.length;++i)
  {
    if (panelContainer.childNodes[i] == rootElem || !panelContainer.childNodes[i].offsetHeight)
    {
      continue;
    }
    newSize -= panelContainer.childNodes[i].offsetHeight;
  }
  rootElem.style.height = newSize-5 + 'px';
  this.dialog.main.style.height = newSize - this.dialog.captionBar.offsetHeight -5 + 'px';
}

RYUMasterStyles.prototype.onUpdateToolbar = function()
{
  if(this.dialog)
  {
    if(this._timeoutID)
    {
      window.clearTimeout(this._timeoutID);
    }
	console.log('onUpdateToolbar');
    var e = this.editor;
    this._timeoutID = window.setTimeout(function() { e._fillRYUMasterStyles(); }, 250);
  }
};

redpajama_set_name: RedPajamaGithub


text:
<?xml version="1.0" encoding="UTF-8"?>

<!--
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->

<xwikidoc>
  <web>GitlabMacro</web>
  <name>GitlabMacroConfigurationSheet</name>
  <language/>
  <defaultLanguage/>
  <translation>0</translation>
  <parent>GitlabMacro.GitlabMacroConfigurationClass</parent>
  <creator>xwiki:XWiki.Admin</creator>
  <author>xwiki:XWiki.Admin</author>
  <customClass/>
  <contentAuthor>xwiki:XWiki.Admin</contentAuthor>
  <creationDate>1407392567000</creationDate>
  <date>1407392567000</date>
  <contentUpdateDate>1407392567000</contentUpdateDate>
  <version>1.1</version>
  <title>#if($doc.name == 'GitlabMacroConfigurationSheet')GitlabMacroConfiguration Sheet#{else}$services.display.title($doc, {'displayerHint': 'default'})#end</title>
  <defaultTemplate/>
  <validationScript/>
  <comment/>
  <minorEdit>false</minorEdit>
  <syntaxId>xwiki/2.1</syntaxId>
  <hidden>true</hidden>
  <content>{{velocity}}
## You can modify this page to customize the presentation of your object.
## At first you should keep the default presentation and just save the document.

#set($class = $doc.getObject('GitlabMacro.GitlabMacroConfigurationClass').xWikiClass)
#foreach($prop in $class.properties)
  ; $prop.prettyName
  : $doc.display($prop.getName())
#end
{{/velocity}}</content>
</xwikidoc>


text:
			<input id="search-ajax" type="search" placeholder="Search...">
			<button></button>


text:
package mysql

type mysqlTx struct {
	mc *mysqlConn
}

func (tx *mysqlTx) Commit() (err error) {
	err = tx.mc.exec("COMMIT")
	tx.mc = nil
	return
}

func (tx *mysqlTx) Rollback() (err error) {
	err = tx.mc.exec("ROLLBACK")
	tx.mc = nil
	return
}


text:
module SystemCheck
  module App
    class DatabaseConfigExistsCheck < SystemCheck::BaseCheck
      set_name 'Database config exists?'

      def check?
        database_config_file = Rails.root.join('config', 'database.yml')

        File.exist?(database_config_file)
      end

      def show_error
        try_fixing_it(
          'Copy config/database.yml.<your db> to config/database.yml',
          'Check that the information in config/database.yml is correct'
        )
        for_more_information(
          'doc/install/databases.md',
          'http://guides.rubyonrails.org/getting_started.html#configuring-a-database'
        )
        fix_and_rerun
      end
    end
  end
end


text:
package org.apache.logging.log4j.core.net.ssl;

/**
 *
 */
public class StoreConfigurationException extends Exception {
    private static final long serialVersionUID = 1L;

    public StoreConfigurationException(final Exception e) {
        super(e);
    }

    public StoreConfigurationException(final String message) {
        super(message);
    }
}


text:
<?php
/**
	* Modèle des commentaires du livre d'or
	*
	* @author Juliana Leclaire <Juliana.Leclaire@etu.univ-savoie.fr>
	* @author Céline de Roland <Celine.de-Roland@etu.univ-savoie.fr>
	*
	* @version = 2.0
	*/
namespace JC\LivreOrBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
	* Modèle des commentaires du livre d'or
	*
	* @author Juliana Leclaire <Juliana.Leclaire@etu.univ-savoie.fr>
	* @author Céline de Roland <Celine.de-Roland@etu.univ-savoie.fr>
	*
	* @version = 2.0
	*
	* @ORM\Table()
	* @ORM\Entity(repositoryClass="JC\LivreOrBundle\Entity\CommentaireRepository")
	*/
class Commentaire
{
	/**
	 * Identificateur en base de données
	 *
	 * @var integer
	 *
	 * @ORM\Column(name="id", type="integer")
	 * @ORM\Id
	 * @ORM\GeneratedValue(strategy="AUTO")
	 */
	private $id;

	/**
	 * Texte du commentaire
	 *
	 * @var string
	 *
	 * @ORM\Column(name="contenu", type="text")
	 */
	private $contenu;

	/**
	 * Pseudo choisi par l'auteur
	 *
	 * @var string
	 *
	 * @ORM\Column(name="auteur", type="string", length=255)
	 */
	private $auteur;

	/**
	 * Date à laquelle il a été écrit
	 *
	 * @var \DateTime
	 *
	 * @ORM\Column(name="date", type="datetime")
	 */
	private $date;

	/**
	 * Constructeur : définit la date au moment présent
	 *
	 * @param string $auteur : nom de l'auteur du commentaire
	 */
	public function __construct($auteur = NULL)
	{
		$this -> date = new \Datetime;
		if ($auteur != NULL) { $this -> setAuteur($auteur); }
	}

	/**
	 * Get id
	 *
	 * @return integer
	 */
	public function getId()
	{
		return $this->id;
	}

	/**
	 * Set contenu
	 *
	 * @param string $contenu
	 * @return Commentaire
	 */
	public function setContenu($contenu)
	{
		$this->contenu = $contenu;

		return $this;
	}

	/**
	 * Get contenu
	 *
	 * @return string
	 */
	public function getContenu()
	{
		return $this->contenu;
	}

	/**
	 * Set auteur
	 *
	 * @param string $auteur
	 * @return Commentaire
	 */
	public function setAuteur($auteur)
	{
		$this->auteur = $auteur;

		return $this;
	}

	/**
	 * Get auteur
	 *
	 * @return string
	 */
	public function getAuteur()
	{
		return $this->auteur;
	}

	/**
	 * Set date
	 *
	 * @param \DateTime $date
	 * @return Commentaire
	 */
	public function setDate($date)
	{
		$this->date = $date;

		return $this;
	}

	/**
	 * Get date
	 *
	 * @return \DateTime
	 */
	public function getDate()
	{
		return $this->date;
	}
}


text:
int main(int argc, char *argv[]) {
  try {
    using namespace kaldi;
    typedef kaldi::int32 int32;

    const char *usage =
        "Do EBW update on weights for MMI, MPE or MCE discriminative training.\n"
        "Numerator stats should not be I-smoothed\n"
        "Usage:  gmm-est-weights-ebw [options] <model-in> <stats-num-in> <stats-den-in> <model-out>\n"
        "e.g.: gmm-est-weights-ebw 1.mdl num.acc den.acc 2.mdl\n";

    bool binary_write = false;
    std::string update_flags_str = "w";

    EbwWeightOptions ebw_weight_opts;
    ParseOptions po(usage);
    po.Register("binary", &binary_write, "Write output in binary mode");
    po.Register("update-flags", &update_flags_str, "Which GMM parameters to "
                "update; only \"w\" flag is looked at.");

    ebw_weight_opts.Register(&po);

    po.Read(argc, argv);

    if (po.NumArgs() != 4) {
      po.PrintUsage();
      exit(1);
    }

    kaldi::GmmFlagsType update_flags =
        StringToGmmFlags(update_flags_str);

    std::string model_in_filename = po.GetArg(1),
        num_stats_filename = po.GetArg(2),
        den_stats_filename = po.GetArg(3),
        model_out_filename = po.GetArg(4);

    AmDiagGmm am_gmm;
    TransitionModel trans_model;
    {
      bool binary_read;
      Input ki(model_in_filename, &binary_read);
      trans_model.Read(ki.Stream(), binary_read);
      am_gmm.Read(ki.Stream(), binary_read);
    }

    Vector<double> num_transition_accs; // won't be used.
    Vector<double> den_transition_accs; // won't be used.

    AccumAmDiagGmm num_stats;
    AccumAmDiagGmm den_stats;
    {
      bool binary;
      Input ki(num_stats_filename, &binary);
      num_transition_accs.Read(ki.Stream(), binary);
      num_stats.Read(ki.Stream(), binary, true);  // true == add; doesn't matter here.
    }

    {
      bool binary;
      Input ki(den_stats_filename, &binary);
      num_transition_accs.Read(ki.Stream(), binary);
      den_stats.Read(ki.Stream(), binary, true);  // true == add; doesn't matter here.
    }

    if (update_flags & kGmmWeights) {  // Update weights.
      BaseFloat auxf_impr, count;
      UpdateEbwWeightsAmDiagGmm(num_stats, den_stats, ebw_weight_opts, &am_gmm,
                                &auxf_impr, &count);
      KALDI_LOG << "Num count " << num_stats.TotCount() << ", den count "
                << den_stats.TotCount();
      KALDI_LOG << "Overall auxf impr/frame from weight update is " << (auxf_impr/count)
                << " over " << count << " frames.";
    } else {
      KALDI_LOG << "Doing nothing because flags do not specify to update the weights.";
    }

    {
      Output ko(model_out_filename, binary_write);
      trans_model.Write(ko.Stream(), binary_write);
      am_gmm.Write(ko.Stream(), binary_write);
    }

    KALDI_LOG << "Written model to " << model_out_filename;

  } catch(const std::exception &e) {
    std::cerr << e.what() << '\n';
    return -1;
  }
}


text:
<?xml version="1.0" encoding="iso-8859-1"?>

        <title>ZoomLine Chart</title>
        <link href="../assets/ui/css/style.css" rel="stylesheet" type="text/css" />
        <link href="../assets/prettify/prettify.css" rel="stylesheet" type="text/css" />

Zoom Line Chart

Chart will load here

Zoom line chart showing daily closing price for Adobe Inc. Dynamic axis has been switched on. Use the mouse to drag, drop and zoom into the chart. Or, use the pin mode for data comparison.


text:
package topo

import (
	"encoding/hex"
	"fmt"
	"html/template"
	"reflect"
	"sort"
	"strings"
	"sync"

	"golang.org/x/net/context"

	log "github.com/golang/glog"

	"github.com/youtube/vitess/go/trace"
	"github.com/youtube/vitess/go/vt/concurrency"
	"github.com/youtube/vitess/go/vt/key"

	pb "github.com/youtube/vitess/go/vt/proto/topodata"
)

// Functions for dealing with shard representations in topology.

// addCells will merge both cells list, settling on nil if either list is empty
func addCells(left, right []string) []string {
	if len(left) == 0 || len(right) == 0 {
		return nil
	}

	for _, cell := range right {
		if !InCellList(cell, left) {
			left = append(left, cell)
		}
	}
	return left
}

// removeCells will remove the cells from the provided list. It returns
// the new list, and a boolean that indicates the returned list is empty.
func removeCells(cells, toRemove, fullList []string) ([]string, bool) {
	// The assumption here is we already migrated something,
	// and we're reverting that part. So we're gonna remove
	// records only.
	leftoverCells := make([]string, 0, len(cells))
	if len(cells) == 0 {
		// we migrated all the cells already, take the full list
		// and remove all the ones we're not reverting
		for _, cell := range fullList {
			if !InCellList(cell, toRemove) {
				leftoverCells = append(leftoverCells, cell)
			}
		}
	} else {
		// we migrated a subset of the cells,
		// remove the ones we're reverting
		for _, cell := range cells {
			if !InCellList(cell, toRemove) {
				leftoverCells = append(leftoverCells, cell)
			}
		}
	}

	if len(leftoverCells) == 0 {
		// we don't have any cell left, we need to clear this record
		return nil, true
	}

	return leftoverCells, false
}

// ParseKeyspaceShardString parse a "keyspace/shard" string and extract
// both keyspace and shard. It also returns empty keyspace and shard if
// input param looks like a old zk path
func ParseKeyspaceShardString(param string) (string, string, error) {
	if param[0] == '/' {
		return "", "", fmt.Errorf("Invalid keyspace/shard: %v, Note: old style zk path is no longer supported, please use a keyspace/shard instead", param)
	}
	keySpaceShard := strings.Split(param, "/")
	if len(keySpaceShard) != 2 {
		return "", "", fmt.Errorf("Invalid shard path: %v", param)
	}
	return keySpaceShard[0], keySpaceShard[1], nil
}

// SourceShardString returns a printable view of a SourceShard.
func SourceShardString(source *pb.Shard_SourceShard) string {
	return fmt.Sprintf("SourceShard(%v,%v/%v)", source.Uid, source.Keyspace, source.Shard)
}

// SourceShardAsHTML returns a HTML version of the object.
func SourceShardAsHTML(source *pb.Shard_SourceShard) template.HTML {
	result := fmt.Sprintf("Uid: %v
\nSource: %v/%v
\n", source.Uid, source.Keyspace, source.Shard)
	if key.KeyRangeIsPartial(source.KeyRange) {
		result += fmt.Sprintf("KeyRange: %v-%v
\n",
			hex.EncodeToString(source.KeyRange.Start),
			hex.EncodeToString(source.KeyRange.End))
	}
	if len(source.Tables) > 0 {
		result += fmt.Sprintf("Tables: %v
\n",
			strings.Join(source.Tables, " "))
	}
	return template.HTML(result)
}

// IsShardUsingRangeBasedSharding returns true if the shard name
// implies it is using range based sharding.
func IsShardUsingRangeBasedSharding(shard string) bool {
	return strings.Contains(shard, "-")
}

// ValidateShardName takes a shard name and sanitizes it, and also returns
// the KeyRange.
func ValidateShardName(shard string) (string, *pb.KeyRange, error) {
	if !IsShardUsingRangeBasedSharding(shard) {
		return shard, nil, nil
	}

	parts := strings.Split(shard, "-")
	if len(parts) != 2 {
		return "", nil, fmt.Errorf("invalid shardId, can only contain one '-': %v", shard)
	}

	keyRange, err := key.ParseKeyRangeParts3(parts[0], parts[1])
	if err != nil {
		return "", nil, err
	}

	if len(keyRange.End) > 0 && string(keyRange.Start) >= string(keyRange.End) {
		return "", nil, fmt.Errorf("out of order keys: %v is not strictly smaller than %v", hex.EncodeToString(keyRange.Start), hex.EncodeToString(keyRange.End))
	}

	return strings.ToLower(shard), keyRange, nil
}

// ShardInfo is a meta struct that contains metadata to give the data
// more context and convenience. This is the main way we interact with a shard.
type ShardInfo struct {
	keyspace  string
	shardName string
	version   int64
	*pb.Shard
}

// Keyspace returns the keyspace a shard belongs to
func (si *ShardInfo) Keyspace() string {
	return si.keyspace
}

// ShardName returns the shard name for a shard
func (si *ShardInfo) ShardName() string {
	return si.shardName
}

// Version returns the shard version from last time it was read or updated.
func (si *ShardInfo) Version() int64 {
	return si.version
}

// NewShardInfo returns a ShardInfo basing on shard with the
// keyspace / shard. This function should be only used by Server
// implementations.
func NewShardInfo(keyspace, shard string, value *pb.Shard, version int64) *ShardInfo {
	return &ShardInfo{
		keyspace:  keyspace,
		shardName: shard,
		version:   version,
		Shard:     value,
	}
}

// HasCell returns true if the cell is listed in the Cells for the shard.
func (si *ShardInfo) HasCell(cell string) bool {
	for _, c := range si.Cells {
		if c == cell {
			return true
		}
	}
	return false
}

// GetShard is a high level function to read shard data.
// It generates trace spans.
func GetShard(ctx context.Context, ts Server, keyspace, shard string) (*ShardInfo, error) {
	span := trace.NewSpanFromContext(ctx)
	span.StartClient("TopoServer.GetShard")
	span.Annotate("keyspace", keyspace)
	span.Annotate("shard", shard)
	defer span.Finish()

	return ts.GetShard(ctx, keyspace, shard)
}

// UpdateShard updates the shard data, with the right version
func UpdateShard(ctx context.Context, ts Server, si *ShardInfo) error {
	span := trace.NewSpanFromContext(ctx)
	span.StartClient("TopoServer.UpdateShard")
	span.Annotate("keyspace", si.Keyspace())
	span.Annotate("shard", si.ShardName())
	defer span.Finish()

	var version int64 = -1
	if si.version != 0 {
		version = si.version
	}

	newVersion, err := ts.UpdateShard(ctx, si, version)
	if err == nil {
		si.version = newVersion
	}
	return err
}

// UpdateShardFields is a high level helper to read a shard record, call an
// update function on it, and then write it back. If the write fails due to
// a version mismatch, it will re-read the record and retry the update.
// If the update succeeds, it returns the updated ShardInfo.
func UpdateShardFields(ctx context.Context, ts Server, keyspace, shard string, update func(*pb.Shard) error) (*ShardInfo, error) {
	for {
		si, err := GetShard(ctx, ts, keyspace, shard)
		if err != nil {
			return nil, err
		}
		if err = update(si.Shard); err != nil {
			return nil, err
		}
		if err = UpdateShard(ctx, ts, si); err != ErrBadVersion {
			return si, err
		}
	}
}

// CreateShard creates a new shard and tries to fill in the right information.
// This should be called while holding the keyspace lock for the shard.
// (call topotools.CreateShard to do that for you).
// In unit tests (that are not parallel), this function can be called directly.
func CreateShard(ctx context.Context, ts Server, keyspace, shard string) error {
	name, keyRange, err := ValidateShardName(shard)
	if err != nil {
		return err
	}

	// start the shard with all serving types. If it overlaps with
	// other shards for some serving types, remove them.
	servedTypes := map[pb.TabletType]bool{
		pb.TabletType_MASTER:  true,
		pb.TabletType_REPLICA: true,
		pb.TabletType_RDONLY:  true,
	}
	s := &pb.Shard{
		KeyRange: keyRange,
	}

	if IsShardUsingRangeBasedSharding(name) {
		// if we are using range-based sharding, we don't want
		// overlapping shards to all serve and confuse the clients.
		sis, err := FindAllShardsInKeyspace(ctx, ts, keyspace)
		if err != nil && err != ErrNoNode {
			return err
		}
		for _, si := range sis {
			if si.KeyRange == nil || key.KeyRangesIntersect3(si.KeyRange, keyRange) {
				for _, st := range si.ServedTypes {
					delete(servedTypes, st.TabletType)
				}
			}
		}
	}

	for st, _ := range servedTypes {
		s.ServedTypes = append(s.ServedTypes, &pb.Shard_ServedType{
			TabletType: st,
		})
	}

	return ts.CreateShard(ctx, keyspace, name, s)
}

// GetTabletControl returns the Shard_TabletControl for the given tablet type,
// or nil if it is not in the map.
func (si *ShardInfo) GetTabletControl(tabletType pb.TabletType) *pb.Shard_TabletControl {
	for _, tc := range si.TabletControls {
		if tc.TabletType == tabletType {
			return tc
		}
	}
	return nil
}

// UpdateSourceBlacklistedTables will add or remove the listed tables
// in the shard record's TabletControl structures. Note we don't
// support a lot of the corner cases:
// - only support one table list per shard. If we encounter a different
//   table list that the provided one, we error out.
// - we don't support DisableQueryService at the same time as BlacklistedTables,
//   because it's not used in the same context (vertical vs horizontal sharding)
func (si *ShardInfo) UpdateSourceBlacklistedTables(tabletType pb.TabletType, cells []string, remove bool, tables []string) error {
	tc := si.GetTabletControl(tabletType)
	if tc == nil {
		// handle the case where the TabletControl object is new
		if remove {
			// we try to remove from something that doesn't exist,
			// log, but we're done.
			log.Warningf("Trying to remove TabletControl.BlacklistedTables for missing type %v in shard %v/%v", tabletType, si.keyspace, si.shardName)
			return nil
		}

		// trying to add more constraints with no existing record
		si.TabletControls = append(si.TabletControls, &pb.Shard_TabletControl{
			TabletType:          tabletType,
			Cells:               cells,
			DisableQueryService: false,
			BlacklistedTables:   tables,
		})
		return nil
	}

	// we have an existing record, check table lists matches and
	// DisableQueryService is not set
	if tc.DisableQueryService {
		return fmt.Errorf("cannot safely alter BlacklistedTables as DisableQueryService is set for shard %v/%v", si.keyspace, si.shardName)
	}

	if remove {
		si.removeCellsFromTabletControl(tc, tabletType, cells)
	} else {
		if !reflect.DeepEqual(tc.BlacklistedTables, tables) {
			return fmt.Errorf("trying to use two different sets of blacklisted tables for shard %v/%v: %v and %v", si.keyspace, si.shardName, tc.BlacklistedTables, tables)
		}

		tc.Cells = addCells(tc.Cells, cells)
	}
	return nil
}

// UpdateDisableQueryService will make sure the disableQueryService is
// set appropriately in the shard record. Note we don't support a lot
// of the corner cases:
// - we don't support DisableQueryService at the same time as BlacklistedTables,
//   because it's not used in the same context (vertical vs horizontal sharding)
func (si *ShardInfo) UpdateDisableQueryService(tabletType pb.TabletType, cells []string, disableQueryService bool) error {
	tc := si.GetTabletControl(tabletType)
	if tc == nil {
		// handle the case where the TabletControl object is new
		if disableQueryService {
			si.TabletControls = append(si.TabletControls, &pb.Shard_TabletControl{
				TabletType:          tabletType,
				Cells:               cells,
				DisableQueryService: true,
				BlacklistedTables:   nil,
			})
		} else {
			log.Warningf("Trying to remove TabletControl.DisableQueryService for missing type: %v", tabletType)
		}
		return nil
	}

	// we have an existing record, check table list is empty and
	// DisableQueryService is set
	if len(tc.BlacklistedTables) > 0 {
		return fmt.Errorf("cannot safely alter DisableQueryService as BlacklistedTables is set")
	}
	if !tc.DisableQueryService {
		return fmt.Errorf("cannot safely alter DisableQueryService as DisableQueryService is not set, this record should not be there")
	}

	if disableQueryService {
		tc.Cells = addCells(tc.Cells, cells)
	} else {
		si.removeCellsFromTabletControl(tc, tabletType, cells)
	}
	return nil
}

func (si *ShardInfo) removeCellsFromTabletControl(tc *pb.Shard_TabletControl, tabletType pb.TabletType, cells []string) {
	result, emptyList := removeCells(tc.Cells, cells, si.Cells)
	if emptyList {
		// we don't have any cell left, we need to clear this record
		var tabletControls []*pb.Shard_TabletControl
		for _, tc := range si.TabletControls {
			if tc.TabletType != tabletType {
				tabletControls = append(tabletControls, tc)
			}
		}
		si.TabletControls = tabletControls
	} else {
		tc.Cells = result
	}
}

// GetServedType returns the Shard_ServedType for a TabletType, or nil
func (si *ShardInfo) GetServedType(tabletType pb.TabletType) *pb.Shard_ServedType {
	for _, st := range si.ServedTypes {
		if st.TabletType == tabletType {
			return st
		}
	}
	return nil
}

// GetServedTypesPerCell returns the list of types this shard is serving
// in the provided cell.
func (si *ShardInfo) GetServedTypesPerCell(cell string) []TabletType {
	result := make([]TabletType, 0, len(si.ServedTypes))
	for _, st := range si.ServedTypes {
		if InCellList(cell, st.Cells) {
			result = append(result, ProtoToTabletType(st.TabletType))
		}
	}
	return result
}

// CheckServedTypesMigration makes sure the provided migration is possible
func (si *ShardInfo) CheckServedTypesMigration(tabletType pb.TabletType, cells []string, remove bool) error {
	// master is a special case with a few extra checks
	if tabletType == pb.TabletType_MASTER {
		if len(cells) > 0 {
			return fmt.Errorf("cannot migrate only some cells for master in shard %v/%v", si.keyspace, si.shardName)
		}
		if remove && len(si.ServedTypes) > 1 {
			return fmt.Errorf("cannot migrate master away from %v/%v until everything else is migrated", si.keyspace, si.shardName)
		}
	}

	// we can't remove a type we don't have
	if si.GetServedType(tabletType) == nil && remove {
		return fmt.Errorf("supplied type %v cannot be migrated out of %#v", tabletType, si)
	}

	return nil
}

// UpdateServedTypesMap handles ServedTypesMap. It can add or remove
// records, cells, ...
func (si *ShardInfo) UpdateServedTypesMap(tabletType pb.TabletType, cells []string, remove bool) error {
	// check parameters to be sure
	if err := si.CheckServedTypesMigration(tabletType, cells, remove); err != nil {
		return err
	}

	sst := si.GetServedType(tabletType)
	if sst == nil {
		// the record doesn't exist
		if remove {
			log.Warningf("Trying to remove ShardServedType for missing type %v in shard %v/%v", tabletType, si.keyspace, si.shardName)
		} else {
			si.ServedTypes = append(si.ServedTypes, &pb.Shard_ServedType{
				TabletType: tabletType,
				Cells:      cells,
			})
		}
		return nil
	}

	if remove {
		result, emptyList := removeCells(sst.Cells, cells, si.Cells)
		if emptyList {
			// we don't have any cell left, we need to clear this record
			var servedTypes []*pb.Shard_ServedType
			for _, st := range si.ServedTypes {
				if st.TabletType != tabletType {
					servedTypes = append(servedTypes, st)
				}
			}
			si.ServedTypes = servedTypes
		} else {
			sst.Cells = result
		}
	} else {
		sst.Cells = addCells(sst.Cells, cells)
	}
	return nil
}

//
// Utility functions for shards
//

// InCellList returns true if the cell list is empty,
// or if the passed cell is in the cell list.
func InCellList(cell string, cells []string) bool {
	if len(cells) == 0 {
		return true
	}
	for _, c := range cells {
		if c == cell {
			return true
		}
	}
	return false
}

// FindAllTabletAliasesInShard uses the replication graph to find all the
// tablet aliases in the given shard.
//
// It can return ErrPartialResult if some cells were not fetched,
// in which case the result only contains the cells that were fetched.
//
// The tablet aliases are sorted by cell, then by UID.
func FindAllTabletAliasesInShard(ctx context.Context, ts Server, keyspace, shard string) ([]*pb.TabletAlias, error) {
	return FindAllTabletAliasesInShardByCell(ctx, ts, keyspace, shard, nil)
}

// FindAllTabletAliasesInShardByCell uses the replication graph to find all the
// tablet aliases in the given shard.
//
// It can return ErrPartialResult if some cells were not fetched,
// in which case the result only contains the cells that were fetched.
//
// The tablet aliases are sorted by cell, then by UID.
func FindAllTabletAliasesInShardByCell(ctx context.Context, ts Server, keyspace, shard string, cells []string) ([]*pb.TabletAlias, error) {
	span := trace.NewSpanFromContext(ctx)
	span.StartLocal("topo.FindAllTabletAliasesInShardbyCell")
	span.Annotate("keyspace", keyspace)
	span.Annotate("shard", shard)
	span.Annotate("num_cells", len(cells))
	defer span.Finish()
	ctx = trace.NewContext(ctx, span)

	// read the shard information to find the cells
	si, err := GetShard(ctx, ts, keyspace, shard)
	if err != nil {
		return nil, err
	}

	resultAsMap := make(map[pb.TabletAlias]bool)
	if si.MasterAlias != nil && !TabletAliasIsZero(si.MasterAlias) {
		if InCellList(si.MasterAlias.Cell, cells) {
			resultAsMap[*si.MasterAlias] = true
		}
	}

	// read the replication graph in each cell and add all found tablets
	wg := sync.WaitGroup{}
	mutex := sync.Mutex{}
	rec := concurrency.AllErrorRecorder{}
	for _, cell := range si.Cells {
		if !InCellList(cell, cells) {
			continue
		}
		wg.Add(1)
		go func(cell string) {
			defer wg.Done()
			sri, err := ts.GetShardReplication(ctx, cell, keyspace, shard)
			if err != nil {
				rec.RecordError(fmt.Errorf("GetShardReplication(%v, %v, %v) failed: %v", cell, keyspace, shard, err))
				return
			}

			mutex.Lock()
			for _, node := range sri.Nodes {
				resultAsMap[*node.TabletAlias] = true
			}
			mutex.Unlock()
		}(cell)
	}
	wg.Wait()
	err = nil
	if rec.HasErrors() {
		log.Warningf("FindAllTabletAliasesInShard(%v,%v): got partial result: %v", keyspace, shard, rec.Error())
		err = ErrPartialResult
	}

	result := make([]*pb.TabletAlias, 0, len(resultAsMap))
	for a := range resultAsMap {
		v := a
		result = append(result, &v)
	}
	sort.Sort(TabletAliasList(result))
	return result, err
}

// GetTabletMapForShard returns the tablets for a shard. It can return
// ErrPartialResult if it couldn't read all the cells, or all
// the individual tablets, in which case the map is valid, but partial.
func GetTabletMapForShard(ctx context.Context, ts Server, keyspace, shard string) (map[pb.TabletAlias]*TabletInfo, error) {
	return GetTabletMapForShardByCell(ctx, ts, keyspace, shard, nil)
}

// GetTabletMapForShardByCell returns the tablets for a shard. It can return
// ErrPartialResult if it couldn't read all the cells, or all
// the individual tablets, in which case the map is valid, but partial.
func GetTabletMapForShardByCell(ctx context.Context, ts Server, keyspace, shard string, cells []string) (map[pb.TabletAlias]*TabletInfo, error) {
	// if we get a partial result, we keep going. It most likely means
	// a cell is out of commission.
	aliases, err := FindAllTabletAliasesInShardByCell(ctx, ts, keyspace, shard, cells)
	if err != nil && err != ErrPartialResult {
		return nil, err
	}

	// get the tablets for the cells we were able to reach, forward
	// ErrPartialResult from FindAllTabletAliasesInShard
	result, gerr := GetTabletMap(ctx, ts, aliases)
	if gerr == nil && err != nil {
		gerr = err
	}
	return result, gerr
}


text:
package backends

import (
	"fmt"
	"net/http"
	"testing"

	compute "google.golang.org/api/compute/v1"
	"google.golang.org/api/googleapi"
	"k8s.io/apimachinery/pkg/util/intstr"
	"k8s.io/apimachinery/pkg/util/sets"
	api_v1 "k8s.io/client-go/pkg/api/v1"

	"k8s.io/ingress/controllers/gce/healthchecks"
	"k8s.io/ingress/controllers/gce/instances"
	"k8s.io/ingress/controllers/gce/storage"
	"k8s.io/ingress/controllers/gce/utils"
)

const defaultZone = "zone-a"

var noOpErrFunc = func(op int, be *compute.BackendService) error { return nil }

var existingProbe = &api_v1.Probe{
	Handler: api_v1.Handler{
		HTTPGet: &api_v1.HTTPGetAction{
			Scheme: api_v1.URISchemeHTTPS,
			Path:   "/my-special-path",
			Port: intstr.IntOrString{
				Type:   intstr.Int,
				IntVal: 443,
			},
		},
	},
}

func newTestJig(f BackendServices, fakeIGs instances.InstanceGroups, syncWithCloud bool) (*Backends, healthchecks.HealthCheckProvider) {
	namer := &utils.Namer{}
	nodePool := instances.NewNodePool(fakeIGs)
	nodePool.Init(&instances.FakeZoneLister{Zones: []string{defaultZone}})
	healthCheckProvider := healthchecks.NewFakeHealthCheckProvider()
	healthChecks := healthchecks.NewHealthChecker(healthCheckProvider, "/", namer)
	bp := NewBackendPool(f, healthChecks, nodePool, namer, []int64{}, syncWithCloud)
	probes := map[ServicePort]*api_v1.Probe{{Port: 443, Protocol: utils.ProtocolHTTPS}: existingProbe}
	bp.Init(NewFakeProbeProvider(probes))

	return bp, healthCheckProvider
}

func TestBackendPoolAdd(t *testing.T) {
	f := NewFakeBackendServices(noOpErrFunc)
	fakeIGs := instances.NewFakeInstanceGroups(sets.NewString())
	pool, _ := newTestJig(f, fakeIGs, false)
	namer := utils.Namer{}

	testCases := []ServicePort{
		{Port: 80, Protocol: utils.ProtocolHTTP},
		{Port: 443, Protocol: utils.ProtocolHTTPS},
	}

	for _, nodePort := range testCases {
		// For simplicity, these tests use 80/443 as nodeports
		t.Run(fmt.Sprintf("Port:%v Protocol:%v", nodePort.Port, nodePort.Protocol), func(t *testing.T) {
			// Add a backend for a port, then re-add the same port and
			// make sure it corrects a broken link from the backend to
			// the instance group.
			err := pool.Add(nodePort)
			if err != nil {
				t.Fatalf("Did not find expect error when adding a nodeport: %v, err: %v", nodePort, err)
			}
			beName := namer.BeName(nodePort.Port)

			// Check that the new backend has the right port
			be, err := f.GetBackendService(beName)
			if err != nil {
				t.Fatalf("Did not find expected backend %v", beName)
			}
			if be.Port != nodePort.Port {
				t.Fatalf("Backend %v has wrong port %v, expected %v", be.Name, be.Port, nodePort)
			}

			// Check that the instance group has the new port
			var found bool
			for _, port := range fakeIGs.Ports {
				if port == nodePort.Port {
					found = true
				}
			}
			if !found {
				t.Fatalf("Port %v not added to instance group", nodePort)
			}

			// Check the created healthcheck is the correct protocol
			hc, err := pool.healthChecker.Get(nodePort.Port)
			if err != nil {
				t.Fatalf("Unexpected err when querying fake healthchecker: %v", err)
			}

			if hc.Protocol() != nodePort.Protocol {
				t.Fatalf("Healthcheck scheme does not match nodeport scheme: hc:%v np:%v", hc.Protocol(), nodePort.Protocol)
			}

			if nodePort.Port == 443 && hc.RequestPath != "/my-special-path" {
				t.Fatalf("Healthcheck for 443 should have special request path from probe")
			}
		})
	}
}

func TestHealthCheckMigration(t *testing.T) {
	f := NewFakeBackendServices(noOpErrFunc)
	fakeIGs := instances.NewFakeInstanceGroups(sets.NewString())
	pool, hcp := newTestJig(f, fakeIGs, false)
	namer := utils.Namer{}

	p := ServicePort{Port: 7000, Protocol: utils.ProtocolHTTP}

	// Create a legacy health check and insert it into the HC provider.
	legacyHC := &compute.HttpHealthCheck{
		Name:               namer.BeName(p.Port),
		RequestPath:        "/my-healthz-path",
		Host:               "k8s.io",
		Description:        "My custom HC",
		UnhealthyThreshold: 30,
		CheckIntervalSec:   40,
	}
	hcp.CreateHttpHealthCheck(legacyHC)

	// Add the service port to the backend pool
	pool.Add(p)

	// Assert the proper health check was created
	hc, _ := pool.healthChecker.Get(p.Port)
	if hc == nil || hc.Protocol() != p.Protocol {
		t.Fatalf("Expected %s health check, received %v: ", p.Protocol, hc)
	}

	// Assert the newer health check has the legacy health check settings
	if hc.RequestPath != legacyHC.RequestPath ||
		hc.Host != legacyHC.Host ||
		hc.UnhealthyThreshold != legacyHC.UnhealthyThreshold ||
		hc.CheckIntervalSec != legacyHC.CheckIntervalSec ||
		hc.Description != legacyHC.Description {
		t.Fatalf("Expected newer health check to have identical settings to legacy health check. Legacy: %+v, New: %+v", legacyHC, hc)
	}
}

func TestBackendPoolUpdate(t *testing.T) {
	f := NewFakeBackendServices(noOpErrFunc)
	fakeIGs := instances.NewFakeInstanceGroups(sets.NewString())
	pool, _ := newTestJig(f, fakeIGs, false)
	namer := utils.Namer{}

	p := ServicePort{Port: 3000, Protocol: utils.ProtocolHTTP}
	pool.Add(p)
	beName := namer.BeName(p.Port)

	be, err := f.GetBackendService(beName)
	if err != nil {
		t.Fatalf("Unexpected err: %v", err)
	}

	if utils.AppProtocol(be.Protocol) != p.Protocol {
		t.Fatalf("Expected scheme %v but got %v", p.Protocol, be.Protocol)
	}

	// Assert the proper health check was created
	hc, _ := pool.healthChecker.Get(p.Port)
	if hc == nil || hc.Protocol() != p.Protocol {
		t.Fatalf("Expected %s health check, received %v: ", p.Protocol, hc)
	}

	// Update service port to encrypted
	p.Protocol = utils.ProtocolHTTPS
	pool.Sync([]ServicePort{p})

	be, err = f.GetBackendService(beName)
	if err != nil {
		t.Fatalf("Unexpected err retrieving backend service after update: %v", err)
	}

	// Assert the backend has the correct protocol
	if utils.AppProtocol(be.Protocol) != p.Protocol {
		t.Fatalf("Expected scheme %v but got %v", p.Protocol, utils.AppProtocol(be.Protocol))
	}

	// Assert the proper health check was created
	hc, _ = pool.healthChecker.Get(p.Port)
	if hc == nil || hc.Protocol() != p.Protocol {
		t.Fatalf("Expected %s health check, received %v: ", p.Protocol, hc)
	}
}

func TestBackendPoolChaosMonkey(t *testing.T) {
	f := NewFakeBackendServices(noOpErrFunc)
	fakeIGs := instances.NewFakeInstanceGroups(sets.NewString())
	pool, _ := newTestJig(f, fakeIGs, false)
	namer := utils.Namer{}

	nodePort := ServicePort{Port: 8080, Protocol: utils.ProtocolHTTP}
	pool.Add(nodePort)
	beName := namer.BeName(nodePort.Port)

	be, _ := f.GetBackendService(beName)

	// Mess up the link between backend service and instance group.
	// This simulates a user doing foolish things through the UI.
	be.Backends = []*compute.Backend{
		{Group: "test edge hop"},
	}
	f.calls = []int{}
	f.UpdateBackendService(be)

	pool.Add(nodePort)
	for _, call := range f.calls {
		if call == utils.Create {
			t.Fatalf("Unexpected create for existing backend service")
		}
	}
	gotBackend, err := f.GetBackendService(beName)
	if err != nil {
		t.Fatalf("Failed to find a backend with name %v: %v", beName, err)
	}
	gotGroup, err := fakeIGs.GetInstanceGroup(namer.IGName(), defaultZone)
	if err != nil {
		t.Fatalf("Failed to find instance group %v", namer.IGName())
	}
	backendLinks := sets.NewString()
	for _, be := range gotBackend.Backends {
		backendLinks.Insert(be.Group)
	}
	if !backendLinks.Has(gotGroup.SelfLink) {
		t.Fatalf(
			"Broken instance group link, got: %+v expected: %v",
			backendLinks.List(),
			gotGroup.SelfLink)
	}
}

func TestBackendPoolSync(t *testing.T) {
	// Call sync on a backend pool with a list of ports, make sure the pool
	// creates/deletes required ports.
	svcNodePorts := []ServicePort{{Port: 81, Protocol: utils.ProtocolHTTP}, {Port: 82, Protocol: utils.ProtocolHTTPS}, {Port: 83, Protocol: utils.ProtocolHTTP}}
	f := NewFakeBackendServices(noOpErrFunc)
	fakeIGs := instances.NewFakeInstanceGroups(sets.NewString())
	pool, _ := newTestJig(f, fakeIGs, true)
	pool.Add(ServicePort{Port: 81})
	pool.Add(ServicePort{Port: 90})
	if err := pool.Sync(svcNodePorts); err != nil {
		t.Errorf("Expected backend pool to sync, err: %v", err)
	}
	if err := pool.GC(svcNodePorts); err != nil {
		t.Errorf("Expected backend pool to GC, err: %v", err)
	}
	if _, err := pool.Get(90); err == nil {
		t.Fatalf("Did not expect to find port 90")
	}
	for _, port := range svcNodePorts {
		if _, err := pool.Get(port.Port); err != nil {
			t.Fatalf("Expected to find port %v", port)
		}
	}

	svcNodePorts = []ServicePort{{Port: 81}}
	deletedPorts := []ServicePort{{Port: 82}, {Port: 83}}
	if err := pool.GC(svcNodePorts); err != nil {
		t.Fatalf("Expected backend pool to GC, err: %v", err)
	}

	for _, port := range deletedPorts {
		if _, err := pool.Get(port.Port); err == nil {
			t.Fatalf("Pool contains %v after deletion", port)
		}
	}

	// All these backends should be ignored because they don't belong to the cluster.
	// foo - non k8s managed backend
	// k8s-be-foo - foo is not a nodeport
	// k8s--bar--foo - too many cluster delimiters
	// k8s-be-3001--uid - another cluster tagged with uid
	unrelatedBackends := sets.NewString([]string{"foo", "k8s-be-foo", "k8s--bar--foo", "k8s-be-30001--uid"}...)
	for _, name := range unrelatedBackends.List() {
		f.CreateBackendService(&compute.BackendService{Name: name})
	}

	namer := &utils.Namer{}
	// This backend should get deleted again since it is managed by this cluster.
	f.CreateBackendService(&compute.BackendService{Name: namer.BeName(deletedPorts[0].Port)})

	// TODO: Avoid casting.
	// Repopulate the pool with a cloud list, which now includes the 82 port
	// backend. This would happen if, say, an ingress backend is removed
	// while the controller is restarting.
	pool.snapshotter.(*storage.CloudListingPool).ReplenishPool()

	pool.GC(svcNodePorts)

	currBackends, _ := f.ListBackendServices()
	currSet := sets.NewString()
	for _, b := range currBackends.Items {
		currSet.Insert(b.Name)
	}
	// Port 81 still exists because it's an in-use service NodePort.
	knownBe := namer.BeName(81)
	if !currSet.Has(knownBe) {
		t.Fatalf("Expected %v to exist in backend pool", knownBe)
	}
	currSet.Delete(knownBe)
	if !currSet.Equal(unrelatedBackends) {
		t.Fatalf("Some unrelated backends were deleted. Expected %+v, got %+v", unrelatedBackends, currSet)
	}
}

func TestBackendPoolDeleteLegacyHealthChecks(t *testing.T) {
	namer := &utils.Namer{}
	f := NewFakeBackendServices(noOpErrFunc)
	fakeIGs := instances.NewFakeInstanceGroups(sets.NewString())
	nodePool := instances.NewNodePool(fakeIGs)
	nodePool.Init(&instances.FakeZoneLister{Zones: []string{defaultZone}})
	hcp := healthchecks.NewFakeHealthCheckProvider()
	healthChecks := healthchecks.NewHealthChecker(hcp, "/", namer)
	bp := NewBackendPool(f, healthChecks, nodePool, namer, []int64{}, false)
	probes := map[ServicePort]*api_v1.Probe{}
	bp.Init(NewFakeProbeProvider(probes))

	// Create a legacy HTTP health check
	beName := namer.BeName(80)
	if err := hcp.CreateHttpHealthCheck(&compute.HttpHealthCheck{
		Name: beName,
		Port: 80,
	}); err != nil {
		t.Fatalf("unexpected error creating http health check %v", err)
	}

	// Verify health check exists
	hc, err := hcp.GetHttpHealthCheck(beName)
	if err != nil {
		t.Fatalf("unexpected error getting http health check %v", err)
	}

	// Create backend service with expected name and link to legacy health check
	f.CreateBackendService(&compute.BackendService{
		Name:         beName,
		HealthChecks: []string{hc.SelfLink},
	})

	// Have pool sync the above backend service
	bp.Add(ServicePort{Port: 80, Protocol: utils.ProtocolHTTPS})

	// Verify the legacy health check has been deleted
	_, err = hcp.GetHttpHealthCheck(beName)
	if err == nil {
		t.Fatalf("expected error getting http health check %v", err)
	}

	// Verify a newer health check exists
	hcNew, err := hcp.GetHealthCheck(beName)
	if err != nil {
		t.Fatalf("unexpected error getting http health check %v", err)
	}

	// Verify the newer health check is of type HTTPS
	if hcNew.Type != string(utils.ProtocolHTTPS) {
		t.Fatalf("expected health check type to be %v, actual %v", string(utils.ProtocolHTTPS), hcNew.Type)
	}
}

func TestBackendPoolShutdown(t *testing.T) {
	f := NewFakeBackendServices(noOpErrFunc)
	fakeIGs := instances.NewFakeInstanceGroups(sets.NewString())
	pool, _ := newTestJig(f, fakeIGs, false)
	namer := utils.Namer{}

	// Add a backend-service and verify that it doesn't exist after Shutdown()
	pool.Add(ServicePort{Port: 80})
	pool.Shutdown()
	if _, err := f.GetBackendService(namer.BeName(80)); err == nil {
		t.Fatalf("%v", err)
	}
}

func TestBackendInstanceGroupClobbering(t *testing.T) {
	f := NewFakeBackendServices(noOpErrFunc)
	fakeIGs := instances.NewFakeInstanceGroups(sets.NewString())
	pool, _ := newTestJig(f, fakeIGs, false)
	namer := utils.Namer{}

	// This will add the instance group k8s-ig to the instance pool
	pool.Add(ServicePort{Port: 80})

	be, err := f.GetBackendService(namer.BeName(80))
	if err != nil {
		t.Fatalf("%v", err)
	}
	// Simulate another controller updating the same backend service with
	// a different instance group
	newGroups := []*compute.Backend{
		{Group: "k8s-ig-bar"},
		{Group: "k8s-ig-foo"},
	}
	be.Backends = append(be.Backends, newGroups...)
	if err = f.UpdateBackendService(be); err != nil {
		t.Fatalf("Failed to update backend service %v", be.Name)
	}

	// Make sure repeated adds don't clobber the inserted instance group
	pool.Add(ServicePort{Port: 80})
	be, err = f.GetBackendService(namer.BeName(80))
	if err != nil {
		t.Fatalf("%v", err)
	}
	gotGroups := sets.NewString()
	for _, g := range be.Backends {
		gotGroups.Insert(g.Group)
	}

	// seed expectedGroups with the first group native to this controller
	expectedGroups := sets.NewString("k8s-ig")
	for _, newGroup := range newGroups {
		expectedGroups.Insert(newGroup.Group)
	}
	if !expectedGroups.Equal(gotGroups) {
		t.Fatalf("Expected %v Got %v", expectedGroups, gotGroups)
	}
}

func TestBackendCreateBalancingMode(t *testing.T) {
	f := NewFakeBackendServices(noOpErrFunc)

	fakeIGs := instances.NewFakeInstanceGroups(sets.NewString())
	pool, _ := newTestJig(f, fakeIGs, false)
	namer := utils.Namer{}
	nodePort := ServicePort{Port: 8080}
	modes := []BalancingMode{Rate, Utilization}

	// block the creation of Backends with the given balancingMode
	// and verify that a backend with the other balancingMode is
	// created
	for i, bm := range modes {
		f.errFunc = func(op int, be *compute.BackendService) error {
			for _, b := range be.Backends {
				if b.BalancingMode == string(bm) {
					return &googleapi.Error{Code: http.StatusBadRequest}
				}
			}
			return nil
		}

		pool.Add(nodePort)
		be, err := f.GetBackendService(namer.BeName(nodePort.Port))
		if err != nil {
			t.Fatalf("%v", err)
		}

		for _, b := range be.Backends {
			if b.BalancingMode != string(modes[(i+1)%len(modes)]) {
				t.Fatalf("Wrong balancing mode, expected %v got %v", modes[(i+1)%len(modes)], b.BalancingMode)
			}
		}
		pool.GC([]ServicePort{})
	}
}

func TestApplyProbeSettingsToHC(t *testing.T) {
	p := "healthz"
	hc := healthchecks.DefaultHealthCheck(8080, utils.ProtocolHTTPS)
	probe := &api_v1.Probe{
		Handler: api_v1.Handler{
			HTTPGet: &api_v1.HTTPGetAction{
				Scheme: api_v1.URISchemeHTTP,
				Path:   p,
				Port: intstr.IntOrString{
					Type:   intstr.Int,
					IntVal: 80,
				},
			},
		},
	}

	applyProbeSettingsToHC(probe, hc)

	if hc.Protocol() != utils.ProtocolHTTPS || hc.Port != 8080 {
		t.Errorf("Basic HC settings changed")
	}
	if hc.RequestPath != "/"+p {
		t.Errorf("Failed to apply probe's requestpath")
	}
}


text:
import React, { Component } from 'react';

import './App.css';

import MainBlock from './main-block/MainBlock';

export default class App extends Component {
    render() {
        return (
            <div className="wrap-calc">
                <MainBlock/>
            </div>
        );
    }
}


text:
/**
 * `BadRequestError` error.
 *
 * @api public
 */
function BadRequestError(message) {
  Error.call(this);
  Error.captureStackTrace(this, arguments.callee);
  this.name = 'BadRequestError';
  this.message = message;
  this.status = 400;
}

/**
 * Inherit from `Error`.
 */
BadRequestError.prototype.__proto__ = Error.prototype;

/**
 * Expose `BadRequestError`.
 */
module.exports = BadRequestError;


text:
package pgp

import (
	"bytes"
	"sync"
	"time"

	"github.com/awnumar/memguard"

	"github.com/leanovate/microtools/logging"
	"github.com/pkg/errors"
	"github.com/untoldwind/trustless/api"
	"github.com/untoldwind/trustless/secrets"
	"github.com/untoldwind/trustless/store"
	"golang.org/x/crypto/openpgp"
)

type pgpSecrets struct {
	lock          sync.Mutex
	store         store.Store
	scrypted      bool
	nodeID        string
	logger        logging.Logger
	identities    []api.Identity
	entities      openpgp.EntityList
	index         *Index
	masterKeyBits int
	autolocker    *secrets.Autolocker
	buffers       []*memguard.LockedBuffer
}

// NewPGPSecrets creats a new secrets store based on openpgp
func NewPGPSecrets(storeURL string, scrypted bool, nodeID string, masterKeyBits int, unlockTimout time.Duration, unlockTimeoutHard bool, logger logging.Logger) (secrets.Secrets, error) {
	store, err := store.NewStore(storeURL, logger)
	if err != nil {
		return nil, err
	}
	pgp := &pgpSecrets{
		store:         store,
		scrypted:      scrypted,
		nodeID:        nodeID,
		logger:        logger.WithField("package", "secrets"),
		masterKeyBits: masterKeyBits,
	}
	pgp.autolocker = secrets.NewAutolocker(pgp, unlockTimout, unlockTimeoutHard)
	if err := pgp.readIdentities(); err != nil {
		return nil, err
	}
	return pgp, nil
}

func (s *pgpSecrets) IsInitialized() bool {
	return len(s.identities) > 0
}

func (s *pgpSecrets) readIdentities() error {
	s.lock.Lock()
	defer s.lock.Unlock()

	ring, err := s.store.GetPublicRing()
	if err != nil {
		return nil
	}
	if ring != nil {
		entities, err := openpgp.ReadKeyRing(bytes.NewBuffer(ring))
		if err != nil {
			return errors.Wrap(err, "Failed to read ring")
		}
		s.identities = identitiesFromEntities(entities)
		return nil
	}
	ring, err = s.store.GetRing()
	if err != nil {
		return err
	}
	if ring == nil {
		return nil
	}
	entities, err := openpgp.ReadKeyRing(bytes.NewBuffer(ring))
	if err != nil {
		return errors.Wrap(err, "Failed to read ring")
	}
	s.identities = identitiesFromEntities(entities)
	buf := bytes.NewBuffer(nil)

	for _, entity := range entities {
		if err := entity.Serialize(buf); err != nil {
			return err
		}
	}
	if err := s.store.StorePublicRing(buf.Bytes()); err != nil {
		return err
	}
	return nil
}


text:
Copyright (c) 2015, Intel Corporation
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
=#

module Comprehension

export @comprehend
import CompilerTools
import ..API

"""
Translate an ast whose head is :comprehension into equivalent code that uses cartesianarray call.
"""
function comprehension_to_cartesianarray(ast)
  assert(ast.head == :comprehension)
  body = ast.args[1]
  if isa(body, Expr) && body.head == :generator
    body = ast.args[1].args[1]
    args = ast.args[1].args[2:end]
    ndim = length(args)
  else
    body = ast.args[1]
    args = ast.args[2:end]
    ndim = length(args)
  end
  body = CompilerTools.AstWalker.AstWalk(body, process_node, nothing)
  params = Array{Symbol}(ndim)
  indices = Array{Symbol}(ndim)
  ranges = Array{Any}(ndim)
  headers = Array{Any}(ndim)
  for i = 1:ndim
    r = args[i]
    assert(r.head == :(=))
    indices[i] = r.args[1]
    params[i] = gensym(string(indices[i]))
    ranges[i] = r.args[2]
    #headers[i] = Expr(:(=), indices[i], Expr(:call, GlobalRef(Base, :getindex), ranges[i], params[i]))
    #first(v) + (i-1)*step(v)
    first = GlobalRef(Base, :first)
    step = GlobalRef(Base, :step)
    headers[i] = :($(indices[i]) = $first($(ranges[i])) + ($(params[i]) - 1) * $step($(ranges[i])))
    # if range is 1:N, generate simple assignment instead of formula
    # this helps copy propagation for nested comprehensions (motivated by K-Means)
    if isa(ranges[i], Expr) && isStart1UnitRange(ranges[i])
        headers[i] = :($(indices[i]) = $(params[i]))
    end
  end
  args = Expr(:tuple, params...)
  dims = [ get_range_length(r) for r in ranges ]
  dimsExpr = Expr(:tuple, [ Expr(:call, GlobalRef(Base, :length), r) for r in ranges ]...)
  tmpret = gensym("tmp")
  tmpinits = [ :($idx = 1) for idx in params ]
  typetest = :(local $tmpret; if 1<0 let $(tmpinits...); $(headers...); $tmpret=$body end end)
  if VERSION < v"0.5.0-dev+5306"
      ast = Expr(:call, GlobalRef(API, :cartesianarray),
                    :($args -> let $(headers...); $body end), Expr(:call, GlobalRef(Core, :apply_type), GlobalRef(Base, :Tuple), Expr(:static_typeof, tmpret)), :($dimsExpr))
      ast = Expr(:block, typetest, ast)
  else
      ast = Expr(:call,  GlobalRef(API, :cartesianarray),
                    :($args -> let $(headers...); $body end), dims...)
  end
  ast
end

function isStart1UnitRange(node::Expr)
    if node.head==:(:) && length(node.args)==2 && node.args[1]==1
        return true
    end
    return false
end

function get_range_length(r::Expr)
    if isStart1UnitRange(r)
        return r.args[2]
    end
    return Expr(:call, GlobalRef(Base, :length), r)
end

function get_range_length(r::ANY)
    return Expr(:call, GlobalRef(Base, :length), r)
end

"""
This function is a AstWalker callback.
"""
function process_node(node, state, top_level_number, is_top_level, read)
  if !isa(node,Expr)
    return CompilerTools.AstWalker.ASTWALK_RECURSE
  end
  if node.head == :typed_comprehension
    typ = node.args[1]
    # Transform into untyped :comprehension because type will be passed as a
    # parameter the same way we handle untyped :comprehensions
    node.head = :comprehension
    node.args = node.args[2:end]
  end
  return (node.head == :comprehension) ? comprehension_to_cartesianarray(node) : CompilerTools.AstWalker.ASTWALK_RECURSE
end

"""
Translate all comprehension in an AST into equivalent code that uses cartesianarray call.
"""
macro comprehend(ast)
  CompilerTools.AstWalker.AstWalk(ast, process_node, nothing)
  Core.eval(current_module(), ast)
end

end


text:
<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at
      http://www.apache.org/licenses/LICENSE-2.0
  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.apache.nifi</groupId>
        <artifactId>nifi-groovyx-bundle</artifactId>
        <version>1.19.0-SNAPSHOT</version>
    </parent>

    <artifactId>nifi-groovyx-processors</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-utils</artifactId>
            <version>1.19.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-record-serialization-service-api</artifactId>
            <version>1.19.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-json</artifactId>
            <version>${nifi.groovy.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-sql</artifactId>
            <version>${nifi.groovy.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- groovy-all does not include groovy-dateutil by default, so must explicitly include it here -->
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-dateutil</artifactId>
            <version>${nifi.groovy.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.ivy</groupId>
            <artifactId>ivy</artifactId>
            <version>2.5.1</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-dbcp-service-api</artifactId>
            <version>1.19.0-SNAPSHOT</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-mock</artifactId>
            <version>1.19.0-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-record</artifactId>
            <version>1.19.0-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-mock-record-utils</artifactId>
            <version>1.19.0-SNAPSHOT</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.derby</groupId>
            <artifactId>derby</artifactId>
            <version>10.14.2.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.rat</groupId>
                <artifactId>apache-rat-plugin</artifactId>
                <configuration>
                    <excludes combine.children="append">
                        <exclude>src/test/resources/groovy/test_sql_04_insert_and_json.json</exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>


text:
{% extends 'admin/master.html' %}
{% from "security/_macros.html" import render_field_with_errors, render_field %}

{% block body %}
    {{ super() }}

Change Password

                <form action="{{ url_for_security('change_password') }}" method="POST" name="change_password_form">
                    {{ change_password_form.hidden_tag() }}
                    {{ render_field_with_errors(change_password_form.password, class="form-control") }}
                    {{ render_field_with_errors(change_password_form.new_password, class="form-control") }}
                    {{ render_field_with_errors(change_password_form.new_password_confirm, class="form-control") }}
                    {{ render_field(change_password_form.submit, class="btn btn-primary block full-width m-b") }}
                </form>

{% endblock body %}


text:
using System;
using MonoTouch.UIKit;

namespace FrozenHeadersGrid.UnitTests.Mocks
{
	internal class UIViewMock : UIView
	{
		public Action<System.Drawing.RectangleF> SetFrameDelegate { get; set; }

		public override System.Drawing.RectangleF Frame
		{
			get
			{
				return base.Frame;
			}
			set
			{
				base.Frame = value;
				if (SetFrameDelegate != null)
					SetFrameDelegate.Invoke(value);
			}
		}
	}
}


text:
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
from google.protobuf import descriptor as _descriptor
from google.protobuf import message as _message
from google.protobuf import reflection as _reflection
from google.protobuf import symbol_database as _symbol_database
from google.protobuf import descriptor_pb2
# @@protoc_insertion_point(imports)

_sym_db = _symbol_database.Default()

DESCRIPTOR = _descriptor.FileDescriptor(
  name='google/cloud/vision_v1p1beta1/proto/geometry.proto',
  package='google.cloud.vision.v1p1beta1',
  syntax='proto3',
  serialized_pb=_b('\n2google/cloud/vision_v1p1beta1/proto/geometry.proto\x12\x1dgoogle.cloud.vision.v1p1beta1\"\x1e\n\x06Vertex\x12\t\n\x01x\x18\x01 \x01(\x05\x12\t\n\x01y\x18\x02 \x01(\x05\"G\n\x0c\x42oundingPoly\x12\x37\n\x08vertices\x18\x01 \x03(\x0b\x32%.google.cloud.vision.v1p1beta1.Vertex\"+\n\x08Position\x12\t\n\x01x\x18\x01 \x01(\x02\x12\t\n\x01y\x18\x02 \x01(\x02\x12\t\n\x01z\x18\x03 \x01(\x02\x42|\n!com.google.cloud.vision.v1p1beta1B\rGeometryProtoP\x01ZCgoogle.golang.org/genproto/googleapis/cloud/vision/v1p1beta1;vision\xf8\x01\x01\x62\x06proto3')
)

_VERTEX = _descriptor.Descriptor(
  name='Vertex',
  full_name='google.cloud.vision.v1p1beta1.Vertex',
  filename=None,
  file=DESCRIPTOR,
  containing_type=None,
  fields=[
    _descriptor.FieldDescriptor(
      name='x', full_name='google.cloud.vision.v1p1beta1.Vertex.x', index=0,
      number=1, type=5, cpp_type=1, label=1,
      has_default_value=False, default_value=0,
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None, file=DESCRIPTOR),
    _descriptor.FieldDescriptor(
      name='y', full_name='google.cloud.vision.v1p1beta1.Vertex.y', index=1,
      number=2, type=5, cpp_type=1, label=1,
      has_default_value=False, default_value=0,
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None, file=DESCRIPTOR),
  ],
  extensions=[
  ],
  nested_types=[],
  enum_types=[
  ],
  options=None,
  is_extendable=False,
  syntax='proto3',
  extension_ranges=[],
  oneofs=[
  ],
  serialized_start=85,
  serialized_end=115,
)

_BOUNDINGPOLY = _descriptor.Descriptor(
  name='BoundingPoly',
  full_name='google.cloud.vision.v1p1beta1.BoundingPoly',
  filename=None,
  file=DESCRIPTOR,
  containing_type=None,
  fields=[
    _descriptor.FieldDescriptor(
      name='vertices', full_name='google.cloud.vision.v1p1beta1.BoundingPoly.vertices', index=0,
      number=1, type=11, cpp_type=10, label=3,
      has_default_value=False, default_value=[],
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None, file=DESCRIPTOR),
  ],
  extensions=[
  ],
  nested_types=[],
  enum_types=[
  ],
  options=None,
  is_extendable=False,
  syntax='proto3',
  extension_ranges=[],
  oneofs=[
  ],
  serialized_start=117,
  serialized_end=188,
)

_POSITION = _descriptor.Descriptor(
  name='Position',
  full_name='google.cloud.vision.v1p1beta1.Position',
  filename=None,
  file=DESCRIPTOR,
  containing_type=None,
  fields=[
    _descriptor.FieldDescriptor(
      name='x', full_name='google.cloud.vision.v1p1beta1.Position.x', index=0,
      number=1, type=2, cpp_type=6, label=1,
      has_default_value=False, default_value=float(0),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None, file=DESCRIPTOR),
    _descriptor.FieldDescriptor(
      name='y', full_name='google.cloud.vision.v1p1beta1.Position.y', index=1,
      number=2, type=2, cpp_type=6, label=1,
      has_default_value=False, default_value=float(0),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None, file=DESCRIPTOR),
    _descriptor.FieldDescriptor(
      name='z', full_name='google.cloud.vision.v1p1beta1.Position.z', index=2,
      number=3, type=2, cpp_type=6, label=1,
      has_default_value=False, default_value=float(0),
      message_type=None, enum_type=None, containing_type=None,
      is_extension=False, extension_scope=None,
      options=None, file=DESCRIPTOR),
  ],
  extensions=[
  ],
  nested_types=[],
  enum_types=[
  ],
  options=None,
  is_extendable=False,
  syntax='proto3',
  extension_ranges=[],
  oneofs=[
  ],
  serialized_start=190,
  serialized_end=233,
)

_BOUNDINGPOLY.fields_by_name['vertices'].message_type = _VERTEX
DESCRIPTOR.message_types_by_name['Vertex'] = _VERTEX
DESCRIPTOR.message_types_by_name['BoundingPoly'] = _BOUNDINGPOLY
DESCRIPTOR.message_types_by_name['Position'] = _POSITION
_sym_db.RegisterFileDescriptor(DESCRIPTOR)

Vertex = _reflection.GeneratedProtocolMessageType('Vertex', (_message.Message,), dict(
  DESCRIPTOR = _VERTEX,
  __module__ = 'google.cloud.vision_v1p1beta1.proto.geometry_pb2'
  ,
  __doc__ = """X coordinate.

  Attributes:
      y:
          Y coordinate.
  """,
  # @@protoc_insertion_point(class_scope:google.cloud.vision.v1p1beta1.Vertex)
  ))
_sym_db.RegisterMessage(Vertex)

BoundingPoly = _reflection.GeneratedProtocolMessageType('BoundingPoly', (_message.Message,), dict(
  DESCRIPTOR = _BOUNDINGPOLY,
  __module__ = 'google.cloud.vision_v1p1beta1.proto.geometry_pb2'
  ,
  __doc__ = """A bounding polygon for the detected image annotation.

  Attributes:
      vertices:
          The bounding polygon vertices.
  """,
  # @@protoc_insertion_point(class_scope:google.cloud.vision.v1p1beta1.BoundingPoly)
  ))
_sym_db.RegisterMessage(BoundingPoly)

Position = _reflection.GeneratedProtocolMessageType('Position', (_message.Message,), dict(
  DESCRIPTOR = _POSITION,
  __module__ = 'google.cloud.vision_v1p1beta1.proto.geometry_pb2'
  ,
  __doc__ = """A 3D position in the image, used primarily for Face detection landmarks.
  A valid Position must have both x and y coordinates. The position
  coordinates are in the same scale as the original image.

  Attributes:
      x:
          X coordinate.
      y:
          Y coordinate.
      z:
          Z coordinate (or depth).
  """,
  # @@protoc_insertion_point(class_scope:google.cloud.vision.v1p1beta1.Position)
  ))
_sym_db.RegisterMessage(Position)

DESCRIPTOR.has_options = True
DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n!com.google.cloud.vision.v1p1beta1B\rGeometryProtoP\001ZCgoogle.golang.org/genproto/googleapis/cloud/vision/v1p1beta1;vision\370\001\001'))
# @@protoc_insertion_point(module_scope)


text:
describe("Ext.app.bind.Formula", function() {
    var vm;
    beforeEach(function() {
        vm = new Ext.app.ViewModel({
            // this is a config not an instance so the VM knows it owns the instance
            scheduler: {
                tickDelay: 1000000
            }
        });
    });

    afterEach(function() {
        vm.destroy();
        vm = null;
        expect(Ext.util.Scheduler.instances.length).toBe(0);
    });

    function makeFormula(fn, name) {
        var o = {};
        o[name || 'fn'] = fn;
        vm.setFormulas(o);
        return vm.getRoot().children.fn.formula;
    }

    function fakeFn(s) {
        return {
            toString: function() {
                return s;
            }
        }
    }

    function matchExpr(fn, result) {
        var fake = makeFormula(Ext.emptyFn),
            expr;

        expr = fake.parseFormula({
            toString: function() {
                return fn;
            }
        });
        delete expr.$literal;
        expect(Ext.Object.getKeys(expr)).toEqual(result);
    }

    // we parse out the argument name, so it should give us argName.expression.
    // here, we just want to check whether we get the name correctly
    describe("argument parsing", function() {
        it("should work with a simple function definition", function() {
            matchExpr("function (get) { return get('foo'); };", ['foo']);
        });

        it("should parse a var with numbers in the name", function() {
            matchExpr("function (g2et) { return g2et('foo'); };", ['foo']);
        });

        it("should parse a var starting with an underscore", function() {
            matchExpr("function (_get) { return _get('foo'); };", ['foo']);
        });

        it("should parse a with multi vars", function() {
            matchExpr("function (get, some, other, stuff) { return get('foo'); };", ['foo']);
        });

        it("should parse with no spaces between function and parens", function() {
            matchExpr("function(get) { return get('foo'); };", ['foo']);
        });

        it("should parse with no spaces between parens and curly", function() {
            matchExpr("function (get){ return get('foo'); };", ['foo']);
        });

        it("should parse without an ending semi colon", function() {
            matchExpr("function (get) { return get('foo'); }", ['foo']);
        });

        it("should parse with leading spaces", function() {
            matchExpr("    function (get) { return get('foo'); }", ['foo']);
        });

        it("should parse with trailing spaces", function() {
            matchExpr("function (get) { return get('foo'); };                ", ['foo']);
        });
    });

    describe("recognizing bindings", function() {
        it("should parse a simple variable", function() {
            matchExpr("function (get) { return get('foo'); };", ['foo']);
        });

        it("should only match a variable once", function() {
            matchExpr("function (get) { return get('foo') + get('foo') + get('foo'); };", ['foo']);
        });

        it("should match multiple expressions", function() {
            matchExpr("function (get) { return get('foo') + get('bar') + get('baz'); };", ['foo', 'bar', 'baz']);
        });

        it("should match an expression with a number in it", function() {
            matchExpr("function (get) { return get('foo1'); };", ['foo1']);
        });

        it("should match an expression that starts with an underscore", function() {
            matchExpr("function (get) { return get('_foo'); };", ['_foo']);
        });

        it("should match as a dynamic property", function() {
            matchExpr("function (get) { return someObj[get('foo')]; };", ['foo']);
        });

        it("should match inside parens", function() {
            matchExpr("function (get) { return (get('foo') + 1 + get('bar')); };", ['foo', 'bar']);
        });

        it("should match an expression with double quotes", function() {
            matchExpr('function (get) { return get("foo"); };', ['foo']);
        });

        describe("non-matches", function() {
            it("should not match when the identifier has a prefix", function() {
                matchExpr("function (get) { return get('foo') + forget('bar'); };", ['foo']);
            });

            it("should not match when the identifier has a suffix", function() {
                matchExpr("function (get) { return get('foo') + getfor('bar'); };", ['foo']);
            });

            it("should not match when the identifier is a property of another object", function() {
                matchExpr("function (get) { return get('foo') + something.get('bar'); };", ['foo']);
            });
        });

        describe("functions", function() {
            it("should match only the expression part", function() {
                matchExpr("function (get) { return get('foo').substring(0, 3); };", ['foo']);
            });

            it("should match as the sole param to a function", function() {
                matchExpr("function (get) { return someFn(get('foo')) };", ['foo']);
            });

            it("should match as the first param to a function", function() {
                matchExpr("function (get) { return someFn(get('foo'), 1, 2) };", ['foo']);
            });

            it("should match as a middle param to a function", function() {
                matchExpr("function (get) { return someFn(1, get('foo'), 2) };", ['foo']);
            });

            it("should match as the last param to a function", function() {
                matchExpr("function (get) { return someFn(1, 2, get('foo')) };", ['foo']);
            });

            it("should match multiple params to a function", function() {
                matchExpr("function (get) { return someFn(get('foo'), get('bar')) };", ['foo', 'bar']);
            });
        });

        describe("nesting", function() {
            it("should match a nested expression", function() {
                matchExpr("function (get) { return get('foo.bar.baz'); };", ['foo.bar.baz']);
            });

            it("should match multiple nested subpaths", function() {
                matchExpr("function (get) { return get('foo.bar.baz.a') + get('foo.bar.baz.b'); };", ['foo.bar.baz.a', 'foo.bar.baz.b']);
            });

            it("should match paths at different depths", function() {
                matchExpr("function (get) { return get('foo') + get('bar.baz.a.b') + get('some.other.path.x.y'); };", ['foo', 'bar.baz.a.b', 'some.other.path.x.y']);
            });

            it("should match get calls inside get calls", function() {
                matchExpr("function (get) { return (get(get('foo') + get('bar')); };", ['foo', 'bar']);
            });
        })
    });
});