text:
Explore and evaluate different options for building golang based cli.

# References
- https://gobyexample.com/command-line-flags
- https://github.com/mitchellh/cli
- https://github.com/spf13/cobra
- https://github.com/alecthomas/kingpin
- https://github.com/urfave/cli

redpajama_set_name: RedPajamaGithub


text:
/*
 * THIS FILE IS AUTO GENERATED FROM 'lib/lex/identifier_lexer.kep'
 * DO NOT EDIT
*/
define(["require", "exports", "bennu/parse", "bennu/text", "./common", "./reserved_word_lexer"], (function(require,
    exports, __o, __o0, __o1, __o2) {
    "use strict";
    var zwnj, zwj, unicodeLetter, unicodeDigit, unicodeConnectorPunctuation, identifierStart, identifierPart,
            identifierParts, identifierName, identifier, always = __o["always"],
        bind = __o["bind"],
        cons = __o["cons"],
        choice = __o["choice"],
        either = __o["either"],
        fail = __o["fail"],
        many = __o["many"],
        label = __o["label"],
        character = __o0["character"],
        oneOf = __o0["oneOf"],
        join = __o1["join"],
        match = __o1["match"],
        reservedWordList = __o2["reservedWordList"];
    (zwnj = character(""));
    (zwj = character(""));
    (unicodeLetter = match(
        "   \\p{Lu}            (?#Uppercase letter)    |   \\p{Ll}            (?#Lowercase letter)    |   \\p{Lt}            (?#Titlecase letter)    |   \\p{Lm}            (?#Modifier letter)    |   \\p{Lo}            (?#Other letter)    |   \\p{Nl}            (?#Letter number)    "
    ));
    (unicodeDigit = match("\\p{Nd}(?#Number digit)"));
    (unicodeConnectorPunctuation = match("\\p{Pc}(?#Connector Punctuation)"));
    (identifierStart = either(unicodeLetter, oneOf("$_")));
    (identifierPart = choice(identifierStart, unicodeDigit, unicodeConnectorPunctuation, zwnj, zwj));
    (identifierParts = many(identifierPart));
    (identifierName = cons(identifierStart, identifierParts));
    (identifier = label("Identifier Lexer", bind(join(identifierName), (function(name) {
        return ((reservedWordList.indexOf(name) >= 0) ? fail() : always(name));
    }))));
    (exports["zwnj"] = zwnj);
    (exports["zwj"] = zwj);
    (exports["unicodeLetter"] = unicodeLetter);
    (exports["unicodeDigit"] = unicodeDigit);
    (exports["unicodeConnectorPunctuation"] = unicodeConnectorPunctuation);
    (exports["identifierStart"] = identifierStart);
    (exports["identifierPart"] = identifierPart);
    (exports["identifierParts"] = identifierParts);
    (exports["identifierName"] = identifierName);
    (exports["identifier"] = identifier);
}));


text:
layout: post
published: true
title: 'Do I Need to test my code?'
subtitle: 'What should I test?'
date: '2019-07-20'
image: /assets/img/test.jpeg
share-img: /assets/img/test.jpeg
tags: [tests, notes]
---

