#!/usr/bin/env python
# coding=utf-8
from __future__ import print_function
import sys

# Tricks to handle Python3
PY3 = sys.version_info.major > 2
if PY3:
    basestring = str

from types import *
import itertools
import random
import math
import bisect
from functools import reduce
from collections import Iterable

__version__ = 2.0

# noinspection PyCallByClass,PyShadowingBuiltins,PyPep8,PyPep8,PyPep8
class underscore(object):
	"""
    Methods usually have a usage example to make the description clearer. Conceptually, the following Python code precedes all examples::

        from underscore import underscore as _
        listOfPlays = [
            {
                "author" : "Shakespeare",
                "year"   : 1611,
                "title"  : "The tempest"
            },
            {
                "author" : "Shakespeare",
                "year"   : 1611,
                "title"  : "Cymbeline"
            },
            {
                "author" : "Shakespeare",
                "year"   : 1601,
                "title"  : "Romeo and Juliet"
            },
        ]

        stooges  = [
            {'name': 'moe', 'age': 40},
            {'name': 'larry', 'age': 50},
            {'name': 'curly', 'age': 60},
            {'name':'joe', 'age':60}
        ]
        stooges0 = [
            {'name': 'moe', 'age': 40},
            {'name': 'larry', 'age': 50},
            {'name': 'curly', 'age': 60}
        ]
        stooges2 = [
            {'name': 'moe', 'age': 40},
            {'name': 'curly', 'age': 60}
        ]

        def createApplication():
            print("created")

        def isPrime(i):
            # code to test whether `i` is prime, returning a Boolean value
            ...

        class Multiplier:
            def __init__(self):
                self.factor = 1
            def setValue(self,i):
                self.factor = i
            def mult(self, x, *args):
                return self.factor * x

    These structures are used in some of the examples and are listed here to avoid repeating their definition separately.

    A further simplification of the examples is the usage of the ``*args`` idioms. Many “iteratee” arguments represent a function with 3-4 arguments, (look at the definition of the underscore methods), but the example uses only the first few. Instead of::

        lambda name, index, list: ...

    the abbreviation::

        lambda name, *args: ...

    is sometimes used.
    """

	@staticmethod
	def _exec1(f, context, a1):
		if isinstance(f, basestring):
			return a1[f]
		elif context is None:
			return f(a1)
		else:
			return f(context, a1)

	@staticmethod
	def _exec2(f, context, a1, a2):
		if context is None:
			return f(a1, a2)
		else:
			return f(context, a1, a2)

	@staticmethod
	def _exec3(f, context, a1, a2, a3):
		if context is None:
			return f(a1, a2, a3)
		else:
			return f(context, a1, a2, a3)

	@staticmethod
	def _exec4(f, context, a1, a2, a3, a4):
		if context is None:
			return f(a1, a2, a3, a4)
		else:
			return f(context, a1, a2, a3, a4)

	@staticmethod
	def _extends(obj, ext):
		if isinstance(obj, dict) and isinstance(ext, dict):
			for key in ext:
				if key not in obj or obj[key] != ext[key]:
					return False
			return True
		return False

	@staticmethod
	def each(lst, iteratee, context = None):
		"""
        **Aliases**:
            :py:meth:`each`, :py:meth:`forEach`

        Iterates over a **lst** of elements, yielding each in turn to an **iteratee** function.
        Each invocation of **iteratee** is called with three arguments: if **lst** is of list type,
        then the arguments are ``(element, index, list)``; if it is of dictionary type
        the arguments are ``(value, key, list``). Returns **lst** for possible chaining.

        The method also works for an arbitrary iterator; however, in that case the **iteratee** is invoked
        with ``None`` for the second and third
        argument. In that case the return value of the method is also ``None``; i.e., no chaining is possible.

        Example:
            >>> _.each([1, 2, 3], pr)
            1
            2
            3
            >>> _.each({'one': 11, 'two': 22, 'three': 33}, pr)
            33
            22
            11
        """
		if iteratee is None:
			return lst
		elif isinstance(lst, list):
			for i in range(0, len(lst)):
				underscore._exec3(iteratee, context, lst[i], i, lst)
			return lst
		elif isinstance(lst, dict):
			for key in lst:
				underscore._exec3(iteratee, context, lst[key], key, lst)
			return lst
		else:
			for value in lst:
				underscore._exec3(iteratee, context, value, None, None)
			return None

	@staticmethod
	def map(lst, iteratee = None, context = None):
		"""
        **Aliases**:
            :py:meth:`map`, :py:meth:`collect`

        Produces a *new* array of values by mapping each value in **lst** through a transformation
        function (**iteratee**). Similarly to :py:meth:`each`, the **iteratee** is passed three arguments:
        the ``value``, then the ``index`` (or ``key``) of the iteration, and finally a reference to the entire list.

        The method also works for an arbitrary iterator; however, in that case the **iteratee** is invoked
        with ``None`` for the second and third argument.

        Example:
            >>> _.map([1, 2, 3], lambda num, index, list: num * 3)
            [3, 6, 9]
            >>> _.map({'one': 1, 'two': 2, 'three': 3}, lambda val, key, *args: val * 4)
            [12, 8, 4]
            >>> _.map([[1, 2], [3, 4]], lambda a, *args: _.first(a))
            [1, 3]
        """
		if iteratee is None:
			return lst
		elif isinstance(lst, list):
			return [underscore._exec3(iteratee, context, lst[i], i, lst) for i in range(0, len(lst))]
		elif isinstance(lst, dict):
			return [underscore._exec3(iteratee, context, lst[key], key, lst) for key in lst]
		else:
			return [underscore._exec3(iteratee, context, value, None, None) for value in lst]

	@staticmethod
	def reduce(lst, iteratee, memo = None, context = None):
		"""
        **Aliases**:
            :py:meth:`reduce`, :py:meth:`inject`

        Reduce boils down a **lst** of values into a single value that is returned. **memo** is the initial state
        of the reduction, and each successive step of it should be returned by **iteratee**. The **iteratee** is
        passed four arguments: ``memo`` (ie, the current state of reduction), then the ``value`` and ``index``
        (or ``key``) of the iteration, and finally a reference to the entire list.

        If no memo is passed to the initial invocation of reduce, **iteratee** is not invoked on the first element
        of the list. The first element is instead passed as the ``memo`` in the invocation of the **iteratee** on
        the next element in the list. In the case of a dictionary this means the first element of the keys, which is n
        ot deterministic (unless an ordered dictionary is used)

        Example:
            >>> _.reduce([1, 2, 3], lambda memo, num, *args: memo + num, 1)
            7
            >>> _.reduce([1, 2, 3], lambda memo, num, *args: memo + num)
            6
            >>> _.reduce({'one':1,'two':2,'three':3,'four':4},lambda memo, value, *args: memo*value, 2)
            48
            >>> _.reduce({'one':1,'two':2,'three':3,'four':4},lambda memo, value, *args: memo*value)
            24
        """
		if isinstance(lst, list):
			if memo is None:
				if len(lst) == 0:
					raise IndexError("empty list with no initial value")
				else :
					return reduce(lambda m, i: underscore._exec4(iteratee, context, m, lst[i], i, lst), range(1, len(lst)), lst[0])
			else:
				return reduce(lambda m, i: underscore._exec4(iteratee, context, m, lst[i], i, lst), range(0, len(lst)), memo)
		elif isinstance(lst, dict):
			if memo is None:
				if len(lst) == 0:
					raise IndexError("empty dict with no initial value")
				else:
					keys = list(lst.keys()) if PY3 else lst.keys()
					return reduce(lambda m, key : underscore._exec4(iteratee, context, m, lst[key], key, lst), keys[1:], lst[keys[0]])
			else:
				return reduce(lambda m, key: underscore._exec4(iteratee, context, m, lst[key], key, lst), iter(lst), memo)
		else:
			return TypeError("should be a list or a dict")

	@staticmethod
	def find(lst, predicate, context = None):
		"""
        **Aliases**:
            :py:meth:`find`, :py:meth:`detect`

        Looks through each value in the **lst**, returning the first one that passes a truth test (**predicate**),
        or ``None`` if no value passes the test. The function returns as soon as it finds an acceptable
        element, and doesn't traverse the entire list.

        Example:
            >>> _.find([1, 2, 3, 4, 5, 6], lambda num: num % 2 == 0)
            2
        """
		if isinstance(lst, Iterable):
			for x in lst:
				if underscore._exec1(predicate, context, x):
					return x
			return None
		else:
			raise TypeError("argument must be Iterable")

	@staticmethod
	def filter(lst, predicate, context = None):
		"""
        **Aliases**:
            :py:meth:`filter`, :py:meth:`select`

        Looks through each value in the **lst**, returning an array of all the values that pass a
        truth test (**predicate**).

        Example:
            >>> _.filter([1, 2, 3, 4, 5, 6], lambda num, *args: num % 2 == 0)
            [2, 4, 6]
        """
		if isinstance(lst, Iterable):
			return [x for x in lst if underscore._exec1(predicate, context, x)]
		else:
			raise TypeError("argument must be Iterable")

	@staticmethod
	def where(lst, properties):
		"""
        Looks through each value in the **lst**, returning an array of all the values that contain all of
        the key-value pairs listed in **properties**.

        Example:
            >>> _.where(listOfPlays, {'author': "Shakespeare", 'year': 1611})
            [{'title': 'The tempest', 'year': 1611, 'author': 'Shakespeare'},
             {'title': 'Cymbeline', 'year': 1611, 'author': 'Shakespeare'}]
        """
		if isinstance(lst, Iterable):
			return [x for x in lst if underscore._extends(x, properties)]
		else:
			raise TypeError("argument must be Iterable")

	@staticmethod
	def findWhere(lst, properties):
		"""
        Looks through the **lst** and returns the *first* value that matches all of the key-value pairs
        listed in **properties**.

        Example:
            >>> _.findWhere(listOfPlays, {'author': "Shakespeare", 'year': 1611})
            {'title': 'The tempest', 'year': 1611, 'author': 'Shakespeare'}
        """
		if isinstance(lst, Iterable):
			for x in lst:
				if underscore._extends(x, properties):
					return x
			return None
		else:
			raise TypeError("argument must be Iterable")

	@staticmethod
	def reject(lst, predicate, context = None):
		"""
        Returns the values in **lst** without the elements that the truth test (**predicate**) passes. The opposite of :py:meth:`filter`.

        Example:
            >>> _.reject([1, 2, 3, 4, 5, 6], lambda num: num % 2 == 0)
            [1, 3, 5]
        """
		if isinstance(lst, Iterable):
			return [x for x in lst if not underscore._exec1(predicate, context, x)]
		else:
			raise TypeError("argument must be Iterable")

	@staticmethod
	def every(lst, predicate = lambda x: x, context = None):
		"""
        Returns true if all of the values in the **lst** pass the **predicate** truth test. The default predicate is the identity.

        Example:
            >>> _.every([True, 1, None, 'yes'], _.identity)
            False
        """
		if isinstance(lst, Iterable):
			for x in lst:
				if not underscore._exec1(predicate, context, x):
					return False
			return True
		else:
			raise TypeError("argument must be Iterable")

	@staticmethod
	def some(lst, predicate = lambda x: x, context = None):
		"""
        **Aliases**:
            :py:meth:`some`, :py:meth:`any`

        Returns ``True`` if any of the values in the **lst** pass the predicate truth test.
        Short-circuits and stops traversing the list if a true element is found.
        The default predicate is the identity.

        Example:
            >>> _.some([None, 0, True, False])
            True
        """
		if isinstance(lst, Iterable):
			for x in lst:
				if underscore._exec1(predicate, context, x):
					return True
			return False
		else:
			raise TypeError("argument must be Iterable")

	@staticmethod
	def contains(lst, value):
		"""
        **Aliases**:
            :py:meth:`contains`, :py:meth:`include`

        Returns ``True`` if the value is present in the list.
        """
		return value in lst

	@staticmethod
	def pluck(lst, propertyName):
		"""
        A convenient version of what is perhaps the most common use-case for :py:meth:`map`:
        extracting a list of property values from an array of dictionaries.

        Example:
            >>> _.pluck(stooges, 'name')
            ['moe', 'larry', 'curly']
        """
		return [l[propertyName] for l in lst]

	@staticmethod
	def max(lst, iteratee = None, context = None):
		"""
        Returns the maximum value in **lst**. If an **iteratee** function is provided,
        it will be used on each value to generate the criterion by which the value is ranked.
        ``float("inf")`` is returned if list is empty.

        Example:
            >>> _.max([1,2,3,4])"
            4
            >>> _.max([1,2,3,4], lambda x: -x)
            1
            >>> _.max([])
            inf
            >>> .max(stooges0, lambda stooge: stooge['age'])
            {'name': 'curly', 'age': 60}
         """
		if isinstance(lst, Iterable):
			if lst is None or len(lst) == 0:
				return float("inf")
			if iteratee is None:
				return max(lst)
			else:
				return max(lst, key=lambda x: underscore._exec1(iteratee, context, x))
		else:
			raise TypeError("argument must be Iterable")

	@staticmethod
	def min(lst, iteratee = None, context = None):
		"""
        Returns the min value in **lst**. If an **iteratee** function is provided,
        it will be used on each value to generate the criterion by which the value
        is ranked. ``float("-inf")`` is returned if list is empty, so an guard may be required.

        Example:
            >>> _.min([1,2,3,4])"
            1
            >>> _.min([1,2,3,4], lambda x: -x)
            4
            >>> _.min([])
            -inf
            >>> .min(stooges0, lambda stooge: stooge['age'])
            {'name': 'moe', 'age': 40}
        """
		if isinstance(lst, Iterable):
			if lst is None or len(lst) == 0:
				return float("-inf")
			if iteratee is None:
				return min(lst)
			else:
				return min(lst, key=lambda x: underscore._exec1(iteratee, context, x))
		else:
			raise TypeError("argument must be Iterable")

	@staticmethod
	def sortBy(lst, iteratee = None, context = None):
		"""
        Returns a sorted copy of **lst**, ranked in ascending order by the results of running each
        value through **iteratee**. **iteratee** may also be the string name of the property.

        Example:
            >>> _.sortBy([1, 2, 3, 4, 5, 6], lambda num: math.sin(num))
            [5, 4, 6, 3, 1, 2]
            >>> _.sortBy(stooges0, 'name')
            [{'age': 60, 'name': 'curly'}, {'age': 50, 'name': 'larry'}, {'age': 40, 'name': 'moe'}]
        """
		if iteratee is None:
			return sorted(lst)
		elif isinstance(iteratee, basestring):
			return sorted(lst, key=lambda x: x[iteratee])
		else:
			return sorted(lst, key=lambda x: underscore._exec1(iteratee, context, x))

	@staticmethod
	def _group(lst, iteratee, context):
		if isinstance(iteratee, basestring):
			func = lambda x: x[iteratee]
		else:
			func = lambda x: underscore._exec1(iteratee, context, x)

		retval = {}
		for x in lst:
			key = func(x)
			if key in retval:
				retval[key].append(x)
			else:
				retval[key] = [x]
		return retval

	@staticmethod
	def groupBy(lst, iteratee, context = None):
		"""
        Splits a **lst** into sets, grouped by the result of running each value through **iteratee**.
        If **iteratee** is a string instead of a function, groups by the property named by
        iteratee on each of the values.

        Example:
            >>> _.groupBy([1.3, 2.1, 2.4], lambda num: math.floor(num))
            {1.0: [1.3], 2.0: [2.1, 2.4]}
            >>> st2 = [{'name': 'joe', 'age': 40}, {'name': 'tom', 'age': 50}, {'name': 'bill', 'age': 50}]
            >>> _.groupBy(st2, 'age')
            {40: [{'age': 40, 'name': 'joe'}], 50: [{'age': 50, 'name': 'tom'}, {'age': 50, 'name': 'bill'}]}
        """
		if isinstance(lst, Iterable):
			return underscore._group(lst, iteratee, context)
		else:
			raise TypeError("lst must be iterable")

	@staticmethod
	def indexBy(lst, iteratee, context = None):
		"""
        Given a **lst**, and an **iteratee** function that returns a key for each element in the
        list (or a property name), returns an object with an index of each item. Just
        like :py:meth:`groupBy`, but when you know your keys are unique.

        Example:
            >>> _.indexBy(stooges0, 'age')
            {40: {'age': 40, 'name': 'moe'}, 50: {'age': 50, 'name': 'larry'}, 60: {'age': 60, 'name': 'curly'}}
        """
		if isinstance(lst, Iterable):
			grouped = underscore._group(lst, iteratee, context)
			return {g:grouped[g][0]  for g in grouped}
		else:
			raise TypeError("lst must be iterable")

	@staticmethod
	def countBy(lst, iteratee, context = None):
		"""
        Sorts a **lst** into groups and returns a count for the number of objects in each group.
        Similar to :py:meth:`groupBy`, but instead of returning a list of values, returns a count for the
        number of values in that group.

        Example:
            >>> _.countBy([1, 2, 3, 4, 5], lambda num: 'even' if num % 2 == 0 else 'odd')
            {'even': 2, 'odd': 3}
        """
		if isinstance(lst, Iterable):
			grouped = underscore._group(lst, iteratee, context)
			return {g: len(grouped[g]) for g in grouped}
		else:
			raise TypeError("lst must be iterable")

	@staticmethod
	def shuffle(lst):
		"""
        Returns a (randomly) shuffled copy of the **lst**.

        Example:
            >>> _.shuffle([1, 2, 3, 4, 5, 6])
            [6, 4, 5, 2, 1, 3]
        """
		indeces = list(range(0, len(lst)))
		random.shuffle(indeces)
		return [lst[i] for i in indeces]

	@staticmethod
	def sample(lst, n = None):
		"""
        Produce a random sample from the **lst**. Pass a number to return **n** random elements from the list. Otherwise a single random item will be returned.

        Example:
            >>> _.sample([1, 2, 3, 4, 5, 6])
            1
            >>> _.sample([1, 2, 3, 4, 5, 6], 3)
            [4, 1, 5]
        """
		return random.sample(lst, 1)[0] if n is None else random.sample(lst, n)

	@staticmethod
	def toArray(lst):
		"""
        Creates a real array from the **lst** (anything that can be iterated over).
		Useful for transmuting the arguments object. An alias to the built-in **list** function.

        Example:
            >>> _.toArray(range(0,4))
            [0, 1, 2, 3]
        """
		if isinstance(lst, Iterable):
			return list(lst)
		else:
			raise TypeError("argument must be Iterable")

	@staticmethod
	def size(lst):
		"""
        Return the number of values in the **lst**. An alias to the built-in *len* function.

        Example:
            >>> _.size({'one': 1, 'two': 2, 'three': 3})
            3
        """
		if isinstance(lst, Iterable):
			return len(lst)
		else:
			raise TypeError("argument must be Iterable")

	@staticmethod
	def partition(lst, predicate, context = None):
		"""
        Split **lst** into two arrays: one with elements that satisfy predicate and one with elements that do not satisfy **predicate**. If **lst** is actually a tuple, then a tuple is returned, otherwise an array, each containing the two generated arrays in the 'yes' and 'no' order.

        Example:
            >>> _.partition([0, 1, 2, 3, 4, 5], lambda num: num % 2 != 0)
            [[1, 3, 5], [0, 2, 4]]
            >>> _.partition((0, 1, 2, 3, 4, 5), lambda num: num % 2 != 0)
            ((1, 3, 5), (0, 2, 4))
        """
		yes = []
		no  = []
		if isinstance(lst, Iterable):
			for x in lst:
				if underscore._exec1(predicate, context, x) is True:
					yes.append(x)
				else:
					no.append(x)
			return (tuple(yes), tuple(no)) if type(lst) is tuple else [yes, no]
		else:
			raise TypeError("argument must be Iterable")

	###############################################################################
	#                                Array Functions                              #
	###############################################################################

	@staticmethod
	def first(array, n = None):
		"""Returns the first element of an **array**. Passing **n** will return the first n elements of the array.

        Example:
            >>> _.first([5, 4, 3, 2, 1])
            5
            >>> _.first([5, 4, 3, 2, 1],3)
            [5, 4, 3]
        """
		if isinstance(array, list):
			return array[0] if n is None else array[0:n]
		else:
			raise TypeError("argument must be a list")

	@staticmethod
	def initial(array, n = 1):
		"""Returns everything but the last entry of the **array**. Especially useful on the arguments object.
		Pass **n** to exclude the last n elements from the result.

        Example:
            >>> _.initial([5, 4, 3, 2, 1])
            [5, 4, 3, 2]
            >>> _.initial([5, 4, 3, 2, 1],3)
            [5, 4]
        """
		if isinstance(array, list):
			return array[:-n]
		else:
			raise TypeError("argument must be a list")

	@staticmethod
	def last(array, n = None):
		"""Returns the last element of **array**. Passing **n** will return the last n elements of the array.

        Example:
            >>> _.last([5, 4, 3, 2, 1])
            1
            >>> _.last([5, 4, 3, 2, 1],3)
            [3, 2, 1]
        """
		if isinstance(array, list):
			return array[-1] if n is None else array[-n:]
		else:
			raise TypeError("argument must be a list")

	@staticmethod
	def rest(array, n = 1):
		"""Returns the rest of the elements in an **array**. Pass an index to return
		the values of the array from that index onward.

        Example:
            >>> _.rest([5, 4, 3, 2, 1])
            [4, 3, 2, 1]
            >>> _.rest([5, 4, 3, 2, 1],3)
            [2, 1]
        """
		if isinstance(array, list):
			return array[n:]
		else:
			raise TypeError("argument must be a list")

	# noinspection PyShadowingNames
	@staticmethod
	def compact(array):
		"""
        Returns a copy of the **array** with all falsy values removed. ``False``, ``None``, 0, "" (empty string), and ``NaN`` for floats are all falsy.

        Example:
            >>> _.compact([0, 1, False, 2, '', 3, None, 4, float('nan'), 5])
            [1, 2, 3, 4, 5]
        """
		if isinstance(array, list):
			falsy = lambda x: x is None or x is False or x == "" or x == 0 or (type(x) is float and math.isnan(x))
			return [x for x in array if falsy(x) is not True]
		else:
			raise TypeError("argument must be a list")

	@staticmethod
	def flatten(array, shallow = False):
		"""Flattens a nested **array** (the nesting can be to any depth). If you pass **shallow** with value ``True``, the array is only be flattened a single level.

        Example:
            >>> _.flatten([1, [2], [3, [[4]]]])
            [1, 2, 3, 4]
            >>> _.flatten([1, [2], [3, [[4]]]], True)
            [1, 2, 3, [[4]]]
        """
		if isinstance(array, list):
			retval = []
			for x in array:
				if type(x) is list:
					retval +=  x if shallow else underscore.flatten(x)
				else:
					retval.append(x)
			return retval
		else:
			raise TypeError("argument must be a list")

	@staticmethod
	def without(array, *values):
		"""Returns a copy of the **array** with all instances in  ***values** removed.

        Example:
            >>> _.without([1, 2, 1, 0, 3, 1, 4], 0, 1)
            [2, 3, 4]
        """
		if isinstance(array, list):
			return [x for x in array if x not in values]
		else:
			raise TypeError("argument must be a list")

	@staticmethod
	def union(*arrays):
		"""
        Returns the union of the passed-in **arrays**: a list of unique items, in order,
		that are present in one or more of the **arrays**.

        Example:
            >>> _.union([1, 2, 3], [101, 2, 1, 10], [2, 1])
            [1, 2, 3, 101, 10]
        """
		if len(arrays) == 0:
			return []

		check = [True if isinstance(x, list) else False for x in arrays]
		if False in [True if isinstance(x, list) else False for x in arrays]:
			raise TypeError("all arguments must be arrays")
		else:
			if len(arrays) == 1:
				return [x for x in arrays[0]]
			else:
				retval = []
				for a in arrays:
					for x in a:
						if x not in retval:
							retval.append(x)
				return retval

	@staticmethod
	def intersection(*arrays):
		"""
        Returns the list of values that are the intersection of all the **arrays**.
		Each value in the result is present in each of the **arrays**.

        Example:
            >>> _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1])
            [1, 2]
        """
		if len(arrays) == 0:
			return []

		if False in [True if isinstance(x, list) else False for x in arrays]:
			raise TypeError("all arguments must be arrays")
		else:
			if len(arrays) == 1:
				return [x for x in arrays[0]]
			else:
				curr = arrays[0]
				retval = []
				for x in curr:
					to_be_added = True
					for Z in arrays[1:]:
						if x not in Z:
							to_be_added = False
							break
					if to_be_added: retval.append(x)
				return retval

	@staticmethod
	def difference(array, *others):
		"""
        Similar to :py:meth:`without`, but returns the values from **array** that are not present in the other arrays.

        Example:
            >>> _.difference([1, 2, 3, 4, 5], [5, 2, 10])
            [1, 3, 4]
        """
		if not isinstance(array, list):
			raise TypeError("argument must be an array")
		if len(others) == 0:
			return [x for x in array]

		if False in [True if isinstance(x, list) else False for x in others]:
			raise TypeError("all arguments must be arrays")
		else:
			retval = []
			for x in array:
				to_be_added = True
				for A in others:
					if x in A:
						to_be_added = False
						break
				if to_be_added: retval.append(x)
			return retval

	# noinspection PyShadowingNames,PyShadowingNames
	@staticmethod
	def uniq(array, iteratee = None, context = None):
		"""
        **Aliases**:
            :py:meth:`uniq`, :py:meth:`unique`

        Returns a duplicate-free version of the **array**, based on the **in** operator of Python's list. If you want to compute unique items after a transformation, pass an **iteratee** function (the retained element in the array will be the first one found).

        Example:
            >>> _.uniq([1, 2, 1, 3, 1, 4, 2])
            [1, 2, 3, 4]
            >>> _.uniq([1, 1, 1, 2, 3, 4, 4, 5], isSorted = True)
            [1, 2, 3, 4, 5]
            >>> _.uniq([1.5, 1.7, 2.0, 2.5, 2.5, 3.0, 4.0], iteratee = math.floor)
            [1.5, 2.0, 3.0, 4.0]
        """
		if not isinstance(array, list):
			raise TypeError("argument must be an array")

		if len(array) == 0:
			return []
		else:
			to_compare = (lambda x: x) if iteratee is None else (lambda x: underscore._exec1(iteratee, context, x))
			retval      = [array[0]]
			comparisons = [to_compare(array[0])]
			for x in array[1:]:
				y = to_compare(x)
				if y not in comparisons:
					retval.append(x)
					comparisons.append(y)
			return retval

	@staticmethod
	def zip(*arrays):
		"""
        Merges together the values of each of the **arrays** with the values at the
		corresponding position. Useful when you have separate data sources that
		are coordinated through matching array indexes. If the arguments are tuples,
		a tuple is returned in each position, otherwise an array.

        Example:
            >>> _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [True, False, False])
            [['moe', 30, True], ['larry', 40, False], ['curly', 50, False]]
            >>> _.zip(('moe', 'larry', 'curly'), (30, 40, 50), (True, False, False))
            [('moe', 30, True), ('larry', 40, False), ('curly', 50, False)]
        """
		if False in [True if isinstance(x, list) or isinstance(x, tuple) else False for x in arrays]:
			raise TypeError("all arguments must be arrays")
		else:
			if PY3:
				zipped = list(zip(*arrays))
			else:
				zipped = zip(*arrays)
			return zipped if isinstance(arrays[0], tuple) else [list(x) for x in zipped]

	@staticmethod
	def object(array, values = None):
		"""
        Converts arrays into a dictionary and return it. Pass either a single list of ``[key, value]`` (or ``(key, value)``) pairs, or a list of keys, and a list of values. If duplicate keys exist, the last value wins.

		The first option is an alias to a possible ``dict`` constructor in Python.

        Example:
            >>> _.object([['moe', 30], ['larry', 40], ['curly', 50]])
            {'larry': 40, 'curly': 50, 'moe': 30}
            >>> _.object([('moe', 30), ('larry', 40), ('curly', 50)])
            {'larry': 40, 'curly': 50, 'moe': 30}
            >>> _.object(['moe', 'larry', 'curly'], [30, 40, 50])
            {'larry': 40, 'curly': 50, 'moe': 30}
        """
		if not isinstance(array, list):
			raise TypeError("all arguments must be arrays")
		if values is None:
			return dict(array)
		else:
			return {array[i]: values[i] for i in range(0, min(len(array), len(values)))}

	@staticmethod
	def indexOf(array, value, startIndex = 0, endIndex = None):
		"""
        Returns the index at which **value** can be found in the **array**, or -1 if value is not present in the **array**. The values of **startIndex** and **endIndex** may be used to refer to an interval where the search should be made.

        Example:
            >>> _.indexOf([1, 2, 3, 1, 2, 3, 4, 2, 5], 2)
            1
            >>> _.indexOf([1, 2, 3, 1, 2, 3, 4, 2, 5], 2, 3, 6)
            4
            _.indexOf([1, 2, 3, 1, 2, 3, 4, 2, 5], 10)
            -1
        """
		# I could have relied on findIndex, but this is way simpler. Actually, I could have
		# also used the built-in facility, but the lastIndexOf cannot be done that way, so
		# I kept this for the sake of symmetry, but also to use bisect for large arrays
		if not isinstance(array, list):
			raise TypeError("arguments must be a list")
		else:
			if endIndex is None:
				endIndex = len(array)
			try:
				return array.index(value, startIndex, endIndex)
			except ValueError:
				return -1

	@staticmethod
	def lastIndexOf(array, value, startIndex = 0, endIndex = None):
		"""
        Returns the index of the last occurrence of value in the **array**, or -1 if value is not present. The values of **startIndex** and **endIndex** may be used to refer to an interval where the search should be made.

        Example:
            >>> _.lastIndexOf([1, 2, 3, 1, 2, 3, 4, 2, 5], 2)
            7
            >>> _.indexOf([1, 2, 3, 1, 2, 3, 4, 2, 5], 2, 3, 6)
            4
        """
		if not isinstance(array, list):
			raise TypeError("arguments must be a list")
		start = len(array) if endIndex is None else endIndex
		end   = startIndex
		for i in range(start-1, end-1, -1):
			if array[i] == value:
				return i
		return -1

	@staticmethod
	def sortedIndex(array, value, iteratee = None, context = None):
		"""
        Determine the index at which the **value** should be inserted into the **array** in order to maintain the list's sorted order. If an **iteratee** function is provided, it will be used to compute the sort ranking of each value, including the value you pass. The **iteratee** may also be the string, providing the name of the key to sort by.

        Example:
            >>> _.sortedIndex([10, 20, 30, 40, 50], 35)
            3
            >>> _.sortedIndex([10, 20, 30, 40, 50], 55)
            5
            >>> stooges2 = [{'name': 'moe', 'age': 40}, {'name': 'curly', 'age': 60}]
            >>> _.sortedIndex(stooges2, {'name': 'larry', 'age': 50}, 'age')
            1
        """
		# The version with a real iteratee is inefficient for larger arrays.
		# Ideally, the bisect module should be rewritten to use the iteratee directly. T.B.D.
		if not isinstance(array, list):
			raise TypeError("arguments must be a list")
		if iteratee is None:
			a = array
			v = value
		else:
			a = [underscore._exec1(iteratee, context, x) for x in array]
			v = underscore._exec1(iteratee, context, value)
		return bisect.bisect_left(a, v)

	@staticmethod
	def findIndex(array, predicate, context = None, startIndex = 0, endIndex = None ):
		"""
        Similar to :py:meth:`indexOf`, returns the first index where the predicate truth test passes; otherwise returns -1. The values of **startIndex** and **endIndex** may be used to refer to an interval where the search should be made.

        Example:
            >>> def isPrime(n):
            ...     (— definition of the function)
            ...
            >>> _.findIndex([4, 6, 8, 12], isPrime)
            -1
            >>> _.findIndex([4, 6, 7, 12], isPrime)
            2
            >>> _.findIndex([4, 6, 3, 12, 14, 16], isPrime, startIndex=3)
            -1
            >>> _.findIndex([4, 6, 3, 12, 14, 16], isPrime, startIndex=1, endIndex=5)
            2
        """
		if not isinstance(array, list):
			raise TypeError("arguments must be a list")
		else:
			if endIndex is None:
				endIndex = len(array)

		for i in range(startIndex, endIndex):
			if underscore._exec1(predicate, context, array[i]):
				return i
		return -1

	@staticmethod
	def findLastIndex(array, predicate, context = None, startIndex = 0, endIndex = None):
		"""
        Like :py:meth:`findIndex` but iterates the array in reverse, returning the index closest to the end where the predicate truth test passes. The values of **startIndex** and **endIndex** may be used to refer to an interval where the search should be made.

        Example:
            >>> _.findLastIndex([4, 6, 5, 7, 12],isPrime)
            3
            >>> _.findLastIndex([2, 6, 7, 12, 13, 16], isPrime, startIndex = 1, endIndex = 3)
            2
        """
		if not isinstance(array, list):
			raise TypeError("arguments must be a list")
		else:
			if endIndex is None:
				endIndex = len(array)

		for i in range(endIndex - 1, startIndex - 1, -1):
			if underscore._exec1(predicate, context, array[i]):
				return i
		return -1

	@staticmethod
	def range(*args):
		"""
        A function to create flexibly-numbered lists of integers, handy for each and map loops. The combination of the arguments can be:

        * **end**: return a list of integers between 0 and **end**, with **end** non inclusive
        * **start**, **end**: like before but starting at **start** instead of 0
        * **start**, **end**, **step**: like before, but stepping with **step** instead of 1. **step** can also be negative

        This is just an alias to Python2's built-in **range** function. In Python3, the result of the same built-in is turned into a list before return.

        Example:
            >>> _.range(10)
            [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
            >>> _.range(3, 10)
            [3, 4, 5, 6, 7, 8, 9]
            >>> _.range(3, 10, 2)
            [3, 5, 7, 9]
        """
		return list(range(*args)) if PY3 else range(*args)

	###############################################################################
	#                             Function Functions                              #
	###############################################################################

	@staticmethod
	def partial(func, *args, **keywords):
		"""
        Return a partially bounded version of the function **func** by fixing any number of its arguments and keywords. You may pass ``None`` in your list of arguments to specify an argument that should not be pre-filled, but left open to supply at call-time.

        Example:
            >>> substract = lambda a, b: b - a
            >>> sub5 = _.partial(substract, 5)
            >>> sub5(20)
            15
            >>> subFrom20 = _.partial(substract, None, 20)
            >>> subFrom20(5)
            15
        """
		def combine(a, b):
			retval = ()
			for i in range(0, len(a)):
				if a[i] is None:
					retval += tuple([b[0]])
					b = b[1:]
				else:
					retval += tuple([a[i]])
			return retval + b

		def newfunc(*fargs, **fkeywords):
			newkeywords = keywords.copy()
			newkeywords.update(fkeywords)
			return func(*(combine(args, fargs)), **newkeywords)
		return newfunc

	@staticmethod
	def once(func):
		"""
        Creates a version of **func**, as a callable object, that can only be called one time. Repeated calls to the modified function will have no effect, returning the value from the original call.

        Example:
            >>> initialize = _.once(createApplication)
            >>> initialize()
            created
            >>> initialize()
            >>>
        """
		return underscore.before(1, func)

	@staticmethod
	def after(count, func):
		"""
        Creates a version of **func**, as a callable object, that will only be run after first being called **count** times.

        Example:
            >>> delayInit = _.after(2, createApplication)
            >>> delayInit()
            >>> delayInit()
            >>> delayInit()
            created
        """
		class _after(object):
			def __init__(self, after_count, after_func):
				self.count  = after_count
				self.called = 0
				self.func   = after_func

			def __call__(self, *args, **keywords):
				if self.called == self.count:
					return self.func(*args, **keywords)
				else:
					self.called += 1
		return _after(count, func)

	@staticmethod
	def before(count, func):
		"""
        Creates a version of **func**, as a callable object, that can be called no more than **count** times. The result of the last function call is memorized and returned when count has been reached.

        Example:
            >>> createOnly3 = _.before(3, createApplication)
            >>> createOnly3()
            created
            >>> createOnly3()
            created
            >>> createOnly3()
            created
            >>> createOnly3()
            >>>
        """
		class _before(object):
			def __init__(self, before_count, before_func):
				self.count  = before_count
				self.called = 0
				self.retval = None
				self.func   = before_func

			def __call__(self, *args, **keywords):
				if self.called < self.count:
					self.retval = self.func(*args, **keywords)
					self.called += 1
					return self.retval
				else:
					return self.retval
		return _before(count, func)

	@staticmethod
	def wrap(function, wrapper):
		"""
        Wraps the first **function** inside of the **wrapper** function, passing it as the first argument. This allows the wrapper to execute code before and after the function runs, adjust the arguments, or execute it conditionally. The generated functions can have arguments and keywords, which will be forwarded to the **wrapper**.

        Example:
            >>> func = lambda x: "Hello: " +x
            >>> def wrap(f, *args, **keywords):
            ...     print(args)
            ...     print(keywords)
            ...     print("before, " + f("name") + ", after")
            ...
            >>> wrapper = _.wrap(func, wrap)
            >>> wrapper(1, 2, 3, a=1)
            (1, 2, 3)
            {'a': 1}
            before, Hello: name, after
        """
		def ff(*args, **keywords):
			return wrapper(function, *args, **keywords)
		return ff

	@staticmethod
	def negate(predicate, *args, **keywords):
		"""Returns a new negated version of the **predicate** function (invoked with the arguments).

        Example:
            >>> test = lambda x, y: x and y
            >>> _.negate(test,False,True)
            True
            >>> _.negate(test,True,True)
            False
        """
		return not predicate(*args, **keywords) if hasattr(predicate, '__call__') else not predicate

	@staticmethod
	def compose(*functions):
		"""
        Returns the composition of a list of **functions**, where each function consumes the return value of the function that follows. In math terms, composing the functions ``f()``, ``g()``, and ``h()`` produces ``f(g(h()))``. The composition function can be invoked with arguments, which will be used for the arguments of the innermost function (``h()`` in this example).

        Example:
            >>> greet    = lambda name: "hi: " + name
            >>> exclaim  = lambda statement: statement.upper() + "!"
            >>> welcome  = _.compose(greet, exclaim)
            >>> welcome('moe')
            'hi: MOE!'
            >>>
        """
		def ff(*args,**keywords):
			nextarg = functions[-1](*args, **keywords)
			for i in range(len(functions) - 2, -1, -1):
				nextarg = functions[i](nextarg)
			return nextarg
		return ff

	###############################################################################
	#                       Object (dictionary) Functions                         #
	###############################################################################

	@staticmethod
	def keys(object):
		"""Retrieve all the names of the **object**'s own enumerable properties. Alias of the built-in Python method, but in case of Python3, it returns a list and not an iterator.

        Example:
            >>> _.keys({'one': 1, 'two': 2, 'three': 3})
            ['three', 'two', 'one']
        """
		if not isinstance(object, dict):
			raise TypeError("argument must be a dictionary")
		return list(object.keys()) if PY3 else object.keys()

	@staticmethod
	def values(object):
		"""Retrieve all the names of the object's own enumerable properties. Alias of the built-in Python method.

        In Python3 this returns an iterator; in Python2 a list.

        Example:
            >>> _.values({'one': 1, 'two': 2, 'three': 3})
            [3,2,1]
        """
		if not isinstance(object, dict):
			raise TypeError("argument must be a dictionary")
		return list(object.values()) if PY3 else object.values()

	@staticmethod
	def mapObject(obj, iteratee = None, context = None):
		"""
        **Aliases**:
            :py:meth:`mapObject`, :py:meth:`collectObject`

		Like :py:meth:`map`, but for objects (a.k.a. dictionaries). Transform the value of each property in turn. The **iteratee** is passed three arguments: the ``index`` (or ``key``) of the iteration, the ``value``, and finally a reference to the entire list. If **iteratee** is not set or is ``None``, a copy of **obj** is returned.

        Example:
            >>> _.mapObject({'one': 1, 'two': 2, 'three': 3})
            {'one': 1, 'three': 3, 'two': 2}
            >>> _.mapObject({'one': 1, 'two': 2, 'three': 3}, lambda key, val, obj: 3*val)
            {'one': 3, 'three': 9, 'two': 6}
        """
		if not isinstance(obj, dict):
			raise TypeError("argument must be a dictionary")
		if iteratee is None:
			return underscore.clone(obj)
		else:
			transform = lambda key: underscore._exec3(iteratee, context, key, obj[key], obj)
			return {k: transform(k) for k in obj}

	@staticmethod
	def pairs(obj, tupl = False):
		"""Convert an **obj** into a list of ``[key, value]`` pairs. If the value of **tuple** is set to ``True``, an array of tuples is returned, instead of an array of (binary) arrays.

        In Python3 this returns an iterator; in Python2 a list.

        Example:
            >>> _.pairs({'one': 1, 'two': 2, 'three': 3})
            [['three', 3], ['two', 2], ['one', 1]]
            >>> _.pairs({'one': 1, 'two': 2, 'three': 3}, tupl = True)
            [('three', 3), ('two', 2), ('one', 1)]
        """
		if not isinstance(obj, dict):
			raise TypeError("argument must be a dictionary")
		else:
			if tupl:
				return list(obj.items()) if PY3 else obj.items()
			else:
				return [[k,v] for (k,v) in obj.items()]

	@staticmethod
	def invert(obj):
		"""Returns a copy of **obj** where the keys have become the values and the values the keys. For this to work, all of your object's values should be unique and string serializable.

        Example:
            >>> _.invert({"Moe": "Moses", "Larry": "Louis", "Curly": "Jerome"})
            {'Louis': 'Larry', 'Moses': 'Moe', 'Jerome': 'Curly'}
        """
		if not isinstance(obj, dict):
			raise TypeError("argument must be a dictionary")
		else:
			return {v:k for (k,v) in obj.items()}

	@staticmethod
	def findKey(obj, predicate, context = None):
		"""Returns the a key where the predicate truth test passes; if none found, returns ``None``.

        Example:
            >>> _.findKey({"Moe": "Moses", "Larry": "Louis", "Curly": "Jerome"}, lambda val: val == "Jerome")
            Curly
        """
		if not isinstance(obj, dict):
			raise TypeError("argument must be a dictionary")
		else:
			check = lambda val: underscore._exec1(predicate, context, val)
			for key in obj:
				if check(obj[key]):
					return key
			return None

	@staticmethod
	def extend(destination, *sources):
		"""Copy all of the properties in the source objects of **sources** over to the **destination** object. It's in-order, so the last source will override properties of the same name in previous arguments.  Returns **destination** (for possible chaining).

        Example:
            >>> _.extend({'name': 'moe', 'age': '40'}, {'age': 50}, {'age': 60, 'gender': 'male'})
            {'gender': 'male', 'age': 60, 'name': 'moe'}
        """
		if not isinstance(destination, dict) or (False in [isinstance(s, dict) for s in sources]):
			raise TypeError("arguments must be dictionaries")

		for source in sources:
			for key in source:
				destination[key] = source[key]
		return destination

	@staticmethod
	def extendOwn(destination, *sources):
		"""Like **extend**, but only copies *own* properties over to the destination object. Return **destination** (for possible chaining).

        Example:
            >>> _.extendOwn({'name': 'moe', age: '40'}, {'age': 50}, {'age': 60, 'gender': 'male'})
            {'age': 60, 'name': 'moe'}
        """
		if not isinstance(destination, dict) or (False in [isinstance(s, dict) for s in sources]):
			raise TypeError("arguments must be dictionaries")

		for source in sources:
			for key in source:
				if key in destination:
					destination[key] = source[key]
		return destination

	@staticmethod
	def pick(obj, *keys):
		"""
        Return a copy of **obj**, filtered to only have values for the whitelisted **keys** (or array of valid keys). Alternatively, accepts a predicate indicating which keys to pick.

        Example:
            >>> _.pick({'name': 'moe', 'age': 50, 'userid': 'moe1'}, 'name', 'age')
            {'age': 50, 'name': 'moe'}
            >>> a = ['name', 'age']
            >>> _.pick({'name': 'moe', 'age': 50, 'userid': 'moe1'}, *a)
            {'age': 50, 'name': 'moe'}
            >>> _.pick({'name': 'moe', 'age': 50, 'userid': 'moe1'}, lambda val, *args: _.isNumber(val))
            {'age': 50}
        """
		if not isinstance(obj, dict):
			raise TypeError("argument must be a dictionary")
		if len(keys) == 0:
			return {}
		elif hasattr(keys[0], '__call__'):
			return {key: obj[key] for key in obj if keys[0](obj[key], key, obj)}
		else:
			return {key: obj[key] for key in obj if key in keys}

	@staticmethod
	def omit(obj, *keys):
		"""
        Return a copy of **obj**, filtered to omit values for the blacklisted **keys** (or array of valid keys). Alternatively accepts a predicate indicating which keys to pick.

        Example:
            >>> _.omit({'name': 'moe', 'age': 50, 'userid': 'moe1'}, 'name', 'age')
            {'userid': 'moe1'}
            >>> a = ['name', 'age']
            >>> _.omit({'name': 'moe', 'age': 50, 'userid': 'moe1'}, *a)
            {'userid': 'moe1'}
            >>> _.omit({'name': 'moe', 'age': 50, 'userid': 'moe1'}, lambda val, *args: _.isNumber(val))
            {'userid': 'moe1', 'name': 'moe'}
        """
		if not isinstance(obj, dict):
			raise TypeError("argument must be a dictionary")
		if len(keys) == 0:
			return {}
		elif hasattr(keys[0], '__call__'):
			return {key: obj[key] for key in obj if not keys[0](obj[key], key, obj)}
		else :
			return {key: obj[key] for key in obj if key not in keys}

	@staticmethod
	def defaults(obj, *defaults):
		"""Fill in undefined properties in **obj** with the first value present in the following list of **defaults** objects. Return **obj** (for possible chaining)

        Example:
            >>> iceCream = {'flavor': "chocolate"}
            >>> _.defaults(iceCream, {'flavor': "vanilla", 'sprinkles': "lots"})
            {'flavor': 'chocolate', 'sprinkles': 'lots'}
            >>> myDefaults = [{'flavor':'vanilla', 'sprinkles':'lots'}, {'toGo': True}]
            >>> _.defaults(iceCream, *myDefaults)
            {'flavor': 'chocolate', 'sprinkles': 'lots', 'toGo' : True}
        """
		if not isinstance(obj, dict) or (False in [isinstance(s, dict) for s in defaults]):
			raise TypeError("arguments must be dictionaries")

		for default in defaults:
			for key in default:
				if key not in obj :
					obj[key] = default[key]
		return obj

	@staticmethod
	def clone(obj, deep = True):
		"""
        Create a clone of the provided plain **obj**. If ``deep`` is False, then any nested objects or arrays will be copied by reference, not duplicated; otherwise each constituent arrays or dictionaries will also be cloned (recursively).
        """
		import copy
		return copy.deepcopy(obj) if deep else copy.copy(obj)

	@staticmethod
	def has(obj, key):
		"""Return ``True`` if the object contain the given key, ``False`` otherwise. Alias to built in dictionary method"""
		return key in obj

	@staticmethod
	def property(key):
		"""
        **Aliases**:
        :py:meth:`property`, :py:meth:`attribute`

		Returns a function that will itself return the **key** property of any passed-in object.

        Example:
            >>> getName = _.property('name')
            >>> getName(stooges[3])
            joe
            >>> getName(stooges0[0])
            moe
        """
		return lambda obj: obj[key]

	@staticmethod
	def propertyOf(obj):
		"""
        **Aliases**:
           :py:meth:`propertyOf`, :py:meth:`attributeOf`

		Inverse of :py:meth:`property`. Takes an **obj** and returns a function which will return the value of a provided property. In effect, the functional equivalent of ``obj[key]`` where ``obj`` is fixed.

        Example:
            >>> getValue = _.propertyOf(stooges[3])
            >>> getValue('name')
            joe
            >>> getValue('age')
            60
        """
		return lambda key: obj[key]

	@staticmethod
	def matcher(attrs):
		"""Returns a predicate function that will tell if a passed object contains all of the key/value properties present in **attrs**.

        Example:
            >>> checkAge = _.matcher({'age': 60})
            >>> checkAge(stooges[0])
            False
            >>> CheckAge(stooges[2])
            True
        """
		if not isinstance(attrs, dict):
			raise TypeError("argument must be a dictionary")

		def func(obj):
			for k in attrs:
				if k not in obj or obj[k] != attrs[k]:
					return False
			return True
		return func

	@staticmethod
	def isMatch(obj, properties):
		"""Returns ``True`` if the keys and values in **properties** are contained in **obj**, ``False`` otherwise.

        Example:
            >>> _.isMatch(stooge[0], {'age': 40})
            True
            >>> _.isMatch(stooge[3], {'age': 40})
            False
        """
		if not isinstance(obj, dict) or not isinstance(properties, dict):
			raise TypeError("arguments must be dictionaries")
		return underscore.matcher(properties)(obj)

	@staticmethod
	def isEqual(obj, other):
		"""Performs an optimized deep comparison between **obj** and **other**, returns ``True`` if they are equal, ``False`` otherwise."""
		return obj == other

	@staticmethod
	def isEmpty(obj):
		"""Returns ``True`` if an enumerable object contains no values (no enumerable own-properties), ``False`` otherwise. For strings and array-like objects the function checks if the length property is 0."""
		return len(obj) == 0

	@staticmethod
	def isArray(obj):
		"""Return ``True`` if **obj** is an Array (i.e., List), ``False`` otherwise."""
		return isinstance(obj, list)

	@staticmethod
	def isTuple(obj):
		"""Return ``True`` if **obj** is an Tuple, ``False`` otherwise."""
		return isinstance(obj, tuple)

	@staticmethod
	def isObject(obj):
		"""Return ``True`` if **obj** is an “Object” (i.e., Dictionary), ``False`` otherwise."""
		return isintance(obj, dict)

	@staticmethod
	def isFunction(obj):
		"""Return ``True`` if **obj** is a function or a method, ``False`` otherwise.

        Example:
            >>> _.isFunction(isPrime)
            True
            >>> _.isFunction(lambda x: x+1)
            True
            >>> _.isFunction(1)
            False
		"""
		return isinstance(obj, (LambdaType, FunctionType, MethodType))

	@staticmethod
	def isCallable(obj):
		"""Return ``True`` if **obj** is callable, ``False`` otherwise. Note that this is a more general form of test than :py:meth:`isFunction`"""
		return hasattr(obj, '__call__')

	@staticmethod
	def isString(obj):
		"""Return ``True`` if **obj** is a string, ``False`` otherwise. For Python2 this checks against a string or a unicode. In (Python3 there is no such distinction.)"""
		return isinstance(obj, basestring)

	@staticmethod
	def isNumber(obj):
		"""Return ``True`` if **obj** is a number (float or integer), ``False`` otherwise."""
		return isinstance(obj, (int, float))

	@staticmethod
	def isFinite(obj):
		"""Return ``True`` if **obj** is number with a finite value, ``False`` otherwise."""
		return isinstance(obj, (int, float)) and not math.isinf(obj)

	@staticmethod
	def isNaN(obj):
		"""Return ``True`` if **obj** is a float with ``NaN`` as value, ``False`` otherwise."""
		return isinstance(obj, float) and math.isnan(obj)

	@staticmethod
	def isBoolean(obj):
		"""Return ``True`` if **obj** is a Boolean, ``False`` otherwise."""
		return isinstance(obj, bool)

	@staticmethod
	def isError(obj):
		"""Return ``True`` if **obj** is an Exception, ``False`` otherwise."""
		return isinstance(obj, Exception)

	@staticmethod
	def isNone(obj):
		"""Return ``True`` if **obj** is ``None``, ``False`` otherwise."""
		return obj is None

	###############################################################################
	#                              Utility Functions                              #
	###############################################################################

	@staticmethod
	def identity(x, *args, **keywords):
		"""Returns the same value that is used as the first argument (and ignore everything else). In math: ``f(x) = x``. This function looks useless, but can be used when debugging other underscore methods."""
		return x

	@staticmethod
	def constant(value):
		"""
        Returns a function that always returns the same **value**.

        Example:
            >>> stooge = {'name': 'moe' }
            >>> const = _.constant(stooge)
            >>> const()
            {'name': 'moe'}
        """
		return lambda *args: value

	@staticmethod
	def noop(*args):
		"""Returns ``None`` irrespective of the arguments passed to it. Useful as the default for optional callback arguments."""
		return None

	@staticmethod
	def times(n, iteratee, context = None):
		"""
        Invokes the given **iteratee** function **n** times. Each invocation of **iteratee** is called with an index argument. Produces an array of the returned values.

        Example:
            >>> _.times(3, _.identity)
            [0, 1, 2]
        """
		return [underscore._exec1(iteratee, context, i) for i in range(0, n)]

	@staticmethod
	def random(min, max = None):
		"""Returns a pseudo-random integer between **min** and **max**, inclusive. If you only pass one argument, it will return a number between 0 and that number. The pseudo-random generator should not be used for security purposes."""
		if isinstance(min, int) and (max is None or isinstance(max,int)) :
			return random.randint(0, min) if max is None else random.randint(min, max)
		else:
			raise TypeError("arguments should be integeters")

	@staticmethod
	def uniqueId(prefix = None):
		"""
        Returns a globally-unique id as a string. If **prefix** is passed, the id will be appended to it. The method relies on the ``uuid.uuid1()`` library function, i.e., is based on the host ID and the current time.
        """
		import uuid
		return str(prefix) + str(uuid.uuid1()) if prefix is not None else str(uuid.uuid1())

	@staticmethod
	def now():
		"""Returns an integer timestamp for the current time"""
		import time
		return int(time.time())

	###############################################################################
	#                                    Chaining                                 #
	###############################################################################

	# Chaining is done by creating an instance of underscore, and catching all method requests
	def __init__(self, val):
		self.current_value = val
		self.chaining_on   = True

	# This method catches **all** attribute dereference attempts. This means that any access to the local variables
	# must be done through the superclass and through the special attributes. A bit convoluted, but does the job...
	def __getattribute__(self, name):
		if name == "value":
			# noinspection PyCallByClass
			def func():
				#
				# i.e.:
				# self.chaining_on = True
				# return self.current_value
				#
				object.__setattr__(self, 'chaining_on', False)
				return object.__getattribute__(self, 'current_value')
			return func
		elif name == "tap":
			def func(f):
				#
				# i.e.:
				# f(self.current_value)
				# return self
				#
				f(object.__getattribute__(self, 'current_value'))
				return self
			return func
		elif name == "__module__" or name == "__doc__" or name not in underscore.__dict__:
			raise AttributeError(name)
		elif object.__getattribute__(self, 'chaining_on'):
			def func(*args):
				#
				# I.e. (approximately)
				# self.current_value = underscore.`name`(self.current_value,*args)
				# return self
				#
				object.__setattr__(self, 'current_value', underscore.__dict__[name].__func__(object.__getattribute__(self, 'current_value'), *args))
				return self
			return func
		else:
			raise AttributeError("Chained value already retrieved, no more chaining")

	@staticmethod
	def chain(obj):
		"""
        Returns a wrapper object for chaining; see the separate description on chaining. The returned object has, beyond the static underscore methods, the additional instance methods:

        **value()**
             Extract the value of the wrapper object. A call to value means that no more chaining is possible.

        **tap(func)**
            Execute the function **func** on the value of the wrapped object; the object itself is returned, and can be used for further chaining. This can be used to 'tap into' the chain.

        Examples:
            >>> _.chain(stooges).sortBy('age').map(lambda st, *args: "%s is %s" % (st['name'], st['age'])).first().value()
            moe is 40
            >>> def pr(a):
            ...        print("intermediate: %s" % a)
            ...
            >>> _.chain([1, 2, 3, 200]).filter(lambda num, *args: num % 2 == 0).map(lambda x, *args: x*x).value()
            [4, 40000]
            >>> _.chain([1, 2, 3, 200]).filter(lambda num, *args: num % 2 == 0).tap(pr).map(lambda x, *args: x*x).value()
            intermediate: [2, 200]
            [4, 40000]
        """
		return underscore(obj)

	###############################################################################
	#                                   Aliases                                   #
	###############################################################################

	# Aliases to some of the core method names
	forEach       = each
	collect       = map
	collectObject = mapObject
	inject        = reduce
	detect        = find
	select        = filter
	any           = some
	include       = contains
	unique        = uniq
	attribute     = property
	attributeOf   = propertyOf

