text:
//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2019, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//      * Redistributions of source code must retain the above
//        copyright notice, this list of conditions and the following
//        disclaimer.
//
//      * Redistributions in binary form must reproduce the above
//        copyright notice, this list of conditions and the following
//        disclaimer in the documentation and/or other materials provided with
//        the distribution.
//
//      * Neither the name of John Haddon nor the names of
//        any other contributors to this software may be used to endorse or
//        promote products derived from this software without specific prior
//        written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "Gaffer/Spreadsheet.h"

#include "Gaffer/Metadata.h"
#include "Gaffer/PlugAlgo.h"
#include "Gaffer/StringPlug.h"

#include "IECore/NullObject.h"

#include "boost/bind/bind.hpp"
#include "boost/container/small_vector.hpp"
#include "boost/lexical_cast.hpp"
#include "boost/multi_index/member.hpp"
#include "boost/multi_index/hashed_index.hpp"
#include "boost/multi_index_container.hpp"
#include "boost/variant.hpp"

#include <unordered_map>

using namespace std;
using namespace boost;
using namespace boost::placeholders;
using namespace IECore;
using namespace Gaffer;

//////////////////////////////////////////////////////////////////////////
// Internal utilities
//////////////////////////////////////////////////////////////////////////

namespace
{

InternedString g_enabledPlugName( "enabled" );

void appendLeafPlugs( const Gaffer::Plug *p, DependencyNode::AffectedPlugsContainer &container )
{
	if( !p->children().size() )
	{
		container.push_back( p );
	}
	else
	{
		for( const auto &c : Plug::Range( *p ) )
		{
			appendLeafPlugs( c.get(), container );
		}
	}
}

// Data type stored on `rowsMapPlug()` and used for quickly
// finding the right row for a selector.
class RowsMap : public IECore::Data
{

	public :

		using Selector = boost::variant<const vector<InternedString> *, string>;

		RowsMap( const Spreadsheet::RowsPlug *rows )
			:	m_enabledRowNames( new StringVectorData )
		{
			vector<string> &enabledRowNames = m_enabledRowNames->writable();

			for( size_t i = 1, e = rows->children().size(); i < e; ++i )
			{
				const auto *row = rows->getChild<Spreadsheet::RowPlug>( i );
				if( !row->enabledPlug()->getValue() )
				{
					continue;
				}

				const std::string name = row->namePlug()->getValue();
				if( name.empty() )
				{
					continue;
				}
				enabledRowNames.push_back( name );

				const bool hasWildcards = StringAlgo::hasWildcards( name );
				if( hasWildcards || name.find( ' ' ) != string::npos )
				{
					m_wildcardRows.push_back( { name, i } );
				}
				else
				{
					m_plainRows.insert( { name, i } );
				}

				const StringAlgo::MatchPatternPath path = StringAlgo::matchPatternPath( name );
				if( hasWildcards || name.find( "..." ) != string::npos )
				{
					m_wildcardPathRows.push_back( { path, i } );
				}
				else
				{
					m_plainPathRows.insert( { path, i } );
				}
			}
		}

		// Hashes everything accessed by the constructor.
		static void hash( const Spreadsheet::RowsPlug *rows, IECore::MurmurHash &h )
		{
			for( int i = 1, e = rows->children().size(); i < e; ++i )
			{
				const auto *row = rows->getChild<Spreadsheet::RowPlug>( i );
				row->namePlug()->hash( h );
				row->enabledPlug()->hash( h );
			}
		}

		// Hashes the contents of the selector.
		static void hash( const Selector &selector, IECore::MurmurHash &h )
		{
			if( auto s = get<string>( &selector ) )
			{
				h.append( *s );
			}
			else if( auto p = get<const vector<InternedString> *>( &selector ) )
			{
				h.append( (*p)->data(), (*p)->size() );
			}
		}

		size_t rowIndex( const Selector &selector ) const
		{
			size_t result = 0;
			if( auto s = get<string>( &selector ) )
			{
				auto it = m_plainRows.find( *s );
				if( it != m_plainRows.end() )
				{
					result = it->second;
				}
				for( auto &row : m_wildcardRows )
				{
					if( result && row.index > result )
					{
						break;
					}

					if( StringAlgo::matchMultiple( *s, row.name ) )
					{
						result = row.index;
						break;
					}
				}
			}
			else if( auto p = get<const vector<InternedString> *>( selector ) )
			{
				auto it = m_plainPathRows.find( *p );
				if( it != m_plainPathRows.end() )
				{
					result = it->second;
				}
				for( auto &row : m_wildcardPathRows )
				{
					if( result && row.index > result )
					{
						break;
					}

					if( StringAlgo::match( *p, row.path ) )
					{
						result = row.index;
						break;
					}
				}
			}
			return result;
		}

		const StringVectorData *enabledRowNames() const
		{
			return m_enabledRowNames.get();
		}

	private :

		// Rows without wildcards. We can look these up
		// directly.
		using Map = std::unordered_map<std::string, size_t>;
		Map m_plainRows;

		// Rows with wildcards. These require a linear search.
		struct Row
		{
			std::string name;
			size_t index;
		};
		using Vector = std::vector<Row>;
		Vector m_wildcardRows;

		// As above, but for when the selector is an InternedStringVectorData,
		// in which case we want to use PathMatcher-style matching. We could do
		// better here if we generalised the PathMatcher::Node data structure to
		// allow us to store our `index` in place of the `bool terminator`. For
		// now we assume that Spreadsheets with extreme numbers of rows will
		// have only plain rows (as in EditScopes), and the PathMap will be
		// sufficient. If this assumption plays out in practice, then a simpler
		// implementation might just be to make `StringAlgo::match()` compatible
		// with the behaviour of `*` and `...` in PathMatcher, so we can just
		// use the original code path for everything . That would be a breaking
		// change though.
		using PathMap = std::map<StringAlgo::MatchPatternPath, size_t>;
		PathMap m_plainPathRows;

		struct PathRow
		{
			StringAlgo::MatchPatternPath path;
			size_t index;
		};
		using PathVector = std::vector<PathRow>;
		PathVector m_wildcardPathRows;

		// List of enabled row names for `enabledRowNamesPlug()`.
		StringVectorDataPtr m_enabledRowNames;

};

IE_CORE_DECLAREPTR( RowsMap )

InternedString g_scenePath( "scene:path" );

// Context scope used for accessing `rowsMapPlug()`. This
// removes all context variables referred to by `selectorPlug()`,
// for two reasons :
//
// 1. Performance. A common use case is to use `${someVariable}`
//    as the selector, and then to have N rows, one for each
//    value that `${someVariable}` will take. This would lead to
//    N calls to `Spreadsheet::hash( rowsMapPlug() )` (one per
//    unique context), each of which would need to visit all N
//    rows. For some uses of the Spreadsheet, N can be large enough
//    that the resultant quadratic scaling is unacceptable. We can
//    avoid this by making a clean context omitting `${someVariable}`,
//    meaning that `rowsMapPlug()` will be hashed only once.
// 2. Sanity. We can't think of any good reason to have row names
//    that include the same context variable as the selector.
//    Trying to reason about them would be mindbending.
class RowsMapScope : boost::noncopyable, public Context::SubstitutionProvider
{

	public :

		RowsMapScope( const Context *context, const std::string &selector )
			:	SubstitutionProvider( context ), m_context( context )
		{
			if( selector == "${scene:path}" )
			{
				// Special case for `scene:path`, which users will expect to use PathMatcher
				// style matching rather than `StringAlgo::match()`.
				if( auto path = context->getIfExists< std::vector<InternedString> >( g_scenePath ) )
				{
					m_selector = path;
				}
				else
				{
					m_selector = "";
				}
			}
			else
			{
				// (Ab)use `StringAlgo::substitute()` as a parser for
				// variable references in the `selector`. We pass
				// ourselves as the VariableProvider so that
				// our `variable()` method is called once for each
				// variable. We could instead implement our
				// own parsing, but that would be non-trivial, particularly
				// because `substitute()` allows recursive substitutions.
				m_selector = IECore::StringAlgo::substitute( selector, *this );
			}
		}

		// Returns the selector with Context substitutions applied.
		const RowsMap::Selector &selector() const
		{
			return m_selector;
		}

		// Methods used by `StringAlgo::substitute()`. We use
		// these to parse variable references in `selector`.

		int frame() const override
		{
			return SubstitutionProvider::frame();
		}

		const std::string &variable( const boost::string_view &name, bool &recurse ) const override
		{
			if( !m_scope )
			{
				m_scope.emplace( m_context );
			}
			m_scope->remove( name );
			return SubstitutionProvider::variable( name, recurse );
		}

	private :

		const Context *m_context;
		mutable std::optional<Context::EditableScope> m_scope;
		RowsMap::Selector m_selector;

};

struct MetadataRegistration
{
	MetadataRegistration()
	{
		Metadata::registerValue( Spreadsheet::RowsPlug::staticTypeId(), "spreadsheet:columnsNeedSerialisation:promotable", new BoolData( false ) );
	}
};

MetadataRegistration g_metadataRegistration;

} // namespace

//////////////////////////////////////////////////////////////////////////
// RowsPlug
//////////////////////////////////////////////////////////////////////////

GAFFER_PLUG_DEFINE_TYPE( Spreadsheet::RowsPlug );

// Manages a data structure mapping between row name
// and row, so we can implement `RowsPlug::row()` without
// linear search.
class Spreadsheet::RowsPlug::RowNameMap
{

	public :

		RowNameMap( Spreadsheet::RowsPlug *rowsPlug )
			:	m_rowsPlug( rowsPlug )
		{
			rowsPlug->childAddedSignal().connect( boost::bind( &RowNameMap::childAdded, this, ::_2 ) );
			rowsPlug->childRemovedSignal().connect( boost::bind( &RowNameMap::childRemoved, this, ::_2 ) );
			rowsPlug->parentChangedSignal().connect( boost::bind( &RowNameMap::parentChanged, this ) );
		}