It is difficult to find any developer who does not agree with the title of this publication, even more, if asked in a job interview. Although, some developers took what Kent Beck once said ["I get paid for **code that works**, not for tests"](https://stackoverflow.com/questions/153234/how-deep-are-your-unit-tests/153565#153565) as a license to not create tests at all. I think we should take his words with special care. He did not mean that you should not develop tests because you are not paid for that, but that you must _concentrate_ on your production code.

Tests are important because they give you confidence when you make changes and ensures a certain level of quality in the service being tested. They also serve as some kind of documentation of the expected behavior of a piece of code. But everything needs moderation, no tests might be as harmful as too many bad tests.

Now, if the title question creates debate, the subtitle is even worse...

## What should I test?

I know of companies that do not care at all about test coverage, others that think anything below 90% is bad. So, *how much testing is enough?*

### Do I need 100% Coverage?

Continuing with Kent Beck quotes I would like to bring one of your tweets on this topic:

> Being proud of 100% test coverage is like being proud of reading every word in the newspaper. Some are more important than others.
>
> --Kent Beck (@KentBeck) [Dec 24, 2016](https://twitter.com/kentbeck/status/812703192437981184)

Also, as pointed in his book [Extreme Programming Explained: Embrace Change](https://www.amazon.com/dp/0201616416/):

> It is impossible to test absolutely everything, without the tests being as complicated and error-prone as the code.

Testing everything will probably lead you to perform non-orthogonal tests, which increases the likelihood that when you make a small change in your code, thousands of tests will be broken. Then, you spend more time fixing tests than creating **code that works**.

When making small changes causes many tests to break, developers are afraid to make changes because each time this happens they feel frustrated and unproductive. If we take into consideration that one of the reasons for testing is to feel safe when making changes to the production code, then we can agree that there is something wrong with the equation.

So, no, I don't think you need 100% coverage. I know that is a controversial statement, there are some good reasons to argue the contrary, but I think that the pros of that aren't enough to aim for 100% coverage.

## What is (not) a Unit Test?

Sometimes is easier to define something by saying what is NOT, and Michael Feathers can help us with that. For him [a test is not a unit test if:](https://www.artima.com/weblogs/viewpost.jsp?thread=126923)

> It talks to the database
> It communicates across the network
> It touches the file system
> It can't run at the same time as any of your other unit tests
> You have to do special things to your environment (such as editing config files) to run it.

You might ask: Why? Well, mainly because tests that do that sort of thing are generally slow and cause unstable tests. The idea of tests is to give you quick feedback on your code; If something broke or if you have the desired behavior; If you have tests that work sometimes and fail other times without obvious reasons, you will lose confidence in your tests, ignore them because "it is normal for these tests to fail".

Finally, unit tests must be quick, they are designed to give you quick feedback. You should not have to think twice before executing them. If they are slow, they lose their reason. Developers will not execute them so often, they will avoid wasting that time.

### Should I test third-party libraries?

Well, if you do it, for sure it won't be an easy task. Steve Freeman in his book [Growing Object-Oriented Software, Guided by Tests](https://www.amazon.es/Growing-Object-Oriented-Software-Guided-Signature/dp/0321503627) has a couple of good arguments to persuade you to avoid it:

> Depending on the quality of the library might be hard to get the right state to be able to test it.

When you use a third-party library, you must adapt to its design implementation. You gain the value of what they provide but lose some freedom in the implementation. Sometimes, that design is not easy to test and will require a lot of work just to establish the correct state to be able to test it. Also, you have to deal with the second point:

> Pain to keep test up to date with upgrades to the library.

Even if you are using an open-source library and can redefine the API to facilitate testing and use for your purpose, you will have to spend some time each time a library update is required.

So, what should we do? No tests at all? No. Define an adapter, test the adapter. And later test these adapters with focused integration tests to confirm your understanding of how the third-party API works.

There are some exceptions where mocking third-party libraries can be helpful. We might use mocks to simulate behavior that is hard to trigger with the real library, such as throwing exceptions. Similarly, we might use mocks to test a sequence of calls, for example making sure that a transaction is rolled back if there's a failure.

### Testing private methods

In [Pragmatic Unit Testing](https://www.amazon.es/Pragmatic-Unit-Testing-Junit-Programmers/dp/0974514012), Dave Thomas and Andy Hunt write:

> Most of the time, you should be able to test a class by exercising its public methods. If there is significant functionality that is hidden behind private or protected access, that might be a warning sign that there's another class in there struggling to get out.

A private method usually is an implementation detail. Testing implementation details is not good for your health. Usually causes that when you do a small refactor many tests fail. You should be able to test your classes through its public methods.

### Testing implementation Details

Programmer tests should be sensitive to behavior changes and insensitive to structural changes. You write a new test when you need to fulfill a new requirement, no because you created a new method or class. That means that you should not write a new test just because you refactored the code, a refactor is a structural change, hence the behavior should remain the same.

When you test implementation details instead of behavior there are a couple of things that can go wrong:

*  Break when you refactor application code.  **False negatives**
*  Not fail when you break the application code.  **False positives**

The first one, because your test is highly coupled to the structure of your application code. The second one, because you are testing structure, not behavior.

To put closure on this subject I would like to quote Ryan Fynke. In [his article](https://teamgaslight.com/blog/testing-behavior-vs-testing-implementation) he found an elegant way to put the difference between testing implementation details and behavior:

>### When I test for behavior, I'm saying:
>"I don't care how you come up with the answer, just make sure that the answer is correct under this set of circumstances"
>### When I test for implementation, I'm saying:
>"I don't care what the answer is, just make sure you do this thing while figuring it out."

PD: Just for fun, read [this](http://edw519.posthaven.com/it-takes-6-days-to-change-1-line-of-code) story.


text:
========
ficloud
========

ficloud alows to deploy your fig infrastructure to remote servers. Also it provides all the services needed for hosting production apps.

NB! ficloud is currently in development stage.

Deploy your fig-docker environment easily
------------------------------------------

 * define your app config through Dockerfile and fig.yml
 * easy deploy through git push
 * pushing several versions of app (dev, staging, prod ... etc)
 * simple nginx based balancer
 * easy switch balancer endpoint between app versions (ex swap prod and dev)
 * persistent storage for containers
 * easy copying persistence storage between containers (prod -> staging, etc)
 * ftp access for container persistence storage

Get started quickly with a simple example in quickstart.

Easy installation
-----------------
You can use pip to install ficloud quickly and easily::

    $ pip install ficloud

Need more help with installing? See installation.

User's Guide
============

.. toctree::
   :maxdepth: 2

   installation
   quickstart

Contribute
==========
Found a bug in or want a feature added to ficloud?
You can fork the official https://github.com/pywizard/ficloud or file an issue ticket
on github. You can also ask questions at the official
ficloud-project@googlegroups.com or directli in google-group https://groups.google.com/forum/#!forum/ficloud-project.

Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`


text:
package de.knightsoftnet.mtwidgets.client.ui.widget.oracle;

import de.knightsoftnet.validators.shared.data.PhoneNumberData;

import org.apache.commons.lang3.StringUtils;

/**
 * suggest oracle of phone number suggest widget.
 *
 * @author Manfred Tremmel
 *
 */
public class PhoneNumberUriOracle
    extends AbstractPhoneNumberLocalOracle<PhoneNumberUriItemSuggest> {

  /**
   * default constructor.
   */
  public PhoneNumberUriOracle() {
    super(PhoneNumberUriItemSuggest.class);
  }

  @Override
  protected PhoneNumberUriItemSuggest createInstance(final PhoneNumberData pentry) {
    return new PhoneNumberUriItemSuggest(pentry.getCountryCode(), pentry.getCountryName(),
        pentry.getAreaCode(), pentry.getAreaName());
  }

  @Override
  protected boolean needSuggest(final String pentry) {
    return StringUtils.isNotEmpty(pentry) && StringUtils.countMatches(pentry, "-") < 2;
  }
}


text:
<?php

namespace Oro\Bundle\LocaleBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Intl\Intl;
use Symfony\Component\OptionsResolver\OptionsResolver;

class LocaleType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(
            [
                'choices' => array_flip(Intl::getLocaleBundle()->getLocaleNames('en')),
            ]
        );
    }

    /**
     * {@inheritdoc}
     */
    public function getParent()
    {
        return 'locale';
    }

    /**
     * {@inheritdoc}
     */
    public function getName()
    {
        return $this->getBlockPrefix();
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'oro_locale';
    }
}


text:
class Turtle
  include Math # turtles understand math methods
  DEG = Math::PI / 180.0

  attr_accessor :track
  alias run instance_eval

  def initialize
    clear
  end

  attr_reader :xy, :heading

  # Place the turtle at [x, y]. The turtle does not draw when it changes
  # position.
  def xy=(coords)
    @xy = coords.dup
  end

  # Set the turtle's heading to <degrees>.
  def heading=(degrees)
    @heading = degrees
  end

  # Raise the turtle's pen. If the pen is up, the turtle will not draw;
  # i.e., it will cease to lay a track until a pen_down command is given.
  def pen_up
    @pen = false
  end

  # Lower the turtle's pen. If the pen is down, the turtle will draw;
  # i.e., it will lay a track until a pen_up command is given.
  def pen_down
    @pen = true
  end

  # Is the pen up?
  def pen_up?
    !pen_down?
  end

  # Is the pen down?
  def pen_down?
    @pen
  end

  # Places the turtle at the origin, facing north, with its pen up.
  # The turtle does not draw when it goes home.
  def home
    @xy = [0.0, 0.0]
    @heading = 0.0
    pen_up
  end

  # Homes the turtle and empties out it's track.
  def clear
    home
    @track = []
  end

  # Turn right through the angle <degrees>.
  def right(degrees)
    @heading += degrees
  end

  # Turn left through the angle <degrees>.
  def left(degrees)
    right(-degrees)
  end

  # Move forward by <steps> turtle steps.
  def forward(steps)
    x = @xy[0] + steps * cos((90 - @heading) * DEG)
    y = @xy[1] + steps * sin((90 - @heading) * DEG)
    go([x,y])
  end

  # Move backward by <steps> turtle steps.
  def back(steps)
    forward(-steps)
  end

  # Move to the given point.
  def go(pt)
    if @pen
      if !@track.empty? && @track.last.last == @xy
        @track.last << pt.dup
      else
        @track << [@xy.dup, pt.dup]
      end
    end
    @xy = pt.dup
  end

  # Turn to face the given point.
  def toward(pt)
    @heading = 90 - acos((pt[0] - @xy[0]) / distance(pt)) / DEG
  end

  # Return the distance between the turtle and the given point.
  def distance(pt)
    sqrt((@xy[0] - pt[0]) ** 2 + (@xy[1] - pt[1]) ** 2)
  end

  # Traditional abbreviations for turtle commands.
  alias fd forward
  alias bk back
  alias rt right
  alias lt left
  alias pu pen_up
  alias pd pen_down
  alias pu? pen_up?
  alias pd? pen_down?
  alias set_h heading=
  alias set_xy xy=
  alias face toward
  alias dist distance
end


text:
//// [commentsVariableStatement1.js]
/** Comment */
var v = 1;

////[commentsVariableStatement1.d.ts]
/** Comment */
declare var v: number;


text:
using UnityEngine;
using System.Collections;

public class AimController : MonoBehaviour {

	public float speed = 1f;

	Camera cam;

	// Use this for initialization
	void Start () {
		cam = GameObject.FindGameObjectWithTag ("MainCamera").GetComponent<Camera>();
		if (cam == null)
			Debug.LogError ("No camera found.");
	}

	// Update is called once per frame
	void Update () {
		if (PauseMenu.PauseMenuEnabled)
			return;

		Vector3 pos = cam.WorldToScreenPoint(transform.position);
		Vector3 dir = Input.mousePosition - pos;
		float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
		transform.rotation = Quaternion.AngleAxis(angle - 90f, Vector3.forward);
	}
}


text:
package macroutils.templates.simtools;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import macroutils.MacroUtils;
import macroutils.UserDeclarations;
import macroutils.creator.MainCreator;
import macroutils.getter.MainGetter;
import macroutils.setter.MainSetter;
import star.base.report.Monitor;
import star.common.HistogramPlot;
import star.common.Simulation;
import star.common.StarPlot;
import star.common.UserTag;

/**
 * This class will create some post processing objects to evaluate Mesh Metrics in current
 * Simulation.
 *
 * The following will be created:
 *

 *
Histogram Plots covering important mesh metrics;
 *

 *
 * @since April of 2019
 * @author Fabio Kasper
 */
public class MeshMetrics {

    private final MainCreator _add;
    private final MainGetter _get;
    private final MacroUtils _mu;
    private final MainSetter _set;
    private final Simulation _sim;
    private final UserTag _tag;
    private final UserDeclarations _ud;

    /**
     * Main constructor for this class.
     *
     * @param m given MacroUtils object.
     */
    public MeshMetrics(MacroUtils m) {

        _mu = m;
        _sim = m.getSimulation();
        _ud = _mu.userDeclarations;
        _add = _mu.add;
        _get = _mu.get;
        _set = _mu.set;

        _tag = _add.tools.tag("Mesh Metrics");

    }

    /**
     * Execute this class.
     */
    public void execute() {

        createHistograms();

    }

    /**
     * Remove all artifacts created by this class.
     */
    public void removeArtifacts() {

        _mu.io.say.action("Removing artifacts", true);

        List<StarPlot> createdPlots = _get.plots.all(false).stream()
                .filter(plot -> plot.getTagGroup().has(_tag))
                .collect(Collectors.toList());

        List<Monitor> createdMonitors = _get.monitors.all(false).stream()
                .filter(monitor -> monitor.getTagGroup().has(_tag))
                .collect(Collectors.toList());

        _mu.io.say.msg("Removing Plots...");
        _sim.getPlotManager().removeObjects(createdPlots);

        _mu.io.say.msg("Removing Monitors...");
        _sim.getMonitorManager().removeObjects(createdMonitors);
        _mu.io.say.ok(true);

        _mu.remove.tag(_tag);

    }

    private void createHistogram(Metric metric) {

        String name;

        _ud.namedObjects.clear();
        _ud.ff = _get.objects.fieldFunction(metric.getFunction(), true);

        if (metric instanceof VolumeMeshMetric) {
            _ud.namedObjects.addAll(_get.regions.all(false));
            name = metric.getFunction() + " on All Regions";
        } else {
            _ud.namedObjects.addAll(_get.partSurfaces.all(false));
            name = metric.getFunction() + " Part Surfaces";
        }

        HistogramPlot hp = _add.plot.histogram(_ud.namedObjects, _ud.ff);
        hp.setPresentationName(name);
        hp.setTitle(name);
        hp.open();

        _set.object.tag(hp, _tag, true);

    }

    private void createHistograms() {

        Arrays.stream(SurfaceMeshMetric.values()).forEach(metric -> createHistogram(metric));
        Arrays.stream(VolumeMeshMetric.values()).forEach(metric -> createHistogram(metric));

    }

    private interface Metric {

        public String getFunction();

    }

    private enum SurfaceMeshMetric implements Metric {

        FACE_VALIDITY("Face Validity");

        private final String function;

        private SurfaceMeshMetric(final String function) {
            this.function = function;
        }

        @Override
        public String getFunction() {
            return function;
        }

    }

    private enum VolumeMeshMetric implements Metric {

        CELL_QUALITY("Cell Quality"),
        SKEWNESS_ANGLE("Skewness Angle"),
        VOLUME_CHANGE("Volume Change");

        private final String function;

        private VolumeMeshMetric(final String function) {
            this.function = function;
        }

        @Override
        public String getFunction() {
            return function;
        }

    }

}


text:
import unittest

from streamlink.plugins.tv999 import TV999

class TestPluginTV999(unittest.TestCase):
    def test_can_handle_url(self):
        should_match = [
            'http://tv999.bg/live.html',
            'http://www.tv999.bg/live.html',
            'https://tv999.bg/live.html',
            'https://www.tv999.bg/live.html',
        ]
        for url in should_match:
            self.assertTrue(TV999.can_handle_url(url))

    def test_can_handle_url_negative(self):
        should_not_match = [
            'http://tv999.bg/',
            'https://tv999.bg/live',
            'https://example.com/index.html',
        ]
        for url in should_not_match:
            self.assertFalse(TV999.can_handle_url(url))


text:
<?php
class TDL_DeadlineTests extends PHPUnit_Framework_TestCase {
    public function testEuropeanDate() {
        // 1416783599
        $a = new TDLDeadline();
        $a->fromForm("23. 11. 2014");
        $this->assertEquals(1416783599, $a->getDeadline());
    }
}
?>


text:
package org.gbif.checklistbank.index;

import org.gbif.api.model.checklistbank.Description;
import org.gbif.api.model.checklistbank.Distribution;
import org.gbif.api.model.checklistbank.NameUsage;
import org.gbif.api.model.checklistbank.NameUsageContainer;
import org.gbif.api.model.checklistbank.SpeciesProfile;
import org.gbif.api.model.checklistbank.VernacularName;
import org.gbif.api.model.registry.Dataset;
import org.gbif.api.service.registry.DatasetService;
import org.gbif.api.vocabulary.Language;
import org.gbif.api.vocabulary.NomenclaturalStatus;
import org.gbif.checklistbank.index.model.NameUsageSolrSearchResult;
import org.gbif.common.search.util.AnnotationUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.common.base.Strings;
import com.google.common.collect.BiMap;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.lucene.analysis.charfilter.HTMLStripCharFilterFactory;
import org.apache.solr.common.SolrInputDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Threadsafe class that transforms a {@link NameUsage} object into {@link SolrInputDocument}.
 */
public class NameUsageDocConverter {

  private static final String CONCAT = " # ";
  private static final Pattern LANG_SPLIT = Pattern.compile("^([a-zA-Z]*)" + CONCAT + "(.*)$");
  private static final HTMLStripCharFilterFactory htmlStripFactory = new HTMLStripCharFilterFactory(Maps.<String, String>newHashMap());
  // Service layer dependencies
  private final DatasetService datasetService;

  /**
   * Holds a map of {@link NameUsage} properties (Java fields) to Solr fields name.
   */
  private final BiMap<String, String> fieldPropertyMap;

  /**
   * Cache used for holding {@link Dataset} objects previously retrieved.
   */
  private final ConcurrentHashMap<UUID, Dataset> checkListCache;

  /**
   * Logger for the {@link NameUsageDocConverter} class
   */
  protected static Logger log = LoggerFactory.getLogger(NameUsageDocConverter.class);

  @Inject
  public NameUsageDocConverter(DatasetService datasetService) {

    this.datasetService = datasetService;

    // initializes the map of Solr fields to Java fields
    fieldPropertyMap = AnnotationUtils.initFieldsPropertiesMap(NameUsageSolrSearchResult.class);
    checkListCache = new ConcurrentHashMap<UUID, Dataset>();
  }

  public static Description deserializeDescription(String description) {
    Description d = new Description();
    d.setDescription(description);
    return d;
  }

  public static VernacularName deserializeVernacularName(String vernacularName) {
    Matcher m = LANG_SPLIT.matcher(vernacularName);
    VernacularName vn = new VernacularName();
    if (m.find()) {
      vn.setLanguage(Language.fromIsoCode(m.group(1)));
      vn.setVernacularName(m.group(2));
    } else {
      vn.setVernacularName(vernacularName);
    }
    return vn;
  }

  public static String serializeDescription(Description description) {
    return stripHtml(description.getDescription());
  }

  private static String stripHtml(String input) {
    if (Strings.isNullOrEmpty(input)) {
      return null;
    }
    StringBuffer sb = new StringBuffer();
    BufferedReader br = new BufferedReader(htmlStripFactory.create(new StringReader(input)));
    String aux;
    try {
      while ((aux = br.readLine()) != null) {
        sb.append(aux);
      }
    } catch (IOException e) {
      log.error("Failed to read description input");
    }
    return sb.toString();
  }

  public static String serializeVernacularName(VernacularName vernacularName) {
    return vernacularName.getLanguage().getIso2LetterCode() + CONCAT + vernacularName.getVernacularName();
  }

  /**
   * Takes a Generic object and transform it into a {@link SolrInputDocument}.
   *
   * @param nameUsage to be transformed into a {@link SolrInputDocument}.
   *
   * @return a {@link SolrInputDocument} using the Object parameter.
   */
  public SolrInputDocument toObject(NameUsage nameUsage, List<VernacularName> vernacularNames,
    List<Description> descriptions, List<Distribution> distributions, List<SpeciesProfile> speciesProfiles) {
    try {
      SolrInputDocument solrInputDocument = new SolrInputDocument();
      // Uses the pre-initialized field-property map to find the corresponding Solr field of a Java field.
      for (String field : fieldPropertyMap.keySet()) {
        String property = fieldPropertyMap.get(field);
        // Complex properties and Enum types properties are handled by utility methods.
        if (!property.endsWith("Serialized") && !property.equals("extinct")
            && !property.equals("marine") && !property.equals("nomenclaturalStatusAsInts") && !property
          .equals("taxonomicStatus") && !property.equals("rank") && !property.equals("nameType")) {
          solrInputDocument.addField(field, BeanUtils.getProperty(nameUsage, property));
        }
      }
      // higher taxa
      addHigherTaxonKeys(nameUsage, solrInputDocument);
      // extract info from usage components
      addVernacularNames(solrInputDocument, vernacularNames);
      addDescriptions(nameUsage, solrInputDocument, descriptions);
      addDistributionsAndThreatStatus(nameUsage, solrInputDocument, distributions);
      addSpeciesProfiles(nameUsage, solrInputDocument, speciesProfiles);
      // enums
      addNomenclaturalStatus(nameUsage, solrInputDocument);
      addTaxonomicStatus(nameUsage, solrInputDocument);
      addRank(nameUsage, solrInputDocument);
      addNameType(nameUsage, solrInputDocument);
      return solrInputDocument;
    } catch (Exception e) {
      log.error("Error converting usage {} to solr document", nameUsage.getKey(), e);
      throw new RuntimeException(e);
    }
  }

  /**
   * Utility method that iterates over all the {@link Description} objects of a {@link NameUsage}.
   *
   * @param nameUsage         existing {@link NameUsage}
   * @param solrInputDocument to be modified by adding the description fields
   */
  private void addDescriptions(NameUsage nameUsage, SolrInputDocument solrInputDocument,
    List<Description> descriptions) {
    if (descriptions == null) {
      return;
    }
    for (Description description : descriptions) {
      solrInputDocument.addField("description", serializeDescription(description));
    }
  }

  /**
   * Utility method that iterates over all the {@link Distribution} objects of a {@link NameUsage}.
   *
   * @param nameUsage         existing {@link NameUsage}
   * @param solrInputDocument to be modified by adding the distributions fields
   */
  private void addDistributionsAndThreatStatus(NameUsage nameUsage, SolrInputDocument solrInputDocument,
    List<Distribution> distributions) {
    if (distributions == null) {
      return;
    }
    for (Distribution distribution : distributions) {
      if (distribution.getThreatStatus() != null) {
        solrInputDocument.addField("threat_status_key", distribution.getThreatStatus().ordinal());
      }
    }
  }

  /**
   * Adds the multivalued field higher_taxon_nub_key field.
   *
   * @param nameUsage         a existing {@link NameUsage}.
   * @param solrInputDocument to be modified by adding the higher taxon fields.
   */
  private void addHigherTaxonKeys(NameUsage nameUsage, SolrInputDocument solrInputDocument) {
    solrInputDocument.addField("higher_taxon_nub_key", nameUsage.getKingdomKey());
    solrInputDocument.addField("higher_taxon_nub_key", nameUsage.getPhylumKey());
    solrInputDocument.addField("higher_taxon_nub_key", nameUsage.getClassKey());
    solrInputDocument.addField("higher_taxon_nub_key", nameUsage.getOrderKey());
    solrInputDocument.addField("higher_taxon_nub_key", nameUsage.getFamilyKey());
    solrInputDocument.addField("higher_taxon_nub_key", nameUsage.getGenusKey());
    solrInputDocument.addField("higher_taxon_nub_key", nameUsage.getSpeciesKey());
  }

  /**
   * Adds the name type field to the Solr document.
   *
   * @param nameUsage         a existing {@link NameUsage}.
   * @param solrInputDocument to be modified by adding the name type fields.
   */
  private void addNameType(NameUsage nameUsage, SolrInputDocument solrInputDocument) {
    try {
      // Uses the converter to get the key value
      if (nameUsage.getNameType() != null) {
        solrInputDocument.addField("name_type", nameUsage.getNameType().ordinal());
      }
    } catch (Exception e) {
      log.error("Error converting enum", e);
    }
  }

  /**
   * Adds the nomenclatural status fields to the Solr document.
   *
   * @param nameUsage         a existing {@link NameUsage}.
   * @param solrInputDocument to be modified by adding the nomenclatural status fields.
   */
  private void addNomenclaturalStatus(NameUsage nameUsage, SolrInputDocument solrInputDocument) {
    try {
      if (nameUsage.getNomenclaturalStatus() != null) {
        for (NomenclaturalStatus ns : nameUsage.getNomenclaturalStatus()) {
          // Uses the converter to get the key and name values
          solrInputDocument.addField("nomenclatural_status_key", ns.ordinal());
        }
      }
    } catch (Exception e) {
      log.error("Error converting enum", e);
    }
  }

  /**
   * Adds the rank fields to the Solr document.
   *
   * @param nameUsage         a existing {@link NameUsage}.
   * @param solrInputDocument to be modified by adding the rank fields.
   */
  private void addRank(NameUsage nameUsage, SolrInputDocument solrInputDocument) {
    try {
      if (nameUsage.getRank() != null) {
        solrInputDocument.addField("rank_key", nameUsage.getRank().ordinal());
      }
    } catch (Exception e) {
      log.error("Error converting enum", e);
    }
  }

  /**
   * Utility method that iterates over all the {@link SpeciesProfile} objects of a {@link NameUsage}.
   *
   * @param nameUsage         existing {@link NameUsage}
   * @param solrInputDocument to be modified by adding the species profiles(extinct & marine) fields
   */
  private void addSpeciesProfiles(NameUsage nameUsage, SolrInputDocument solrInputDocument,
    List<SpeciesProfile> speciesProfiles) {
    if (speciesProfiles == null) {
      return;
    }    // add profiles to container that has logic to calculate a single boolean flag
    NameUsageContainer container = new NameUsageContainer();
    container.setSpeciesProfiles(speciesProfiles);

    // use container logic to build a single value
    solrInputDocument.addField("extinct", container.isExtinct());
    solrInputDocument.addField("marine", container.isMarine());
  }

  /**
   * Adds the taxonomic status fields to the Solr document.
   *
   * @param nameUsage         a existing {@link NameUsage}.
   * @param solrInputDocument to be modified by adding the taxonomic statu fields.
   */
  private void addTaxonomicStatus(NameUsage nameUsage, SolrInputDocument solrInputDocument) {
    try {
      if (nameUsage.getTaxonomicStatus() != null) {
        // Uses the converter to get the key and name values
        solrInputDocument.addField("taxonomic_status_key", nameUsage.getTaxonomicStatus().ordinal());
      }
    } catch (Exception e) {
      log.error("Error converting enum", e);
    }
  }

  /**
   * Utility method that iterates over all the {@link VernacularName} objects of a {@link NameUsage}.
   *
   * @param solrInputDocument to be modified by adding the vernacular name fields
   */
  private void addVernacularNames(SolrInputDocument solrInputDocument,
    List<VernacularName> vernacularNames) {
    if (vernacularNames == null) {
      return;
    }
    for (VernacularName vernacularName : vernacularNames) {
      solrInputDocument.addField("vernacular_name", vernacularName.getVernacularName());
      if (vernacularName.getLanguage() != null) {
        solrInputDocument.addField("vernacular_lang", vernacularName.getLanguage().getIso2LetterCode());
        solrInputDocument.addField("vernacular_name_lang", serializeVernacularName(vernacularName));
      }
    }
  }

  /**
   * Uses the cache to get a instance of the {@link Dataset} using the checklistUUID parameter.
   * If the {@link UUID} paramater is not found in the Cache the Data Base is consulted.
   *
   * @param checklistUUID existing {@link Dataset} key.
   *
   * @return a {@link Dataset} object.
   */
  private Dataset getChecklist(UUID checklistUUID) {
    if (!checkListCache.containsKey(checklistUUID)) {
      Dataset ds = datasetService.get(checklistUUID);
      if (ds == null) {
        log.warn("Checklist {} not found in registry!", checklistUUID);
        ds = new Dataset();
        ds.setKey(checklistUUID);
        ds.setTitle("[" + checklistUUID.toString() + "] ???");
      }
      checkListCache.put(checklistUUID, ds);
    }
    return checkListCache.get(checklistUUID);
  }

}


text:
To start searching a file as you type the search string, turn on the `incsearch` option in your `.vimrc` file:

```
set incsearch
```

You can also turn on the highlighting of search results:

```
set hlsearch
```


text:
#include "android-base/strings.h"

#include <gtest/gtest.h>

#include <string>
#include <vector>
#include <set>
#include <unordered_set>

TEST(strings, split_empty) {
  std::vector<std::string> parts = android::base::Split("", ",");
  ASSERT_EQ(1U, parts.size());
  ASSERT_EQ("", parts[0]);
}

TEST(strings, split_single) {
  std::vector<std::string> parts = android::base::Split("foo", ",");
  ASSERT_EQ(1U, parts.size());
  ASSERT_EQ("foo", parts[0]);
}

TEST(strings, split_simple) {
  std::vector<std::string> parts = android::base::Split("foo,bar,baz", ",");
  ASSERT_EQ(3U, parts.size());
  ASSERT_EQ("foo", parts[0]);
  ASSERT_EQ("bar", parts[1]);
  ASSERT_EQ("baz", parts[2]);
}

TEST(strings, split_with_empty_part) {
  std::vector<std::string> parts = android::base::Split("foo,,bar", ",");
  ASSERT_EQ(3U, parts.size());
  ASSERT_EQ("foo", parts[0]);
  ASSERT_EQ("", parts[1]);
  ASSERT_EQ("bar", parts[2]);
}

TEST(strings, split_with_trailing_empty_part) {
  std::vector<std::string> parts = android::base::Split("foo,bar,", ",");
  ASSERT_EQ(3U, parts.size());
  ASSERT_EQ("foo", parts[0]);
  ASSERT_EQ("bar", parts[1]);
  ASSERT_EQ("", parts[2]);
}

TEST(strings, split_null_char) {
  std::vector<std::string> parts =
      android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1));
  ASSERT_EQ(2U, parts.size());
  ASSERT_EQ("foo", parts[0]);
  ASSERT_EQ("bar", parts[1]);
}

TEST(strings, split_any) {
  std::vector<std::string> parts = android::base::Split("foo:bar,baz", ",:");
  ASSERT_EQ(3U, parts.size());
  ASSERT_EQ("foo", parts[0]);
  ASSERT_EQ("bar", parts[1]);
  ASSERT_EQ("baz", parts[2]);
}

TEST(strings, split_any_with_empty_part) {
  std::vector<std::string> parts = android::base::Split("foo:,bar", ",:");
  ASSERT_EQ(3U, parts.size());
  ASSERT_EQ("foo", parts[0]);
  ASSERT_EQ("", parts[1]);
  ASSERT_EQ("bar", parts[2]);
}

TEST(strings, trim_empty) {
  ASSERT_EQ("", android::base::Trim(""));
}

TEST(strings, trim_already_trimmed) {
  ASSERT_EQ("foo", android::base::Trim("foo"));
}

TEST(strings, trim_left) {
  ASSERT_EQ("foo", android::base::Trim(" foo"));
}

TEST(strings, trim_right) {
  ASSERT_EQ("foo", android::base::Trim("foo "));
}

TEST(strings, trim_both) {
  ASSERT_EQ("foo", android::base::Trim(" foo "));
}

TEST(strings, trim_no_trim_middle) {
  ASSERT_EQ("foo bar", android::base::Trim("foo bar"));
}

TEST(strings, trim_other_whitespace) {
  ASSERT_EQ("foo", android::base::Trim("\v\tfoo\n\f"));
}

TEST(strings, join_nothing) {
  std::vector<std::string> list = {};
  ASSERT_EQ("", android::base::Join(list, ','));
}

TEST(strings, join_single) {
  std::vector<std::string> list = {"foo"};
  ASSERT_EQ("foo", android::base::Join(list, ','));
}

TEST(strings, join_simple) {
  std::vector<std::string> list = {"foo", "bar", "baz"};
  ASSERT_EQ("foo,bar,baz", android::base::Join(list, ','));
}

TEST(strings, join_separator_in_vector) {
  std::vector<std::string> list = {",", ","};
  ASSERT_EQ(",,,", android::base::Join(list, ','));
}

TEST(strings, join_simple_ints) {
  std::set<int> list = {1, 2, 3};
  ASSERT_EQ("1,2,3", android::base::Join(list, ','));
}

TEST(strings, join_unordered_set) {
  std::unordered_set<int> list = {1, 2};
  ASSERT_TRUE("1,2" == android::base::Join(list, ',') ||
              "2,1" == android::base::Join(list, ','));
}

TEST(strings, StartsWith_empty) {
  ASSERT_FALSE(android::base::StartsWith("", "foo"));
  ASSERT_TRUE(android::base::StartsWith("", ""));
}

TEST(strings, StartsWithIgnoreCase_empty) {
  ASSERT_FALSE(android::base::StartsWithIgnoreCase("", "foo"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("", ""));
}

TEST(strings, StartsWith_simple) {
  ASSERT_TRUE(android::base::StartsWith("foo", ""));
  ASSERT_TRUE(android::base::StartsWith("foo", "f"));
  ASSERT_TRUE(android::base::StartsWith("foo", "fo"));
  ASSERT_TRUE(android::base::StartsWith("foo", "foo"));
}

TEST(strings, StartsWithIgnoreCase_simple) {
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", ""));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "f"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "F"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fo"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fO"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Fo"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FO"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foo"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foO"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOo"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOO"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Foo"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FoO"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOo"));
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOO"));
}

TEST(strings, StartsWith_prefix_too_long) {
  ASSERT_FALSE(android::base::StartsWith("foo", "foobar"));
}

TEST(strings, StartsWithIgnoreCase_prefix_too_long) {
  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "foobar"));
  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "FOOBAR"));
}

TEST(strings, StartsWith_contains_prefix) {
  ASSERT_FALSE(android::base::StartsWith("foobar", "oba"));
  ASSERT_FALSE(android::base::StartsWith("foobar", "bar"));
}

TEST(strings, StartsWithIgnoreCase_contains_prefix) {
  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "oba"));
  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "OBA"));
  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "bar"));
  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "BAR"));
}

TEST(strings, StartsWith_char) {
  ASSERT_FALSE(android::base::StartsWith("", 'f'));
  ASSERT_TRUE(android::base::StartsWith("foo", 'f'));
  ASSERT_FALSE(android::base::StartsWith("foo", 'o'));
}

TEST(strings, EndsWith_empty) {
  ASSERT_FALSE(android::base::EndsWith("", "foo"));
  ASSERT_TRUE(android::base::EndsWith("", ""));
}

TEST(strings, EndsWithIgnoreCase_empty) {
  ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "foo"));
  ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "FOO"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("", ""));
}

TEST(strings, EndsWith_simple) {
  ASSERT_TRUE(android::base::EndsWith("foo", ""));
  ASSERT_TRUE(android::base::EndsWith("foo", "o"));
  ASSERT_TRUE(android::base::EndsWith("foo", "oo"));
  ASSERT_TRUE(android::base::EndsWith("foo", "foo"));
}

TEST(strings, EndsWithIgnoreCase_simple) {
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", ""));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "o"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "O"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oo"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oO"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Oo"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "OO"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foo"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foO"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOo"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOO"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Foo"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FoO"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOo"));
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOO"));
}

TEST(strings, EndsWith_prefix_too_long) {
  ASSERT_FALSE(android::base::EndsWith("foo", "foobar"));
}

TEST(strings, EndsWithIgnoreCase_prefix_too_long) {
  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "foobar"));
  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "FOOBAR"));
}

TEST(strings, EndsWith_contains_prefix) {
  ASSERT_FALSE(android::base::EndsWith("foobar", "oba"));
  ASSERT_FALSE(android::base::EndsWith("foobar", "foo"));
}

TEST(strings, EndsWithIgnoreCase_contains_prefix) {
  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "OBA"));
  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "FOO"));
}

TEST(strings, StartsWith_std_string) {
  ASSERT_TRUE(android::base::StartsWith("hello", std::string{"hell"}));
  ASSERT_FALSE(android::base::StartsWith("goodbye", std::string{"hell"}));
}

TEST(strings, StartsWithIgnoreCase_std_string) {
  ASSERT_TRUE(android::base::StartsWithIgnoreCase("HeLlO", std::string{"hell"}));
  ASSERT_FALSE(android::base::StartsWithIgnoreCase("GoOdByE", std::string{"hell"}));
}

TEST(strings, EndsWith_std_string) {
  ASSERT_TRUE(android::base::EndsWith("hello", std::string{"lo"}));
  ASSERT_FALSE(android::base::EndsWith("goodbye", std::string{"lo"}));
}

TEST(strings, EndsWithIgnoreCase_std_string) {
  ASSERT_TRUE(android::base::EndsWithIgnoreCase("HeLlO", std::string{"lo"}));
  ASSERT_FALSE(android::base::EndsWithIgnoreCase("GoOdByE", std::string{"lo"}));
}

TEST(strings, EndsWith_char) {
  ASSERT_FALSE(android::base::EndsWith("", 'o'));
  ASSERT_TRUE(android::base::EndsWith("foo", 'o'));
  ASSERT_FALSE(android::base::EndsWith("foo", "f"));
}

TEST(strings, EqualsIgnoreCase) {
  ASSERT_TRUE(android::base::EqualsIgnoreCase("foo", "FOO"));
  ASSERT_TRUE(android::base::EqualsIgnoreCase("FOO", "foo"));
  ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "bar"));
  ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "fool"));
}

TEST(strings, ubsan_28729303) {
  android::base::Split("/dev/null", ":");
}


text:
package org.simpleframework.http.core;

import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Map;

import org.simpleframework.common.lease.Lease;
import org.simpleframework.http.MockTrace;
import org.simpleframework.transport.Certificate;
import org.simpleframework.transport.Channel;
import org.simpleframework.transport.ByteCursor;
import org.simpleframework.transport.ByteWriter;
import org.simpleframework.transport.trace.Trace;

public class MockChannel implements Channel {

   private ByteCursor cursor;

   public MockChannel(ByteCursor cursor) {
      this.cursor = cursor;
   }

   public boolean isSecure() {
      return false;
   }

   public Trace getTrace(){
      return new MockTrace();
   }

   public Lease getLease() {
      return null;
   }

   public Certificate getCertificate() {
      return null;
   }

   public ByteCursor getCursor() {
      return cursor;
   }

   public ByteWriter getWriter() {
      return new MockSender();
   }

   public Map getAttributes() {
      return new HashMap();
   }

   public void close() {}

   public SocketChannel getSocket() {
      return null;
   }
}


text:
package org.apache.camel.spring.interceptor;

import java.io.StringReader;

import javax.xml.transform.stream.StreamSource;

import org.apache.camel.CamelContext;
import org.apache.camel.ContextTestSupport;
import org.apache.camel.Exchange;
import org.apache.camel.StreamCache;
import org.apache.camel.component.mock.MockEndpoint;
import org.junit.Test;

import static org.apache.camel.spring.processor.SpringTestHelper.createSpringCamelContext;

public class MixedStreamCachingInterceptorTest extends ContextTestSupport {

    @Test
    public void testStreamCaching() throws Exception {
        MockEndpoint a = getMockEndpoint("mock:a");
        a.expectedMessageCount(1);

        StreamSource message = new StreamSource(new StringReader("<hello>world!</hello>"));
        template.sendBody("direct:a", message);

        assertMockEndpointsSatisfied();

        Exchange exchange = a.getExchanges().get(0);
        StreamCache cache = assertIsInstanceOf(StreamCache.class, exchange.getIn().getBody());
        assertNotNull(cache);

        assertNotSame(message, cache);
    }

    @Test
    public void testNoStreamCaching() throws Exception {
        MockEndpoint b = getMockEndpoint("mock:b");
        b.expectedMessageCount(1);

        StreamSource message = new StreamSource(new StringReader("<hello>world!</hello>"));
        template.sendBody("direct:b", message);

        assertMockEndpointsSatisfied();

        Exchange exchange = b.getExchanges().get(0);
        StreamSource stream = assertIsInstanceOf(StreamSource.class, exchange.getIn().getBody());
        assertNotNull(stream);
    }

    protected CamelContext createCamelContext() throws Exception {
        return createSpringCamelContext(this, "org/apache/camel/spring/interceptor/mixedStreamCachingInterceptorTest.xml");
    }

}


text:
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.

package org.cef;

import org.cef.callback.CefSchemeHandlerFactory;
import org.cef.handler.CefAppHandler;
import org.cef.handler.CefAppHandlerAdapter;
import org.cef.util.SwingThreadBridge;
import org.slf4j.Logger;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FilenameFilter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Exposes static methods for managing the global CEF context.
 */
public class CefApp extends CefAppHandlerAdapter {

    /**
     * According the singleton pattern, this attribute keeps
     * one single object of this class.
     */
    private static CefApp self;
    private static CefAppHandler appHandler;
    private static CefAppState state = CefAppState.NONE;
    private static CefThreadBridge cefThreadBridge = new SwingThreadBridge();

    private final Lock lock = new ReentrantLock();
    private final Condition cefShutdown = lock.newCondition();
    private Timer workTimer;
    private CefSettings settings ;
    private HashSet<CefClient> clients = new HashSet<>();
    private List<Runnable> shutdownActions = new CopyOnWriteArrayList<>();
    private List<Runnable> shutdownHookActions = new CopyOnWriteArrayList<>();

    /**
     * To get an instance of this class, use the method
     * getInstance() instead of this CTOR.
     *

     * The CTOR is called by getInstance() as needed and
     * loads all required JCEF libraries.
     *
     * @throws UnsatisfiedLinkError
     */
    private CefApp(String[] args, CefSettings settings) throws UnsatisfiedLinkError {
        super(args);

        if (settings != null) {
            this.settings = settings.clone();
        }

        if (OS.isWindows()) {
            System.loadLibrary("jawt");
            System.loadLibrary("chrome_elf");
            System.loadLibrary("libcef");
        }
        else if (OS.isLinux()) {
            System.loadLibrary("cef");
        }

        System.loadLibrary("jcef");

        if (appHandler == null) {
            appHandler = this;
        }

        // Execute on the AWT event dispatching thread.
        try {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    // Perform native pre-initialization.
                    if (!N_PreInitialize()) {
                        throw new IllegalStateException("Failed to pre-initialize native code");
                    }
                }
            };
            if (cefThreadBridge.isEventDispatchThread()) {
                r.run();
            }
            else {
                cefThreadBridge.invokeAndWait(r);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        Runtime.getRuntime().addShutdownHook(new Thread("JCEF Shutdown Hook") {
            @Override
            public void run() {
                CefApp.getLogger().info("Shutdown Hook called");

                for (Runnable action : shutdownHookActions) {
                    action.run();
                }

                try {
                    for (CefClient c : clients) {
                        c.dispose();
                    }
                    // Wait for shutdown() to complete.
                    cefShutdown.awaitUninterruptibly();

                    // Avoid a deadlock. Give the native code at least 150 milliseconds
                    // to terminate.
                    Thread.sleep(150);
                } catch (Exception e) {
                }
            }
        });
    }

    /**
     * Assign an AppHandler to CefApp. The AppHandler can be used to evaluate
     * application arguments, to register your own schemes and to hook into the
     * shutdown sequence. See CefAppHandler for more details.
     *

     * This method must be called before CefApp is initialized. CefApp will be
     * initialized automatically if you call createClient() the first time.
     *
     * @param appHandler An instance of CefAppHandler.
     * @throws IllegalStateException in case of CefApp is already initialized
     */
    public static void addAppHandler(CefAppHandler appHandler) throws IllegalStateException {
        if (getState().compareTo(CefAppState.NEW) > 0) {
            throw new IllegalStateException("Must be called before CefApp is initialized");
        }
        CefApp.appHandler = appHandler;
    }

    public static Logger getLogger() {
        return CefLogger.CEF_LOGGER;
    }

    /**
     * Get an instance of this class.
     *
     * @return an instance of this class
     * @throws UnsatisfiedLinkError
     */
    public static synchronized CefApp getInstance() throws UnsatisfiedLinkError {
        return getInstance(null, null);
    }

    public static synchronized CefApp getInstance(String[] args) throws UnsatisfiedLinkError {
        return getInstance(args, null);
    }

    public static synchronized CefApp getInstance(CefSettings settings) throws UnsatisfiedLinkError {
        return getInstance(null, settings);
    }

    public static synchronized CefApp getInstance(String[] args, CefSettings settings) throws UnsatisfiedLinkError {
        if (settings != null) {
            if (getState() != CefAppState.NONE && getState() != CefAppState.NEW) {
                throw new IllegalStateException("Settings can only be passed to CEF" + " before createClient is called the first time.");
            }
        }
        if (self == null) {
            if (getState() == CefAppState.TERMINATED) {
                throw new IllegalStateException("CefApp was terminated");
            }
            self = new CefApp(args, settings);
            setState(CefAppState.NEW);
        }
        return self;
    }

    public final void setSettings(CefSettings settings) throws IllegalStateException {
        if (getState() != CefAppState.NONE && getState() != CefAppState.NEW) {
            throw new IllegalStateException("Settings can only be passed to CEF" + " before createClient is called the first time.");
        }
        this.settings = settings.clone();
    }

    public final CefVersion getVersion() {
        try {
            return N_GetVersion();
        } catch (UnsatisfiedLinkError ule) {
            ule.printStackTrace();
        }
        return null;
    }

    /**
     * Returns the current state of CefApp.
     *
     * @return current state.
     */
    public static CefAppState getState() {
        synchronized (state) {
            return state;
        }
    }

    private static void setState(final CefAppState state) {
        synchronized (CefApp.state) {
            CefApp.state = state;
        }
        // Execute on the AWT event dispatching thread.
        cefThreadBridge.invokeLater(new Runnable() {
            @Override
            public void run() {
                if (appHandler != null) {
                    appHandler.stateHasChanged(state);
                }
            }
        });
    }

    /**
     * To shutdown the system, it's important to call the dispose
     * method. Calling this method closes all client instances with
     * and all browser instances each client owns. After that the
     * message loop is terminated and CEF is shutdown.
     */
    public synchronized final void dispose() {
        switch (getState()) {
            case NEW:
                // Nothing to do inspite of invalidating the state
                setState(CefAppState.TERMINATED);
                break;

            case INITIALIZING:
            case INITIALIZED:
                // (3) Shutdown sequence. Close all clients and continue.
                setState(CefAppState.SHUTTING_DOWN);
                if (clients.isEmpty()) {
                    shutdown();
                    CefApp.getLogger().info("a1");
                }
                else {
                    // shutdown() will be called from clientWasDisposed() when the last
                    // client is gone.
                    for (CefClient c : clients) {
                        c.dispose();
                    }
                }
                break;

            case NONE:
            case SHUTTING_DOWN:
            case TERMINATED:
                // Ignore shutdown, CefApp is already terminated, in shutdown progress
                // or was never created (shouldn't be possible)
                break;
        }
    }

    /**
     * Creates a new client instance and returns it to the caller.
     * One client instance is responsible for one to many browser
     * instances
     *
     * @return a new client instance
     */
    public synchronized CefClient createClient() {
        switch (getState()) {
            case NEW:
                setState(CefAppState.INITIALIZING);
                initialize();
                // FALL THRU

            case INITIALIZING:
            case INITIALIZED:
                CefClient client = new CefClient();
                clients.add(client);
                return client;

            default:
                throw new IllegalStateException("Can't crate client in state " + state);
        }

    }

    /**
     * Register a scheme handler factory for the specified |scheme_name| and
     * optional |domain_name|. An empty |domain_name| value for a standard scheme
     * will cause the factory to match all domain names. The |domain_name| value
     * will be ignored for non-standard schemes. If |scheme_name| is a built-in
     * scheme and no handler is returned by |factory| then the built-in scheme
     * handler factory will be called. If |scheme_name| is a custom scheme then
     * also implement the CefApp::OnRegisterCustomSchemes() method in all processes.
     * This function may be called multiple times to change or remove the factory
     * that matches the specified |scheme_name| and optional |domain_name|.
     * Returns false if an error occurs. This function may be called on any thread
     * in the browser process.
     */
    public boolean registerSchemeHandlerFactory(String schemeName, String domainName, CefSchemeHandlerFactory factory) {
        try {
            return N_RegisterSchemeHandlerFactory(schemeName, domainName, factory);
        } catch (Exception err) {
            err.printStackTrace();
        }
        return false;
    }

    /**
     * Clear all registered scheme handler factories. Returns false on error. This
     * function may be called on any thread in the browser process.
     */
    public boolean clearSchemeHandlerFactories() {
        try {
            return N_ClearSchemeHandlerFactories();
        } catch (Exception err) {
            err.printStackTrace();
        }
        return false;
    }

    /**
     * This method is called by a CefClient if it was disposed. This causes
     * CefApp to clean up its list of available client instances. If all clients
     * are disposed, CefApp will be shutdown.
     *
     * @param client the disposed client.
     */
    final protected void clientWasDisposed(CefClient client) {
        clients.remove(client);
        if (clients.isEmpty() && getState().compareTo(CefAppState.SHUTTING_DOWN) >= 0) {
            // Shutdown native system.
            shutdown();
        }
    }

    /**
     * Initialize the context.
     *
     * @return true on success.
     */
    private final void initialize() {
        // Execute on the AWT event dispatching thread.
        try {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    String library_path = getJcefLibPath();
                    CefApp.getLogger().info("Initialize on " + Thread.currentThread() + " with library path " + library_path);

                    CefSettings settings = CefApp.this.settings != null ? CefApp.this.settings : new CefSettings();

                    // Avoid to override user values by testing on NULL
                    if (OS.isMacintosh()) {
                        if (settings.browser_subprocess_path == null) {
                            Path path = Paths.get(library_path, "../Frameworks/jcef Helper.app/Contents/MacOS/jcef Helper");
                            settings.browser_subprocess_path = path.normalize().toAbsolutePath().toString();
                        }
                    }
                    else if (OS.isWindows()) {
                        if (settings.browser_subprocess_path == null) {
                            settings.browser_subprocess_path = library_path + "\\jcef_helper.exe";
                        }
                    }
                    else if (OS.isLinux()) {
                        if (settings.browser_subprocess_path == null) {
                            settings.browser_subprocess_path = library_path + "/jcef_helper";
                        }
                        if (settings.resources_dir_path == null) {
                            settings.resources_dir_path = library_path;
                        }
                        if (settings.locales_dir_path == null) {
                            settings.locales_dir_path = library_path + "/locales";
                        }
                    }

                    if (N_Initialize(library_path, appHandler, settings)) {
                        setState(CefAppState.INITIALIZED);
                    }
                }
            };

            if (OS.isLinux()) {
                if (SwingUtilities.isEventDispatchThread()) {
                    r.run();
                }
                else {
                    SwingUtilities.invokeAndWait(r);
                }
            }
            else {
                if (cefThreadBridge.isEventDispatchThread()) {
                    r.run();
                }
                else {
                    cefThreadBridge.invokeLater(r);
                    Thread.sleep(1000);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * This method is invoked by the native code (currently on Mac only) in case
     * of a termination event (e.g. someone pressed CMD+Q).
     */
    protected final void handleBeforeTerminate() {
        // Execute on the AWT event dispatching thread. Always call asynchronously
        // so the call stack has a chance to unwind.
        cefThreadBridge.invokeLater(new Runnable() {
            @Override
            public void run() {
                CefAppHandler handler = (CefAppHandler) ((appHandler == null) ? this : appHandler);
                if (!handler.onBeforeTerminate()) {
                    dispose();
                }
            }
        });
    }

    /**
     * Shut down the context.
     */
    private final void shutdown() {
        // Execute on the AWT event dispatching thread. Always call asynchronously
        // so the call stack has a chance to unwind.
        cefThreadBridge.invokeLater(new Runnable() {
            @Override
            public void run() {
                CefApp.getLogger().info("Shutdown on " + Thread.currentThread());

                // Shutdown native CEF.
                N_Shutdown();

                setState(CefAppState.TERMINATED);
                CefApp.self = null;

                // Allow the shutdown hook to terminate.
                lock.lock();
                cefShutdown.signal();
                lock.unlock();

                for (Runnable action : shutdownActions) {
                    action.run();
                }
            }
        });
    }

    public void shutdownNative() {
        N_Shutdown();
    }

    public void addShutdownAction(Runnable action) {
        shutdownActions.add(action);
    }

    public void addShutdownHookAction(Runnable action) {
        shutdownHookActions.add(action);
    }

    public static void setThreadBridge(CefThreadBridge threadBridge) {
        cefThreadBridge = threadBridge;
    }

    /**
     * Perform a single message loop iteration. Used on all platforms except
     * Windows with windowed rendering.
     */
    public final void doMessageLoopWork(final long delay_ms) {
        // Execute on the AWT event dispatching thread.
        cefThreadBridge.invokeLater(new Runnable() {
            @Override
            public void run() {
                if (getState() == CefAppState.TERMINATED) {
                    return;
                }

                // The maximum number of milliseconds we're willing to wait between
                // calls to DoMessageLoopWork().
                final long kMaxTimerDelay = 1000 / 30;  // 30fps

                if (workTimer != null) {
                    workTimer.stop();
                    workTimer = null;
                }

                if (delay_ms <= 0) {
                    // Execute the work immediately.
                    N_DoMessageLoopWork();

                    // Schedule more work later.
                    doMessageLoopWork(kMaxTimerDelay);
                }
                else {
                    long timer_delay_ms = delay_ms;
                    // Never wait longer than the maximum allowed time.
                    if (timer_delay_ms > kMaxTimerDelay) {
                        timer_delay_ms = kMaxTimerDelay;
                    }

                    workTimer = new Timer((int) timer_delay_ms, new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent evt) {
                            // Timer has timed out.
                            workTimer.stop();
                            workTimer = null;

                            N_DoMessageLoopWork();

                            // Schedule more work later.
                            doMessageLoopWork(kMaxTimerDelay);
                        }
                    });
                    workTimer.start();
                }
            }
        });
    }

    /**
     * Get the path which contains the jcef library
     *
     * @return The path to the jcef library
     */
    private String getJcefLibPath() {
        String library_path = System.getProperty("java.library.path");
        String[] paths = library_path.split(System.getProperty("path.separator"));
        for (String path : paths) {
            File dir = new File(path);
            String[] found = dir.list(new FilenameFilter() {
                @Override
                public boolean accept(File dir, String name) {
                    return (name.equalsIgnoreCase("libjcef.dylib") || name.equalsIgnoreCase("libjcef.so") || name.equalsIgnoreCase("jcef.dll"));
                }
            });
            if (found != null && found.length != 0) {
                return path;
            }
        }
        return library_path;
    }

    private final native boolean N_PreInitialize();

    private final native boolean N_Initialize(String pathToJavaDLL, CefAppHandler appHandler, CefSettings settings);

    private final native void N_Shutdown();

    private final native void N_DoMessageLoopWork();

    private final native CefVersion N_GetVersion();

    private final native boolean N_RegisterSchemeHandlerFactory(String schemeName, String domainName, CefSchemeHandlerFactory factory);

    private final native boolean N_ClearSchemeHandlerFactories();

    public final class CefVersion {
        public final int JCEF_COMMIT_NUMBER;

        public final int CEF_VERSION_MAJOR;
        public final int CEF_COMMIT_NUMBER;

        public final int CHROME_VERSION_MAJOR;
        public final int CHROME_VERSION_MINOR;
        public final int CHROME_VERSION_BUILD;
        public final int CHROME_VERSION_PATCH;

        private CefVersion(int jcefCommitNo, int cefMajor, int cefCommitNo, int chrMajor, int chrMin, int chrBuild, int chrPatch) {
            JCEF_COMMIT_NUMBER = jcefCommitNo;

            CEF_VERSION_MAJOR = cefMajor;
            CEF_COMMIT_NUMBER = cefCommitNo;

            CHROME_VERSION_MAJOR = chrMajor;
            CHROME_VERSION_MINOR = chrMin;
            CHROME_VERSION_BUILD = chrBuild;
            CHROME_VERSION_PATCH = chrPatch;
        }

        public String getJcefVersion() {
            return CEF_VERSION_MAJOR + "." + CHROME_VERSION_BUILD + "." + JCEF_COMMIT_NUMBER;
        }

        public String getCefVersion() {
            return CEF_VERSION_MAJOR + "." + CHROME_VERSION_BUILD + "." + CEF_COMMIT_NUMBER;
        }

        public String getChromeVersion() {
            return CHROME_VERSION_MAJOR + "." + CHROME_VERSION_MINOR + "." + CHROME_VERSION_BUILD + "." + CHROME_VERSION_PATCH;
        }

        @Override
        public String toString() {
            return "JCEF Version = " + getJcefVersion() + "\n" + "CEF Version = " + getCefVersion() + "\n" + "Chromium Version = " + getChromeVersion();
        }
    }

    /**
     * The CefAppState gives you a hint if the CefApp is already usable or not usable
     * any more. See values for details.
     */
    public enum CefAppState {
        /**
         * No CefApp instance was created yet. Call getInstance() to create a new
         * one.
         */
        NONE,

        /**
         * CefApp is new created but not initialized yet. No CefClient and no
         * CefBrowser was created until now.
         */
        NEW,

        /**
         * CefApp is in its initializing process. Please wait until initializing is
         * finished.
         */
        INITIALIZING,

        /**
         * CefApp is up and running. At least one CefClient was created and the
         * message loop is running. You can use all classes and methods of JCEF now.
         */
        INITIALIZED,

        /**
         * CefApp is in its shutdown process. All CefClients and CefBrowser
         * instances will be disposed. No new CefClient or CefBrowser is allowed to
         * be created. The message loop will be performed until all CefClients and
         * all CefBrowsers are disposed completely.
         */
        SHUTTING_DOWN,

        /**
         * CefApp is terminated and can't be used any more. You can shutdown the
         * application safely now.
         */
        TERMINATED
    }
}


text:
(function(__global) {
    var tmp0;
    tmp0 = /world/;
})(typeof global === 'undefined' ? this : global);


text:
RSpec.describe "Snapshots API" do
  describe "as a subcollection of VMs" do
    describe "GET /api/vms/:c_id/snapshots" do
      it "can list the snapshots of a VM" do
        api_basic_authorize(subcollection_action_identifier(:vms, :snapshots, :read, :get))
        vm = FactoryGirl.create(:vm_vmware)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => vm)
        _other_snapshot = FactoryGirl.create(:snapshot)

        run_get("#{vms_url(vm.id)}/snapshots")

        expected = {
          "count"     => 2,
          "name"      => "snapshots",
          "subcount"  => 1,
          "resources" => [
            {"href" => a_string_matching("#{vms_url(vm.id)}/snapshots/#{snapshot.id}")}
          ]
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "will not list snapshots unless authorized" do
        api_basic_authorize
        vm = FactoryGirl.create(:vm_vmware)
        FactoryGirl.create(:snapshot, :vm_or_template => vm)

        run_get("#{vms_url(vm.id)}/snapshots")

        expect(response).to have_http_status(:forbidden)
      end
    end

    describe "GET /api/vms/:c_id/snapshots/:s_id" do
      it "can show a VM's snapshot" do
        api_basic_authorize(subcollection_action_identifier(:vms, :snapshots, :read, :get))
        vm = FactoryGirl.create(:vm_vmware)
        create_time = Time.zone.parse("2017-01-11T00:00:00Z")
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => vm, :create_time => create_time)

        run_get("#{vms_url(vm.id)}/snapshots/#{snapshot.id}")

        expected = {
          "create_time"       => create_time.iso8601,
          "href"              => a_string_matching("#{vms_url(vm.id)}/snapshots/#{snapshot.id}"),
          "id"                => snapshot.id,
          "vm_or_template_id" => vm.id
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "will not show a snapshot unless authorized" do
        api_basic_authorize
        vm = FactoryGirl.create(:vm_vmware)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => vm)

        run_get("#{vms_url(vm.id)}/snapshots/#{snapshot.id}")

        expect(response).to have_http_status(:forbidden)
      end
    end

    describe "POST /api/vms/:c_id/snapshots" do
      it "can queue the creation of a snapshot" do
        api_basic_authorize(subcollection_action_identifier(:vms, :snapshots, :create))
        ems = FactoryGirl.create(:ext_management_system)
        host = FactoryGirl.create(:host, :ext_management_system => ems)
        vm = FactoryGirl.create(:vm_vmware, :name => "Alice's VM", :host => host, :ext_management_system => ems)

        run_post("#{vms_url(vm.id)}/snapshots", :name => "Alice's snapshot")

        expected = {
          "results" => [
            a_hash_including(
              "success"   => true,
              "message"   => "Creating snapshot Alice's snapshot for Virtual Machine id:#{vm.id} name:'Alice's VM'",
              "task_id"   => anything,
              "task_href" => a_string_matching(tasks_url)
            )
          ]
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "renders a failed action response if snapshotting is not supported" do
        api_basic_authorize(subcollection_action_identifier(:vms, :snapshots, :create))
        vm = FactoryGirl.create(:vm_vmware)

        run_post("#{vms_url(vm.id)}/snapshots", :name => "Alice's snapsnot")

        expected = {
          "results" => [
            a_hash_including(
              "success" => false,
              "message" => "The VM is not connected to a Host"
            )
          ]
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "renders a failed action response if a name is not provided" do
        api_basic_authorize(subcollection_action_identifier(:vms, :snapshots, :create))
        ems = FactoryGirl.create(:ext_management_system)
        host = FactoryGirl.create(:host, :ext_management_system => ems)
        vm = FactoryGirl.create(:vm_vmware, :name => "Alice's VM", :host => host, :ext_management_system => ems)

        run_post("#{vms_url(vm.id)}/snapshots", :description => "Alice's snapshot")

        expected = {
          "results" => [
            a_hash_including(
              "success" => false,
              "message" => "Must specify a name for the snapshot"
            )
          ]
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "will not create a snapshot unless authorized" do
        api_basic_authorize
        vm = FactoryGirl.create(:vm_vmware)

        run_post("#{vms_url(vm.id)}/snapshots", :description => "Alice's snapshot")

        expect(response).to have_http_status(:forbidden)
      end
    end

    describe "POST /api/vms/:c_id/snapshots/:s_id with revert action" do
      it "can queue a VM for reverting to a snapshot" do
        api_basic_authorize(action_identifier(:vms, :revert, :snapshots_subresource_actions))
        ems = FactoryGirl.create(:ext_management_system)
        host = FactoryGirl.create(:host, :ext_management_system => ems)
        vm = FactoryGirl.create(:vm_vmware, :name => "Alice's VM", :host => host, :ext_management_system => ems)
        snapshot = FactoryGirl.create(:snapshot, :name => "Alice's snapshot", :vm_or_template => vm)

        run_post("#{vms_url(vm.id)}/snapshots/#{snapshot.id}", :action => "revert")

        expected = {
          "message"   => "Reverting to snapshot Alice's snapshot for Virtual Machine id:#{vm.id} name:'Alice's VM'",
          "success"   => true,
          "task_href" => a_string_matching(tasks_url),
          "task_id"   => anything
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "renders a failed action response if reverting is not supported" do
        api_basic_authorize(action_identifier(:vms, :revert, :snapshots_subresource_actions))
        vm = FactoryGirl.create(:vm_vmware)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => vm)

        run_post("#{vms_url(vm.id)}/snapshots/#{snapshot.id}", :action => "revert")

        expected = {
          "success" => false,
          "message" => "The VM is not connected to a Host"
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "will not revert to a snapshot unless authorized" do
        api_basic_authorize
        vm = FactoryGirl.create(:vm_vmware)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => vm)

        run_post("#{vms_url(vm.id)}/snapshots/#{snapshot.id}", :action => "revert")

        expect(response).to have_http_status(:forbidden)
      end
    end

    describe "POST /api/vms/:c_id/snapshots/:s_id with delete action" do
      it "can queue a snapshot for deletion" do
        api_basic_authorize(action_identifier(:vms, :delete, :snapshots_subresource_actions, :delete))
        ems = FactoryGirl.create(:ext_management_system)
        host = FactoryGirl.create(:host, :ext_management_system => ems)
        vm = FactoryGirl.create(:vm_vmware, :name => "Alice's VM", :host => host, :ext_management_system => ems)
        snapshot = FactoryGirl.create(:snapshot, :name => "Alice's snapshot", :vm_or_template => vm)

        run_post("#{vms_url(vm.id)}/snapshots/#{snapshot.id}", :action => "delete")

        expected = {
          "message"   => "Deleting snapshot Alice's snapshot for Virtual Machine id:#{vm.id} name:'Alice's VM'",
          "success"   => true,
          "task_href" => a_string_matching(tasks_url),
          "task_id"   => anything
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "renders a failed action response if deleting is not supported" do
        api_basic_authorize(action_identifier(:vms, :delete, :snapshots_subresource_actions, :post))
        vm = FactoryGirl.create(:vm_vmware)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => vm)

        run_post("#{vms_url(vm.id)}/snapshots/#{snapshot.id}", :action => "delete")

        expected = {
          "success" => false,
          "message" => "The VM is not connected to a Host"
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "will not delete a snapshot unless authorized" do
        api_basic_authorize
        vm = FactoryGirl.create(:vm_vmware)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => vm)

        run_post("#{vms_url(vm.id)}/snapshots/#{snapshot.id}", :action => "delete")

        expect(response).to have_http_status(:forbidden)
      end
    end

    describe "POST /api/vms/:c_id/snapshots with delete action" do
      it "can queue multiple snapshots for deletion" do
        api_basic_authorize(action_identifier(:vms, :delete, :snapshots_subresource_actions, :delete))
        ems = FactoryGirl.create(:ext_management_system)
        host = FactoryGirl.create(:host, :ext_management_system => ems)
        vm = FactoryGirl.create(:vm_vmware, :name => "Alice and Bob's VM", :host => host, :ext_management_system => ems)
        snapshot1 = FactoryGirl.create(:snapshot, :name => "Alice's snapshot", :vm_or_template => vm)
        snapshot2 = FactoryGirl.create(:snapshot, :name => "Bob's snapshot", :vm_or_template => vm)

        run_post(
          "#{vms_url(vm.id)}/snapshots",
          :action    => "delete",
          :resources => [
            {:href => "#{vms_url(vm.id)}/snapshots/#{snapshot1.id}"},
            {:href => "#{vms_url(vm.id)}/snapshots/#{snapshot2.id}"}
          ]
        )

        expected = {
          "results" => a_collection_containing_exactly(
            a_hash_including(
              "message"   => "Deleting snapshot Alice's snapshot for Virtual Machine id:#{vm.id} name:'Alice and Bob's VM'",
              "success"   => true,
              "task_href" => a_string_matching(tasks_url),
              "task_id"   => anything
            ),
            a_hash_including(
              "message"   => "Deleting snapshot Bob's snapshot for Virtual Machine id:#{vm.id} name:'Alice and Bob's VM'",
              "success"   => true,
              "task_href" => a_string_matching(tasks_url),
              "task_id"   => anything
            )
          )
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end
    end

    describe "DELETE /api/vms/:c_id/snapshots/:s_id" do
      it "can delete a snapshot" do
        api_basic_authorize(action_identifier(:vms, :delete, :snapshots_subresource_actions, :delete))
        vm = FactoryGirl.create(:vm_vmware)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => vm)

        run_delete("#{vms_url(vm.id)}/snapshots/#{snapshot.id}")

        expect(response).to have_http_status(:no_content)
      end

      it "will not delete a snapshot unless authorized" do
        api_basic_authorize
        vm = FactoryGirl.create(:vm_vmware)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => vm)

        run_delete("#{vms_url(vm.id)}/snapshots/#{snapshot.id}")

        expect(response).to have_http_status(:forbidden)
      end
    end
  end

  describe "as a subcollection of instances" do
    describe "GET /api/instances/:c_id/snapshots" do
      it "can list the snapshots of an Instance" do
        api_basic_authorize(subcollection_action_identifier(:instances, :snapshots, :read, :get))
        instance = FactoryGirl.create(:vm_openstack)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => instance)
        _other_snapshot = FactoryGirl.create(:snapshot)

        run_get("#{instances_url(instance.id)}/snapshots")

        expected = {
          "count"     => 2,
          "name"      => "snapshots",
          "subcount"  => 1,
          "resources" => [
            {"href" => a_string_matching("#{instances_url(instance.id)}/snapshots/#{snapshot.id}")}
          ]
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "will not list snapshots unless authorized" do
        api_basic_authorize
        instance = FactoryGirl.create(:vm_openstack)
        _snapshot = FactoryGirl.create(:snapshot, :vm_or_template => instance)

        run_get("#{instances_url(instance.id)}/snapshots")

        expect(response).to have_http_status(:forbidden)
      end
    end

    describe "GET /api/instances/:c_id/snapshots/:s_id" do
      it "can show an Instance's snapshot" do
        api_basic_authorize(subcollection_action_identifier(:instances, :snapshots, :read, :get))
        instance = FactoryGirl.create(:vm_openstack)
        create_time = Time.zone.parse("2017-01-11T00:00:00Z")
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => instance, :create_time => create_time)

        run_get("#{instances_url(instance.id)}/snapshots/#{snapshot.id}")

        expected = {
          "create_time"       => create_time.iso8601,
          "href"              => a_string_matching("#{instances_url(instance.id)}/snapshots/#{snapshot.id}"),
          "id"                => snapshot.id,
          "vm_or_template_id" => instance.id
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "will not show a snapshot unless authorized" do
        api_basic_authorize
        instance = FactoryGirl.create(:vm_openstack)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => instance)

        run_get("#{instances_url(instance.id)}/snapshots/#{snapshot.id}")

        expect(response).to have_http_status(:forbidden)
      end
    end

    describe "POST /api/instances/:c_id/snapshots" do
      it "can queue the creation of a snapshot" do
        api_basic_authorize(subcollection_action_identifier(:instances, :snapshots, :create))
        ems = FactoryGirl.create(:ems_openstack_infra)
        host = FactoryGirl.create(:host_openstack_infra, :ext_management_system => ems)
        instance = FactoryGirl.create(:vm_openstack, :name => "Alice's Instance", :ext_management_system => ems, :host => host)

        run_post("#{instances_url(instance.id)}/snapshots", :name => "Alice's snapshot")

        expected = {
          "results" => [
            a_hash_including(
              "success"   => true,
              "message"   => "Creating snapshot Alice's snapshot for Instance id:#{instance.id} name:'Alice's Instance'",
              "task_id"   => anything,
              "task_href" => a_string_matching(tasks_url)
            )
          ]
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "renders a failed action response if snapshotting is not supported" do
        api_basic_authorize(subcollection_action_identifier(:instances, :snapshots, :create))
        instance = FactoryGirl.create(:vm_openstack)

        run_post("#{instances_url(instance.id)}/snapshots", :name => "Alice's snapsnot")

        expected = {
          "results" => [
            a_hash_including(
              "success" => false,
              "message" => "The VM is not connected to an active Provider"
            )
          ]
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "renders a failed action response if a name is not provided" do
        api_basic_authorize(subcollection_action_identifier(:instances, :snapshots, :create))
        ems = FactoryGirl.create(:ems_openstack_infra)
        host = FactoryGirl.create(:host_openstack_infra, :ext_management_system => ems)
        instance = FactoryGirl.create(:vm_openstack, :name => "Alice's Instance", :ext_management_system => ems, :host => host)

        run_post("#{instances_url(instance.id)}/snapshots", :description => "Alice's snapshot")

        expected = {
          "results" => [
            a_hash_including(
              "success" => false,
              "message" => "Must specify a name for the snapshot"
            )
          ]
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "will not create a snapshot unless authorized" do
        api_basic_authorize
        instance = FactoryGirl.create(:vm_openstack)

        run_post("#{instances_url(instance.id)}/snapshots", :description => "Alice's snapshot")

        expect(response).to have_http_status(:forbidden)
      end
    end

    describe "POST /api/instances/:c_id/snapshots/:s_id with delete action" do
      it "can queue a snapshot for deletion" do
        api_basic_authorize(action_identifier(:instances, :delete, :snapshots_subresource_actions, :delete))

        ems = FactoryGirl.create(:ems_openstack_infra)
        host = FactoryGirl.create(:host_openstack_infra, :ext_management_system => ems)
        instance = FactoryGirl.create(:vm_openstack, :name => "Alice's Instance", :ext_management_system => ems, :host => host)
        snapshot = FactoryGirl.create(:snapshot, :name => "Alice's snapshot", :vm_or_template => instance)

        run_post("#{instances_url(instance.id)}/snapshots/#{snapshot.id}", :action => "delete")

        expected = {
          "message"   => "Deleting snapshot Alice's snapshot for Instance id:#{instance.id} name:'Alice's Instance'",
          "success"   => true,
          "task_href" => a_string_matching(tasks_url),
          "task_id"   => anything
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "renders a failed action response if deleting is not supported" do
        api_basic_authorize(action_identifier(:instances, :delete, :snapshots_subresource_actions, :post))
        instance = FactoryGirl.create(:vm_openstack)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => instance)

        run_post("#{instances_url(instance.id)}/snapshots/#{snapshot.id}", :action => "delete")

        expected = {
          "success" => false,
          "message" => "The VM is not connected to an active Provider"
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end

      it "will not delete a snapshot unless authorized" do
        api_basic_authorize
        instance = FactoryGirl.create(:vm_openstack)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => instance)

        run_post("#{instances_url(instance.id)}/snapshots/#{snapshot.id}", :action => "delete")

        expect(response).to have_http_status(:forbidden)
      end
    end

    describe "POST /api/instances/:c_id/snapshots with delete action" do
      it "can queue multiple snapshots for deletion" do
        api_basic_authorize(action_identifier(:instances, :delete, :snapshots_subresource_actions, :delete))

        ems = FactoryGirl.create(:ems_openstack_infra)
        host = FactoryGirl.create(:host_openstack_infra, :ext_management_system => ems)
        instance = FactoryGirl.create(:vm_openstack, :name => "Alice and Bob's Instance", :ext_management_system => ems, :host => host)
        snapshot1 = FactoryGirl.create(:snapshot, :name => "Alice's snapshot", :vm_or_template => instance)
        snapshot2 = FactoryGirl.create(:snapshot, :name => "Bob's snapshot", :vm_or_template => instance)

        run_post(
          "#{instances_url(instance.id)}/snapshots",
          :action    => "delete",
          :resources => [
            {:href => "#{instances_url(instance.id)}/snapshots/#{snapshot1.id}"},
            {:href => "#{instances_url(instance.id)}/snapshots/#{snapshot2.id}"}
          ]
        )

        expected = {
          "results" => a_collection_containing_exactly(
            a_hash_including(
              "message"   => "Deleting snapshot Alice's snapshot for Instance id:#{instance.id} name:'Alice and Bob's Instance'",
              "success"   => true,
              "task_href" => a_string_matching(tasks_url),
              "task_id"   => anything
            ),
            a_hash_including(
              "message"   => "Deleting snapshot Bob's snapshot for Instance id:#{instance.id} name:'Alice and Bob's Instance'",
              "success"   => true,
              "task_href" => a_string_matching(tasks_url),
              "task_id"   => anything
            )
          )
        }
        expect(response.parsed_body).to include(expected)
        expect(response).to have_http_status(:ok)
      end
    end

    describe "DELETE /api/instances/:c_id/snapshots/:s_id" do
      it "can delete a snapshot" do
        api_basic_authorize(action_identifier(:instances, :delete, :snapshots_subresource_actions, :delete))
        instance = FactoryGirl.create(:vm_openstack)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => instance)

        run_delete("#{instances_url(instance.id)}/snapshots/#{snapshot.id}")

        expect(response).to have_http_status(:no_content)
      end

      it "will not delete a snapshot unless authorized" do
        api_basic_authorize
        instance = FactoryGirl.create(:vm_openstack)
        snapshot = FactoryGirl.create(:snapshot, :vm_or_template => instance)

        run_delete("#{instances_url(instance.id)}/snapshots/#{snapshot.id}")

        expect(response).to have_http_status(:forbidden)
      end
    end
  end
end


text:
@interface AddMessageViewController : UIViewController
@property (weak, nonatomic) IBOutlet UITextView *messageContent;
- (IBAction)saveMessage:(id)sender;

@end


text:
/*
 * Licensed 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.
 */
package com.facebook.presto.pinot;

import com.facebook.presto.pinot.query.PinotQueryGenerator;
import com.facebook.presto.spi.ConnectorTableHandle;
import com.facebook.presto.spi.SchemaTableName;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static com.google.common.base.MoreObjects.toStringHelper;
import static java.util.Objects.requireNonNull;

public final class PinotTableHandle
        implements ConnectorTableHandle
{
    private final String connectorId;
    private final String schemaName;
    private final String tableName;
    private final Optional<Boolean> forBroker;
    private final Optional<PinotQueryGenerator.GeneratedPinotQuery> pinotQuery;
    private final Optional<List<PinotColumnHandle>> expectedColumnHandles;

    public PinotTableHandle(
            String connectorId,
            String schemaName,
            String tableName)
    {
        this(connectorId, schemaName, tableName, Optional.empty(), Optional.empty(), Optional.empty());
    }

    @JsonCreator
    public PinotTableHandle(
            @JsonProperty("connectorId") String connectorId,
            @JsonProperty("schemaName") String schemaName,
            @JsonProperty("tableName") String tableName,
            @JsonProperty("forBroker") Optional<Boolean> forBroker,
            @JsonProperty("expectedColumnHandles") Optional<List<PinotColumnHandle>> expectedColumnHandles,
            @JsonProperty("pinotQuery") Optional<PinotQueryGenerator.GeneratedPinotQuery> pinotQuery)
    {
        this.connectorId = requireNonNull(connectorId, "connectorId is null");
        this.schemaName = requireNonNull(schemaName, "schemaName is null");
        this.tableName = requireNonNull(tableName, "tableName is null");
        this.forBroker = requireNonNull(forBroker, "safe to execute is null");
        this.pinotQuery = requireNonNull(pinotQuery, "broker pinotQuery is null");
        this.expectedColumnHandles = requireNonNull(expectedColumnHandles, "expected column handles is null");
    }

    @JsonProperty
    public Optional<PinotQueryGenerator.GeneratedPinotQuery> getPinotQuery()
    {
        return pinotQuery;
    }

    @JsonProperty
    public String getConnectorId()
    {
        return connectorId;
    }

    @JsonProperty
    public String getSchemaName()
    {
        return schemaName;
    }

    @JsonProperty
    public String getTableName()
    {
        return tableName;
    }

    @JsonProperty
    public Optional<Boolean> getForBroker()
    {
        return forBroker;
    }

    @JsonProperty
    public Optional<List<PinotColumnHandle>> getExpectedColumnHandles()
    {
        return expectedColumnHandles;
    }

    public SchemaTableName toSchemaTableName()
    {
        return new SchemaTableName(schemaName, tableName);
    }

    @Override
    public boolean equals(Object o)
    {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        PinotTableHandle that = (PinotTableHandle) o;
        return Objects.equals(connectorId, that.connectorId) &&
                Objects.equals(schemaName, that.schemaName) &&
                Objects.equals(tableName, that.tableName) &&
                Objects.equals(forBroker, that.forBroker) &&
                Objects.equals(expectedColumnHandles, that.expectedColumnHandles) &&
                Objects.equals(pinotQuery, that.pinotQuery);
    }

    @Override
    public int hashCode()
    {
        return Objects.hash(connectorId, schemaName, tableName, forBroker, expectedColumnHandles, pinotQuery);
    }

    @Override
    public String toString()
    {
        return toStringHelper(this)
                .add("connectorId", connectorId)
                .add("schemaName", schemaName)
                .add("tableName", tableName)
                .add("forBroker", forBroker)
                .add("expectedColumnHandles", expectedColumnHandles)
                .add("pinotQuery", pinotQuery)
                .toString();
    }
}