if __name__ == '__main__':
	pass


from django.db.models import Sum, F, Case, When
from rest_framework import serializers
from .models import StockTransaction
from users.serializers import UserSerializer
from stocks.serializers import StockSerializer

class StockTransactionsSerializer(serializers.ModelSerializer):

    user = UserSerializer(read_only=True)
    stock = StockSerializer

    class Meta:
        model = StockTransaction
        fields = (
            "user",
            "transaction_type",
            "date",
            "stock",
            "price",
            "quantity",
        )

    def create(self, validated_data):
        request = self.context.get("request")
        transaction = StockTransaction.objects.create(
            **validated_data, shareholder=request.user
        )
        return transaction

    def validate(self, data):
        # get data
        user = self.context.get("request").user
        if self.instance:
            transaction_type = data.get(
                "transaction_type", self.instance.transaction_type
            )
            stock_pk = data.get("stock", self.instance.stock).pk
            quantity = data.get("quantity", self.instance.quantity)
            price = data.get("price", self.instance.price)
        else:
            transaction_type = data.get("transaction_type")
            stock_pk = data.get("stock").pk
            quantity = data.get("quantity")
            price = data.get("price")
        # check negative value
        if quantity < 0 or price < 0:
            raise serializers.ValidationError(
                "Quantity or price should not be negative"
            )
        # check action that sell more than they have
        stocks = user.transactions.filter(stock=stock_pk).annotate(
            Quantity=Case(
                When(transaction_type="buy", then=F("quantity")),
                When(transaction_type="sell", then=-1 * F("quantity")),
            ),
        )
        if stocks.count() != 0:
            result = stocks.aggregate(total_quantity=Sum("Quantity"))
            total_quantity = result["total_quantity"]
        else:
            total_quantity = 0
        if transaction_type == "sell" and total_quantity < quantity:
            raise serializers.ValidationError("You can't sell more than you have")
        return data


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import numpy as np, scipy as sp, scipy.stats as stats