		RowPlug *row( const string &rowName )
		{
			if( !m_plugSetConnection.connected() )
			{
				// If we can't track name changes, we must do
				// a brute force update. This should basically never
				// happen, so we put no effort into making something more
				// performant.
				updateRowNames();
			}

			const auto &index = m_map.get<1>();
			auto range = index.equal_range( rowName );
			if( range.first == index.end() )
			{
				return nullptr;
			}
			else if( range.first == range.second )
			{
				// Single row with the requested name.
				// This is the common case we are optimising
				// for.
				return range.first->plug;
			}
			else
			{
				// Multiple rows with the requested name.
				// We must return the first one.
				size_t minIndex = std::numeric_limits<size_t>::max();
				RowPlug *result = nullptr;
				for( auto it = range.first; it != range.second; ++it )
				{
					/// \todo We need GraphComponent to provide constant-time
					/// access to a child's index.
					const auto childIt = find( m_rowsPlug->children().begin(), m_rowsPlug->children().end(), it->plug );
					const size_t index = childIt - m_rowsPlug->children().begin();
					if( index < minIndex )
					{
						minIndex = index;
						result = it->plug;
					}
				}
				return result;
			}
		}

	private :

		string rowName( const RowPlug *row )
		{
			auto namePlug = row->namePlug()->source<StringPlug>();
			if( namePlug->direction() == Plug::Out )
			{
				return "__rowNameMap::computedNameSentinel__";
			}
			else
			{
				return row->namePlug()->getValue();
			}
		}

		void childAdded( GraphComponent *child )
		{
			auto row = static_cast<RowPlug *>( child ); // Guaranteed by `RowsPlug::acceptsChild()`.
			if( row != m_rowsPlug->defaultRow() )
			{
				m_map.insert( { row, rowName( row ) } );
			}
		}

		void childRemoved( GraphComponent *child )
		{
			auto row = static_cast<RowPlug *>( child ); // Guaranteed by `RowsPlug::acceptsChild()`.
			m_map.erase( row );
		}

		void parentChanged()
		{
			if( auto node = m_rowsPlug->node() )
			{
				m_plugSetConnection = node->plugSetSignal().connect( boost::bind( &RowNameMap::plugSet, this, ::_1 ) );
				m_plugInputChangedConnection = node->plugInputChangedSignal().connect( boost::bind( &RowNameMap::plugInputChanged, this, ::_1 ) );
				// While we had no parent, we couldn't track
				// value or input changes, so we must manually
				// update all the names.
				updateRowNames();
			}
			else
			{
				m_plugSetConnection.disconnect();
				m_plugInputChangedConnection.disconnect();
			}
		}

		void plugSet( Plug *plug )
		{
			updateRowName( plug );
		}

		void plugInputChanged( Plug *plug )
		{
			updateRowName( plug );
		}

		void updateRowName( Plug *plug )
		{
			if( auto row = plug->parent<RowPlug>() )
			{
				if( plug == row->namePlug() && row->parent() == m_rowsPlug && row != m_rowsPlug->defaultRow() )
				{
					auto it = m_map.find( row );
					assert( it != m_map.end() );
					m_map.get<1>().modify_key(
						m_map.project<1>( it ),
						[row, this] ( string &name ) {
							name = this->rowName( row );
						}
					);
				}
			}
		}

		void updateRowNames()
		{
			auto &index = m_map.get<1>();

			// `modify_key()` doesn't invalidate iterators, but it does
			// reorder them, so to visit everything we must first grab
			// all the iterators.
			std::vector<Map::nth_index<1>::type::iterator> iterators;
			for( auto it = index.begin(); it != index.end(); ++it )
			{
				iterators.push_back( it );
			}

			for( const auto &it : iterators )
			{
				index.modify_key(
					it,
					[it, this] ( string &name ) {
						name = this->rowName( it->plug );
					}
				);
			}
		}

		RowsPlug *m_rowsPlug;

		Signals::ScopedConnection m_plugSetConnection;
		Signals::ScopedConnection m_plugInputChangedConnection;

		struct Row
		{
			RowPlug *plug;
			string name;
		};

		using Map = multi_index::multi_index_container<
			Row,
			multi_index::indexed_by<
				multi_index::hashed_unique<
					multi_index::member<Row, RowPlug *, &Row::plug>
				>,
				multi_index::hashed_non_unique<
					multi_index::member<Row, string, &Row::name>
				>
			>
		>;

		Map m_map;

};

Spreadsheet::RowsPlug::RowsPlug( const std::string &name, Direction direction, unsigned flags )
	:	ValuePlug( name, direction, flags ), m_rowNameMap( new RowNameMap( this ) )
{
	RowPlugPtr defaultRow = new RowPlug( "default" );
	addChild( defaultRow );
}

Spreadsheet::RowsPlug::~RowsPlug()
{
}

Spreadsheet::RowPlug *Spreadsheet::RowsPlug::defaultRow()
{
	return getChild<RowPlug>( 0 );
}

const Spreadsheet::RowPlug *Spreadsheet::RowsPlug::defaultRow() const
{
	return getChild<RowPlug>( 0 );
}

Spreadsheet::RowPlug *Spreadsheet::RowsPlug::row( const std::string &rowName )
{
	return m_rowNameMap->row( rowName );
}

const Spreadsheet::RowPlug *Spreadsheet::RowsPlug::row( const std::string &rowName ) const
{
	return m_rowNameMap->row( rowName );
}

size_t Spreadsheet::RowsPlug::addColumn( const ValuePlug *value, IECore::InternedString name, bool adoptEnabledPlug )
{
	if( name.string().empty() )
	{
		name = value->getName();
	}

	for( auto &row : RowPlug::Range( *this ) )
	{
		CellPlugPtr cellPlug = new CellPlug( name, value, adoptEnabledPlug );
		cellPlug->valuePlug()->setFrom( value );
		row->cellsPlug()->addChild( cellPlug );
	}
	for( auto o : outPlugs() )
	{
		PlugPtr outColumn = value->createCounterpart( name, Plug::Out );
		outColumn->setFlags( Plug::Dynamic, false );
		o->addChild( outColumn );
	}
	return defaultRow()->cellsPlug()->children().size() - 1;
}

size_t Spreadsheet::RowsPlug::addColumn( const ValuePlug *value, IECore::InternedString name )
{
	return addColumn( value, name, /* adoptEnabledPlug = */ false );
}

void Spreadsheet::RowsPlug::removeColumn( size_t columnIndex )
{
	if( columnIndex >= defaultRow()->cellsPlug()->children().size() )
	{
		throw IECore::Exception( "Column index out of range" );
	}

	for( auto o : outPlugs() )
	{
		o->removeChild( o->getChild( columnIndex ) );
	}
	for( auto &row : RowPlug::Range( *this ) )
	{
		row->cellsPlug()->removeChild( row->cellsPlug()->getChild( columnIndex ) );
	}
}

Spreadsheet::RowPlug *Spreadsheet::RowsPlug::addRow()
{
	RowPlugPtr newRow = new RowPlug( "row" + boost::lexical_cast<std::string>( children().size() ), direction() );
	for( auto &defaultCell : CellPlug::Range( *defaultRow()->cellsPlug() ) )
	{
		CellPlugPtr newCell = boost::static_pointer_cast<CellPlug>(
			defaultCell->createCounterpart( defaultCell->getName(), Plug::In )
		);
		newCell->setFrom( defaultCell.get() );
		newRow->cellsPlug()->addChild( newCell );
	}
	addChild( newRow );
	return newRow.get();
}

void Spreadsheet::RowsPlug::addRows( size_t numRows )
{
	for( ; numRows; --numRows )
	{
		addRow();
	}
}

void Spreadsheet::RowsPlug::removeRow( Spreadsheet::RowPlugPtr row )
{
	if( row->parent() != this )
	{
		throw Exception( boost::str(
			boost::format( "Row \"%1%\" is not a child of \"%2%\"." ) % row->fullName() % fullName()
		) );
	}

	if( row == getChild( 0 ) )
	{
		throw Exception( boost::str(
			boost::format( "Cannot remove default row from \"%1%\"." ) % fullName()
		) );
	}

	removeChild( row );
}

std::vector<Gaffer::ValuePlug *> Spreadsheet::RowsPlug::outPlugs()
{
	// Find `Spreadsheet::outPlug()` on all the Spreadsheet nodes
	// driven by this plug. Because of plug promotion, an `outPlug()`
	// may belong to a different node than ours, and if someone has
	// been really creative we might even be driving multiple
	// spreadsheets.
	//
	// We use this from `add/removeColumn()` so that we can add the
	// appropriate columns to the output plugs. It's not ideal that
	// this responsibility falls to us. What might be nice would be
	// to rename RowsPlug to SheetPlug and let it manage both "rows"
	// and "out" children, so that it's more natural to modify "out".
	// We can't do that at present because we don't allow connections
	// to plugs which have a mix of input and output children.

	vector<Gaffer::ValuePlug *> result;
	if( auto *s = parent<Spreadsheet>() )
	{
		if( s->rowsPlug() == this )
		{
			result.push_back( s->outPlug() );
		}
	}

	for( auto output : outputs() )
	{
		if( auto outputRow = runTimeCast<Spreadsheet::RowsPlug>( output ) )
		{
			auto v = outputRow->outPlugs();
			result.insert( result.end(), v.begin(), v.end() );
		}
	}

	return result;
}

bool Spreadsheet::RowsPlug::acceptsChild( const GraphComponent *potentialChild ) const
{
	return runTimeCast<const RowPlug>( potentialChild );
}

