text: var exceptions = require('../core').exceptions
  var types = require('../types')
  
  var inspect = {
      __doc__: '',
      __file__: 'batavia/modules/inspect.js',
      __name__: 'inspect',
      __package__: '',
  
      'CO_OPTIMIZED': 0x1,
      'CO_NEWLOCALS': 0x2,
      'CO_VARARGS': 0x4,
      'CO_VARKEYWORDS': 0x8,
      'CO_NESTED': 0x10,
      'CO_GENERATOR': 0x20,
      'CO_NOFREE': 0x40
  }
  
  inspect.FullArgSpec = function(kwargs) {
      this.args = kwargs.args || []
      this.varargs = kwargs.getcallargs
      this.varkw = kwargs.varkw
      this.defaults = kwargs.defaults || {}
      this.kwonlyargs = kwargs.kwonlyargs || []
      this.kwonlydefaults = kwargs.kwonlydefaults || {}
      this.annotations = kwargs.annotations || {}
  }
  
  // inspect._signature_get_user_defined_method = function(cls, method_name) {
      // try:
      //     meth = getattr(cls, method_name)
      // catch (err) {
      //     return
      // }
      // else {
      //     if not isinstance(meth, _NonUserDefinedCallables) {
      //         // # Once '__signature__' will be added to 'C'-level
      //         // callables, this check won't be necessary
      //         return meth
      //     }
      // }
  // }
  
  // inspect._signature_bound_method = function(sig) {
  //     // Internal helper to transform signatures for unbound
  //     // functions to bound methods
  
  //     var params = sig.parameters.values()
  
  //     if (!params || params[0].kind in (_VAR_KEYWORD, _KEYWORD_ONLY)) {
  //         throw new exceptions.ValueError.$pyclass('invalid method signature')
  //     }
  
  //     var kind = params[0].kind
  //     if (kind in (_POSITIONAL_OR_KEYWORD, _POSITIONAL_ONLY)) {
  //         // Drop first parameter:
  //         // '(p1, p2[, ...])' -> '(p2[, ...])'
  //         params = params.slice(1)
  //     } else {
  //         if (kind !== _VAR_POSITIONAL) {
  //             // Unless we add a new parameter type we never
  //             // get here
  //             throw new exceptions.ValueError.$pyclass('invalid argument type')
  //         }
  //         // It's a var-positional parameter.
  //         // Do nothing. '(*args[, ...])' -> '(*args[, ...])'
  //     }
  
  //     return sig.replace(parameters = params)
  // }
  
  inspect._signature_internal = function(obj, follow_wrapper_chains, skip_bound_arg) {
      // if (!callable(obj)) {
      //     throw TypeError('{!r} is not a callable object'.format(obj));
      // }
  
      // if (isinstance(obj, types.MethodType)) {
          // In this case we skip the first parameter of the underlying
          // function (usually `self` or `cls`).
          // sig = inspect._signature_internal(obj.__func__, follow_wrapper_chains, skip_bound_arg);
          // if (skip_bound_arg) {
          //     return inspect._signature_bound_method(sig);
          // } else {
          //     return sig;
          // }
      // }
  
      // // Was this function wrapped by a decorator?
      // if (follow_wrapper_chains) {
      //     obj = unwrap(obj, stop=function(f) { return hasattr(f, "__signature__"); });
      // }
  
      // try {
      //     sig = obj.__signature__;
      // } catch (err) {
      // } else {
      //     if (sig !== null) {
      //         if (!isinstance(sig, Signature)) {
      //             throw TypeError(
      //                 'unexpected object {!r} in __signature__ ' +
      //                 'attribute'.format(sig));
      //         }
      //         return sig;
      //     }
      // }
      // try {
      //     partialmethod = obj._partialmethod
      // } catch (err) {
      //     pass
      // } else {
      //     if isinstance(partialmethod, functools.partialmethod):
      //         // Unbound partialmethod (see functools.partialmethod)
      //         // This means, that we need to calculate the signature
      //         // as if it's a regular partial object, but taking into
      //         // account that the first positional argument
      //         // (usually `self`, or `cls`) will not be passed
      //         // automatically (as for boundmethods)
  
      //         wrapped_sig = inspect._signature_internal(partialmethod.func,
      //                                           follow_wrapper_chains,
      //                                           skip_bound_arg)
      //         sig = inspect._signature_get_partial(wrapped_sig, partialmethod, (None,))
  
      //         first_wrapped_param = tuple(wrapped_sig.parameters.values())[0]
      //         new_params = (first_wrapped_param,) + tuple(sig.parameters.values())
  
      //         return sig.replace(parameters=new_params)
  
      // if isfunction(obj) or _signature_is_functionlike(obj):
      //     # If it's a pure Python function, or an object that is duck type
      //     # of a Python function (Cython functions, for instance), then:
      return inspect.Signature.from_function(obj)
  
      // if _signature_is_builtin(obj):
      //     return inspect._signature_from_builtin(Signature, obj,
      //                                    skip_bound_arg=skip_bound_arg)
  
      // if isinstance(obj, functools.partial):
      //     wrapped_sig = inspect._signature_internal(obj.func,
      //                                       follow_wrapper_chains,
      //                                       skip_bound_arg)
      //     return inspect._signature_get_partial(wrapped_sig, obj)
  
      // sig = None
      // if isinstance(obj, type):
      //     // obj is a class or a metaclass
  
      //     // First, let's see if it has an overloaded __call__ defined
      //     // in its metaclass
      //     call = inspect._signature_get_user_defined_method(type(obj), '__call__')
      //     if call is not None:
      //         sig = inspect._signature_internal(call,
      //                                   follow_wrapper_chains,
      //                                   skip_bound_arg)
      //     else:
      //         # Now we check if the 'obj' class has a '__new__' method
      //         new = _signature_get_user_defined_method(obj, '__new__')
      //         if new is not None:
      //             sig = inspect._signature_internal(new,
      //                                       follow_wrapper_chains,
      //                                       skip_bound_arg)
      //         else:
      //             # Finally, we should have at least __init__ implemented
      //             init = _signature_get_user_defined_method(obj, '__init__')
      //             if init is not None:
      //                 sig = inspect._signature_internal(init,
      //                                           follow_wrapper_chains,
      //                                           skip_bound_arg)
  
      //     if sig is None:
      //         # At this point we know, that `obj` is a class, with no user-
      //         # defined '__init__', '__new__', or class-level '__call__'
  
      //         for base in obj.__mro__[:-1]:
      //             # Since '__text_signature__' is implemented as a
      //             # descriptor that extracts text signature from the
      //             # class docstring, if 'obj' is derived from a builtin
      //             # class, its own '__text_signature__' may be 'None'.
      //             # Therefore, we go through the MRO (except the last
      //             # class in there, which is 'object') to find the first
      //             # class with non-empty text signature.
      //             try:
      //                 text_sig = base.__text_signature__
      //             except AttributeError:
      //                 pass
      //             else:
      //                 if text_sig:
      //                     # If 'obj' class has a __text_signature__ attribute:
      //                     # return a signature based on it
      //                     return _signature_fromstr(Signature, obj, text_sig)
  
      //         # No '__text_signature__' was found for the 'obj' class.
      //         # Last option is to check if its '__init__' is
      //         # object.__init__ or type.__init__.
      //         if type not in obj.__mro__:
      //             # We have a class (not metaclass), but no user-defined
      //             # __init__ or __new__ for it
      //             if obj.__init__ is object.__init__:
      //                 # Return a signature of 'object' builtin.
      //                 return signature(object)
  
      // elif not isinstance(obj, _NonUserDefinedCallables):
      //     # An object with __call__
      //     # We also check that the 'obj' is not an instance of
      //     # _WrapperDescriptor or _MethodWrapper to avoid
      //     # infinite recursion (and even potential segfault)
      //     call = _signature_get_user_defined_method(type(obj), '__call__')
      //     if call is not None:
      //         try:
      //             sig = _signature_internal(call,
      //                                       follow_wrapper_chains,
      //                                       skip_bound_arg)
      //         except ValueError as ex:
      //             msg = 'no signature found for {!r}'.format(obj)
      //             raise ValueError(msg) from ex
  
      // if sig is not None:
      //     # For classes and objects we skip the first parameter of their
      //     # __call__, __new__, or __init__ methods
      //     if skip_bound_arg:
      //         return _signature_bound_method(sig)
      //     else:
      //         return sig
  
      // if isinstance(obj, types.BuiltinFunctionType):
      //     # Raise a nicer error message for builtins
      //     msg = 'no signature found for builtin function {!r}'.format(obj)
      //     raise ValueError(msg)
  
      // raise ValueError('callable {!r} is not supported by signature'.format(obj))
  }
  
  /*
   * Get the names and default values of a callable object's arguments.
   *
   * A tuple of seven things is returned:
   * (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults annotations).
   * 'args' is a list of the argument names.
   * 'varargs' and 'varkw' are the names of the * and ** arguments or None.
   * 'defaults' is an n-tuple of the default values of the last n arguments.
   * 'kwonlyargs' is a list of keyword-only argument names.
   * 'kwonlydefaults' is a dictionary mapping names from kwonlyargs to defaults.
   * 'annotations' is a dictionary mapping argument names to annotations.
   *
   * The first four items in the tuple correspond to getargspec().
   */
  inspect.getfullargspec = function(func) {
      // try {
          // Re: `skip_bound_arg=false`
          //
          // There is a notable difference in behaviour between getfullargspec
          // and Signature: the former always returns 'self' parameter for bound
          // methods, whereas the Signature always shows the actual calling
          // signature of the passed object.
          //
          // To simulate this behaviour, we "unbind" bound methods, to trick
          // inspect.signature to always return their first parameter ("self",
          // usually)
  
          // Re: `follow_wrapper_chains=false`
          //
          // getfullargspec() historically ignored __wrapped__ attributes,
          // so we ensure that remains the case in 3.3+
  
      var sig = inspect._signature_internal(func, false, false)
  
      var args = []
      var varargs = null
      var varkw = null
      var kwonlyargs = []
      var defaults = []
      var annotations = {}
      var kwdefaults = {}
  
      if (sig.return_annotation.length > 0) {
          annotations['return'] = sig.return_annotation
      }
  
      for (var p in sig.parameters) {
          if (sig.parameters.hasOwnProperty(p)) {
              var param = sig.parameters[p]
  
              if (param.kind === inspect.Parameter.POSITIONAL_ONLY) {
                  args.push(param.name)
              } else if (param.kind === inspect.Parameter.POSITIONAL_OR_KEYWORD) {
                  args.push(param.name)
                  if (param.default !== undefined) {
                      defaults.push(param.default)
                  }
              } else if (param.kind === inspect.Parameter.VAR_POSITIONAL) {
                  varargs = param.name
              } else if (param.kind === inspect.Parameter.KEYWORD_ONLY) {
                  kwonlyargs.push(param.name)
                  if (param.default !== undefined) {
                      kwdefaults[param.name] = param.default
                  }
              } else if (param.kind === inspect.Parameter.VAR_KEYWORD) {
                  varkw = param.name
              }
  
              if (param.annotation !== undefined) {
                  annotations[param.name] = param.annotation
              }
          }
      }
  
      if (kwdefaults.length === 0) {
              // compatibility with 'func.__kwdefaults__'
          kwdefaults = null
      }
  
      if (defaults.length === 0) {
              // compatibility with 'func.__defaults__'
          defaults = null
      }
  
      return new inspect.FullArgSpec({
          'args': args,
          'varargs': varargs,
          'varkw': varkw,
          'defaults': defaults,
          'kwonlyargs': kwonlyargs,
          'kwdefaults': kwdefaults,
          'annotations': annotations
      })
  
      // } catch (ex) {
          // Most of the times 'signature' will raise ValueError.
          // But, it can also raise AttributeError, and, maybe something
          // else. So to be fully backwards compatible, we catch all
          // possible exceptions here, and reraise a TypeError.
          // raise TypeError('unsupported callable') from ex
          // throw TypeError('unsupported callable');
      // }
  }
  
  inspect._missing_arguments = function(f_name, argnames, pos, values) {
      throw exceptions.RuntimeError.$pyclass('Missing arguments')
      // var names = [];
      // for (var name in argnames) {
      //     if (!name in values) {
      //         names.push(name);
      //     }
      // }
      // var missing = names.length;
      // if (missing === 1) {
      //     s = names[0];
      // } else if (missing === 2) {
      //     s = "{} and {}".format(*names)
      // } else {
      //     tail = ", {} and {}".format(*names[-2:])
      //     del names[-2:]
      //     s = ", ".join(names) + tail
      // }
      // raise TypeError("%s() missing %i required %s argument%s: %s" %
      //                 (f_name, missing,
      //                   "positional" if pos else "keyword-only",
      //                   "" if missing === 1 else "s", s))
  }
  
  inspect._too_many = function(f_name, args, kwonly, varargs, defcount, given, values) {
      throw exceptions.RuntimeError.$pyclass('FIXME: Too many arguments')
      // atleast = len(args) - defcount
      // kwonly_given = len([arg for arg in kwonly if arg in values])
      // if varargs:
      //     plural = atleast !== 1
      //     sig = "at least %d" % (atleast,)
      // elif defcount:
      //     plural = True
      //     sig = "from %d to %d" % (atleast, len(args))
      // else:
      //     plural = len(args) !== 1
      //     sig = str(len(args))
      // kwonly_sig = ""
      // if kwonly_given:
      //     msg = " positional argument%s (and %d keyword-only argument%s)"
      //     kwonly_sig = (msg % ("s" if given !== 1 else "", kwonly_given,
      //                          "s" if kwonly_given !== 1 else ""))
      // raise TypeError("%s() takes %s positional argument%s but %d%s %s given" %
      //         (f_name, sig, "s" if plural else "", given, kwonly_sig,
      //          "was" if given === 1 and not kwonly_given else "were"))
  }
  
  /*
   * Get the mapping of arguments to values.
   *
   * A dict is returned, with keys the function argument names (including the
   * names of the * and ** arguments, if any), and values the respective bound
   * values from 'positional' and 'named'.
   */
  inspect.getcallargs = function(func, positional, named) {
      var arg2value = new types.JSDict()
  
      // if ismethod(func) and func.__self__ is not None:
      if (func.__self__) {
          // implicit 'self' (or 'cls' for classmethods) argument
          positional = [func.__self__].concat(positional)
      }
      var num_pos = positional.length
      var num_args = func.argspec.args.length
      var num_defaults
      if (func.argspec.defaults) {
          num_defaults = func.argspec.defaults.length
      } else {
          num_defaults = 0
      }
  
      var i, arg
      var n = Math.min(num_pos, num_args)
      for (i = 0; i < n; i++) {
          arg2value[func.argspec.args[i]] = positional[i]
      }
  
      if (func.argspec.varargs) {
          arg2value[func.argspec.varargs] = positional.slice(n)
      }
  
      var possible_kwargs = new types.Set()
      possible_kwargs.update(func.argspec.args)
      possible_kwargs.update(func.argspec.kwonlyargs)
  
      if (func.argspec.varkw) {
          arg2value[func.argspec.varkw] = {}
      }
  
      for (var kw in named) {
          if (named.hasOwnProperty(kw)) {
              if (!possible_kwargs.__contains__(new types.Str(kw)).valueOf()) {
                  if (!func.argspec.varkw) {
                      throw new exceptions.TypeError.$pyclass('%s() got an unexpected keyword argument %r' %
                                  (func.__name__, kw))
                  }
                  arg2value[func.argspec.varkw][kw] = named[kw]
                  continue
              }
              if (kw in arg2value) {
                  throw new exceptions.TypeError.$pyclass('%s() got multiple values for argument %r' %
                                  (func.__name__, kw))
              }
              arg2value[kw] = named[kw]
          }
      }
  
      if (num_pos > num_args && (func.argspec.varargs === undefined || func.argspec.varargs.length === 0)) {
          inspect._too_many(func.__name__, func.argspec.args, func.argspec.kwonlyargs, func.argspec.varargs, num_defaults, num_pos, arg2value)
      }
      if (num_pos < num_args) {
          var req = func.argspec.args.slice(0, num_args - num_defaults)
          for (arg in req) {
              if (req.hasOwnProperty(arg)) {
                  if (!(req[arg] in arg2value)) {
                      inspect._missing_arguments(func.__name__, req, true, arg2value)
                  }
              }
          }
          for (i = num_args - num_defaults; i < func.argspec.args.length; i++) {
              arg = func.argspec.args[i]
              if (!arg2value.hasOwnProperty(arg)) {
                  arg2value[arg] = func.argspec.defaults[i - num_pos]
              }
          }
      }
      var missing = 0
      for (var kwarg in func.argspec.kwonlyargs) {
          if (func.argspec.kwonlydefaults.hasOwnProperty(kwarg)) {
              if (!arg2value.hasOwnProperty(kwarg)) {
                  if (func.argspec.kwonlydefaults.hasOwnProperty(kwarg)) {
                      arg2value[kwarg] = func.argspec.kwonlydefaults[kwarg]
                  } else {
                      missing += 1
                  }
              }
          }
      }
      if (missing) {
          inspect._missing_arguments(func.__name__, func.argspec.kwonlyargs, false, arg2value)
      }
      return arg2value
  }
  
  /*
  Represents a parameter in a function signature.
  
  Has the following public attributes:
  
  * name : str
  The name of the parameter as a string.
  * default : object
  The default value for the parameter if specified.  If the
  parameter has no default value, this attribute is set to
  `Parameter.empty`.
  * annotation
  The annotation for the parameter if specified.  If the
  parameter has no annotation, this attribute is set to
  `Parameter.empty`.
  * kind : str
  Describes how argument values are bound to the parameter.
  Possible values: `Parameter.POSITIONAL_ONLY`,
  `Parameter.POSITIONAL_OR_KEYWORD`, `Parameter.VAR_POSITIONAL`,
  `Parameter.KEYWORD_ONLY`, `Parameter.VAR_KEYWORD`.
  */
  inspect.Parameter = function(kwargs) {
      this.name = kwargs.name
      this.kind = kwargs.kind
      this.annotation = kwargs.annotation
      this.default = kwargs.default
  
      // if kind not in (POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD,
      //                 _VAR_POSITIONAL, _KEYWORD_ONLY, _VAR_KEYWORD):
      //     raise ValueError("invalid value for 'Parameter.kind' attribute")
  
      // if def is not _empty:
      //     if kind in (_VAR_POSITIONAL, _VAR_KEYWORD):
      //         msg = '{} parameters cannot have def values'.format(kind)
      //         raise ValueError(msg)
  
      // if name is _empty:
      //     raise ValueError('name is a required attribute for Parameter')
  
      // if not isinstance(name, str):
      //     raise TypeError("name must be a str, not a {!r}".format(name))
  
      // if not name.isidentifier():
      //     raise ValueError('{!r} is not a valid parameter name'.format(name))
  }
  
  inspect.Parameter.POSITIONAL_ONLY = 0
  inspect.Parameter.POSITIONAL_OR_KEYWORD = 1
  inspect.Parameter.VAR_POSITIONAL = 2
  inspect.Parameter.KEYWORD_ONLY = 3
  inspect.Parameter.VAR_KEYWORD = 4
  
  //    '''Creates a customized copy of the Parameter.'''
  inspect.Parameter.prototype.replace = function(kwargs) {
      var name = kwargs.name || this.name
      var kind = kwargs.kind || this.kind
      var annotation = kwargs.annotation || this.annotation
      var def = kwargs.default || this.default
  
      return new inspect.Paramter(name, kind, def, annotation)
  }
  
  // def __str__(self):
  //     kind = self.kind
  //     formatted = self._name
  
  //     # Add annotation and default value
  //     if self._annotation is not _empty:
  //         formatted = '{}:{}'.format(formatted,
  //                                    formatannotation(self._annotation))
  
  //     if self._default is not _empty:
  //         formatted = '{}={}'.format(formatted, repr(self._default))
  
  //     if kind === _VAR_POSITIONAL:
  //         formatted = '*' + formatted
  //     elif kind === _VAR_KEYWORD:
  //         formatted = '**' + formatted
  
  //     return formatted
  
  // def __repr__(self):
  //     return '<{} at {:#x} {!r}>'.format(self.__class__.__name__,
  //                                        id(self), self.name)
  
  // def __eq__(self, other):
  //     return (issubclass(other.__class__, Parameter) and
  //             self._name === other._name and
  //             self._kind === other._kind and
  //             self._default === other._default and
  //             self._annotation === other._annotation)
  
  // def __ne__(self, other):
  //     return not self.__eq__(other)
  
  // class BoundArguments:
  //     '''Result of `Signature.bind` call.  Holds the mapping of arguments
  //     to the function's parameters.
  
  //     Has the following public attributes:
  
  //     * arguments : OrderedDict
  //         An ordered mutable mapping of parameters' names to arguments' values.
  //         Does not contain arguments' default values.
  //     * signature : Signature
  //         The Signature object that created this instance.
  //     * args : tuple
  //         Tuple of positional arguments values.
  //     * kwargs : dict
  //         Dict of keyword arguments values.
  //     '''
  
  //     def __init__(self, signature, arguments):
  //         self.arguments = arguments
  //         self._signature = signature
  
  //     @property
  //     def signature(self):
  //         return self._signature
  
  //     @property
  //     def args(self):
  //         args = []
  //         for param_name, param in self._signature.parameters.items():
  //             if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
  //                 break
  
  //             try:
  //                 arg = self.arguments[param_name]
  //             except KeyError:
  //                 # We're done here. Other arguments
  //                 # will be mapped in 'BoundArguments.kwargs'
  //                 break
  //             else:
  //                 if param.kind === _VAR_POSITIONAL:
  //                     # *args
  //                     args.extend(arg)
  //                 else:
  //                     # plain argument
  //                     args.push(arg)
  
  //         return tuple(args)
  
  //     @property
  //     def kwargs(self):
  //         kwargs = {}
  //         kwargs_started = False
  //         for param_name, param in self._signature.parameters.items():
  //             if not kwargs_started:
  //                 if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
  //                     kwargs_started = True
  //                 else:
  //                     if param_name not in self.arguments:
  //                         kwargs_started = True
  //                         continue
  
  //             if not kwargs_started:
  //                 continue
  
  //             try:
  //                 arg = self.arguments[param_name]
  //             except KeyError:
  //                 pass
  //             else:
  //                 if param.kind === _VAR_KEYWORD:
  //                     # **kwargs
  //                     kwargs.update(arg)
  //                 else:
  //                     # plain keyword argument
  //                     kwargs[param_name] = arg
  
  //         return kwargs
  
  //     def __eq__(self, other):
  //         return (issubclass(other.__class__, BoundArguments) and
  //                 self.signature === other.signature and
  //                 self.arguments === other.arguments)
  
  //     def __ne__(self, other):
  //         return not self.__eq__(other)
  
  /*
   * A Signature object represents the overall signature of a function.
  It stores a Parameter object for each parameter accepted by the
  function, as well as information specific to the function itself.
  
  A Signature object has the following public attributes and methods:
  
  * parameters : OrderedDict
      An ordered mapping of parameters' names to the corresponding
      Parameter objects (keyword-only arguments are in the same order
      as listed in `code.co_varnames`).
  * return_annotation : object
      The annotation for the return type of the function if specified.
      If the function has no annotation for its return type, this
      attribute is set to `Signature.empty`.
  * bind(*args, **kwargs) -> BoundArguments
      Creates a mapping from positional and keyword arguments to
      parameters.
  * bind_partial(*args, **kwargs) -> BoundArguments
      Creates a partial mapping from positional and keyword arguments
      to parameters (simulating 'functools.partial' behavior.)
  */
  /* Constructs Signature from the given list of Parameter
  * objects and 'return_annotation'.  All arguments are optional.
  */
  inspect.Signature = function(parameters, return_annotation, __validate_parameters__) {
      this.parameters = {}
      if (parameters !== null) {
          if (__validate_parameters__) {
              // params = OrderedDict()
              // top_kind = _POSITIONAL_ONLY
              // kind_defaults = false
  
              // for idx, param in enumerate(parameters):
              //     kind = param.kind
              //     name = param.name
  
              //     if kind < top_kind:
              //         msg = 'wrong parameter order: {!r} before {!r}'
              //         msg = msg.format(top_kind, kind)
              //         raise ValueError(msg)
              //     elif kind > top_kind:
              //         kind_defaults = false
              //         top_kind = kind
  
              //     if kind in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD):
              //         if param.default is _empty:
              //             if kind_defaults:
              //                 # No default for this parameter, but the
              //                 # previous parameter of the same kind had
              //                 # a default
              //                 msg = 'non-default argument follows default ' \
              //                       'argument'
              //                 raise ValueError(msg)
              //         else:
              //             # There is a default for this parameter.
              //             kind_defaults = True
  
              //     if name in params:
              //         msg = 'duplicate parameter name: {!r}'.format(name)
              //         raise ValueError(msg)
  
              //     params[name] = param
          } else {
              // params = OrderedDict(((param.name, param) for param in parameters));
              for (var p in parameters) {
                  if (parameters.hasOwnProperty(p)) {
                      this.parameters[parameters[p].name] = parameters[p]
                  }
              }
          }
      }
  
      this.return_annotation = return_annotation
  }
  
  // inspect.Signature._parameter_cls = Parameter;
  // inspect.Signature._bound_arguments_cls = BoundArguments;
  
  /*
  * Constructs Signature for the given python function
  */
  inspect.Signature.from_function = function(func) {
      var is_duck_function = false
      // if (!isfunction(func)) {
      //     if (_signature_is_functionlike(func)) {
      //         is_duck_function = true;
      //     } else {
      //         // If it's not a pure Python function, and not a duck type
      //         // of pure function:
      //         throw TypeError('{!r} is not a Python function'.format(func));
      //     }
      // }
  
      // Parameter = cls._parameter_cls
  
      // Parameter information.
      var func_code = func.__code__
      var pos_count = func_code.co_argcount
      var arg_names = func_code.co_varnames
      var positional = arg_names.slice(0, pos_count)
      var keyword_only_count = func_code.co_kwonlyargcount
      var keyword_only = arg_names.slice(pos_count, pos_count + keyword_only_count)
      var annotations = func.__annotations__
      var defs = func.__defaults__
      var kwdefaults = func.__kwdefaults__
  
      var pos_default_count
      if (defs) {
          pos_default_count = defs.length
      } else {
          pos_default_count = 0
      }
  
      var parameters = []
      var n, name, annotation, def, offset
  
      // Non-keyword-only parameters w/o defaults.
      var non_default_count = pos_count - pos_default_count
      for (n = 0; n < non_default_count; n++) {
          name = positional[n]
          annotation = annotations[name]
          parameters.push(new inspect.Parameter({
              'name': name,
              'annotation': annotation,
              'kind': inspect.Parameter.POSITIONAL_OR_KEYWORD
          }))
      }
  
      // ... w/ defaults.
      for (offset = 0, n = non_default_count; n < positional.length; offset++, n++) {
          name = positional[n]
          annotation = annotations[name]
          parameters.push(new inspect.Parameter({
              'name': name,
              'annotation': annotation,
              'kind': inspect.Parameter.POSITIONAL_OR_KEYWORD,
              'default': defs[offset]
          }))
      }
  
      // *args
      if (func_code.co_flags & inspect.CO_VARARGS) {
          name = arg_names[pos_count + keyword_only_count]
          annotation = annotations[name]
          parameters.push(new inspect.Parameter({
              'name': name,
              'annotation': annotation,
              'kind': inspect.Parameter.VAR_POSITIONAL
          }))
      }
  
      // Keyword-only parameters.
      for (n = 0; n < keyword_only.length; n++) {
          def = null
          if (kwdefaults !== null) {
              def = kwdefaults[name]
          }
  
          annotation = annotations[name]
          parameters.push(new inspect.Parameter({
              'name': name,
              'annotation': annotation,
              'kind': inspect.Parameter.KEYWORD_ONLY,
              'default': def
          }))
      }
  
      // **kwargs
      if (func_code.co_flags & inspect.CO_VARKEYWORDS) {
          var index = pos_count + keyword_only_count
          if (func_code.co_flags & inspect.CO_VARARGS) {
              index += 1
          }
  
          name = arg_names[index]
          annotation = annotations[name]
          parameters.push(new inspect.Parameter({
              'name': name,
              'annotation': annotation,
              'kind': inspect.Parameter.VAR_KEYWORD
          }))
      }
  
      // Is 'func' is a pure Python function - don't validate the
      // parameters list (for correct order and defaults), it should be OK.
      return new inspect.Signature(parameters, annotations['return'] || {}, is_duck_function)
  }
  
      // @classmethod
      // def from_builtin(cls, func):
      //     return _signature_from_builtin(cls, func)
  
      // def replace(self, *, parameters=_void, return_annotation=_void):
      //     '''Creates a customized copy of the Signature.
      //     Pass 'parameters' and/or 'return_annotation' arguments
      //     to override them in the new copy.
      //     '''
  
      //     if parameters is _void:
      //         parameters = self.parameters.values()
  
      //     if return_annotation is _void:
      //         return_annotation = self._return_annotation
  
      //     return type(self)(parameters,
      //                       return_annotation=return_annotation)
  
      // def __eq__(self, other):
      //     if (not issubclass(type(other), Signature) or
      //                 self.return_annotation !== other.return_annotation or
      //                 len(self.parameters) !== len(other.parameters)):
      //         return false
  
      //     other_positions = {param: idx
      //                        for idx, param in enumerate(other.parameters.keys())}
  
      //     for idx, (param_name, param) in enumerate(self.parameters.items()):
      //         if param.kind === _KEYWORD_ONLY:
      //             try:
      //                 other_param = other.parameters[param_name]
      //             except KeyError:
      //                 return false
      //             else:
      //                 if param !== other_param:
      //                     return false
      //         else:
      //             try:
      //                 other_idx = other_positions[param_name]
      //             except KeyError:
      //                 return false
      //             else:
      //                 if (idx !== other_idx or
      //                                 param !== other.parameters[param_name]):
      //                     return false
  
      //     return True
  
      // def __ne__(self, other):
      //     return not self.__eq__(other)
  
      // def _bind(self, args, kwargs, *, partial=false):
      //     '''Private method.  Don't use directly.'''
  
      //     arguments = OrderedDict()
  
      //     parameters = iter(self.parameters.values())
      //     parameters_ex = ()
      //     arg_vals = iter(args)
  
      //     while True:
      //         # Let's iterate through the positional arguments and corresponding
      //         # parameters
      //         try:
      //             arg_val = next(arg_vals)
      //         except StopIteration:
      //             # No more positional arguments
      //             try:
      //                 param = next(parameters)
      //             except StopIteration:
      //                 # No more parameters. That's it. Just need to check that
      //                 # we have no `kwargs` after this while loop
      //                 break
      //             else:
      //                 if param.kind === _VAR_POSITIONAL:
      //                     # That's OK, just empty *args.  Let's start parsing
      //                     # kwargs
      //                     break
      //                 elif param.name in kwargs:
      //                     if param.kind === _POSITIONAL_ONLY:
      //                         msg = '{arg!r} parameter is positional only, ' \
      //                               'but was passed as a keyword'
      //                         msg = msg.format(arg=param.name)
      //                         raise TypeError(msg) from None
      //                     parameters_ex = (param,)
      //                     break
      //                 elif (param.kind === _VAR_KEYWORD or
      //                                             param.default is not _empty):
      //                     # That's fine too - we have a default value for this
      //                     # parameter.  So, lets start parsing `kwargs`, starting
      //                     # with the current parameter
      //                     parameters_ex = (param,)
      //                     break
      //                 else:
      //                     # No default, not VAR_KEYWORD, not VAR_POSITIONAL,
      //                     # not in `kwargs`
      //                     if partial:
      //                         parameters_ex = (param,)
      //                         break
      //                     else:
      //                         msg = '{arg!r} parameter lacking default value'
      //                         msg = msg.format(arg=param.name)
      //                         raise TypeError(msg) from None
      //         else:
      //             # We have a positional argument to process
      //             try:
      //                 param = next(parameters)
      //             except StopIteration:
      //                 raise TypeError('too many positional arguments') from None
      //             else:
      //                 if param.kind in (_VAR_KEYWORD, _KEYWORD_ONLY):
      //                     # Looks like we have no parameter for this positional
      //                     # argument
      //                     raise TypeError('too many positional arguments')
  
      //                 if param.kind === _VAR_POSITIONAL:
      //                     # We have an '*args'-like argument, let's fill it with
      //                     # all positional arguments we have left and move on to
      //                     # the next phase
      //                     values = [arg_val]
      //                     values.extend(arg_vals)
      //                     arguments[param.name] = tuple(values)
      //                     break
  
      //                 if param.name in kwargs:
      //                     raise TypeError('multiple values for argument '
      //                                     '{arg!r}'.format(arg=param.name))
  
      //                 arguments[param.name] = arg_val
  
      //     # Now, we iterate through the remaining parameters to process
      //     # keyword arguments
      //     kwargs_param = None
      //     for param in itertools.chain(parameters_ex, parameters):
      //         if param.kind === _VAR_KEYWORD:
      //             # Memorize that we have a '**kwargs'-like parameter
      //             kwargs_param = param
      //             continue
  
      //         if param.kind === _VAR_POSITIONAL:
      //             # Named arguments don't refer to '*args'-like parameters.
      //             # We only arrive here if the positional arguments ended
      //             # before reaching the last parameter before *args.
      //             continue
  
      //         param_name = param.name
      //         try:
      //             arg_val = kwargs.pop(param_name)
      //         except KeyError:
      //             # We have no value for this parameter.  It's fine though,
      //             # if it has a default value, or it is an '*args'-like
      //             # parameter, left alone by the processing of positional
      //             # arguments.
      //             if (not partial and param.kind !== _VAR_POSITIONAL and
      //                                                 param.default is _empty):
      //                 raise TypeError('{arg!r} parameter lacking default value'. \
      //                                 format(arg=param_name)) from None
  
      //         else:
      //             if param.kind === _POSITIONAL_ONLY:
      //                 # This should never happen in case of a properly built
      //                 # Signature object (but let's have this check here
      //                 # to ensure correct behaviour just in case)
      //                 raise TypeError('{arg!r} parameter is positional only, '
      //                                 'but was passed as a keyword'. \
      //                                 format(arg=param.name))
  
      //             arguments[param_name] = arg_val
  
      //     if kwargs:
      //         if kwargs_param is not None:
      //             // Process our '**kwargs'-like parameter
      //             arguments[kwargs_param.name] = kwargs
      //         else:
      //             raise TypeError('too many keyword arguments')
  
      //     return self._bound_arguments_cls(self, arguments)
  
      // def bind(*args, **kwargs):
      //     '''Get a BoundArguments object, that maps the passed `args`
      //     and `kwargs` to the function's signature.  Raises `TypeError`
      //     if the passed arguments can not be bound.
      //     '''
      //     return args[0]._bind(args[1:], kwargs)
  
      // def bind_partial(*args, **kwargs):
      //     '''Get a BoundArguments object, that partially maps the
      //     passed `args` and `kwargs` to the function's signature.
      //     Raises `TypeError` if the passed arguments can not be bound.
      //     '''
      //     return args[0]._bind(args[1:], kwargs, partial=True)
  
      // def __str__(self):
      //     result = []
      //     render_pos_only_separator = false
      //     render_kw_only_separator = True
      //     for param in self.parameters.values():
      //         formatted = str(param)
  
      //         kind = param.kind
  
      //         if kind === _POSITIONAL_ONLY:
      //             render_pos_only_separator = True
      //         elif render_pos_only_separator:
      //             # It's not a positional-only parameter, and the flag
      //             # is set to 'True' (there were pos-only params before.)
      //             result.push('/')
      //             render_pos_only_separator = false
  
      //         if kind === _VAR_POSITIONAL:
      //             # OK, we have an '*args'-like parameter, so we won't need
      //             # a '*' to separate keyword-only arguments
      //             render_kw_only_separator = false
      //         elif kind === _KEYWORD_ONLY and render_kw_only_separator:
      //             # We have a keyword-only parameter to render and we haven't
      //             # rendered an '*args'-like parameter before, so add a '*'
      //             # separator to the parameters list ("foo(arg1, *, arg2)" case)
      //             result.push('*')
      //             # This condition should be only triggered once, so
      //             # reset the flag
      //             render_kw_only_separator = false
  
      //         result.push(formatted)
  
      //     if render_pos_only_separator:
      //         # There were only positional-only parameters, hence the
      //         # flag was not reset to 'false'
      //         result.push('/')
  
      //     rendered = '({})'.format(', '.join(result))
  
      //     if self.return_annotation is not _empty:
      //         anno = formatannotation(self.return_annotation)
      //         rendered += ' -> {}'.format(anno)
  
      //     return rendered
  
  module.exports = inspect
  