from scipy.optimize import minimize
from scipy.stats import multivariate_normal

from numpy import exp, log, sqrt
from scipy.misc import logsumexp
import distributions as dist

from scipy.spatial.distance import squareform, pdist, cdist

def median_heuristic(data, distance, per_dimension = True):
    if isinstance(distance, str):
        dist_fn = lambda x: pdist(x, distance)
    else:
        dist_fn = distance
    if per_dimension is False:
        return np.median(dist_fn(data))
    else:
        def single_dim_heuristic(data_dim):
            return median_heuristic(data_dim[:, None], dist_fn, per_dimension = False)
        return np.apply_along_axis(single_dim_heuristic, 0, data)

class Kernel(object):
    def __call__(self, *args, **kwargs):
        return self.gram(*args, **kwargs)

    def gram(self, X, Y = None, diag = False):
        """compute the gram matrix, i.e. the kernel evaluated at every element of X paired with each element of Y"""
        raise NotImplementedError()

    def get_params(self):
        # get unconstrained parameters
        assert()

    def set_params(self, params):
        # set unconstrained parameters, possibly transform them
        assert()

    def rkhsel_gram(self, X, Y = None, logsp = False):
        """
        X - axis 0 contains observations (of sample sets), axis 1 is input dimension, axis 2 are different points per observation (the samples of a sample set)
        """

        assert(not logsp)
        if Y is not None:
            assert(len(Y.shape) == 2)
        if len(X.shape) == 2:
            return self.gram(X, Y)
        assert(len(X.shape) == 3)

        X_resh = np.concatenate(np.swapaxes(X,0,2), axis=1).T #np.swapaxes(X, 1,2).reshape(-1, X.shape[1])
        if Y is None:
            # compute the full gram matrix
            G = self.gram(X_resh)
            # sum up the blockmatrices of shape (X.shape[2], X.shape[2]) that make up G
            G = np.mean(np.split(np.mean(np.split(G, X.shape[2], 1), 0), X.shape[2]), 0)

            # return the matrix of RKHS inner products of the mean embeding objects
            return G
        else:
            return np.mean(np.split(self.gram(X_resh, Y), X.shape[2]), 0)