Gaffer::PlugPtr Spreadsheet::RowsPlug::createCounterpart( const std::string &name, Direction direction ) const
{
	RowsPlugPtr result = new RowsPlug( name, direction, getFlags() );
	for( const auto &row : RowPlug::Range( *this ) )
	{
		// Using `setChild()` rather than `addChild()` because we want to replace
		// the default-constructed default row with one with the right number of
		// cells.
		result->setChild( row->getName(), row->createCounterpart( row->getName(), direction ) );
	}
	return result;
}

//////////////////////////////////////////////////////////////////////////
// RowPlug
//////////////////////////////////////////////////////////////////////////

GAFFER_PLUG_DEFINE_TYPE( Spreadsheet::RowPlug );

Spreadsheet::RowPlug::RowPlug( const std::string &name, Plug::Direction direction, unsigned flags )
	:	ValuePlug( name, direction, flags )
{
	addChild( new StringPlug( "name", direction ) );
	addChild( new BoolPlug( "enabled",direction, true ) );
	addChild( new ValuePlug( "cells", direction ) );
}

StringPlug *Spreadsheet::RowPlug::namePlug()
{
	return getChild<StringPlug>( 0 );
}

const StringPlug *Spreadsheet::RowPlug::namePlug() const
{
	return getChild<StringPlug>( 0 );
}

BoolPlug *Spreadsheet::RowPlug::enabledPlug()
{
	return getChild<BoolPlug>( 1 );
}

const BoolPlug *Spreadsheet::RowPlug::enabledPlug() const
{
	return getChild<BoolPlug>( 1 );
}

ValuePlug *Spreadsheet::RowPlug::cellsPlug()
{
	return getChild<ValuePlug>( 2 );
}

const ValuePlug *Spreadsheet::RowPlug::cellsPlug() const
{
	return getChild<ValuePlug>( 2 );
}

Gaffer::PlugPtr Spreadsheet::RowPlug::createCounterpart( const std::string &name, Direction direction ) const
{
	RowPlugPtr result = new RowPlug( name, direction );
	for( const auto &cell : CellPlug::Range( *cellsPlug() ) )
	{
		result->cellsPlug()->addChild( cell->createCounterpart( cell->getName(), direction ) );
	}
	return result;
}

//////////////////////////////////////////////////////////////////////////
// CellPlug
//////////////////////////////////////////////////////////////////////////

GAFFER_PLUG_DEFINE_TYPE( Spreadsheet::CellPlug );

Spreadsheet::CellPlug::CellPlug( const std::string &name, const Gaffer::Plug *value, bool adoptEnabledPlug, Plug::Direction direction )
	:	ValuePlug( name, direction )
{
	if( adoptEnabledPlug )
	{
		if( !value->getChild<BoolPlug>( g_enabledPlugName ) )
		{
			throw IECore::Exception( "Value plug has no \"enabled\" plug to adopt" );
		}
	}
	else
	{
		addChild( new BoolPlug( g_enabledPlugName, direction, true ) );
	}

	addChild( value->createCounterpart( "value", direction ) );
	valuePlug()->setFlags( Plug::Dynamic, false );
}

BoolPlug *Spreadsheet::CellPlug::enabledPlug()
{
	if( children().size() > 1 )
	{
		return getChild<BoolPlug>( 0 );
	}
	else
	{
		return valuePlug()->getChild<BoolPlug>( g_enabledPlugName );
	}
}

const BoolPlug *Spreadsheet::CellPlug::enabledPlug() const
{
	if( children().size() > 1 )
	{
		return getChild<BoolPlug>( 0 );
	}
	else
	{
		return valuePlug()->getChild<BoolPlug>( g_enabledPlugName );
	}
}

Gaffer::PlugPtr Spreadsheet::CellPlug::createCounterpart( const std::string &name, Direction direction ) const
{
	return new CellPlug( name, valuePlug(), /* adoptEnabledPlug = */ children().size() == 1, direction );
}

//////////////////////////////////////////////////////////////////////////
// Spreadsheet
//////////////////////////////////////////////////////////////////////////

size_t Spreadsheet::g_firstPlugIndex = 0;
GAFFER_NODE_DEFINE_TYPE( Spreadsheet );

Spreadsheet::Spreadsheet( const std::string &name )
	:	ComputeNode( name )
{
	storeIndexOfNextChild( g_firstPlugIndex );

	addChild( new BoolPlug( "enabled", Plug::In, true ) );
	addChild( new StringPlug( "selector", Plug::In, "", Plug::Default, IECore::StringAlgo::NoSubstitutions ) );
	addChild( new RowsPlug( "rows" ) );
	addChild( new ValuePlug( "out", Plug::Out ) );
	addChild( new StringVectorDataPlug( "enabledRowNames", Plug::Out, new IECore::StringVectorData ) );
	addChild( new CompoundObjectPlug( "resolvedRows", Plug::Out, new IECore::CompoundObject() ) );
	addChild( new IntPlug( "activeRowIndex", Plug::Out ) );
	addChild( new ObjectPlug( "__rowsMap", Plug::Out, IECore::NullObject::defaultNullObject() ) );
}

Spreadsheet::~Spreadsheet()
{
}

BoolPlug *Spreadsheet::enabledPlug()
{
	return getChild<BoolPlug>( g_firstPlugIndex );
}

const BoolPlug *Spreadsheet::enabledPlug() const
{
	return getChild<BoolPlug>( g_firstPlugIndex );
}

StringPlug *Spreadsheet::selectorPlug()
{
	return getChild<StringPlug>( g_firstPlugIndex + 1 );
}

const StringPlug *Spreadsheet::selectorPlug() const
{
	return getChild<StringPlug>( g_firstPlugIndex + 1 );
}

Spreadsheet::RowsPlug *Spreadsheet::rowsPlug()
{
	return getChild<RowsPlug>( g_firstPlugIndex + 2 );
}

const Spreadsheet::RowsPlug *Spreadsheet::rowsPlug() const
{
	return getChild<RowsPlug>( g_firstPlugIndex + 2 );
}

ValuePlug *Spreadsheet::outPlug()
{
	return getChild<ValuePlug>( g_firstPlugIndex + 3 );
}

const ValuePlug *Spreadsheet::outPlug() const
{
	return getChild<ValuePlug>( g_firstPlugIndex + 3 );
}

StringVectorDataPlug *Spreadsheet::enabledRowNamesPlug()
{
	return getChild<StringVectorDataPlug>( g_firstPlugIndex + 4 );
}

const StringVectorDataPlug *Spreadsheet::enabledRowNamesPlug() const
{
	return getChild<StringVectorDataPlug>( g_firstPlugIndex + 4 );
}

CompoundObjectPlug *Spreadsheet::resolvedRowsPlug()
{
	return getChild<CompoundObjectPlug>( g_firstPlugIndex + 5 );
}

const CompoundObjectPlug *Spreadsheet::resolvedRowsPlug() const
{
	return getChild<CompoundObjectPlug>( g_firstPlugIndex + 5 );
}

IntPlug *Spreadsheet::activeRowIndexPlug()
{
	return getChild<IntPlug>( g_firstPlugIndex + 6 );
}

const IntPlug *Spreadsheet::activeRowIndexPlug() const
{
	return getChild<IntPlug>( g_firstPlugIndex + 6 );
}

ObjectPlug *Spreadsheet::rowsMapPlug()
{
	return getChild<ObjectPlug>( g_firstPlugIndex + 7 );
}

const ObjectPlug *Spreadsheet::rowsMapPlug() const
{
	return getChild<ObjectPlug>( g_firstPlugIndex + 7 );
}

void Spreadsheet::affects( const Plug *input, DependencyNode::AffectedPlugsContainer &outputs ) const
{
	ComputeNode::affects( input, outputs );

	if( const auto *row = input->parent<RowPlug>() )
	{
		if(
			input == row->namePlug() ||
			input == row->enabledPlug()
		)
		{
			outputs.push_back( rowsMapPlug() );
		}
	}

	if(
		input == enabledPlug() ||
		input == selectorPlug() ||
		input == rowsMapPlug()
	)
	{
		outputs.push_back( activeRowIndexPlug() );
	}

	if( input == activeRowIndexPlug() )
	{
		appendLeafPlugs( outPlug(), outputs );
	}

	if( const auto *cell = input->ancestor<CellPlug>() )
	{
		if( const Plug *out = outPlug()->getChild<ValuePlug>( cell->getName() ) )
		{
			if( input == cell->enabledPlug() )
			{
				appendLeafPlugs( out, outputs );
			}
			else if( input == cell->valuePlug() )
			{
				outputs.push_back( out );
			}
			else
			{
				outputs.push_back(
					out->descendant<Plug>( input->relativeName( cell->valuePlug() ) )
				);
			}
		}
	}

	if( input == rowsMapPlug() )
	{
		outputs.push_back( enabledRowNamesPlug() );
	}

	if( rowsPlug()->isAncestorOf( input ) )
	{
		outputs.push_back( resolvedRowsPlug() );
	}
}

Plug *Spreadsheet::correspondingInput( const Plug *output )
{
	return const_cast<Plug *>( const_cast<const Spreadsheet *>( this)->correspondingInput( output ) );
}

const Plug *Spreadsheet::correspondingInput( const Plug *output ) const
{
	if( const Plug *p = correspondingInput( output, /* rowIndex = */ 0 ) )
	{
		return p;
	}

	return DependencyNode::correspondingInput( output );
}