class FeatMapKernel(Kernel):
    def __init__(self, feat_map):
        self.features = feat_map

    def features_mean(self, samps):
        return self.features(samps).mean(0)

    def gram(self, X, Y = None, diag = False):
        f_X = self.features(X)
        if Y is None:
            f_Y = f_X
        else:
            f_Y = self.features(Y)
        if diag:
            return np.sum(f_X * f_Y, 1)
        else:
            return f_X.dot(f_Y.T)

class LinearKernel(FeatMapKernel):
    def __init__(self):
        FeatMapKernel.__init__(self, lambda x: x)

def int_softplus(x):
    if x >= 34:
        # in this case, limitations in floating-point
        # precision result in log(exp(y) - 1) == y
        return x
    elif x <= -37:
        # this also results from precision limits
        return 10**-8
    else:
        return log(1 + exp(x))

softplus = np.vectorize(int_softplus)

def int_invsoftplus(y):
    y = float(y)
    if y >= 34:
        # in this case, limitations in floating-point
        # precision result in log(exp(y) - 1) == y
        return y
    elif y < 0:
        raise ValueError("Function defined only for y >= 0")
    elif y == 0:
        #perturb input so as not to return -inf
        y += stats.gamma(100,scale=0.00001).rvs()
    return log(exp(y) - 1)