void Spreadsheet::hash( const ValuePlug *output, const Context *context, IECore::MurmurHash &h ) const
{
	if( output == rowsMapPlug() )
	{
		ComputeNode::hash( output, context, h );
		RowsMap::hash( rowsPlug(), h );
		return;
	}
	else if( output == activeRowIndexPlug() )
	{
		ComputeNode::hash( output, context, h );
		enabledPlug()->hash( h );
		RowsMapScope rowsMapScope( context, selectorPlug()->getValue() );
		rowsMapPlug()->hash( h );
		RowsMap::hash( rowsMapScope.selector(), h );
		return;
	}
	else if( outPlug()->isAncestorOf( output ) )
	{
		h = correspondingInput( output, activeRowIndexPlug()->getValue() )->hash();
		return;
	}
	else if( output == enabledRowNamesPlug() )
	{
		ComputeNode::hash( output, context, h );
		RowsMapScope rowsMapScope( context, selectorPlug()->getValue() );
		rowsMapPlug()->hash( h );
		return;
	}
	else if( output == resolvedRowsPlug() )
	{
		ComputeNode::hash( output, context, h );
		rowsPlug()->hash( h );
	}

	ComputeNode::hash( output, context, h );
}

void Spreadsheet::compute( ValuePlug *output, const Context *context ) const
{
	if( output == rowsMapPlug() )
	{
		static_cast<ObjectPlug *>( output )->setValue(
			new RowsMap( rowsPlug() )
		);
		return;
	}
	else if( output == activeRowIndexPlug() )
	{
		size_t result = 0;
		if( enabledPlug()->getValue() )
		{
			RowsMapScope rowsMapScope( context, selectorPlug()->getValue() );
			ConstRowsMapPtr rowsMap = boost::static_pointer_cast<const RowsMap>( rowsMapPlug()->getValue() );
			result = rowsMap->rowIndex( rowsMapScope.selector() );
		}
		static_cast<IntPlug *>( output )->setValue( result );
		return;
	}
	else if( outPlug()->isAncestorOf( output ) )
	{
		output->setFrom( correspondingInput( output, activeRowIndexPlug()->getValue() ) );
		return;
	}
	else if( output == enabledRowNamesPlug() )
	{
		RowsMapScope rowsMapScope( context, selectorPlug()->getValue() );
		ConstRowsMapPtr rowsMap = boost::static_pointer_cast<const RowsMap>( rowsMapPlug()->getValue() );
		static_cast<StringVectorDataPlug *>( output )->setValue( rowsMap->enabledRowNames() );
		return;
	}
	else if( output == resolvedRowsPlug() )
	{
		CompoundObjectPtr defaults = new CompoundObject;
		for( const auto &cellPlug : CellPlug::Range( *rowsPlug()->defaultRow()->cellsPlug() ) )
		{
			defaults->members()[cellPlug->getName()] = PlugAlgo::getValueAsData( cellPlug->valuePlug() );
		}

		CompoundObjectPtr result = new CompoundObject;
		for( size_t i = 1, s = rowsPlug()->children().size(); i < s; ++i )
		{
			const RowPlug *rowPlug = rowsPlug()->getChild<RowPlug>( i );
			if( !rowPlug->enabledPlug()->getValue() )
			{
				continue;
			}

			const string name = rowPlug->namePlug()->getValue();
			if( name.empty() || result->members().count( name ) )
			{
				continue;
			}

			CompoundObjectPtr cells = new CompoundObject;
			for( const auto &cellPlug : CellPlug::Range( *rowPlug->cellsPlug() ) )
			{
				if( cellPlug->enabledPlug()->getValue() )
				{
					cells->members()[cellPlug->getName()] = PlugAlgo::getValueAsData( cellPlug->valuePlug() );
				}
				else
				{
					cells->members()[cellPlug->getName()] = defaults->members().at( cellPlug->getName() );
				}
			}

			result->members()[name] = cells;
		}
		static_cast<CompoundObjectPlug *>( output )->setValue( result );
	}

	ComputeNode::compute( output, context );
}

const ValuePlug *Spreadsheet::correspondingInput( const Plug *plug, size_t rowIndex ) const
{
	const ValuePlug *out = outPlug();
	boost::container::small_vector<IECore::InternedString, 4> names;
	while( plug && plug != out )
	{
		names.push_back( plug->getName() );
		plug = plug->parent<Plug>();
	}

	if( !plug || names.empty() )
	{
		return nullptr;
	}

	const CellPlug *cell = rowsPlug()->getChild<RowPlug>( rowIndex )->cellsPlug()->getChild<CellPlug>( names.back() );
	if( rowIndex && !cell->enabledPlug()->getValue() )
	{
		cell = rowsPlug()->defaultRow()->cellsPlug()->getChild<CellPlug>( names.back() );
	}

	names.pop_back();
	const ValuePlug *result = cell->valuePlug();
	for( auto it = names.rbegin(), eIt = names.rend(); it != eIt; ++it )
	{
		result = result->getChild<ValuePlug>( *it );
	}

	return result;
}

ValuePlug *Spreadsheet::activeInPlug( const ValuePlug *output )
{
	return const_cast<ValuePlug *>( correspondingInput( output, activeRowIndexPlug()->getValue() ) );
}

const ValuePlug *Spreadsheet::activeInPlug( const ValuePlug *output ) const
{
	return correspondingInput( output, activeRowIndexPlug()->getValue() );
}


text:
	<title>K.T. Tunstall's panel show appearances</title>

	<link rel="stylesheet" media="all" href="../style.css" type="text/css"/>

K.T. Tunstall's panel show appearances

K.T. Tunstall (born 1975-06-23[ref]) has appeared in 5 episodes between 2008-2016.  K.T. Tunstall on IMDB. K.T. Tunstall on Wikipedia.

2008

2009

2010

2011

2012

2013

2014

2015

2016

2016-07-04 / The Infinite Monkey Cage

2013-07-01 / The Infinite Monkey Cage

2013-06-11 / Loose Women

2010-12-21 / Never Mind The Buzzcocks

2008-01-10 / Never Mind The Buzzcocks

redpajama_set_name: RedPajamaGithub


text:
package com.commonsware.cwac.saferoom.test;

import android.content.Context;
import android.text.SpannableStringBuilder;
import androidx.sqlite.db.SupportSQLiteOpenHelper;
import com.commonsware.cwac.saferoom.SafeHelperFactory;
import com.commonsware.dbtest.FactoryProvider;

import java.io.File;

class SafeFactoryProvider implements FactoryProvider {
  @Override
  public SupportSQLiteOpenHelper.Factory getFactory() {
    return SafeHelperFactory.fromUser(new SpannableStringBuilder("sekrit"));
  }

  @Override
  public void tearDownDatabase(Context ctxt,
                               SupportSQLiteOpenHelper.Factory factory,
                               SupportSQLiteOpenHelper helper) {
    String name=helper.getDatabaseName();

    if (name!=null) {
      File db=ctxt.getDatabasePath(name);

      if (db.exists()) {
        db.delete();
      }

      File journal=new File(db.getParentFile(), name+"-journal");

      if (journal.exists()) {
        journal.delete();
      }
    }
  }
}


text:
const should = require('should'),
  nock = require('nock'),
  crypto = require('crypto');

const OAuth2Service = require('../../src/services/oauth2');

// Shared test data
const SAMPLE_SERVICE = new OAuth2Service({
  domain: 'https://testDomain.com',
  callbackUrl: 'testCallbackUrl',
  consumerKey: 'testConsumerKey',
  consumerSecret: 'testConsumerSecret'
});

describe('when calling OAuth2Service.getAuthorizationUrl', function () {

  it('should return the correct URL', function () {
    const options = {scope: 'api'};
    const expectedUrl = 'https://testDomain.com/services/oauth2/authorize?client_id=testConsumerKey&redirect_uri=testCallbackUrl&response_type=code&scope=api';

    const actualUrl = SAMPLE_SERVICE.getAuthorizationUrl(options);

    actualUrl.should.eql(expectedUrl);
  });
});

describe('when calling OAuth2Service.authenticate', function () {

  const expectedUrl = '/services/oauth2/token?client_id=testConsumerKey&client_secret=testConsumerSecret&redirect_uri=testCallbackUrl&grant_type=authorization_code&code=testCode';

  it('should throw error if authorization code is not set', function () {
    (function() {
	  SAMPLE_SERVICE.authenticate({});
    }).should.throw('Missing authorization code');
  });

  it('should return error if response signature is missing', function (done) {
    const server = nock('https://testDomain.com')
      .post(expectedUrl)
      .reply(200, {});

    const expectedError = {
      message: 'Missing payload signature.',
      statusCode: 500,
      response: '{}'
    };

    SAMPLE_SERVICE.authenticate({code: 'testCode'}, function(error, payload) {
      error.should.eql(expectedError);
      server.done();
      done();
    });
  });

  it('should return error if response signature is invalid', function (done) {
    const mockResponse = {signature: 'invalidSignature', id: 'https://testDomain.com', issued_at:'1332093834282'};
    const server = nock('https://testDomain.com')
      .post(expectedUrl)
      .reply(200, mockResponse);

    const expectedError = {
      message: 'The signature could not be verified.',
      statusCode: 500,
      response: JSON.stringify(mockResponse)
    };

    SAMPLE_SERVICE.authenticate({code: 'testCode'}, function(error, payload) {
      error.should.eql(expectedError);
      server.done();
      done();
    });
  });

  it('should send the right request and receive the right response', function (done) {
    const mockResponse = {
        id: 'https://testDomain.com',
        issued_at: '1332093834282',
        scope: 'api',
        instance_url: 'https://na14.salesforce.com',
        access_token: '00Dd0000000dsWL!AR8AQCKKVxOwRhqhwXqNthdufggKWdUOOrp866CrJeEqF41eYP1kxtYmLMGxTkfRjFbzsD.Aqh8wvDyKyOPAVrDuyJS_bh2.'
    };
    const hmac = crypto.createHmac('sha256', 'testConsumerSecret');
    hmac.update(mockResponse.id);
    hmac.update(mockResponse.issued_at);
    mockResponse.signature = hmac.digest('base64');

    const server = nock('https://testDomain.com')
      .post(expectedUrl)
      .reply(200, mockResponse);

	SAMPLE_SERVICE.authenticate({code: 'testCode'}, function(error, payload) {
      should.not.exist(error);
      payload.should.eql(mockResponse);
      server.done();
      done();
    });
  });
});