invsoftplus = np.vectorize(int_invsoftplus)

class GaussianKernel(Kernel):
    def __init__(self, sigma, diffable = False):
        self.set_params(invsoftplus(sigma))
        self.diffable = diffable

    def get_params(self):
        return self.params

    def get_double_var_kern(self):
        return GaussianKernel(np.sqrt(2) * self._sd)

    def set_params(self, params):
        self.params = np.atleast_1d(params).flatten()[0]
        self.__set_standard_dev(softplus(self.params))

    def __set_standard_dev(self, sd):
        assert(np.all(sd > 0))
        self._sd = sd
        self._const_factor = -0.5 / sd**2
        self._normalization = (sqrt(2*np.pi)*sd)
        self._log_norm = log(self._normalization)

    def get_var(self):
        return self._sd**2

    def gram(self, X, Y=None, diag = False, logsp = False):
        assert(len(np.shape(X))==2)

        # if X=Y, use more efficient pdist call which exploits symmetry

        if diag:
            if Y is None:
                sq_dists = np.zeros(X.shape[0])
            else:
                assert(X.shape == Y.shape)
                sq_dists = np.sum((X - Y)**2, 1)
        else:
            if not self.diffable:
                if Y is None:
                    sq_dists = squareform(pdist(X, 'sqeuclidean'))
                else:
                    assert(len(Y.shape) == 2)
                    assert(X.shape[1] == Y.shape[1])
                    sq_dists = cdist(X, Y, 'sqeuclidean')
            else:
                assert(len(np.shape(Y))==2)
                assert(np.shape(X)[1]==np.shape(Y)[1])
                sq_dists = ((np.tile(X,(Y.shape[0], 1)) - np.repeat(Y, X.shape[0], 0))**2).sum(-1).reshape(Y.shape[0], X.shape[0]).T

        rval = self._const_factor* sq_dists - self._log_norm * np.shape(X)[1]
        if not logsp:
            return exp(rval)
        return rval

    def rvs(self, nrows, ncols):
        return np.random.randn(nrows, ncols) * self._sd

class LaplaceKernel(Kernel):
    def __init__(self, sigma, diffable = False):
        self.set_params(log(exp(sigma) - 1))
        self.diffable = diffable

    def get_params(self):
        return self.params

    def set_params(self, params):
        self.params = np.atleast_1d(params).flatten()[0]
        self.__set_standard_dev(log(exp(self.params) + 1))

    def __set_standard_dev(self, sd):
        self._sd = sd
        self._scale = sd
        self._const_factor = -1./self._scale
        self._normalization = 2 * self._scale
        self._log_norm = log(self._normalization)

    def get_var(self):
        return 2 * self._scale**2

    def gram(self, X, Y=None, diag = False, logsp = False):
        assert(len(np.shape(X))==2)

        # if X=Y, use more efficient pdist call which exploits symmetry

        if diag:
            if Y is None:
                dists = np.zeros(X.shape[0])
            else:
                assert(X.shape == Y.shape)
                dists = np.sum((X - Y)**2, 1)
        else:
            if not self.diffable:
                if Y is None:
                    dists = squareform(pdist(X, 'cityblock'))
                else:
                    assert(len(Y.shape) == 2)
                    assert(X.shape[1] == Y.shape[1])
                    dists = cdist(X, Y, 'cityblock')
            else:
                assert(len(np.shape(Y))==2)
                assert(np.shape(X)[1]==np.shape(Y)[1])
                assert("This is not tested!")
                dists = (np.abs(np.tile(X,(Y.shape[0], 1)) - np.repeat(Y, X.shape[0], 0))).sum(-1).reshape(Y.shape[0], X.shape[0]).T

        rval = self._const_factor * dists - self._log_norm * np.shape(X)[1]
        if not logsp:
            return exp(rval)
        return rval

    def rvs(self, nrows, ncols):
        return stats.laplace.rvs(scale=self._scale, size = (nrows, ncols))

class StudentKernel(Kernel):
    def __init__(self, s2, df, diffable = False):
        self.set_params(log(exp(np.array([s2,df])) - 1))
        self.diffable = diffable

    def get_params(self):
        return self.params

    def set_params(self, params):
        self.params = params
        self.dens = dist.mvt(0, log(exp(params[0]) + 1), log(exp(params[1]) + 1))

    def gram(self, X, Y=None, diag = False, logsp = False):
        assert(len(np.shape(X))==2)

        # if X=Y, use more efficient pdist call which exploits symmetry

        if diag:
            if Y is None:
                sq_dists = np.zeros(X.shape[0])
            else:
                assert(X.shape == Y.shape)
                sq_dists = np.sum((X - Y)**2, 1)
        else:
            if not self.diffable:
                if Y is None:
                    sq_dists = squareform(pdist(X, 'sqeuclidean'))
                else:
                    assert(len(Y.shape) == 2)
                    assert(X.shape[1] == Y.shape[1])
                    sq_dists = cdist(X, Y, 'sqeuclidean')
            else:
                assert(len(np.shape(Y))==2)
                assert(np.shape(X)[1]==np.shape(Y)[1])
                sq_dists = ((np.tile(X,(Y.shape[0], 1)) - np.repeat(Y, X.shape[0], 0))**2).sum(-1).reshape(Y.shape[0], X.shape[0]).T
        dists = np.sqrt(sq_dists)
        rval = self.dens.logpdf(dists.flatten()).reshape(dists.shape)
        if not logsp:
            return rval
        else:
            return exp(rval)

class SplitDimsKernel(Kernel):
    def __init__(self, intervals, kernels, operation = "*", weights = None):
        assert(len(intervals) - 1 == len(kernels))
        self.intervals = intervals
        self.kernels = kernels
        if operation == "*":
            self.weights = np.ones(len(kernels))
            self.op = lambda x: np.prod(x, 0)
            self.log_op = lambda x: np.sum(x, 0)
            if weights is None:
                self.weights = np.ones(len(kernels))
            else:
                self.weights = weights
        else:
            assert(operation == '+')
            self.op = lambda x: np.sum(x, 0)
            self.log_op = lambda x: logsumexp(x, 0)
            if weights is None:
                self.weights = np.ones(len(kernels))
            else:
                self.weights = weights

    def gram(self, X, Y=None, diag = False, logsp = False):
        assert(not logsp)

        split_X = [X[:, self.intervals[i]:self.intervals[i + 1]] for i in range(len(self.kernels))]
        if Y is None:
            split_Y = [None] * len(self.kernels)
        else:
            split_Y = [Y[:, self.intervals[i]:self.intervals[i + 1]] for i in range(len(self.kernels))]
        sub_grams = np.array([self.kernels[i].gram(split_X[i], split_Y[i], diag = diag) * self.weights[i]  for i in range(len(self.kernels))])
        return self.op(sub_grams)

def test_SplitDimsKernel():
    (intervals, kernels) = ([0, 2, 5], [GaussianKernel(0.1), GaussianKernel(1)])
    X = np.arange(15).reshape((3,5))
    Y = (X + 3)[:-1,:]
    for op in "+", "*":
        k = SplitDimsKernel(intervals, kernels, op)
        assert(k.gram(X, Y).shape == (len(X), len(Y)))
        assert(k.gram(X).shape == (len(X), len(X)))
        assert(k.gram(X, diag = True).shape == (len(X),))

class SKlKernel(Kernel):
    def __init__(self, sklearn_kernel):
        self.skl = sklearn_kernel

    def gram(self, X, Y=None, diag = False, logsp = False):
        if diag:
            assert(Y is None)
            rval = self.skl.diag(X)
        else:
            rval = self.skl(X, Y)
        if logsp:
            rval = log(rval)
        return rval


from typing import Optional, Callable, List

from constrained_decoding.dfa import DFA
from constrained_decoding.autoregressive_dfa_constraining.dfa_constrained_beam_search import dfa_constrained_beam_search
from constrained_decoding.autoregressive_dfa_constraining.dfa_constrained_generate import dfa_constrained_generate

def set_decoding_to_dfa_constrained(model,
                                    dfa: Optional[DFA] = None,
                                    dfa_factory: Optional[Callable[[List[int], ], DFA]] = None,
                                    dfas: Optional[List[DFA]] = None,
                                    dfa_factories: Optional[List[Callable[[List[int], ], DFA]]] = None,
                                    tokenizer=None):
    """ Set the beam search method of the model to be constrained to decoding according to a Deterministic Finite Automaton.
        Either `dfa` or `dfa_factory` must be specified.
    Args:
        model ([type]): A Huggingface model supporting text generation. The function will modify `model.beam_search`.
        dfa (Optional[DFA]): When specified, the same DFA is used for all batch instances and beams, regardless of input sequence. Defaults to None.
        dfa_factory (Optional[Callable[[List[int]], DFA]]): When specified, used for instanciating a `DFA` for each batch item.
            Assumed to be a functions which gets `input_ids` (token ids of input sequence) and returns a `DFA`. Defaults to None.
        tokenizer ([type], optional): The instanciated DFAs or provided `dfa` would be adjusted to this tokenizer.
            if `dfa` is provided and `dfa.tokenizer` is not None, `tokenizer` would not be used.

    """
    # Validate arguments
    if not (dfa or dfa_factory or dfas or dfa_factories):
        raise ValueError("Either `dfa`, `dfas`, `dfa_factory` or `dfa_factories` must be provided.")
    from transformers.generation_utils import GenerationMixin
    assert isinstance(model, GenerationMixin), "Model must be an instance of `transformers.generation_utils.GenerationMixin` to be applied the dfa-constrained `beam_search` method."

    # Replace model's beam_search method with our custom function as a bound method
    import types
    model.beam_search = types.MethodType(dfa_constrained_beam_search, model)
    # Provide our custom beam_search method with dfa or dfa_factory (as function-object attributes)
    if dfa or dfas:
        dfas = dfas or [dfa]
        for dfa in dfas:
            # make sure DFA is adjusted to tokenizer
            if dfa.tokenizer is None and tokenizer is not None:
                dfa = dfa.adjust_for_tokenizer(tokenizer, convert_to_word_ids=True)
            elif dfa.tokenizer is None and tokenizer is None:
                raise ValueError("Either `dfa` should be adjusted to model's tokenizer, or `tokenizer` should be provided for adjusting the `dfa` to it.")
        # provide the beam_search method with dfa
        dfa_constrained_beam_search.multiple_dfas = dfas
    elif dfa_factory or dfa_factories:
        dfa_factories = dfa_factories or [dfa_factory]
        dfa_constrained_beam_search.multiple_dfa_factories = dfa_factories
        dfa_constrained_beam_search.tokenizer = tokenizer
    # needs also to replace `model.generate` to our custom generate function that sends `encoder_input_ids` to model.beam_search
    model.generate = types.MethodType(dfa_constrained_generate, model)