describe('when calling OAuth2Service.password', function () {

  const expectedUrl = '/services/oauth2/token?client_id=testConsumerKey&client_secret=testConsumerSecret&grant_type=password';

  it('should return error if response signature is missing', function (done) {
    const server = nock('https://testDomain.com')
      .post(expectedUrl)
      .reply(200, {});

    const expectedError = {
      message: 'Missing payload signature.',
      statusCode: 500,
      response: '{}'
    };

    SAMPLE_SERVICE.password({}, function(error, payload) {
      error.should.eql(expectedError);
      server.done();
      done();
    });
  });

  it('should return error if response signature is invalid', function (done) {
    const mockResponse = {signature: 'invalidSignature', id: 'https://testDomain.com', issued_at:'1332093834282'};
    const server = nock('https://testDomain.com')
      .post(expectedUrl)
      .reply(200, mockResponse);

    const expectedError = {
      message: 'The signature could not be verified.',
      statusCode: 500,
      response: JSON.stringify(mockResponse)
    };

    SAMPLE_SERVICE.password({}, function(error, payload) {
      error.should.eql(expectedError);
      server.done();
      done();
    });
  });

  it('should send the right request and receive the right response', function (done) {
    const mockResponse = {
        id: 'https://testDomain.com',
        issued_at: '1332093834282',
        scope: 'api',
        instance_url: 'https://na14.salesforce.com',
        access_token: '00Dd0000000dsWL!AR8AQCKKVxOwRhqhwXqNthdufggKWdUOOrp866CrJeEqF41eYP1kxtYmLMGxTkfRjFbzsD.Aqh8wvDyKyOPAVrDuyJS_bh2.'
    };
    const hmac = crypto.createHmac('sha256', 'testConsumerSecret');
    hmac.update(mockResponse.id);
    hmac.update(mockResponse.issued_at);
    mockResponse.signature = hmac.digest('base64');

    const server = nock('https://testDomain.com')
      .post(expectedUrl)
      .reply(200, mockResponse);

	SAMPLE_SERVICE.password({}, function(error, payload) {
      should.not.exist(error);
      payload.should.eql(mockResponse);
      server.done();
      done();
    });
  });
});

describe('when calling OAuth2Service.refresh', function () {

  const expectedUrl = '/services/oauth2/token?client_id=testConsumerKey&client_secret=testConsumerSecret&redirect_uri=testCallbackUrl&grant_type=refresh_token';

  it('should return error if response signature is missing', function (done) {
    const server = nock('https://testDomain.com')
      .post(expectedUrl)
      .reply(200, {});

    const expectedError = {
      message: 'Missing payload signature.',
      statusCode: 500,
      response: '{}'
    };

    SAMPLE_SERVICE.refresh({}, function(error, payload) {
      error.should.eql(expectedError);
      server.done();
      done();
    });
  });

  it('should return error if response signature is invalid', function (done) {
    const mockResponse = {signature: 'invalidSignature', id: 'https://testDomain.com', issued_at:'1332093834282'};
    const server = nock('https://testDomain.com')
      .post(expectedUrl)
      .reply(200, mockResponse);

    const expectedError = {
      message: 'The signature could not be verified.',
      statusCode: 500,
      response: JSON.stringify(mockResponse)
    };

    SAMPLE_SERVICE.refresh({}, function(error, payload) {
      error.should.eql(expectedError);
      server.done();
      done();
    });
  });

  it('should send the right request and receive the right response', function (done) {
    const mockResponse = {
        id: 'https://testDomain.com',
        issued_at: '1332093834282',
        scope: 'api',
        instance_url: 'https://na14.salesforce.com',
        access_token: '00Dd0000000dsWL!AR8AQCKKVxOwRhqhwXqNthdufggKWdUOOrp866CrJeEqF41eYP1kxtYmLMGxTkfRjFbzsD.Aqh8wvDyKyOPAVrDuyJS_bh2.'
    };
    const hmac = crypto.createHmac('sha256', 'testConsumerSecret');
    hmac.update(mockResponse.id);
    hmac.update(mockResponse.issued_at);
    mockResponse.signature = hmac.digest('base64');

    const server = nock('https://testDomain.com')
      .post(expectedUrl)
      .reply(200, mockResponse);

	SAMPLE_SERVICE.refresh({}, function(error, payload) {
      should.not.exist(error);
      payload.should.eql(mockResponse);
      server.done();
      done();
    });
  });
});

describe('when calling OAuth2Service.revoke', function () {

  const expectedUrl = '/services/oauth2/revoke?token=testToken';

  it('should throw error if token is not set', function () {
    (function() {
	  SAMPLE_SERVICE.revoke({});
    }).should.throw('Missing token.');
  });

  it('should send the right request and receive the right response', function (done) {
    const server = nock('https://testDomain.com')
      .post(expectedUrl)
      .reply(200, {});

	SAMPLE_SERVICE.revoke({token: 'testToken'}, function(error, payload) {
      should.not.exist(error);
      should.not.exist(payload);
      server.done();
      done();
    });
  });
});


text:
package io.corylee.mapgen.domain;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Set;

import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity
@Table(name = "T_CORNER")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Corner implements Serializable {

	private static final long serialVersionUID = -8310345595092676585L;

	@Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(name = "x", precision=10, scale=2)
    private BigDecimal x;

    @Column(name = "y", precision=10, scale=2)
    private BigDecimal y;

    @Column(name = "ocean")
    private Boolean ocean;

    @Column(name = "water")
    private Boolean water;

    @Column(name = "coast")
    private Boolean coast;

    @Column(name = "elevation")
    private Integer elevation;

    @Column(name = "moisture")
    private Integer moisture;

    @ElementCollection
    @CollectionTable(name="T_CORNER_POLY", joinColumns=@JoinColumn(name="corner_id"))
    @Column(name="polygon_id")
    public Set<Long> touches;

    @ElementCollection
    @CollectionTable(name="T_CORNER_EDGE", joinColumns=@JoinColumn(name="corner_id"))
    @Column(name="edge_id")
    public Set<Long> protrudes;

    @ElementCollection
    @CollectionTable(name="T_CORNER_CORNER", joinColumns=@JoinColumn(name="corner_id"))
    @Column(name="target_corner_id")
    public Set<Long> adjacent;

    @ManyToOne
    private Map map;

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public BigDecimal getX() {
		return x;
	}

	public void setX(BigDecimal x) {
		this.x = x;
	}

	public BigDecimal getY() {
		return y;
	}

	public void setY(BigDecimal y) {
		this.y = y;
	}

	public Boolean getOcean() {
		return ocean;
	}

	public void setOcean(Boolean ocean) {
		this.ocean = ocean;
	}

	public Boolean getWater() {
		return water;
	}

	public void setWater(Boolean water) {
		this.water = water;
	}

	public Boolean getCoast() {
		return coast;
	}

	public void setCoast(Boolean coast) {
		this.coast = coast;
	}

	public Integer getElevation() {
		return elevation;
	}

	public void setElevation(Integer elevation) {
		this.elevation = elevation;
	}

    public Integer getMoisture() {
		return moisture;
	}

	public void setMoisture(Integer moisture) {
		this.moisture = moisture;
	}

	public Map getMap() {
		return map;
	}

	public Set<Long> getTouches() {
		return touches;
	}

	public void setTouches(Set<Long> touches) {
		this.touches = touches;
	}

	public Set<Long> getProtrudes() {
		return protrudes;
	}

	public void setProtrudes(Set<Long> protrudes) {
		this.protrudes = protrudes;
	}

	public Set<Long> getAdjacent() {
		return adjacent;
	}

	public void setAdjacent(Set<Long> adjacent) {
		this.adjacent = adjacent;
	}

	public void setMap(Map map) {
		this.map = map;
	}

	@Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        Corner corner = (Corner) o;

        if (id != null ? !id.equals(corner.id) : corner.id != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return (int) (id ^ (id >>> 32));
    }

    @Override
    public String toString() {
        return "Polygon{" +
                "id=" + id +
                ", x='" + x + "'" +
                ", y='" + y + "'" +
                ", ocean='" + ocean + "'" +
                ", water='" + water + "'" +
                ", coast='" + coast + "'" +
                ", elevation='" + elevation + "'" +
                ", moisture='" + moisture + "'" +
				", touches='" + touches + "'" +
				", protrudes='" + protrudes + "'" +
				", adjacent='" + adjacent + "'" +
                '}';
    }
}


text:
using System;
using OTA.Command;
using Terraria;
using OTA;

namespace TDSM.Core.Command.Commands
{
    public class TeleportHereCommand : CoreCommand
    {
        public override void Initialise()
        {
            AddCommand("tphere")
                .WithAccessLevel(AccessLevel.OP)
                .WithDescription("Teleport a player to yourself")
                .WithHelpText("<player>")
                .WithPermissionNode("tdsm.tphere")
                .Calls(this.TeleportHere);
        }

        /// <summary>
        /// Teleports specified player to sending player's location.
        /// </summary>
        /// <param name="sender">Sending player</param>
        /// <param name="args">Arguments sent with command</param>
        public void TeleportHere(ISender sender, ArgumentList args)
        {
            if (sender is Player)
            {
                Player player = ((Player)sender);
                Player subject;

                if (args.TryPopOne(out subject))
                {
                    if (subject == null)
                    {
                        sender.Message("Cannot find player");
                        return;
                    }

                    subject.Teleport(player);

                    Utils.NotifyAllOps("Teleported " + subject.name + " to " +
                        player.name + " [" + sender.SenderName + "]", true);
                }
            }
            else
            {
                throw new CommandError("This command is for players only");
            }
        }
    }
}