'''
@   Two Sum | 01

@   Problem
    Given an array of integers nums and an integer target, return indices of the two
    numbers such that they add up to target. Assume that each input would have exactly
    one solution, and you may not use the same element twice.

@   Example
    Input:  nums = [2,7,11,15], target = 9
    Output: [0,1]

@   Template

'''

def twoSum(nums, target):
    """
    :type nums: List[int]
    :type target: int
    :rtype: List[int]
    """

    d = {}                              # {11:0, 15:1, 2:2, 7:3}

    for i, num in enumerate(nums):      # [(0, 2),(1,7),(2,11),(3,15)]

        m = target - num

        if m in d:
            return [d[m], i]

        else:
            d[num] = i

# TEST _______________________________________________________________________________

nums = [2,7,11,15]
target = 9

print(twoSum(nums, target))


from django.conf.urls import patterns, include, url
from django.conf import settings
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    url(r'^admin/', include(admin.site.urls)),
    url(r'^', include('website.urls', namespace='website')),
    url(r'^', include('registration.auth_urls')),
    url(r'^', include('registration.urls', namespace='registration')),
    url(r'^', include('profiles.urls', namespace='profiles')),
    url(r'^books/', include('books.urls', namespace='books')),
    url(r'^search/', include('haystack.urls')),
)

if settings.DEBUG:
    urlpatterns += patterns('',
        url(r'^media/(?P<path>.*)$', 'django.views.static.serve', {
            'document_root': settings.MEDIA_ROOT}),
    )


import numpy as np
from utils import *
from sklearn.ensemble import RandomForestClassifier

def cv_train_rfcls(x,y,n_estimators,min_samples_leaf,max_feature,num_cross=10):
    cross_train_x, cross_train_y, cross_valid_x, cross_valid_y = cross_validation(x,y,num_cross)
    num_cross = len(cross_train_x)
    max_score = 0
    score_list=[]
    for i in range(num_cross):
        model = RandomForestClassifier(n_estimators=n_estimators, min_samples_leaf=min_samples_leaf, max_features=max_feature, n_jobs=-1)
        model.fit(cross_train_x[i], cross_train_y[i])
        score = model.score(cross_valid_x[i], cross_valid_y[i])
        score_list.append(score)
    print(score_list)
    return sum(score_list)/num_cross

def grid_search_rfcls(x,y,n_e_list,min_sl_list,max_f_list,num_cross=10):
    max_ne ,max_msl, max_mf ,max_score= 0,0,0,0
    for i in n_e_list:
        for j in min_sl_list:
            for k in max_f_list:
                score = cv_train_rfcls(x,y,i,j,k,num_cross)
                print("n_estimators",i," min_samples_leaf=",j," max_feature=",k," score=",score,"\n")
                if score>max_score:
                    max_ne = i
                    max_msl = j
                    max_mf = k
                    max_score = score
    model = RandomForestClassifier(n_estimators=max_ne, min_samples_leaf=max_msl,
                                   max_features=max_mf, n_jobs=-1)
    print(max_ne ,max_msl, max_mf ,max_score)
    model.fit(x,y)
    return model

if __name__ == "__main__":
    train_x = np.load("train_x.npy")
    train_y = np.load("train_y.npy")
    mid = np.median(train_y)
    for i in range(len(train_y)):
        if train_y[i] > mid:
            train_y[i] = 1
        else:
            train_y[i] = 0
    num_cross = 10
    model = grid_search_rfcls(train_x,train_y,[100],[1,2,4,8,16,32],[8,16,32,64,128,256],num_cross=10)


""" Class holding data of one or more features
"""
from logging import warning
from typing import List, Tuple, Union
import xarray as xa
import pandas as pd
import numpy as np
import numpy.typing as npt
from proteolizarddata.data import PyTimsDataHandleDDA
from proteolizardalgo.feature_loader_dda import FeatureLoaderDDA

# typing
NDArrayFloat = npt.NDArray[np.float64]
NDArrayInt = npt.NDArray[np.int64]

class AlignedFeatureData:
    """This class manages import, alignment and processing
        of feature data.

    Using FeatureLoaderDDA the features are stored in an aligned fashion,
    meaning from all features 'num_data_points' highest signals are chosen.
    Features that do not have enough signals are discarded.

    Attributes:
        feature_data (xa.Dataset): Feature data is stored in
            xarray format. If several features are aligned 'feature'
            dimensions stores the feature's ids as coordinates.
            Note: If only one feature is used, the dimension 'feature'
            still exists, however length of 'datapoint' dimension is
            depending on the feature's size and not on 'num_data_points'
        accepted_feature_ids (List[int]): List of feature ids, that are
            stored in feature_data.
    Args:
        data_handle (Union[str,PyTimsDataHandleDDA]): Path to experimental data
            or data_handle.
        ids (List[int]): List with feature ids.
        is_parallel (bool, optional): Wether several features are to
            be aligned. If True 'num_data_points' highest signals
            are loaded from features, if False all data points of the
            single feature are loaded. Defaults to True.
        num_data_points (int, optional): Number of data_points to load
            from features to align. Defaults to 10.
    """

    def __init__(
        self,
        data_handle: Union[str, PyTimsDataHandleDDA],
        ids: List[int],
        is_parallel: bool = True,
        num_data_points=10,
    ) -> None:
        self.accepted_feature_ids = []
        charges = []
        feature_data = []
        if isinstance(data_handle, str):
            data_path = data_handle
            data_handle = PyTimsDataHandleDDA(data_path)
        for feature_id in ids:
            feature = FeatureLoaderDDA(data_handle, feature_id)
            if np.isnan(feature.monoisotopic_mz):
                continue
            try:
                # estimate feature hull boundaries with
                # averagine model for isotopic pattern
                # and gaussian model for IMS
                data_tmp = feature.load_hull_data_3d(
                    intensity_min=0,
                    ims_model="gaussian",
                    plot_feature=False,
                )
            except RuntimeError:
                warning(f"RuntimeError with feature {feature_id}")
                continue
            if is_parallel:
                if len(data_tmp) < num_data_points:
                    continue
                feature_data.append(
                    data_tmp.nlargest(num_data_points, columns="Intensity")
                )
            else:
                feature_data.append(data_tmp)
            self.accepted_feature_ids.append(feature_id)
            charges.append(feature.charge)

        if len(self.accepted_feature_ids) == 0:
            raise ValueError("No accepted features. Check chosen features.")
        s, mz, i = self._set_data_parallel(feature_data)
        data_dict = {
            "Charge": ("feature", charges),
            "Scan": (("data_point", "feature"), s),
            "Mz": (("data_point", "feature"), mz),
            "Intensity": (("data_point", "feature"), i),
        }
        coord_dict = {"feature": self.accepted_feature_ids}
        self.feature_data = xa.Dataset(data_vars=data_dict, coords=coord_dict)

    def _set_data_parallel(
        self, feature_data_list: List[pd.DataFrame]
    ) -> Tuple[NDArrayFloat, NDArrayFloat, NDArrayFloat]:
        """Stacking features in axis 1

        Args:
            feature_data_list (List[pd.DataFrame]): Loaded feature dataframes.
        Returns:
            Tuple[NDArrayFloat,NDArrayFloat,NDArrayFloat]: stacked scan, mz and
                intensity data.
        """
        s = np.stack([fd["Scan"] for fd in feature_data_list], axis=1)
        mz = np.stack([fd["Mz"] for fd in feature_data_list], axis=1)
        i = np.stack([fd["Intensity"] for fd in feature_data_list], axis=1).astype(
            "float"
        )

        return (s, mz, i)


##########################################################
# Trick setup:
# enable real-time
trick.real_time_enable()
trick.exec_set_software_frame(0.1)
# turn on frame logging
#trick.frame_log_on()

# turn on sim control panel
#trick.sim_control_panel_set_enabled(True)
# start sim in freeze?
#trick.exec_set_freeze_command(True)
# allow ctrl-C freezing
trick.exec_set_enable_freeze(True)

stop_time = 5
trick.stop(stop_time)

##########################################################
# Trick unit test setup:
from trick.unit_test import *
trick_utest.unit_tests.enable()
trick_utest.unit_tests.set_file_name( os.getenv("TRICK_HOME") + "/trick_test/SIM_events.xml" )
trick_utest.unit_tests.set_test_name( "EventsTest" )
from array import array
expected= array('f')
result = array('f')
##########################################################
test_suite = "events cyclic"

# TEST 0: event created in S_define, fire only once
trick.add_event(ev.event0)
expected.append(1)
result.append(0)

# TEST 1: cyclic event, fire every second
event1 = trick.new_event("event1")
event1.condition(0, "ev.cond_var_true==True")
event1.action(0, "print (\"event1\"); result[1] += 1");
event1.action(1, "event1.activate()")
event1.set_cycle(1.0)
event1.activate()
trick.add_event(event1)
expected.append(1+stop_time)
result.append(0)

# TEST 2: cyclic event, condition variable, added to 0.5 sched job so fire twice a second
event2 = trick.new_event("event2")
event2.condition_var(0, "ev.cond_var_true")
event2.action(0, "print (\"event2\"); result[2] += 1");
event2.action(1, "event2.activate()")
event2.activate()
trick.add_event_after(event2, "ev.sched")
expected.append(1+(stop_time*2))
result.append(0)

# TEST 3: cyclic event, condition variable, change condition and change action
event3 = trick.new_event("event3")
event3.condition_var(0, "ev.cond_var_true")
event3.action(0, "print (\"event3\"); result[3] += 1");
event3.action(1, "event3.activate()")
event3.set_cycle(1.0)
event3.activate()
trick.add_event(event3)
#condition will be false during sim time 2.0 and 3.0
trick.add_read(2.0, """event3.condition(0, "False")""")
trick.add_read(2.0, """event3.action(0, \"print (\\\"event3_changed\\\"); result[3] += 5\")""")
trick.add_read(4.0, """event3.condition_var(0, "ev.cond_var_true")""")
expected.append(2+((stop_time-3)*5))
result.append(0)

# TEST 4: cyclic event, condition variable, delete event and add again with new cycle time
event4 = trick.new_event("event4")
event4.condition_var(0, "ev.cond_var_true")
event4.action(0, "print (\"event4\"); result[4] += 1");
event4.action(1, "event4.activate()")
event4.set_cycle(1.0)
event4.activate()
trick.add_event(event4)
# deleting of event will occur in current frame 2.0
event4_deleted1 = False
trick.add_read(2.0, """
trick.delete_event(event4)
event4_deleted1 = (trick.get_event("event4") == None)
""")
# adding of event will occur in next frame after 4.0
event4_deleted2 = False
trick.add_read(4.0, """
event4.set_cycle(0.1)
trick.add_event(event4)
event4_deleted2 = (trick.get_event("event4") == None)
""")
expected.append(2+((stop_time-4)*10))
result.append(0)