text:
package org.apache.flink.streaming.connectors.kinesis.util;

import org.apache.flink.streaming.connectors.kinesis.config.AWSConfigConstants;
import org.apache.flink.streaming.connectors.kinesis.config.ConsumerConfigConstants;
import org.apache.flink.streaming.connectors.kinesis.config.ProducerConfigConstants;
import org.apache.flink.streaming.connectors.kinesis.testutils.TestUtils;

import com.amazonaws.services.kinesis.producer.KinesisProducerConfiguration;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;

import static org.apache.flink.streaming.connectors.kinesis.config.ConsumerConfigConstants.DEFAULT_STREAM_TIMESTAMP_DATE_FORMAT;
import static org.apache.flink.streaming.connectors.kinesis.config.ConsumerConfigConstants.STREAM_INITIAL_TIMESTAMP;
import static org.apache.flink.streaming.connectors.kinesis.config.ConsumerConfigConstants.STREAM_TIMESTAMP_DATE_FORMAT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

/**
 * Tests for KinesisConfigUtil.
 */
@RunWith(PowerMockRunner.class)
@PrepareForTest(KinesisConfigUtil.class)
public class KinesisConfigUtilTest {

	@Rule
	private ExpectedException exception = ExpectedException.none();

	// ----------------------------------------------------------------------
	// getValidatedProducerConfiguration() tests
	// ----------------------------------------------------------------------

	@Test
	public void testUnparsableLongForProducerConfiguration() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Error trying to set field RateLimit with the value 'unparsableLong'");

		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_REGION, "us-east-1");
		testConfig.setProperty("RateLimit", "unparsableLong");

		KinesisConfigUtil.getValidatedProducerConfiguration(testConfig);
	}

	@Test
	public void testRateLimitInProducerConfiguration() {
		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_REGION, "us-east-1");
		KinesisProducerConfiguration kpc = KinesisConfigUtil.getValidatedProducerConfiguration(testConfig);

		assertEquals(100, kpc.getRateLimit());

		testConfig.setProperty(KinesisConfigUtil.RATE_LIMIT, "150");
		kpc = KinesisConfigUtil.getValidatedProducerConfiguration(testConfig);

		assertEquals(150, kpc.getRateLimit());
	}

	@Test
	public void testThreadingModelInProducerConfiguration() {
		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_REGION, "us-east-1");
		KinesisProducerConfiguration kpc = KinesisConfigUtil.getValidatedProducerConfiguration(testConfig);

		assertEquals(KinesisProducerConfiguration.ThreadingModel.POOLED, kpc.getThreadingModel());

		testConfig.setProperty(KinesisConfigUtil.THREADING_MODEL, "PER_REQUEST");
		kpc = KinesisConfigUtil.getValidatedProducerConfiguration(testConfig);

		assertEquals(KinesisProducerConfiguration.ThreadingModel.PER_REQUEST, kpc.getThreadingModel());
	}

	@Test
	public void testThreadPoolSizeInProducerConfiguration() {
		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_REGION, "us-east-1");
		KinesisProducerConfiguration kpc = KinesisConfigUtil.getValidatedProducerConfiguration(testConfig);

		assertEquals(10, kpc.getThreadPoolSize());

		testConfig.setProperty(KinesisConfigUtil.THREAD_POOL_SIZE, "12");
		kpc = KinesisConfigUtil.getValidatedProducerConfiguration(testConfig);

		assertEquals(12, kpc.getThreadPoolSize());
	}

	@Test
	public void testReplaceDeprecatedKeys() {
		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_REGION, "us-east-1");
		// these deprecated keys should be replaced
		testConfig.setProperty(ProducerConfigConstants.AGGREGATION_MAX_COUNT, "1");
		testConfig.setProperty(ProducerConfigConstants.COLLECTION_MAX_COUNT, "2");
		Properties replacedConfig = KinesisConfigUtil.replaceDeprecatedProducerKeys(testConfig);

		assertEquals("1", replacedConfig.getProperty(KinesisConfigUtil.AGGREGATION_MAX_COUNT));
		assertEquals("2", replacedConfig.getProperty(KinesisConfigUtil.COLLECTION_MAX_COUNT));
	}

	@Test
	public void testCorrectlySetRegionInProducerConfiguration() {
		String region = "us-east-1";
		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_REGION, region);
		KinesisProducerConfiguration kpc = KinesisConfigUtil.getValidatedProducerConfiguration(testConfig);

		assertEquals("incorrect region", region, kpc.getRegion());
	}

	@Test
	public void testMissingAwsRegionInProducerConfig() {
		String expectedMessage = String.format("For FlinkKinesisProducer AWS region ('%s') must be set in the config.",
				AWSConfigConstants.AWS_REGION);
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage(expectedMessage);

		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_ACCESS_KEY_ID, "accessKey");
		testConfig.setProperty(AWSConfigConstants.AWS_SECRET_ACCESS_KEY, "secretKey");

		KinesisConfigUtil.getValidatedProducerConfiguration(testConfig);
	}

	// ----------------------------------------------------------------------
	// validateAwsConfiguration() tests
	// ----------------------------------------------------------------------

	@Test
	public void testUnrecognizableAwsRegionInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid AWS region");

		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_REGION, "wrongRegionId");
		testConfig.setProperty(AWSConfigConstants.AWS_ACCESS_KEY_ID, "accessKeyId");
		testConfig.setProperty(AWSConfigConstants.AWS_SECRET_ACCESS_KEY, "secretKey");

		KinesisConfigUtil.validateAwsConfiguration(testConfig);
	}

	@Test
	public void testCredentialProviderTypeSetToBasicButNoCredentialSetInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Please set values for AWS Access Key ID ('" + AWSConfigConstants.AWS_ACCESS_KEY_ID + "') " +
				"and Secret Key ('" + AWSConfigConstants.AWS_SECRET_ACCESS_KEY + "') when using the BASIC AWS credential provider type.");

		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_REGION, "us-east-1");
		testConfig.setProperty(AWSConfigConstants.AWS_CREDENTIALS_PROVIDER, "BASIC");

		KinesisConfigUtil.validateAwsConfiguration(testConfig);
	}

	@Test
	public void testUnrecognizableCredentialProviderTypeInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid AWS Credential Provider Type");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(AWSConfigConstants.AWS_CREDENTIALS_PROVIDER, "wrongProviderType");

		KinesisConfigUtil.validateAwsConfiguration(testConfig);
	}

	// ----------------------------------------------------------------------
	// validateConsumerConfiguration() tests
	// ----------------------------------------------------------------------

	@Test
	public void testNoAwsRegionOrEndpointInConsumerConfig() {
		String expectedMessage = String.format("For FlinkKinesisConsumer AWS region ('%s') and/or AWS endpoint ('%s') must be set in the config.",
				AWSConfigConstants.AWS_REGION, AWSConfigConstants.AWS_ENDPOINT);
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage(expectedMessage);

		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_ACCESS_KEY_ID, "accessKey");
		testConfig.setProperty(AWSConfigConstants.AWS_SECRET_ACCESS_KEY, "secretKey");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testAwsRegionAndEndpointInConsumerConfig() {
		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_REGION, "us-east-1");
		testConfig.setProperty(AWSConfigConstants.AWS_ENDPOINT, "fake");
		testConfig.setProperty(AWSConfigConstants.AWS_ACCESS_KEY_ID, "accessKey");
		testConfig.setProperty(AWSConfigConstants.AWS_SECRET_ACCESS_KEY, "secretKey");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testAwsRegionInConsumerConfig() {
		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_REGION, "us-east-1");
		testConfig.setProperty(AWSConfigConstants.AWS_ACCESS_KEY_ID, "accessKey");
		testConfig.setProperty(AWSConfigConstants.AWS_SECRET_ACCESS_KEY, "secretKey");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testEndpointInConsumerConfig() {
		Properties testConfig = new Properties();
		testConfig.setProperty(AWSConfigConstants.AWS_ENDPOINT, "fake");
		testConfig.setProperty(AWSConfigConstants.AWS_ACCESS_KEY_ID, "accessKey");
		testConfig.setProperty(AWSConfigConstants.AWS_SECRET_ACCESS_KEY, "secretKey");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnrecognizableStreamInitPositionTypeInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid initial position in stream");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.AWS_CREDENTIALS_PROVIDER, "BASIC");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_POSITION, "wrongInitPosition");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testStreamInitPositionTypeSetToAtTimestampButNoInitTimestampSetInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Please set value for initial timestamp ('"
				+ ConsumerConfigConstants.STREAM_INITIAL_TIMESTAMP + "') when using AT_TIMESTAMP initial position.");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.AWS_CREDENTIALS_PROVIDER, "BASIC");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_POSITION, "AT_TIMESTAMP");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableDateForInitialTimestampInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for initial timestamp for AT_TIMESTAMP initial position in stream.");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.AWS_CREDENTIALS_PROVIDER, "BASIC");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_POSITION, "AT_TIMESTAMP");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_TIMESTAMP, "unparsableDate");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testIllegalValueForInitialTimestampInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for initial timestamp for AT_TIMESTAMP initial position in stream.");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.AWS_CREDENTIALS_PROVIDER, "BASIC");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_POSITION, "AT_TIMESTAMP");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_TIMESTAMP, "-1.0");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testDateStringForValidateOptionDateProperty() {
		String timestamp = "2016-04-04T19:58:46.480-00:00";

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.AWS_CREDENTIALS_PROVIDER, "BASIC");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_POSITION, "AT_TIMESTAMP");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_TIMESTAMP, timestamp);

		try {
			KinesisConfigUtil.validateConsumerConfiguration(testConfig);
		} catch (Exception e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void testUnixTimestampForValidateOptionDateProperty() {
		String unixTimestamp = "1459799926.480";

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.AWS_CREDENTIALS_PROVIDER, "BASIC");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_POSITION, "AT_TIMESTAMP");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_TIMESTAMP, unixTimestamp);

		try {
			KinesisConfigUtil.validateConsumerConfiguration(testConfig);
		} catch (Exception e) {
			e.printStackTrace();
			fail();
		}
	}

	@Test
	public void testInvalidPatternForInitialTimestampInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for initial timestamp for AT_TIMESTAMP initial position in stream.");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.AWS_CREDENTIALS_PROVIDER, "BASIC");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_POSITION, "AT_TIMESTAMP");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_TIMESTAMP, "2016-03-14");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_TIMESTAMP_DATE_FORMAT, "InvalidPattern");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableDateForUserDefinedDateFormatForInitialTimestampInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for initial timestamp for AT_TIMESTAMP initial position in stream.");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.AWS_CREDENTIALS_PROVIDER, "BASIC");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_POSITION, "AT_TIMESTAMP");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_TIMESTAMP, "stillUnparsable");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_TIMESTAMP_DATE_FORMAT, "yyyy-MM-dd");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testDateStringForUserDefinedDateFormatForValidateOptionDateProperty() {
		String unixTimestamp = "2016-04-04";
		String pattern = "yyyy-MM-dd";

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.AWS_CREDENTIALS_PROVIDER, "BASIC");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_POSITION, "AT_TIMESTAMP");
		testConfig.setProperty(ConsumerConfigConstants.STREAM_INITIAL_TIMESTAMP, unixTimestamp);
		testConfig.setProperty(ConsumerConfigConstants.STREAM_TIMESTAMP_DATE_FORMAT, pattern);

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableLongForListShardsBackoffBaseMillisInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for list shards operation base backoff milliseconds");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.LIST_SHARDS_BACKOFF_BASE, "unparsableLong");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableLongForListShardsBackoffMaxMillisInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for list shards operation max backoff milliseconds");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.LIST_SHARDS_BACKOFF_MAX, "unparsableLong");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableDoubleForListShardsBackoffExponentialConstantInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for list shards operation backoff exponential constant");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.LIST_SHARDS_BACKOFF_EXPONENTIAL_CONSTANT, "unparsableDouble");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableIntForGetRecordsRetriesInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for maximum retry attempts for getRecords shard operation");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.SHARD_GETRECORDS_RETRIES, "unparsableInt");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableIntForGetRecordsMaxCountInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for maximum records per getRecords shard operation");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.SHARD_GETRECORDS_MAX, "unparsableInt");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableLongForGetRecordsBackoffBaseMillisInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for get records operation base backoff milliseconds");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.SHARD_GETRECORDS_BACKOFF_BASE, "unparsableLong");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableLongForGetRecordsBackoffMaxMillisInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for get records operation max backoff milliseconds");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.SHARD_GETRECORDS_BACKOFF_MAX, "unparsableLong");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableDoubleForGetRecordsBackoffExponentialConstantInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for get records operation backoff exponential constant");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.SHARD_GETRECORDS_BACKOFF_EXPONENTIAL_CONSTANT, "unparsableDouble");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableLongForGetRecordsIntervalMillisInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for getRecords sleep interval in milliseconds");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.SHARD_GETRECORDS_INTERVAL_MILLIS, "unparsableLong");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableIntForGetShardIteratorRetriesInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for maximum retry attempts for getShardIterator shard operation");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.SHARD_GETITERATOR_RETRIES, "unparsableInt");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableLongForGetShardIteratorBackoffBaseMillisInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for get shard iterator operation base backoff milliseconds");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.SHARD_GETITERATOR_BACKOFF_BASE, "unparsableLong");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableLongForGetShardIteratorBackoffMaxMillisInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for get shard iterator operation max backoff milliseconds");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.SHARD_GETITERATOR_BACKOFF_MAX, "unparsableLong");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableDoubleForGetShardIteratorBackoffExponentialConstantInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for get shard iterator operation backoff exponential constant");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.SHARD_GETITERATOR_BACKOFF_EXPONENTIAL_CONSTANT, "unparsableDouble");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testUnparsableLongForShardDiscoveryIntervalMillisInConfig() {
		exception.expect(IllegalArgumentException.class);
		exception.expectMessage("Invalid value given for shard discovery sleep interval in milliseconds");

		Properties testConfig = TestUtils.getStandardProperties();
		testConfig.setProperty(ConsumerConfigConstants.SHARD_DISCOVERY_INTERVAL_MILLIS, "unparsableLong");

		KinesisConfigUtil.validateConsumerConfiguration(testConfig);
	}

	@Test
	public void testParseStreamTimestampStartingPositionUsingDefaultFormat() throws Exception {
		String timestamp = "2020-08-13T09:18:00.0+01:00";
		Date expectedTimestamp = new SimpleDateFormat(DEFAULT_STREAM_TIMESTAMP_DATE_FORMAT).parse(timestamp);

		Properties consumerProperties = new Properties();
		consumerProperties.setProperty(STREAM_INITIAL_TIMESTAMP, timestamp);

		Date actualimestamp = KinesisConfigUtil.parseStreamTimestampStartingPosition(consumerProperties);

		assertEquals(expectedTimestamp, actualimestamp);
	}

	@Test
	public void testParseStreamTimestampStartingPositionUsingCustomFormat() throws Exception {
		String format = "yyyy-MM-dd'T'HH:mm";
		String timestamp = "2020-08-13T09:23";
		Date expectedTimestamp = new SimpleDateFormat(format).parse(timestamp);

		Properties consumerProperties = new Properties();
		consumerProperties.setProperty(STREAM_INITIAL_TIMESTAMP, timestamp);
		consumerProperties.setProperty(STREAM_TIMESTAMP_DATE_FORMAT, format);

		Date actualimestamp = KinesisConfigUtil.parseStreamTimestampStartingPosition(consumerProperties);

		assertEquals(expectedTimestamp, actualimestamp);
	}

	@Test
	public void testParseStreamTimestampStartingPositionUsingParseError() {
		exception.expect(NumberFormatException.class);

		Properties consumerProperties = new Properties();
		consumerProperties.setProperty(STREAM_INITIAL_TIMESTAMP, "bad");

		KinesisConfigUtil.parseStreamTimestampStartingPosition(consumerProperties);
	}

	@Test
	public void testParseStreamTimestampStartingPositionIllegalArgumentException() {
		exception.expect(IllegalArgumentException.class);

		Properties consumerProperties = new Properties();

		KinesisConfigUtil.parseStreamTimestampStartingPosition(consumerProperties);
	}

}


text:
package org.onetwo.boot.module.rxtx;

public interface SeriaDeivceCommand<T> {

	/***
	 * 指令
	 * @author weishao zeng
	 * @return
	 */
	String getCommand();

	/***
	 * 收到数据
	 * @author weishao zeng
	 * @param serialEvent
	 */
	void onSerialEvent(JSerialEvent serialEvent);

	T decodeData();

	void clearData();

}


text:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Code generated by Microsoft (R) AutoRest Code Generator.

package com.azure.resourcemanager.machinelearning.models;

import com.azure.core.annotation.Fluent;
import com.azure.resourcemanager.machinelearning.fluent.models.DatastoreSecretsInner;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;

/** Datastore account key secrets. */
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "secretsType")
@JsonTypeName("AccountKey")
@Fluent
public final class AccountKeyDatastoreSecrets extends DatastoreSecretsInner {
    /*
     * Storage account key.
     */
    @JsonProperty(value = "key")
    private String key;

    /** Creates an instance of AccountKeyDatastoreSecrets class. */
    public AccountKeyDatastoreSecrets() {
    }

    /**
     * Get the key property: Storage account key.
     *
     * @return the key value.
     */
    public String key() {
        return this.key;
    }

    /**
     * Set the key property: Storage account key.
     *
     * @param key the key value to set.
     * @return the AccountKeyDatastoreSecrets object itself.
     */
    public AccountKeyDatastoreSecrets withKey(String key) {
        this.key = key;
        return this;
    }

    /**
     * Validates the instance.
     *
     * @throws IllegalArgumentException thrown if the instance is not valid.
     */
    @Override
    public void validate() {
        super.validate();
    }
}


text:
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">

  <title>Qt 4.3: Custom Widget Plugin Example</title>
  <link href="classic.css" rel="stylesheet" type="text/css" />

  	Home · All Classes · Main Classes · Grouped Classes · Modules · Functions

Custom Widget Plugin Example

Files:

designer/customwidgetplugin/analogclock.cpp

designer/customwidgetplugin/analogclock.h

designer/customwidgetplugin/customwidgetplugin.cpp

designer/customwidgetplugin/customwidgetplugin.h

The Custom Widget example shows how to create a custom widget plugin for Qt Designer.

In this example, the custom widget used is based on the Analog Clock example, and does not provide any custom signals or slots.

Preparation

To provide a custom widget that can be used with Qt Designer, we need to supply a self-contained implementation and provide a plugin interface. In this example, we reuse the Analog Clock example for convenience.

Since custom widgets plugins rely on components supplied with Qt Designer, the project file that we use needs to contain information about Qt Designer's library components:

 TEMPLATE    = lib
 CONFIG      += designer plugin debug_and_release

The <tt>TEMPLATE</tt> variable's value makes <tt>qmake</tt> create the custom widget as a library. Later, we will ensure that the widget will be recognized as a plugin by Qt by using the Q_EXPORT_PLUGIN2() macro to export the relevant widget information.