# TEST 5: cyclic event, set hold on so that it continues to fire until hold off
event5 = trick.new_event("event5")
event5.condition(0, "trick.exec_get_sim_time()==1.0")
event5.condition_hold_on(0)
event5.action(0, "print (\"event5\"); result[5] += 1");
event5.action(1, "event5.activate()")
event5.set_cycle(1.0)
event5.activate()
trick.add_event(event5)
trick.add_read(4.0, """event5.condition_hold_off(0)""")
expected.append(3)
result.append(0)

# TEST 6: cyclic event, condition job, then action_disable so it is not reactivated
event6 = trick.new_event("event6")
event6.condition_job(0, "ev.cond_job_true")
event6.action(0, "print (\"event6\"); result[6] += 1");
event6.action(1, "event6.activate()")
event6.set_cycle(1.0)
event6.activate()
trick.add_event(event6)
trick.add_read(3.0, """event6.action_disable(1)""")
expected.append(4)
result.append(0)

# TEST 7: cyclic event, condition_all true & false, then condition_disable the false one so event will fire
event7 = trick.new_event("event7")
event7.condition_var(0, "ev.cond_var_true")
event7.condition_var(1, "ev.cond_var_false")
event7.condition_all()
event7.action(0, "print (\"event7\"); result[7] += 1");
event7.action(1, "event7.activate()")
event7.set_cycle(1.0)
event7.activate()
trick.add_event(event7)
trick.add_read(4.0, """event7.condition_disable(1)""")
expected.append(1+stop_time-4)
result.append(0)

# TEST 8: cyclic event, action_job_off the sched_count job, so ev.count variable should stop updating prior to 2.0
event8 = trick.new_event("event8")
event8.condition(0, "trick.exec_get_sim_time()==2.0")
event8.condition(1, "trick.exec_get_sim_time()==4.0")
event8.condition_any()
event8.action(0, "print (\"event8\"); result[8] = ev.count");
event8.action(1, "event8.activate()")
event8.action_job_off(2, "ev.sched_count")
event8.set_cycle(1.0)
event8.activate()
trick.add_event(event8)
expected.append(2)
result.append(0)

# TEST 9: cyclic event, action_job is the sched_count job, note: results are partially dependent on event8
event9 = trick.new_event("event9")
event9.condition(0, "trick.exec_get_sim_time()==5.0")
event9.action_job(0, "ev.sched_count")
event9.action_job(1, "ev.sched_count")
event9.action_job(2, "ev.sched_count")
event9.action_job(3, "ev.sched_count")
event9.action(4, "print (\"event9\"); result[9] = ev.count");
event9.action(5, "event9.activate()")
event9.set_cycle(1.0)
event9.activate()
trick.add_event(event9)
expected.append(6)
result.append(0)

# TEST 10: manual_on event fires every cycle
manual10 = trick.new_event("manual10")
manual10.condition(0, "False")
manual10.action(0, "print (\"manual10\"); result[10] += 1");
# you don't have to reactivate a manual mode event
manual10.set_cycle(1.0)
manual10.activate()
manual10.manual_on()
trick.add_event(manual10)
expected.append(1+stop_time)
result.append(0)

# TEST 11: manual_off event does not fire, manual_done will make condition be used (cyclic)
manual11 = trick.new_event("manual11")
manual11.condition(0, "True")
manual11.action(0, "print (\"manual11\"); result[11] += 1");
manual11.action(1, "manual11.activate()")
manual11.set_cycle(1.0)
manual11.activate()
manual11.manual_off()
trick.add_event(manual11)
trick.add_read(4.0, """manual11.manual_done()""")
expected.append(1+stop_time-4)
result.append(0)

# TEST 12: manual_fire at a certain time and see if it fires at that time
manual12 = trick.new_event("manual12")
manual12.action(0, "print (\"manual12\"); result[12] = trick.exec_get_sim_time()");
manual12.action(1, "manual12.activate()")
manual12.set_cycle(1.0)
manual12.activate()
trick.add_event(manual12)
trick.add_read(3.5, """manual12.manual_fire()""")
expected.append(3.5)
result.append(0)

##########################################################
# TEST RESULTS AT SHUTDOWN
result_event = trick.new_event("result_event")
result_event.condition(0, "True")
result_event.action(0, """
print (\"RESULTS...\")
TRICK_EXPECT_EQ(result[0], expected[0], test_suite, "event0")
TRICK_EXPECT_EQ(result[1], expected[1], test_suite, "event1")
TRICK_EXPECT_EQ(result[2], expected[2], test_suite, "event2")
TRICK_EXPECT_EQ(result[3], expected[3], test_suite, "event3")
TRICK_EXPECT_TRUE(event4_deleted1, test_suite, "event4_deleted1")
TRICK_EXPECT_FALSE(event4_deleted2, test_suite, "event4_deleted2")
TRICK_EXPECT_EQ(result[4], expected[4], test_suite, "event4")
TRICK_EXPECT_EQ(result[5], expected[5], test_suite, "event5")
TRICK_EXPECT_EQ(result[6], expected[6], test_suite, "event6")
TRICK_EXPECT_EQ(result[7], expected[7], test_suite, "event7")
TRICK_EXPECT_EQ(result[8], expected[8], test_suite, "event8")
TRICK_EXPECT_EQ(result[9], expected[9], test_suite, "event9")
TRICK_EXPECT_EQ(result[10], expected[10], test_suite, "manual10")
TRICK_EXPECT_EQ(result[11], expected[11], test_suite, "manual11")
TRICK_EXPECT_EQ(result[12], expected[12], test_suite, "manual12")
""")
result_event.activate()
trick.add_event_after(result_event, "ev.shutdown")


import time
import numpy as np
import tensorflow as tf

ani_mod = tf.load_op_library('ani.so');

Xs = np.load('Xs.npy')
Ys = np.load('Ys.npy')
Zs = np.load('Zs.npy')
As = np.load('As.npy')
MOs = np.load('MOs.npy')
MACs = np.load('MACs.npy')
# TCs = np.zeros(4, dtype=np.int32)

# for z in As:
# 	# print(z)
# 	TCs[z] += 1

feat = ani_mod.ani(Xs, Ys, Zs, As, MOs, MACs)

st = time.time()

with tf.Session(config=tf.ConfigProto(log_device_placement=True)) as sess:

	for idx in range(1000):
		results = sess.run(feat)
		print(len(results))
		print("python samples per minute: ", (idx+1)*len(MOs)/(time.time()-st) * 60)

	# res = res.reshape(len(Xs), 384)
	# for f in res:
		# print(f)

	# print(res.shape)


# Input:
#  integers = [i_0, i_1, ..., i_n]
#  The set of n integers.
#
#  target = integer
#
# Output:
#  subset_exists = boolean representing the answer to the question
#   "Does there exist a subset of integers that sums to the target?"
#  subset_indices = [p_0, p_1, ..., p_k]
#   Each element in this array corresponds to the index of the element
#   in the array of integers that is included in the subset that sums
#   to the target.

class subset_decorator(object):
  def __init__(self, f):
    self.f = f

  def __call__(self, integers, target):
    print("Set of integers: {0}".format(integers))
    subset_exists, subset_indices = self.f(integers, target=0)
    if subset_exists:
      print("Subset: {0}".format([integers[i] for i in subset_indices]))
    else:
      print("No subset exists")
    return subset_exists, subset_indices

@subset_decorator
def solve(integers, target=0):
  n = len(integers)
  for subset_binary in range(1, 2**n):
    subset_indices = construct_subset_indices(subset_binary)
    sum_of_subset = sum([integers[i] for i in subset_indices])
    if sum_of_subset == target:
      return True, subset_indices

  return False, None

def construct_subset_indices(subset_binary):
  subset_indices = []
  index = 0
  current_binary = subset_binary
  while current_binary:
    # Extract least significant bit
    bit_of_interest = current_binary & 1
    # Check if that bit is a 1
    if bit_of_interest:
      # If it is a 1, append its index in the subset of indices
      subset_indices.append(index)

    # Shift to the next bit
    current_binary = current_binary >> 1
    index += 1

  return subset_indices

if __name__ == "__main__":
  test_binary = '1010000101'
  test_number = 645
  expected_subset_indices = [0, 2, 7, 9]
  assert expected_subset_indices == construct_subset_indices(test_number)

  sample_integers = [4, 2, 8, 3, -9, -5]
  actual_result, actual_subset_indices = solve(sample_integers)
  assert actual_result, "False negative"

  sample_integers = [-12, 13, 18, 19]
  actual_result, actual_subset_indices = solve(sample_integers)
  assert not actual_result, "False positive"


N = int(input())
graph = dict()

for person in range(N):
    friends = input()

    # 한 사람의 친구 목록을 set로 받는다.
    graph[person] = set()
    for i, f in enumerate(friends):
        if f == "N":
            continue
        else:
            graph[person].add(i)

def mostFamousPerson(n, graph):
    answer = 0

    for p in graph:
        # 한 사람의 친구 목록 초기화
        friend = set() | graph[p]

        # 친구의 친구들을 내 친구에 포함시키기
        for f in list(graph[p]):
            friend = friend | graph[f]
        # '나'는 친구가 아니므로 모든 친구에서 1 빼기
        answer = max(answer, len(friend) - 1)

    return answer

print(mostFamousPerson(N, graph))


# -*- coding: utf-8 -*-
"""
Abstract Dataset Loader
=======================

Defines the abstract class implementing support for dataset loading:

-   :class:`colour_datasets.loaders.AbstractDatasetLoader`
"""

from __future__ import division, unicode_literals

from abc import ABCMeta, abstractmethod
from six import add_metaclass

__author__ = 'Colour Developers'
__copyright__ = 'Copyright (C) 2019 - Colour Developers'
__license__ = 'New BSD License - https://opensource.org/licenses/BSD-3-Clause'
__maintainer__ = 'Colour Developers'
__email__ = 'colour-science@googlegroups.com'
__status__ = 'Production'

__all__ = ['AbstractDatasetLoader']

@add_metaclass(ABCMeta)
class AbstractDatasetLoader:
    """
    Defines the base class for a dataset loader.

    This is an :class:`ABCMeta` abstract class that must be inherited by
    sub-classes.

    The sub-classes are expected to implement the
    :meth:`colour_datasets.loaders.AbstractDatasetLoader.load` method that
    handles the syncing, parsing, conversion and return of the dataset content
    as a *Python* object.

    Attributes
    ----------
    ID
    record
    id
    content

    Methods
    -------
    load
    sync

    Parameters
    ----------
    record : Record
        Dataset record.
    """

    ID = None
    """
    Dataset record id, i.e. the *Zenodo* record number.

    ID : unicode
    """

    def __init__(self, record):
        self._record = record
        self._content = None

    @property
    def record(self):
        """
        Getter and setter property for the dataset record.

        Parameters
        ----------
        value : Record
            Value to set the dataset record with.

        Returns
        -------
        unicode
            Dataset record.
        """

        return self._record

    @property
    def id(self):
        """
        Getter and setter property for the dataset id.

        Parameters
        ----------
        value : unicode
            Value to set the dataset id with.

        Returns
        -------
        unicode
            Dataset id.
        """

        return self.__class__.ID

    @property
    def content(self):
        """
        Getter and setter property for the dataset content.

        Parameters
        ----------
        value : object
            Value to set the dataset content with.

        Returns
        -------
        unicode
           Dataset content.
        """

        return self._content

    @abstractmethod
    def load(self):
        """
        Syncs, parses, converts and returns the dataset content as a *Python*
        object.

        Returns
        -------
        object
            Dataset content as a *Python* object.

        Notes
        -----
        -   Sub-classes are required to call
            :meth:`colour_datasets.loaders.AbstractDatasetLoader.sync` method
            when they implement it, e.g.
            ``super(MyDatasetLoader, self).sync()``.
        """

        pass

    def sync(self):
        """
        Syncs the dataset content, i.e. checks whether it is synced and pulls
        it if required.
        """

        if not self.record.synced():
            self.record.pull()