The <tt>CONFIG</tt> variable contains two values, <tt>designer</tt> and <tt>plugin</tt>:

<tt>designer</tt>: Since custom widgets plugins rely on components supplied with Qt Designer, this value ensures that our plugin links against Qt Designer's library (<tt>libQtDesigner.so</tt>).

<tt>plugin</tt>: We also need to ensure that <tt>qmake</tt> considers the custom widget a plugin library.

When Qt is configured to build in both debug and release modes, Qt Designer will be built in release mode. When this occurs, it is necessary to ensure that plugins are also built in release mode. For that reason we add the <tt>debug_and_release</tt> value to the <tt>CONFIG</tt> variable. Otherwise, if a plugin is built in a mode that is incompatible with Qt Designer, it won't be loaded and installed.

The header and source files for the widget are declared in the usual way, and we provide an implementation of the plugin interface so that Qt Designer can use the custom widget:

 HEADERS     = analogclock.h \
               customwidgetplugin.h
 SOURCES     = analogclock.cpp \
               customwidgetplugin.cpp

It is also important to ensure that the plugin is installed in a location that is searched by Qt Designer. We do this by specifying a target path for the project and adding it to the list of items to install:

 target.path = $$[QT_INSTALL_PLUGINS]/designer
 INSTALLS += target

The custom widget is created as a library, and will be installed alongside the other Qt Designer plugins when the project is installed (using <tt>make install</tt> or an equivalent installation procedure). Later, we will ensure that it is recognized as a plugin by Qt Designer by using the Q_EXPORT_PLUGIN2() macro to export the relevant widget information.

Note that if you want the plugins to appear in a Visual Studio integration, the plugins must be built in release mode and their libraries must be copied into the plugin directory in the install path of the integration (for an example, see <tt>C:/program files/trolltech as/visual studio integration/plugins</tt>).

For more information about plugins, see the How to Create Qt Plugins documentation.

AnalogClock Class Definition and Implementation

The <tt>AnalogClock</tt> class is defined and implemented in exactly the same way as described in the Analog Clock example. Since the class is self-contained, and does not require any external configuration, it can be used without modification as a custom widget in Qt Designer.

AnalogClockPlugin Class Definition

The <tt>AnalogClock</tt> class is exposed to Qt Designer through the <tt>AnalogClockPlugin</tt> class. This class inherits from both QObject and the QDesignerCustomWidgetInterface class, and implements an interface defined by QDesignerCustomWidgetInterface:

 class AnalogClockPlugin : public QObject, public QDesignerCustomWidgetInterface
 {
     Q_OBJECT
     Q_INTERFACES(QDesignerCustomWidgetInterface)

 public:
     AnalogClockPlugin(QObject *parent = 0);

     bool isContainer() const;
     bool isInitialized() const;
     QIcon icon() const;
     QString domXml() const;
     QString group() const;
     QString includeFile() const;
     QString name() const;
     QString toolTip() const;
     QString whatsThis() const;
     QWidget *createWidget(QWidget *parent);
     void initialize(QDesignerFormEditorInterface *core);

 private:
     bool initialized;
 };

The functions provide information about the widget that Qt Designer can use in the widget box. The <tt>initialized</tt> private member variable is used to record whether the plugin has been initialized by Qt Designer.

Note that the only part of the class definition that is specific to this particular custom widget is the class name.

AnalogClockPlugin Implementation

The class constructor simply calls the QObject base class constructor and sets the <tt>initialized</tt> variable to <tt>false</tt>.

 AnalogClockPlugin::AnalogClockPlugin(QObject *parent)
     : QObject(parent)
 {
     initialized = false;
 }

Qt Designer will initialize the plugin when it is required by calling the <tt>initialize()</tt> function:

 void AnalogClockPlugin::initialize(QDesignerFormEditorInterface * /* core */)
 {
     if (initialized)
         return;

     initialized = true;
 }

In this example, the <tt>initialized</tt> private variable is tested, and only set to <tt>true</tt> if the plugin is not already initialized. Although, this plugin does not require any special code to be executed when it is initialized, we could include such code after the test for initialization.

The <tt>isInitialized()</tt> function lets Qt Designer know whether the plugin is ready for use:

 bool AnalogClockPlugin::isInitialized() const
 {
     return initialized;
 }

Instances of the custom widget are supplied by the <tt>createWidget()</tt> function. The implementation for the analog clock is straightforward:

 QWidget *AnalogClockPlugin::createWidget(QWidget *parent)
 {
     return new AnalogClock(parent);
 }

In this case, the custom widget only requires a <tt>parent</tt> to be specified. If other arguments need to be supplied to the widget, they can be introduced here.

The following functions provide information for Qt Designer to use to represent the widget in the widget box. The <tt>name()</tt> function returns the name of class that provides the custom widget:

 QString AnalogClockPlugin::name() const
 {
     return "AnalogClock";
 }

The <tt>group()</tt> function is used to describe the type of widget that the custom widget belongs to:

 QString AnalogClockPlugin::group() const
 {
     return "Display Widgets [Examples]";
 }

The widget plugin will be placed in a section identified by its group name in Qt Designer's widget box. The icon used to represent the widget in the widget box is returned by the <tt>icon()</tt> function:

 QIcon AnalogClockPlugin::icon() const
 {
     return QIcon();
 }

In this case, we return a null icon to indicate that we have no icon that can be used to represent the widget.

A tool tip and "What's This?" help can be supplied for the custom widget's entry in the widget box. The <tt>toolTip()</tt> function should return a short message describing the widget:

 QString AnalogClockPlugin::toolTip() const
 {
     return "";
 }

The <tt>whatsThis()</tt> function can return a longer description:

 QString AnalogClockPlugin::whatsThis() const
 {
     return "";
 }

The <tt>isContainer()</tt> function tells Qt Designer whether the widget is supposed to be used as a container for other widgets. If not, Qt Designer will not allow the user to place widgets inside it.

 bool AnalogClockPlugin::isContainer() const
 {
     return false;
 }

Most widgets in Qt can contain child widgets, but it only makes sense to use dedicated container widgets for this purpose in Qt Designer. By returning <tt>false</tt>, we indicate that the custom widget cannot hold other widgets; if we returned true, Qt Designer would allow other widgets to be placed inside the analog clock and a layout to be defined.

The <tt>domXml()</tt> function provides a way to include default settings for the widget in the standard XML format used by Qt Designer. In this case, we only specify the widget's geometry:

 QString AnalogClockPlugin::domXml() const
 {
     return "<widget class=\"AnalogClock\" name=\"analogClock\">\n"
            " <property name=\"geometry\">\n"
            "  <rect>\n"
            "   <x>0</x>\n"
            "   <y>0</y>\n"
            "   <width>100</width>\n"
            "   <height>100</height>\n"
            "  </rect>\n"
            " </property>\n"
            " <property name=\"toolTip\" >\n"
            "  <string>The current time</string>\n"
            " </property>\n"
            " <property name=\"whatsThis\" >\n"
            "  <string>The analog clock widget displays "
            "the current time.</string>\n"
            " </property>\n"
            "</widget>\n";
 }

If the widget provides a reasonable size hint, it is not necessary to define it here. In addition, returning an empty string instead of a <tt><widget></tt> element will tell Qt Designer not to install the widget in the widget box.

To make the analog clock widget usable by applications, we implement the <tt>includeFile()</tt> function to return the name of the header file containing the custom widget class definition:

 QString AnalogClockPlugin::includeFile() const
 {
     return "analogclock.h";
 }

Finally, we use the Q_EXPORT_PLUGIN2() macro to export the <tt>AnalogClockPlugin</tt> class for use with Qt Designer:

 Q_EXPORT_PLUGIN2(customwidgetplugin, AnalogClockPlugin)

This macro ensures that Qt Designer can access and construct the custom widget. Without this macro, there is no way for Qt Designer to use the widget.

<address>

Copyright © 2008 Trolltech
Trademarks

Qt 4.3.5

</address>


text:
jQuery(document).ready(function(){
	$('#contactform').submit(function(){
		var action = $(this).attr('action');
		$("#message").slideUp(750,function() {
		$('#message').hide();
 		$('#submit')
			.attr('disabled','disabled');
		$.post(action, {
			name: $('#name').val(),
			email: $('#email').val(),
			comments: $('#comments').val()
		},
			function(data){
				document.getElementById('message').innerHTML = data;
				$('#message').slideDown('slow');
				$('#submit').removeAttr('disabled');
				if(data.match('success') != null) $('#contactform').fadeOut('fast');
			}
		);
		});
		return false;
	});
});


text:
#ifndef __CocosGUI_h__
#define __CocosGUI_h__

#include "BaseClasses/UIWidget.h"
#include "Layouts/UILayout.h"
#include "BaseClasses/UIRootWidget.h"
#include "UIWidgets/UIButton.h"
#include "UIWidgets/UICheckBox.h"
#include "UIWidgets/UIImageView.h"
#include "UIWidgets/UILabel.h"
#include "UIWidgets/UILabelAtlas.h"
#include "UIWidgets/UILoadingBar.h"
#include "UIWidgets/ScrollWidget/UIScrollView.h"
#include "UIWidgets/ScrollWidget/UIListView.h"
#include "UIWidgets/UISlider.h"
#include "UIWidgets/UITextField.h"
#include "UIWidgets/UILabelBMFont.h"
#include "UIWidgets/ScrollWidget/UIPageView.h"
#include "System/UIHelper.h"
#include "System/UILayer.h"

#define NS_GUI_BEGIN						namespace gui {
#define NS_GUI_END							}
#define USING_NS_GUI						using namespace gui

namespace gui
{
	const KDchar*	CocosGUIVersion ( KDvoid );
}

#endif	// __CocosGUI_h__