text:
"""
Common constants, classes and functions used across GoLismero.
"""

__license__ = """
GoLismero 2.0 - The web knife - Copyright (C) 2011-2014

Golismero project site: https://github.com/golismero
Golismero project mail: contact@golismero-project.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
"""

__all__ = [

    # Dynamically loaded modules, picks the fastest one available.
    "pickle", "random", "json_encode", "json_decode",

    # Helper functions.
    "get_user_settings_folder", "get_default_config_file",
    "get_default_user_config_file", "get_default_plugins_folder",
    "get_data_folder", "get_wordlists_folder",
    "get_install_folder", "get_tools_folder",
    "get_profiles_folder", "get_profile", "get_available_profiles",

    # Helper classes and decorators.
    "Singleton", "decorator", "export_methods_as_functions",
    "EmptyNewStyleClass",

    # Configuration objects.
    "OrchestratorConfig", "AuditConfig"
]

# Load the fast C version of pickle,
# if not available use the pure-Python version.
try:
    import cPickle as pickle
except ImportError:
    import pickle

# Import @decorator from the decorator module, if available.
# Otherwise define a simple but crude replacement.
try:
    from decorator import decorator
except ImportError:
    import functools
    def decorator(w):
        """
        The decorator module was not found. You can install it from:
        http://pypi.python.org/pypi/decorator/
        """
        def d(fn):
            @functools.wraps(fn)
            def x(*args, **kwargs):
                return w(fn, *args, **kwargs)
            return x
        return d

try:
    # The fastest JSON parser available for Python.
    from cjson import decode as json_decode
    from cjson import encode as json_encode
except ImportError:
    try:
        # Faster than the built-in module, usually found.
        from simplejson import loads as json_decode
        from simplejson import dumps as json_encode
    except ImportError:
        # Built-in module since Python 2.6, very very slow!
        from json import loads as json_decode
        from json import dumps as json_encode

# Other imports.
from netaddr import IPNetwork
from ConfigParser import RawConfigParser
from keyword import iskeyword
from os import path

import os
import random  #noqa
import sys

# Remove the docstrings. This prevents errors when generating the API docs.
try:
    json_encode.__doc__ = ""
except Exception:
    _orig_json_encode = json_encode
    def json_encode(*args, **kwargs):
        return _orig_json_encode(*args, **kwargs)
try:
    json_decode.__doc__ = ""
except Exception:
    _orig_json_decode = json_decode
    def json_decode(*args, **kwargs):
        return _orig_json_decode(*args, **kwargs)

#------------------------------------------------------------------------------
# Helper class for instance creation without calling __init__().
class EmptyNewStyleClass (object):
    pass

#------------------------------------------------------------------------------
_user_settings_folder = None
def get_user_settings_folder():
    """
    Get the current user's GoLismero settings folder.

    This folder will be used to store the various caches
    and the user-defined plugins.

    :returns: GoLismero settings folder.
    :rtype: str
    """

    # TODO: on Windows, use the roaming data folder instead.

    # Return the cached value if available.
    global _user_settings_folder
    if _user_settings_folder:
        return _user_settings_folder

    # Get the user's home folder.
    home = os.getenv("HOME")              # Unix
    if not home:
        home = os.getenv("USERPROFILE")   # Windows

        # If all else fails, use the current directory.
        if not home:
            home = os.getcwd()

    # Get the user settings folder.
    folder = path.join(home, ".golismero")

    # Make sure it ends with a slash.
    if not folder.endswith(path.sep):
        folder += path.sep

    # Make sure it exists.
    try:
        os.makedirs(folder)
    except Exception:
        pass

    # Cache the folder.
    _user_settings_folder = folder

    # Return the folder.
    return folder

#------------------------------------------------------------------------------
def get_default_config_file():
    """
    :returns:
        Pathname of the default configuration file,
        or None if it doesn't exist.
    :rtype: str | None
    """
    config_file = path.split(path.abspath(__file__))[0]
    config_file = path.join(config_file, "..", "golismero.conf")
    config_file = path.abspath(config_file)
    if not path.isfile(config_file):
        if path.sep == "/" and path.isfile("/etc/golismero.conf"):
            config_file = "/etc/golismero.conf"
        else:
            config_file = None
    return config_file

#------------------------------------------------------------------------------
def get_default_user_config_file():
    """
    :returns:
        Pathname of the default per-user configuration file,
        or None if it doesn't exist.
    :rtype: str | None
    """
    config_file = path.join(get_user_settings_folder(), "user.conf")
    if not path.isfile(config_file):
        config_file = path.split(path.abspath(__file__))[0]
        config_file = path.join(config_file, "..", "user.conf")
        config_file = path.abspath(config_file)
        if not path.isfile(config_file):
            config_file = None
    return config_file

#------------------------------------------------------------------------------
_install_folder = None
def get_install_folder():
    """
    :returns: Pathname of the install folder.
    :rtype: str
    """
    global _install_folder
    if not _install_folder:
        pathname = path.split(path.abspath(__file__))[0]
        pathname = path.join(pathname, "..")
        pathname = path.abspath(pathname)
        _install_folder = pathname
    return _install_folder

#------------------------------------------------------------------------------
def get_tools_folder():
    """
    :returns: Pathname of the bundled tools folder.
    :rtype: str
    """
    return path.join(get_install_folder(), "tools")

#------------------------------------------------------------------------------
def get_wordlists_folder():
    """
    :returns: Pathname of the wordlists folder.
    :rtype: str
    """
    return path.join(get_install_folder(), "wordlist")

#------------------------------------------------------------------------------
def get_data_folder():
    """
    :returns: Pathname of the data folder.
    :rtype: str
    """
    return path.join(get_install_folder(), "data")

#------------------------------------------------------------------------------
def get_default_plugins_folder():
    """
    :returns: Default location for the plugins folder.
    :rtype: str
    """
    return path.join(get_install_folder(), "plugins")

#------------------------------------------------------------------------------
def get_profiles_folder():
    """
    :returns: Pathname of the profiles folder.
    :rtype: str
    """
    return path.join(get_install_folder(), "profiles")

#------------------------------------------------------------------------------
def get_profile(name):
    """
    Get the profile configuration file for the requested profile name.

    :param name: Name of the profile.
    :type name: str

    :returns: Pathname of the profile configuration file.
    :rtype: str

    :raises ValueError: The name was invalid, or the profile was not found.
    """

    # Trivial case.
    if not name:
        raise ValueError("No profile name given")

    # Get the profiles folder.
    profiles = get_profiles_folder()

    # Get the filename for the requested profile.
    filename = path.abspath(path.join(profiles, name + ".profile"))

    # Check if it's outside the profiles folder or it doesn't exist.
    if not profiles.endswith(path.sep):
        profiles += path.sep
    if not filename.startswith(profiles) or not path.isfile(filename):
        raise ValueError("Profile not found: %r" % name)

    # Return the filename.
    return filename

#------------------------------------------------------------------------------
def get_available_profiles():
    """
    :returns: Available profiles.
    :rtype: set(str)
    """
    profiles_folder = get_profiles_folder()
    if not profiles_folder or not path.isdir(profiles_folder):
        return set()
    return {
        path.splitext(name)[0]
        for name in os.listdir(profiles_folder)
        if name.endswith(".profile")
    }

#------------------------------------------------------------------------------
class Singleton (object):
    """
    Implementation of the Singleton pattern.
    """

    # Variable where we keep the instance.
    _instance = None

    def __new__(cls):

        # If the singleton has already been instanced, return it.
        if cls._instance is not None:
            return cls._instance

        # Create the singleton's instance.
        cls._instance = super(Singleton, cls).__new__(cls)

        # Call the constructor.
        cls.__init__(cls._instance)

        # Delete the constructor so it won't be called again.
        cls._instance.__init__ = object.__init__
        cls.__init__ = object.__init__

        # Return the instance.
        return cls._instance

#------------------------------------------------------------------------------
def export_methods_as_functions(singleton, module):
    """
    Export all methods from a Singleton instance as bare functions of a module.

    :param singleton: Singleton instance to export.
    :type singleton: Singleton

    :param module: Target module name.
        This would typically be \\_\\_name\\_\\_.
    :type module: str

    :raises KeyError: No module with that name is loaded.
    """
    # TODO: maybe take the module name as input instead,
    # and pull everything else from sys.modules.
    clazz = singleton.__class__
    module_obj = sys.modules[module]
    try:
        exports = module_obj.__all__
    except AttributeError:
        exports = module_obj.__all__ = []
    for name in dir(clazz):
        if name[0] != "_":
            unbound = getattr(clazz, name)
            if callable(unbound) and not isinstance(unbound, property):
                bound = getattr(singleton, name)
                setattr(module_obj, name, bound)
                if name not in exports:
                    exports.append(name)

#------------------------------------------------------------------------------
class Configuration (object):
    """
    Generic configuration class.
    """

    #--------------------------------------------------------------------------
    # The logic in configuration classes is always:
    # - Checking options without fixing them is done in check_params().
    # - Sanitizing (fixing) options is done in parsers or in property setters.
    # - For each source, there's a "from_*" method. They add to the
    #   current options rather than overwriting them completely.
    #   This allows options to be read from multiple sources.

    #--------------------------------------------------------------------------
    # Here's where subclasses define the options.
    #
    # It's a dictionary of tuples of the following format:
    #
    #   name: ( parser, default )
    #
    # Where "name" is the option name, "parser" is an optional
    # callback to parse the input values, and "default" is an
    # optional default value.
    #
    # If no parser is given, the values are preserved when set.
    #
    # Example:
    #    class MySettings(Configuration):
    #      _settings_  = {
    #         "verbose": (int, 0), # A complete definition.
    #         "output_file": str,  # Omitting the default value (None is used).
    #         "data": None,        # Omitting the parser too.
    #      }
    #
    _settings_ = dict()

    # This is a set of properties that may not be loaded from a config file.
    # They will still be loaded from objects, dictionaries, JSON, etc.
    _forbidden_ = set()

    #--------------------------------------------------------------------------
    # Some helper parsers.

    @staticmethod
    def string(x):
        if x is None:
            return None
        if isinstance(x, unicode):
            return x.encode("UTF-8")
        return str(x)

    @staticmethod
    def integer(x):
        if type(x) in (int, long):
            return x
        return int(x, 0) if x else 0

    @staticmethod
    def integer_or_none(x):
        if x is None or (hasattr(x, "lower") and
                                 x.lower() in ("", "none", "inf", "infinite")):
            return None
        return Configuration.integer(x)

    @staticmethod
    def float(x):
        return float(x) if x else 0.0

    @staticmethod
    def comma_separated_list(x):
        if not x:
            return []
        if isinstance(x, str):
            return [t.strip() for t in x.split(",")]
        if isinstance(x, unicode):
            return [t.strip().encode("UTF-8") for t in x.split(u",")]
        return list(x)

    @staticmethod
    def boolean(x):
        if not x:
            return False
        if x is True:
            return x
        if hasattr(x, "lower"):
            return {
                "enabled": True,        # True
                "enable": True,
                "true": True,
                "yes": True,
                "y": True,
                "1": True,
                "disabled": False,      # False
                "disable": False,
                "false": False,
                "no": False,
                "f": False,
                "0": False,
            }.get(x.lower(), bool(x))
        return bool(x)

    @staticmethod
    def trinary(x):
        if x in (None, True, False):
            return x
        if not hasattr(x, "lower"):
            raise ValueError(
                "Trinary values only accept True, False and None")
        try:
            return {
                "enabled": True,        # True
                "enable": True,
                "true": True,
                "yes": True,
                "y": True,
                "1": True,
                "disabled": False,      # False
                "disable": False,
                "false": False,
                "no": False,
                "f": False,
                "0": False,
                "default": None,        # None
                "def": None,
                "none": None,
                "maybe": None,
                "?": None,
                "-1": None,
            }[x.lower()]
        except KeyError:
            raise ValueError("Unknown value: %r" % x)

    #--------------------------------------------------------------------------
    def __init__(self):
        history = set()
        for name, definition in self._settings_.iteritems():
            if name in history:
                raise SyntaxError("Duplicated option name: %r" % name)
            history.add(name)
            if type(definition) not in (tuple, list):
                definition = (definition, None)
            self.__init_option(name, *definition)

    #--------------------------------------------------------------------------
    def __init_option(self, name, parser = None, default = None):
        if name.endswith("_") or not name.replace("_", "").isalnum():
            msg = "Option name %r is not a valid Python identifier"
            raise SyntaxError(msg % name)
        if iskeyword(name):
            msg = "Option name %r is a Python reserved keyword"
            raise SyntaxError(msg % name)
        if name.startswith("__"):
            msg = "Option name %r is a private Python identifier"
            raise SyntaxError(msg % name)
        if name.startswith("_"):
            msg = "Option name %r is a protected Python identifier"
            raise SyntaxError(msg % name)
        if parser is not None and not callable(parser):
            msg = "Option parser cannot be of type %s"
            raise SyntaxError(msg % type(parser))
        setattr(self, name, default)

    #--------------------------------------------------------------------------
    def __setattr__(self, name, value):
        if not name.startswith("_"):
            definition = self._settings_.get(name, (None, None))
            if type(definition) not in (tuple, list):
                definition = (definition, None)
            parser = definition[0]
            if parser is not None:
                value = parser(value)
        object.__setattr__(self, name, value)

    #--------------------------------------------------------------------------
    def check_params(self):
        """
        Check if parameters are valid. Raises an exception otherwise.

        This method only checks the validity of the arguments,
        it won't modify them.

        :raises ValueError: The parameters are incorrect.
        """
        return

    #--------------------------------------------------------------------------
    def from_dictionary(self, args):
        """
        Get the settings from a Python dictionary.

        :param args: Settings.
        :type args: dict(str -> \\*)
        """
        for name, value in args.iteritems():
            if name in self._settings_:
                setattr(self, name, value)

    #--------------------------------------------------------------------------
    def from_object(self, args):
        """
        Get the settings from the attributes of a Python object.

        :param args:
            Python object,
            for example the command line arguments parsed by argparse.
        :type args: object
        """

        # Builds a dictionary with the object's public attributes.
        args = {
            k : getattr(args, k)
            for k in dir(args) if not k.startswith("_")
        }

        # Remove all attributes whose values are None.
        args = { k:v for k,v in args.iteritems() if v is not None }

        # Extract the settings from the dictionary.
        if args:
            self.from_dictionary(args)

    #--------------------------------------------------------------------------
    def from_json(self, json_raw_data):
        """
        Get the settings from a JSON encoded dictionary.

        :param json_raw_data: JSON raw data.
        :type json_raw_data: str
        """

        # Converts the JSON data into a dictionary.
        args = json_decode(json_raw_data)
        if not isinstance(args, dict):
            raise TypeError("Invalid JSON data")

        # Extract the settings from the dictionary.
        if args:
            self.from_dictionary(args)

    #--------------------------------------------------------------------------
    def from_config_file(self, config_file, allow_profile = False):
        """
        Get the settings from a configuration file.

        :param config_file: Configuration file.
        :type config_file: str

        :param allow_profile: True to allow reading the profile name
            from the config file, False to forbid it. Global config
            files should allow setting a default profile, but profile
            config files should not, as it wouldn't make sense.
        """
        parser = RawConfigParser()
        parser.read(config_file)
        if parser.has_section("golismero"):
            options = { k:v for k,v in parser.items("golismero") if v }
            if "profile" in options:
                if allow_profile:
                    self.profile = options["profile"]
                    self.profile_file = get_profile(self.profile)
                else:
                    del options["profile"]
            for k in self._forbidden_:
                if k in options:
                    del options[k]
            if options:
                self.from_dictionary(options)

    #--------------------------------------------------------------------------
    def to_dictionary(self):
        """
        Copy the settings to a Python dictionary.

        :returns: Dictionary that maps the setting names to their values.
        :rtype: dict(str -> \\*)
        """
        result = {}
        for name, definition in self._settings_.iteritems():
            default = None
            if type(definition) in (tuple, list) and len(definition) > 1:
                default = definition[1]
            value = getattr(self, name, default)
            result[name] = value
        return result

    #--------------------------------------------------------------------------
    def to_json(self):
        """
        Copy the settings to a JSON encoded dictionary.

        :returns: Settings as a JSON encoded dictionary.
        :rtype: str
        """

        # Extract the settings to a dictionary and encode it with JSON.
        return json_encode( self.to_dictionary() )

#------------------------------------------------------------------------------
class OrchestratorConfig (Configuration):
    """
    Orchestrator configuration object.
    """

    #--------------------------------------------------------------------------
    # The options definitions, they will be read from the config file:
    #
    _forbidden_ = set((  # except for these:
        "config_file", "user_config_file",
        "profile_file", "plugin_args", "ui_mode",
    ))
    _settings_ = {

        #
        # Main options.
        #

        # UI mode.
        "ui_mode": (str, "console"),

        # Verbosity level.
        "verbose": (Configuration.integer, 2),

        # Colorize console?
        "color": (Configuration.boolean, False),

        #
        # Plugin options.
        #

        # Enabled plugins.
        "enable_plugins": (Configuration.comma_separated_list, ["all"]),

        # Disabled plugins.
        "disable_plugins": (Configuration.comma_separated_list, []),

        # Plugins folder.
        "plugins_folder": Configuration.string,

        # Maximum number plugins to execute concurrently.
        "max_concurrent": (Configuration.integer, 4),

        #
        # Network options.
        #

        # Maximum number of connections per host.
        "max_connections": (Configuration.integer, 20),

        # Use persistent cache?
        "use_cache_db": (Configuration.boolean, True),

        # When run as a service.
        "listen_address": Configuration.string,
        "listen_port": Configuration.integer,
        "server_push": Configuration.string,
    }

    #--------------------------------------------------------------------------
    # Options that are only set in runtime, not loaded from the config file.

    # Configuration files.
    config_file      = get_default_config_file()
    user_config_file = get_default_user_config_file()

    # Profile.
    profile      = None
    profile_file = None

    # Plugin arguments.
    plugin_args  = dict()   # plugin_id -> key -> value

    #--------------------------------------------------------------------------

    @staticmethod
    def _load_profile(self, args):
        if "profile" in args:
            self.profile = args["profile"]
            if isinstance(self.profile, unicode):
                self.profile = self.profile.encode("UTF-8")
            self.profile_file = get_profile(self.profile)

    @staticmethod
    def _load_plugin_args(self, args):
        if "plugin_args" in args:
            plugin_args = {}
            for (plugin_id, target_args) in args["plugin_args"].iteritems():
                if isinstance(plugin_id, unicode):
                    plugin_id = plugin_id.encode("UTF-8")
                if not plugin_id in plugin_args:
                    plugin_args[plugin_id] = {}
                for (key, value) in target_args.iteritems():
                    if isinstance(key, unicode):
                        key = key.encode("UTF-8")
                    if isinstance(value, unicode):
                        value = value.encode("UTF-8")
                    plugin_args[plugin_id][key] = value
            self.plugin_args = plugin_args

    def from_dictionary(self, args):
        # Security note: do not copy config filenames!
        # See the _forbidden_ property.
        super(OrchestratorConfig, self).from_dictionary(args)
        self._load_profile(self, args)      # "self" is twice on purpose!
        self._load_plugin_args(self, args)  # don't change it or it breaks

    def to_dictionary(self):
        result = super(OrchestratorConfig, self).to_dictionary()
        result["config_file"]      = self.config_file
        result["user_config_file"] = self.user_config_file
        result["profile"]          = self.profile
        result["profile_file"]     = self.profile_file
        result["plugin_args"]      = self.plugin_args
        return result

    #--------------------------------------------------------------------------
    def check_params(self):

        # Validate the network connections limit.
        if self.max_connections < 1:
            raise ValueError(
                "Number of connections must be greater than 0,"
                " got %i." % self.max_connections)

        # Validate the number of concurrent processes.
        if self.max_concurrent < 0:
            raise ValueError(
                "Number of processes cannot be a negative number,"
                " got %i." % self.max_concurrent)

        # Validate the list of plugins.
        if not self.enable_plugins:
            raise ValueError("No plugins selected for execution.")
        if set(self.enable_plugins).intersection(self.disable_plugins):
            raise ValueError(
                "Conflicting plugins selection, aborting execution.")

#------------------------------------------------------------------------------
class AuditConfig (Configuration):
    """
    Audit configuration object.
    """

    #--------------------------------------------------------------------------
    # The options definitions, they will be read from the config file:
    #
    _forbidden = set(( # except for these:
        "config_file", "user_config_file", "profile_file", "plugin_args",
        "plugin_load_overrides", "command",
    ))
    _settings_ = {

        #
        # Main options
        #

        # Targets
        "targets": (Configuration.comma_separated_list, []),

        #
        # Report options
        #

        # Output files
        "reports": (Configuration.comma_separated_list, []),

        # Only display vulnerabilities
        "only_vulns": (Configuration.trinary, None),

        #
        # Audit options
        #

        # Audit name
        "audit_name": Configuration.string,

        # Audit database
        "audit_db": (None, ":memory:"),

        # Input files
        "imports": (Configuration.comma_separated_list, []),

        # Redo the audit?
        "redo": (Configuration.boolean, False),

        #
        # Plugin options
        #

        # Enabled plugins
        "enable_plugins": (Configuration.comma_separated_list, ["all"]),

        # Disabled plugins
        "disable_plugins": (Configuration.comma_separated_list, []),

        # Plugin execution timeout
        "plugin_timeout": (Configuration.float, 3600.0),

        #
        # Network options
        #

        # Include subdomains?
        "include_subdomains": (Configuration.boolean, True),

        # Include parent folders?
        "allow_parent": (Configuration.boolean, True),

        # Depth level for spider
        "depth": (Configuration.integer_or_none, 1),

        # Limits
        "max_links" : (Configuration.integer, 0), # 0 -> infinite

        # Follow redirects
        "follow_redirects": (Configuration.boolean, True),

        # Follow a redirection on the target URL itself,
        # regardless of "follow_redirects"
        "follow_first_redirect": (Configuration.boolean, True),

        # Proxy options
        "proxy_addr": Configuration.string,
        "proxy_port": Configuration.integer,
        "proxy_user": Configuration.string,
        "proxy_pass": Configuration.string,

        # Cookie
        "cookie": Configuration.string,

        # User Agent
        "user_agent": Configuration.string,
    }

    #--------------------------------------------------------------------------
    # Options that are only set in runtime, not loaded from the config file.

    # Configuration files.
    config_file      = get_default_config_file()
    user_config_file = get_default_user_config_file()

    # Profiles.
    profile      = None
    profile_file = None

    # Plugin arguments.
    plugin_args = None   # list of (plugin_id, key, value)

    # Plugin load overrides.
    plugin_load_overrides = None

    # Command to run.
    command = "SCAN"

    #--------------------------------------------------------------------------
    def from_dictionary(self, args):

        # Security note: do not copy config filenames!
        # See the _forbidden_ property.
        super(AuditConfig, self).from_dictionary(args)
        OrchestratorConfig._load_profile(self, args) # not a filename
        OrchestratorConfig._load_plugin_args(self, args)

        # Load the "command" property.
        if "command" in args:
            self.command = args["command"]
            if isinstance(self.command, unicode):
                self.command = self.command.encode("UTF-8")

        # Load the "plugin_load_overrides" property.
        if "plugin_load_overrides" in args:
            if not self.plugin_load_overrides:
                self.plugin_load_overrides = []
            for (val, plugin_id) in args["plugin_load_overrides"]:
                self.plugin_load_overrides.append((bool(val), str(plugin_id)))

    #--------------------------------------------------------------------------
    def to_dictionary(self):
        result = super(AuditConfig, self).to_dictionary()
        result["config_file"]           = self.config_file
        result["user_config_file"]      = self.user_config_file
        result["profile"]               = self.profile
        result["profile_file"]          = self.profile_file
        result["plugin_args"]           = self.plugin_args
        result["command"]               = self.command
        result["plugin_load_overrides"] = self.plugin_load_overrides
        return result

    #--------------------------------------------------------------------------

    @property
    def targets(self):
        return self._targets

    @targets.setter
    def targets(self, targets):
        # Always append, never overwrite.
        # Fix target URLs if the scheme part is missing.

        # Make sure self._targets contains a list.
        self._targets = getattr(self, "_targets", [])

        # Ignore the trivial case.
        if not targets:
            return

        # Strip whitespace.
        targets = [
            x.strip()
            for x in targets
            if x not in self._targets
        ]

        # Remove duplicates.
        targets = [
            x
            for x in set(targets)
            if x not in self._targets
        ]

        # Encode all Unicode strings as UTF-8.
        targets = [
            x.encode("UTF-8") if isinstance(x, unicode) else str(x)
            for x in targets
            if x not in self._targets
        ]

        # Detect network ranges, like 30.30.30.0/24, and get all IPs on it.
        parsed_targets = []
        for host in targets:

            # Try to parse the address as a network range.
            try:
                tmp_target = IPNetwork(host)
            except:
                parsed_targets.append(host)
                continue

            # If it's a range, iterate it and get all IP addresses.
            # If it's a single IP address, just add it.
            if tmp_target.size != 1:
                parsed_targets.extend(
                    str(x) for x in tmp_target.iter_hosts()
                )
            else:
                parsed_targets.append( str(tmp_target.ip) )

        # Add the new targets.
        self._targets.extend(parsed_targets)

    @targets.deleter
    def targets(self):
        self._targets = []

    #--------------------------------------------------------------------------

    @property
    def imports(self):
        return self._imports

    @imports.setter
    def imports(self, imports):
        # Always append, never overwrite.
        self._imports = getattr(self, "_imports", [])
        if imports:
            self._imports.extend( (str(x) if x else None) for x in imports )

    #--------------------------------------------------------------------------

    @property
    def reports(self):
        return self._reports

    @reports.setter
    def reports(self, reports):
        # Always append, never overwrite.
        self._reports = getattr(self, "_reports", [])
        if reports:
            self._reports.extend( (str(x) if x else None) for x in reports )

    #--------------------------------------------------------------------------

    @property
    def audit_db(self):
        return self._audit_db

    @audit_db.setter
    def audit_db(self, audit_db):
        if (
            not audit_db or not audit_db.strip() or
            audit_db.strip().lower() == ":auto:"
        ):
            audit_db = ":auto:"
        elif audit_db.strip().lower() == ":memory:":
            audit_db = ":memory:"
        self._audit_db = audit_db

    #--------------------------------------------------------------------------

    @property
    def user_agent(self):
        return self._user_agent

    @user_agent.setter
    def user_agent(self, user_agent):
        if user_agent:
            if isinstance(user_agent, unicode):
                user_agent = user_agent.encode("UTF-8")
            self._user_agent = user_agent
        else:
            self._user_agent = None

    #--------------------------------------------------------------------------

    @property
    def cookie(self):
        return self._cookie

    @cookie.setter
    def cookie(self, cookie):
        if cookie:
            # Parse the cookies argument.
            try:
                if isinstance(cookie, unicode):
                    cookie = cookie.encode("UTF-8")
                # Prepare cookie.
                cookie = cookie.replace(" ", "").replace("=", ":")
                # Remove 'Cookie:' start, if exits.
                if cookie.startswith("Cookie:"):
                    cookie = cookie[len("Cookie:"):]
                # Split.
                cookie = cookie.split(";")
                # Parse.
                cookie = { c.split(":")[0]:c.split(":")[1] for c in cookie}
            except ValueError:
                raise ValueError(
                    "Invalid cookie format specified."
                    " Use this format: 'Key=value; key=value'.")
        else:
            cookie = None
        self._cookie = cookie

    #--------------------------------------------------------------------------

    @property
    def proxy_addr(self):
        return self._proxy_addr

    @proxy_addr.setter
    def proxy_addr(self, proxy_addr):
        if proxy_addr:
            proxy_addr = proxy_addr.strip()
            if isinstance(proxy_addr, unicode):
                proxy_addr = proxy_addr.encode("UTF-8")
            if ":" in proxy_addr:
                proxy_addr, proxy_port = proxy_addr.split(":", 1)
                proxy_addr = proxy_addr.strip()
                proxy_port = proxy_port.strip()
                self.proxy_port = proxy_port
            self._proxy_addr = proxy_addr
        else:
            self._proxy_addr = None

    #--------------------------------------------------------------------------

    @property
    def proxy_port(self):
        return self._proxy_port

    @proxy_port.setter
    def proxy_port(self, proxy_port):
        if proxy_port:
            self._proxy_port = int(proxy_port)
            if self._proxy_port < 1 or self._proxy_port > 65534:
                raise ValueError(
                    "Invalid proxy port number: %d" % self._proxy_port)
        else:
            self._proxy_port = None

    #--------------------------------------------------------------------------
    def check_params(self):

        # Validate the list of plugins.
        if not self.enable_plugins:
            raise ValueError(
                "No plugins selected for execution.")
        if set(self.enable_plugins).intersection(self.disable_plugins):
            raise ValueError(
                "Conflicting plugins selection, aborting execution.")

        # Validate the recursion depth.
        if self.depth is not None and self.depth < 0:
            raise ValueError(
                "Spidering depth can't be negative: %r" % self.depth)
        if self.depth is not None and self.depth == 0:
            raise ValueError(
                "Spidering depth can't be zero (nothing would be done!)")

    #--------------------------------------------------------------------------
    def is_new_audit(self):
        """
        Determine if this is a brand new audit.

        :returns: True if this is a new audit, False if it's an old audit.
        :rtype: bool
        """

        # Memory databases are always new audits.
        if (
            not self.audit_db or not self.audit_db.strip() or
            self.audit_db.strip().lower() == ":memory:"
        ):
            self.audit_db = ":memory:"
            return True

        # SQLite databases are new audits if the file doesn't exist.
        # If we have no filename, use the audit name.
        # If we don't have that either it's a new audit.
        filename = self.audit_db
        if not filename:
            filename = self.audit_name + ".db"
            if not filename:
                return True
        return not path.exists(filename)


text:
A `<Video>` component for react-native, forked from https://github.com/react-native-community/react-native-video

Limited scope video component for Android and iOS:
- No DRM
- Only iOS and Android
- Remote video and Local media sources are the priority
- Expansion files not supported
- Only ExoPlayer and native iOS player support
- Only supports hls (and dash - Android Only)

Requires react-native >= 0.50.0, no backward compatibility.

### Add it to your project

Run `yarn add react-native-video`

#### iOS

Run `react-native link` to link the react-native-video library.

If you would like to allow other apps to play music over your video component, add:

**AppDelegate.m**

```objective-c
#import <AVFoundation/AVFoundation.h>  // import

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  ...
  [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];  // allow
  ...
}
```

#### Android

Run `react-native link` to link the react-native-video library.

Or if you have trouble, make the following additions to the given files manually:

**android/settings.gradle**

```
include ':react-native-video'
project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android-exoplayer')
```

**android/app/build.gradle**

```
dependencies {
   ...
   compile project(':react-native-video')
}
```

**MainApplication.java** (react-native >= 0.29.0)

On top, where imports are:

```java
import com.brentvatne.react.ReactVideoPackage;
```

Under `.addPackage(new MainReactPackage())`:

```java
.addPackage(new ReactVideoPackage())
```

## Usage

```javascript
// Within your render function, assuming you have a file called
// "background.mp4" in your project. You can include multiple videos
// on a single screen if you like.

<Video source={{uri: "background"}}   // Can be a URL or a local file.
       ref={(ref) => {
         this.player = ref
       }}                                      // Store reference
       rate={1.0}                              // 0 is paused, 1 is normal.
       volume={1.0}                            // 0 is muted, 1 is normal.
       muted={false}                           // Mutes the audio entirely.
       paused={false}                          // Pauses playback entirely.
       resizeMode="cover"                      // Fill the whole screen at aspect ratio.*
       repeat={true}                           // Repeat forever.
       playInBackground={false}                // Audio continues to play when app entering background.
       playWhenInactive={false}                // [iOS] Video continues to play when control or notification center are shown.
       progressUpdateInterval={250.0}          // [iOS] Interval to fire onProgress (default to ~250ms)
       onLoadStart={this.loadStart}            // Callback when video starts to load
       onLoad={this.setDuration}               // Callback when video loads
       onProgress={this.setTime}               // Callback every ~250ms with currentTime
       onEnd={this.onEnd}                      // Callback when playback finishes
       onError={this.videoError}               // Callback when video cannot be loaded
       onBuffer={this.onBuffer}                // Callback when remote video is buffering
       onTimedMetadata={this.onTimedMetadata}  // Callback when the stream receive some metadata
       style={styles.backgroundVideo} />

// Later to trigger fullscreen
this.player.presentFullscreenPlayer()

// To set video position in seconds (seek)
this.player.seek(0)

// Later on in your styles..
var styles = StyleSheet.create({
  backgroundVideo: {
    position: 'absolute',
    top: 0,
    left: 0,
    bottom: 0,
    right: 0,
  },
});
```

- * *For iOS you also need to specify muted for this to work*

### Load files with the RN Asset System

The asset system [introduced in RN `0.14`](http://www.reactnative.com/react-native-v0-14-0-released/) allows loading image resources shared across iOS and Android without touching native code. As of RN `0.31` [the same is true](https://github.com/facebook/react-native/commit/91ff6868a554c4930fd5fda6ba8044dbd56c8374) of mp4 video assets for Android. As of [RN `0.33`](https://github.com/facebook/react-native/releases/tag/v0.33.0) iOS is also supported. Requires `react-native-video@0.9.0`.

```
<Video
  repeat
  resizeMode='cover'
  source={require('../assets/video/turntable.mp4')}
  style={styles.backgroundVideo}
/>
```

### Play in background on iOS

To enable audio to play in background on iOS the audio session needs to be set to `AVAudioSessionCategoryPlayback`. See [Apple documentation][3] for additional details. (NOTE: there is now a ticket to [expose this as a prop]( https://github.com/react-native-community/react-native-video/issues/310) )

## Static Methods

`seek(seconds)`

Seeks the video to the specified time (in seconds). Access using a ref to the component

`presentFullscreenPlayer()`

Toggles a fullscreen player. Access using a ref to the component.

## Examples

- DRIVETRIBE app

## TODOS

- [ ] Add support for captions
- [ ] Add support for playing multiple videos in a sequence (will interfere with current `repeat` implementation)
- [x] Callback to get buffering progress for remote videos
- [ ] Bring API closer to HTML5 `<Video>` [reference](http://devdocs.io/html/element/video)

[1]: https://github.com/brentvatne/react-native-login/blob/56c47a5d1e23781e86e19b27e10427fd6391f666/App/Screens/UserInfoScreen.js#L32-L35
[2]: https://github.com/react-native-community/react-native-video/tree/master/example
[3]: https://developer.apple.com/library/ios/qa/qa1668/_index.html

---

**MIT Licensed**

redpajama_set_name: RedPajamaGithub


text:
<?php
/**
 * This xls helper is based on the one at
 * http://bakery.cakephp.org/articles/view/excel-xls-helper
 *
 * The difference compared with the original one is this helper
 * actually creates an xml which is openable in Microsoft Excel.
 *
 * Written by Yuen Ying Kit @ ykyuen.wordpress.com
 *
 */
class XlsHelper extends AppHelper
{
    /**
     * set the header of the http response.
     *
     * @param unknown_type $filename
     */
    function setHeader($filename)
    {
        header("Pragma: public");
        header("Expires: 0");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Content-Type: application/vnd.ms-excel; charset=UTF-8");
        header("Content-Type: application/force-download");
        header("Content-Type: application/download");;
        header("Content-Disposition: inline; filename=\"".$filename.".xls\"");
    }

    /**
     * add the xml header for the .xls file.
     *
     */
    function addXmlHeader()
    {
        echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
        echo "<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"\n";
        echo "          xmlns:x=\"urn:schemas-microsoft-com:office:excel\"\n";
        echo "          xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\"\n";
        echo "          xmlns:html=\"http://www.w3.org/TR/REC-html40\">\n";
        return;
    }

    /**
     * add the worksheet name for the .xls.
     * it has to be added otherwise the xml format is incomplete.
     *
     * @param unknown_type $workSheetName
     */
    function setWorkSheetName($workSheetName)
    {
        echo "\t<Worksheet ss:Name=\"".$workSheetName."\">\n";
        echo "\t\t<Table>\n";
        return;
    }

    /**
     * add the footer to the end of xml.
     * it has to be added otherwise the xml format is incomplete.
     *
     */
    function addXmlFooter()
    {
        echo "\t\t</Table>\n";
        echo "\t</Worksheet>\n";
        echo "</Workbook>\n";
        return;
    }

    /**
     * move to the next row in the .xls.
     * must be used with closeRow() in pair.
     *
     */
    function openRow()
    {
        echo "\t\t\t<Row>\n";
        return;
    }

    /**
     * end the row in the .xls.
     * must be used with openRow() in pair.
     *
     */
    function closeRow()
    {
        echo "\t\t\t</Row>\n";
        return;
    }

    /**
     * Write the content of a cell in number format
     *
     * @param unknown_type $Value
     */
    function writeNumber($Value)
    {
        if (is_null($Value)) {
            echo "\t\t\t\t<Cell><Data ss:Type=\"String\"> </Data></Cell>\n";
        } else {
            echo "\t\t\t\t<Cell><Data ss:Type=\"Number\">".$Value."</Data></Cell>\n";
        }
        return;
    }

    /**
     * Write the content of a cell in string format
     *
     * @param unknown_type $Value
     */
    function writeString($Value)
    {
        echo "\t\t\t\t<Cell><Data ss:Type=\"String\">".$Value."</Data></Cell>\n";
        return;
    }
}


text:
class B(object):
    def __init__(self) -> None:
        self.some_attr = unresolved


text:
package android.support.v4.view;

import android.view.LayoutInflater;

// Referenced classes of package android.support.v4.view:
//            LayoutInflaterCompat, LayoutInflaterCompatHC, LayoutInflaterFactory

static class  extends
{

    public void setFactory(LayoutInflater layoutinflater, LayoutInflaterFactory layoutinflaterfactory)
    {
        LayoutInflaterCompatHC.setFactory(layoutinflater, layoutinflaterfactory);
    }

    ()
    {
    }
}


text:
import React from 'react';
import {expect} from 'chai';
import {shallow, mount, render} from 'enzyme';
import {Link} from 'react-router';
import PieChart from '../../public/js/components/polls/pie_chart';
import Arc from '../../public/js/components/polls/arc';
import factory from '../factories';
import sinon from 'sinon';
import _ from 'underscore';

// https://github.com/airbnb/enzyme/issues/341
import jsdom from 'jsdom';
const doc = jsdom.jsdom('<!doctype html>');
global.document = doc;
global.window = doc.defaultView;

describe('<PieChart />', () => {
  let wrapper,
    pieData,
    expectedProps;

  beforeEach( (done) => {
    factory.attrs('poll')
      .then( (attrs) => {
        pieData = attrs.options.map( (option, i) =>{
          return {value: option.votes, label: `${option.name}: ${option.votes}`};
        } );

        const colorsStub = (i) => {
          return '#000000';
        };
        expectedProps = {x: 100, y: 100, data: pieData, outerRadius: 100,
          innerRadius: 50, colors: colorsStub,
        };

        wrapper = mount(<PieChart {...expectedProps} />);
        done();
      }).catch( (err) => {
        done(err);
      });
  });

  it('has a g element at root', (done) => {
    expect(wrapper.find('g')).to.have.length(1);
    done();
  });

  it('transforms g element based on props', (done) => {
    const expectedTranslate = `translate(${expectedProps.x}, ${expectedProps.y})`;
    expect(wrapper
      .find('g')
      .filterWhere( (i) => {
        return i.prop('transform') === expectedTranslate;
      })
    ).to.have.lengthOf(1);
    done();
  });

  it('contains an Arc', (done) => {
    expect(wrapper.find(Arc)).to.have.length(1);
    done();
  });

  describe('passes props to Arc', () => {
    let actualProps;

    beforeEach( (done) => {
      actualProps = wrapper.find(Arc).first().props();
      done();
    });

    const radiusProps = ['innerRadius', 'outerRadius'];

    radiusProps.forEach( (prop) => {
      it(`passes ${prop}`, (done) => {
        expect(expectedProps[prop]).to.equal(actualProps[prop]);
        done();
      });
    }); // loop

    it('passes the right color', (done) => {
      expect(actualProps.color).to.equal('#000000');
      done();
    });
  }); // inner describe
});


text:
function defaultActions(type, item){
    return '\
    ✔ Approve\
    ✔ Unapprove\
    − Edit Profile\
    × Delete\
    × Undelete';
}

function createItemHTML(user){
    return dataListEntry(user, user.nickname + ' (' + user.auth_provider + ')', defaultActions('users', user), defaultTags());
}

function editItem(){

}

jQuery(function(){
    jQuery.getJSON('/api/users/list', {}, function(users){
        var user, html = [];
        for (var i = 0, len = users.length; i < len; ++i){
            user = users[i];
            html.push(createItemHTML(user));
        }
        jQuery('#data-list').html(html.join(''));
    });
});


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">

<title>BlockDistance.BlockDistance</title>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
    <meta name="generator" content="Doc-O-Matic">
    <link rel="STYLESHEET" href="default.css" type="text/css">

<xml>
    <MSHelp:Attr Name="Locale" Value="kbEnglish"/>
    <MSHelp:Attr Name="TopicType" Value="kbSyntax"/>
</xml>

SimMetrics library v 1.5 for .NET 2.0

Contents | Index | Reference

Up | Previous | Next

BlockDistance.BlockDistance

BlockDistance | Body Source

constructor

public BlockDistance(ITokeniser tokeniserToUse);

Parameters

Parameters
Description

tokeniserToUse
the tokeniser to use should a different tokeniser be required

Body Source

public BlockDistance(ITokeniser tokeniserToUse) {
    tokeniser = tokeniserToUse;
    tokenUtilities = new TokeniserUtilities<string>();
}

Class

BlockDistance

Links

BlockDistance, Body Source

Copyright (c) 2006. All rights reserved.

Contents | Index | Reference


text:
:mod:`whichdb` --- Guess which DBM module created a database
============================================================

.. module:: whichdb
   :synopsis: Guess which DBM-style module created a given database.

.. note::
   The :mod:`whichdb` module's only function has been put into the :mod:`dbm`
   module in Python 3.0.  The :term:`2to3` tool will automatically adapt imports
   when converting your sources to 3.0.

The single function in this module attempts to guess which of the several simple
database modules available--\ :mod:`dbm`, :mod:`gdbm`, or :mod:`dbhash`\
--should be used to open a given file.

.. function:: whichdb(filename)

   Returns one of the following values: ``None`` if the file can't be opened
   because it's unreadable or doesn't exist; the empty string (``''``) if the
   file's format can't be guessed; or a string containing the required module name,
   such as ``'dbm'`` or ``'gdbm'``.


text:
[![Greenkeeper badge](https://badges.greenkeeper.io/skyrpex/vue-jsx-hot-loader.svg)](https://greenkeeper.io/)

> Works with:
>
> ![Vue 2](https://img.shields.io/badge/vue-%5E2.0-green.svg)
> ![Webpack](https://img.shields.io/badge/webpack-%5E2.0-green.svg)

This loader will enable `Hot Module Replacement` for [Webpack](http://webpack.js.org/) when using Vue's JSX render functions.

*NOTE: This plugin is still an experiment.*

## Installation

`npm install vue-jsx-hot-loader`

## Usage

```js
// path/to/component.jsx
export default {
  render(h) {
    return <div>
      <p>Hello</p>
    </div>;
  },
};
```

```js
// webpack.config.js
export default {
  // ...
  module: {
    loaders: [
      // Enable HMR for JSX.
      {
        test: /\.jsx$/,
        use: [
          'babel-loader',
          'vue-jsx-hot-loader',
        ],
      },
      // Remember to use babel on the rest of the JS files.
      {
        test: /\.js$/,
        use: 'babel-loader',
      },
    ],
  },
};
```


text:
module Carto
  module Api
    module Public
      class UsersController < Carto::Api::Public::ApplicationController
        ssl_required

        def me_public
          presentation = if request_api_key.user_data.try(:include?, 'profile')
                           UserPublicProfilePresenter.new(request_api_key.user).to_hash
                         else
                           UserPublicPresenter.new(request_api_key.user).to_hash
                         end

          render(json: presentation)
        end
      end
    end
  end
end


text:
<?php
class Ticket_1727_Model2 extends Doctrine_Record
{
    public function setTableDefinition()
    {
        $this->hasColumn('name', 'string', 255);
    }
}


text:
package psidev.psi.mi.jami.utils.comparator.experiment;

import org.junit.Assert;
import org.junit.Test;
import psidev.psi.mi.jami.model.VariableParameterValueSet;
import psidev.psi.mi.jami.model.impl.DefaultVariableParameterValue;
import psidev.psi.mi.jami.model.impl.DefaultVariableParameterValueSet;

/**
 * Unit tester for VariableParameterSetComparator
 *
 * @author Marine Dumousseau (marine@ebi.ac.uk)
 * @version $Id$
 * @since
24/05/13

 */

public class VariableParameterValueSetComparatorTest {

    private VariableParameterValueSetComparator comparator = new VariableParameterValueSetComparator();

    @Test
    public void test_variable_parameter_value_set_null_after() throws Exception {
        VariableParameterValueSet valueSet1 = null;
        VariableParameterValueSet valueSet2 = new DefaultVariableParameterValueSet();

        Assert.assertTrue(comparator.compare(valueSet1, valueSet2) > 0);
        Assert.assertTrue(comparator.compare(valueSet2, valueSet1) < 0);

        Assert.assertFalse(VariableParameterValueSetComparator.areEquals(valueSet1, valueSet2));
        Assert.assertTrue(VariableParameterValueSetComparator.hashCode(valueSet1) != VariableParameterValueSetComparator.hashCode(valueSet2));
    }

    @Test
    public void test_variable_parameter_value_set_bigger_after() throws Exception {
        VariableParameterValueSet valueSet1 = new DefaultVariableParameterValueSet();
        valueSet1.add(new DefaultVariableParameterValue("S phase", null));
        VariableParameterValueSet valueSet2 = new DefaultVariableParameterValueSet();

        Assert.assertTrue(comparator.compare(valueSet1, valueSet2) > 0);
        Assert.assertTrue(comparator.compare(valueSet2, valueSet1) < 0);

        Assert.assertFalse(VariableParameterValueSetComparator.areEquals(valueSet1, valueSet2));
        Assert.assertTrue(VariableParameterValueSetComparator.hashCode(valueSet1) != VariableParameterValueSetComparator.hashCode(valueSet2));
    }

    @Test
    public void test_variable_parameter_value_set_different_values() throws Exception {
        VariableParameterValueSet valueSet1 = new DefaultVariableParameterValueSet();
        valueSet1.add(new DefaultVariableParameterValue("S phase", null));
        VariableParameterValueSet valueSet2 = new DefaultVariableParameterValueSet();
        valueSet2.add(new DefaultVariableParameterValue("G phase", null));

        Assert.assertTrue(comparator.compare(valueSet1, valueSet2) > 0);
        Assert.assertTrue(comparator.compare(valueSet2, valueSet1) < 0);

        Assert.assertFalse(VariableParameterValueSetComparator.areEquals(valueSet1, valueSet2));
        Assert.assertTrue(VariableParameterValueSetComparator.hashCode(valueSet1) != VariableParameterValueSetComparator.hashCode(valueSet2));
    }

    @Test
    public void test_variable_parameter_value_set_same_values() throws Exception {
        VariableParameterValueSet valueSet1 = new DefaultVariableParameterValueSet();
        valueSet1.add(new DefaultVariableParameterValue("S phase", null));
        valueSet1.add(new DefaultVariableParameterValue("G phase", null));
        VariableParameterValueSet valueSet2 = new DefaultVariableParameterValueSet();
        valueSet2.add(new DefaultVariableParameterValue("G phase", null));
        valueSet2.add(new DefaultVariableParameterValue("S phase", null));

        Assert.assertTrue(comparator.compare(valueSet1, valueSet2) == 0);
        Assert.assertTrue(comparator.compare(valueSet2, valueSet1) == 0);

        Assert.assertTrue(VariableParameterValueSetComparator.areEquals(valueSet1, valueSet2));
        Assert.assertTrue(VariableParameterValueSetComparator.hashCode(valueSet1) == VariableParameterValueSetComparator.hashCode(valueSet2));
    }
}


text:
package org.springframework.cloud.stream.schema.registry.client.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @author Marius Bogoevici
 * @author Vinicius Carvalho
 * @author Christian Tzolov
 */
@ConfigurationProperties(prefix = "spring.cloud.stream.schema-registry-client")
public class SchemaRegistryClientProperties {

	private String endpoint;

	private boolean cached = false;

	public String getEndpoint() {
		return this.endpoint;
	}

	public void setEndpoint(String endpoint) {
		this.endpoint = endpoint;
	}

	public boolean isCached() {
		return this.cached;
	}

	public void setCached(boolean cached) {
		this.cached = cached;
	}

}


text:
using System;
using FluentNHibernate.Conventions.AcceptanceCriteria;
using FluentNHibernate.Conventions.Instances;
using FluentNHibernate.Conventions.Helpers.Prebuilt;
using FluentNHibernate.Conventions.Inspections;

namespace FluentNHibernate.Conventions.Helpers.Builders
{
    public class IdConventionBuilder : IConventionBuilder<IIdConvention, IIdentityInspector, IIdentityInstance>
    {
        public IIdConvention Always(Action<IIdentityInstance> convention)
        {
            return new BuiltIdConvention(accept => { }, convention);
        }

        public IIdConvention When(Action<IAcceptanceCriteria<IIdentityInspector>> expectations, Action<IIdentityInstance> convention)
        {
            return new BuiltIdConvention(expectations, convention);
        }
    }
}


text:
EmberSockets
============

Socket.io (WebSockets) integrated with Ember.js' observer pattern.

Example
------------

Install EmberSockets:

 * `npm install`;
 * `bower install`;
 * `grunt build`;

You need Node.js installed to use the example.

If you have it installed, you can simply run `node example/server.js` and then open the file `example/index.html` with your web-browser.

Getting Started
------------

First of all you need to bootstrap the module, which is done very much the same way that `Ember.DS` and `Ember.Router` go about it.

In your `Ember.Application` you need to configure EmberSockets by defining the host (default is `localhost`), the port (default is `80`) and the controllers capable of responding to WebSocket events.

```javascript
window.App = Ember.Application.create({

    Socket: EmberSockets.extend({
        host: 'localhost',
        port: 8888,
        controllers: ['cats', 'dogs', 'rabbits']
    })

});
```

In the above configuration, we'll be attempting to connect to `localhost` on port `8888`. Only three controllers will be able to respond to WebSocket events: `CatsController`, `DogsController`, and the `RabbitsController`. If you'd like the connection to occur automatically, you can set `autoConnect: true`.

To begin responding to events, you need to create a map of events to their properties. When the event is invoked the property will be updated with the response.

Since the release of Ember 1.0, you have been encouraged to place your actions into the `actions` hash on each controller – EmberSockets works in a similar way by defining the `sockets` hash.

```javascript
sockets: {
    cherryPickedName: 'name',

    // support multi words event name also
    'cherry picked name': 'name'
}
```

From this we can deduce that whenever the `cherryPickedName` event has been invoked, the `name` property on the controller will be updated with the event's data.

As the properties are all updated with the typical `Ember.get`, all computed properties and observers will work as usual.

```html
<section>Your name is {{name}}!</section>
```

If you would like to `emit` an event, you can use the `this.socket.emit` method from **any** controller – passing in the event name followed by any options.

Dereferencing

EmberSockets also allows you to specify an array of properties to update with a corresponding value. For example, if your backend responds with a name and age, then you'll want to specify an array of those two distinct properties to update.

```javascript
sockets: {
    person: ['name', 'age']
}
```

Supplying a function

You may not wish to simply update a property based on the received data, in these cases you can specify a method to invoke when the event occurs. When the callback is invoked, `this` is preserved for your controller, and the event data is passed through as the arguments.

```javascript
cherryPickedName: function(name) {
    this.set('name', name);
}
```

Using autoConnect=false
------------
Defer the connection by setting autoConnect to false.

```javascript
$window.App = Ember.Application.create({

  Socket: EmberSockets.extend({
    controllers: ['index'],
    autoConnect: false
  })

});
```

And then in your controller – such as your ApplicationController, manually connect to the WebSockets server using the connect method, passing in any params into the connect method:

```javascript
this.socket.connect({
  query: { token: 123 }
});
```

Also, if you'd like to connect using a socket.io namespace
```javascript
this.socket.connect({
  namespace: '/my-namespace'
});
```

Ember-cli Adapter Example
------------
In **example/app/adapters/application.js** you will find an **ember-data** socket adapter for Models in ember-cli. To use simply copy this to into your Apps file structure in **app/adapters/application.js**.

By default all Models will try and get data from the ember-sockets connection.

NodeJS/Express Server Side example code snippet

```javascript

    socket.on('findAll', function(data, callback) {
		console.log('['+nsp+']' + " | findall: ", data);
		console.log('['+nsp+']' + " typeof: ", typeof callback);
		var _this = this;
		var dataOut = {};
		/*
		* Put all your database lookups in here....
		*/
		switch(data.type) {
			case'message': 	getMessages(data.query, callback); 	break;
			case'user':		getUsers(data.query, callback);		break;
		}

	});

	socket.on('find', function(data, callback) {
			console.log('['+nsp+']' + "-------DB-------");
			console.log('['+nsp+']' + " | find: ", data);
			console.log('['+nsp+']' + " typeof: ", typeof callback);

			var dataOut = {status: true, content: [{test:'test'}]};

			if(typeof callback === 'function') callback(dataOut);
	});

	// then the functions to collect & return the actual data
	getMessages = function(query, cb) {
		var dataOut = {status: true, content: [{
	        id: 1,
	        text: "Hello You There?",
	        sender: "David Bazan",
	        time: 'now',
	        user: 1
	    	},
	    	{
			id: 2,
			text: "Huh? what time is it?",
			sender: "Bon Iver",
			time: 'yesterday',
			user: 2
		}]
		};
		if(typeof cb === 'function') cb(dataOut);
	};

	getUsers = function(query, cb) {
		var dataOut = {status: true, content: [{
		        id: 1,
		        name: "Paul",
		        img: "/assets/img/profiles/d.jpg"
	    	},
	    	{
	    		id: 2,
		        name: "Paul2",
		        img: "/assets/img/profiles/d.jpg"
	    	}]
		};
		if(typeof cb === 'function') cb(dataOut);
	};
```


text:
require 'support/shared/integration/integration_helper'
require 'chef/knife/list'
require 'chef/knife/delete'
require 'chef/knife/show'
require 'chef/knife/raw'
require 'chef/knife/cookbook_upload'

describe 'knife raw -z' do
  extend IntegrationSupport
  include KnifeSupport

  when_the_repository "has one of each thing" do
    file 'clients/x.json', {}
    file 'cookbooks/x/metadata.rb', 'version "1.0.0"'
    file 'data_bags/x/y.json', {}
    file 'environments/x.json', {}
    file 'nodes/x.json', {}
    file 'roles/x.json', {}
    file 'users/x.json', {}

    context 'GET /TYPE' do
      it 'knife list -z -R returns everything' do
        knife('list -z -Rfp /').should_succeed <<EOM
/clients/
/clients/x.json
/cookbooks/
/cookbooks/x/
/cookbooks/x/metadata.rb
/data_bags/
/data_bags/x/
/data_bags/x/y.json
/environments/
/environments/x.json
/nodes/
/nodes/x.json
/roles/
/roles/x.json
/users/
/users/x.json
EOM
      end
    end

    context 'DELETE /TYPE/NAME' do
      it 'knife delete -z /clients/x.json works' do
        knife('delete -z /clients/x.json').should_succeed "Deleted /clients/x.json\n"
        knife('list -z -Rfp /clients').should_succeed ''
      end

      it 'knife delete -z -r /cookbooks/x works' do
        knife('delete -z -r /cookbooks/x').should_succeed "Deleted /cookbooks/x\n"
        knife('list -z -Rfp /cookbooks').should_succeed ''
      end

      it 'knife delete -z -r /data_bags/x works' do
        knife('delete -z -r /data_bags/x').should_succeed "Deleted /data_bags/x\n"
        knife('list -z -Rfp /data_bags').should_succeed ''
      end

      it 'knife delete -z /data_bags/x/y.json works' do
        knife('delete -z /data_bags/x/y.json').should_succeed "Deleted /data_bags/x/y.json\n"
        knife('list -z -Rfp /data_bags').should_succeed "/data_bags/x/\n"
      end

      it 'knife delete -z /environments/x.json works' do
        knife('delete -z /environments/x.json').should_succeed "Deleted /environments/x.json\n"
        knife('list -z -Rfp /environments').should_succeed ''
      end

      it 'knife delete -z /nodes/x.json works' do
        knife('delete -z /nodes/x.json').should_succeed "Deleted /nodes/x.json\n"
        knife('list -z -Rfp /nodes').should_succeed ''
      end

      it 'knife delete -z /roles/x.json works' do
        knife('delete -z /roles/x.json').should_succeed "Deleted /roles/x.json\n"
        knife('list -z -Rfp /roles').should_succeed ''
      end

      it 'knife delete -z /users/x.json works' do
        knife('delete -z /users/x.json').should_succeed "Deleted /users/x.json\n"
        knife('list -z -Rfp /users').should_succeed ''
      end
    end

    context 'GET /TYPE/NAME' do
      it 'knife show -z /clients/x.json works' do
        knife('show -z /clients/x.json').should_succeed /"x"/
      end

      it 'knife show -z /cookbooks/x/metadata.rb works' do
        knife('show -z /cookbooks/x/metadata.rb').should_succeed "/cookbooks/x/metadata.rb:\nversion \"1.0.0\"\n"
      end

      it 'knife show -z /data_bags/x/y.json works' do
        knife('show -z /data_bags/x/y.json').should_succeed /"y"/
      end

      it 'knife show -z /environments/x.json works' do
        knife('show -z /environments/x.json').should_succeed /"x"/
      end

      it 'knife show -z /nodes/x.json works' do
        knife('show -z /nodes/x.json').should_succeed /"x"/
      end

      it 'knife show -z /roles/x.json works' do
        knife('show -z /roles/x.json').should_succeed /"x"/
      end

      it 'knife show -z /users/x.json works' do
        knife('show -z /users/x.json').should_succeed /"x"/
      end
    end

    context 'PUT /TYPE/NAME' do
      file 'empty.json', {}
      file 'rolestuff.json', '{"description":"hi there","name":"x"}'
      file 'cookbooks_to_upload/x/metadata.rb', "version '1.0.0'\n\n"

      it 'knife raw -z -i empty.json -m PUT /clients/x' do
        knife("raw -z -i #{path_to('empty.json')} -m PUT /clients/x").should_succeed /"x"/
        knife('list --local /clients').should_succeed "/clients/x.json\n"
      end

      it 'knife cookbook upload works' do
        knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} x").should_succeed <<EOM
Uploading x              [1.0.0]
Uploaded 1 cookbook.
EOM
        knife('list --local -Rfp /cookbooks').should_succeed "/cookbooks/x/\n/cookbooks/x/metadata.rb\n"
      end

      it 'knife raw -z -i empty.json -m PUT /data/x/y' do
        knife("raw -z -i #{path_to('empty.json')} -m PUT /data/x/y").should_succeed /"y"/
        knife('list --local -Rfp /data_bags').should_succeed "/data_bags/x/\n/data_bags/x/y.json\n"
      end

      it 'knife raw -z -i empty.json -m PUT /environments/x' do
        knife("raw -z -i #{path_to('empty.json')} -m PUT /environments/x").should_succeed /"x"/
        knife('list --local /environments').should_succeed "/environments/x.json\n"
      end

      it 'knife raw -z -i empty.json -m PUT /nodes/x' do
        knife("raw -z -i #{path_to('empty.json')} -m PUT /nodes/x").should_succeed /"x"/
        knife('list --local /nodes').should_succeed "/nodes/x.json\n"
      end

      it 'knife raw -z -i empty.json -m PUT /roles/x' do
        knife("raw -z -i #{path_to('empty.json')} -m PUT /roles/x").should_succeed /"x"/
        knife('list --local /roles').should_succeed "/roles/x.json\n"
      end

      it 'knife raw -z -i empty.json -m PUT /users/x' do
        knife("raw -z -i #{path_to('empty.json')} -m PUT /users/x").should_succeed /"x"/
        knife('list --local /users').should_succeed "/users/x.json\n"
      end

      it 'After knife raw -z -i rolestuff.json -m PUT /roles/x, the output is pretty', :pending => (RUBY_VERSION < "1.9") do
        knife("raw -z -i #{path_to('rolestuff.json')} -m PUT /roles/x").should_succeed /"x"/
        IO.read(path_to('roles/x.json')).should == <<EOM.strip
{
  "name": "x",
  "description": "hi there"
}
EOM
      end
    end
  end

  when_the_repository 'is empty' do
    context 'POST /TYPE/NAME' do
      file 'empty.json', { 'name' => 'z' }
      file 'empty_x.json', { 'name' => 'x' }
      file 'empty_id.json', { 'id' => 'z' }
      file 'rolestuff.json', '{"description":"hi there","name":"x"}'
      file 'cookbooks_to_upload/z/metadata.rb', "version '1.0.0'"

      it 'knife raw -z -i empty.json -m POST /clients' do
        knife("raw -z -i #{path_to('empty.json')} -m POST /clients").should_succeed /uri/
        knife('list --local /clients').should_succeed "/clients/z.json\n"
      end

      it 'knife cookbook upload works' do
        knife("cookbook upload -z --cookbook-path #{path_to('cookbooks_to_upload')} z").should_succeed <<EOM
Uploading z            [1.0.0]
Uploaded 1 cookbook.
EOM
        knife('list --local -Rfp /cookbooks').should_succeed "/cookbooks/z/\n/cookbooks/z/metadata.rb\n"
      end

      it 'knife raw -z -i empty.json -m POST /data' do
        knife("raw -z -i #{path_to('empty.json')} -m POST /data").should_succeed /uri/
        knife('list --local -Rfp /data_bags').should_succeed "/data_bags/z/\n"
      end

      it 'knife raw -z -i empty.json -m POST /data/x' do
        knife("raw -z -i #{path_to('empty_x.json')} -m POST /data").should_succeed /uri/
        knife("raw -z -i #{path_to('empty_id.json')} -m POST /data/x").should_succeed /"z"/
        knife('list --local -Rfp /data_bags').should_succeed "/data_bags/x/\n/data_bags/x/z.json\n"
      end

      it 'knife raw -z -i empty.json -m POST /environments' do
        knife("raw -z -i #{path_to('empty.json')} -m POST /environments").should_succeed /uri/
        knife('list --local /environments').should_succeed "/environments/z.json\n"
      end

      it 'knife raw -z -i empty.json -m POST /nodes' do
        knife("raw -z -i #{path_to('empty.json')} -m POST /nodes").should_succeed /uri/
        knife('list --local /nodes').should_succeed "/nodes/z.json\n"
      end

      it 'knife raw -z -i empty.json -m POST /roles' do
        knife("raw -z -i #{path_to('empty.json')} -m POST /roles").should_succeed /uri/
        knife('list --local /roles').should_succeed "/roles/z.json\n"
      end

      it 'knife raw -z -i empty.json -m POST /users' do
        knife("raw -z -i #{path_to('empty.json')} -m POST /users").should_succeed /uri/
        knife('list --local /users').should_succeed "/users/z.json\n"
      end

      it 'After knife raw -z -i rolestuff.json -m POST /roles, the output is pretty', :pending => (RUBY_VERSION < "1.9") do
        knife("raw -z -i #{path_to('rolestuff.json')} -m POST /roles").should_succeed /uri/
        IO.read(path_to('roles/x.json')).should == <<EOM.strip
{
  "name": "x",
  "description": "hi there"
}
EOM
      end
    end

    it 'knife list -z -R returns nothing' do
      knife('list -z -Rfp /').should_succeed <<EOM
/clients/
/cookbooks/
/data_bags/
/environments/
/nodes/
/roles/
/users/
EOM
    end

    context 'DELETE /TYPE/NAME' do
      it 'knife delete -z /clients/x.json fails with an error' do
        knife('delete -z /clients/x.json').should_fail "ERROR: /clients/x.json: No such file or directory\n"
      end

      it 'knife delete -z -r /cookbooks/x fails with an error' do
        knife('delete -z -r /cookbooks/x').should_fail "ERROR: /cookbooks/x: No such file or directory\n"
      end

      it 'knife delete -z -r /data_bags/x fails with an error' do
        knife('delete -z -r /data_bags/x').should_fail "ERROR: /data_bags/x: No such file or directory\n"
      end

      it 'knife delete -z /data_bags/x/y.json fails with an error' do
        knife('delete -z /data_bags/x/y.json').should_fail "ERROR: /data_bags/x/y.json: No such file or directory\n"
      end

      it 'knife delete -z /environments/x.json fails with an error' do
        knife('delete -z /environments/x.json').should_fail "ERROR: /environments/x.json: No such file or directory\n"
      end

      it 'knife delete -z /nodes/x.json fails with an error' do
        knife('delete -z /nodes/x.json').should_fail "ERROR: /nodes/x.json: No such file or directory\n"
      end

      it 'knife delete -z /roles/x.json fails with an error' do
        knife('delete -z /roles/x.json').should_fail "ERROR: /roles/x.json: No such file or directory\n"
      end

      it 'knife delete -z /users/x.json fails with an error' do
        knife('delete -z /users/x.json').should_fail "ERROR: /users/x.json: No such file or directory\n"
      end
    end

    context 'GET /TYPE/NAME' do
      it 'knife show -z /clients/x.json fails with an error' do
        knife('show -z /clients/x.json').should_fail "ERROR: /clients/x.json: No such file or directory\n"
      end

      it 'knife show -z /cookbooks/x/metadata.rb fails with an error' do
        knife('show -z /cookbooks/x/metadata.rb').should_fail "ERROR: /cookbooks/x/metadata.rb: No such file or directory\n"
      end

      it 'knife show -z /data_bags/x/y.json fails with an error' do
        knife('show -z /data_bags/x/y.json').should_fail "ERROR: /data_bags/x/y.json: No such file or directory\n"
      end

      it 'knife show -z /environments/x.json fails with an error' do
        knife('show -z /environments/x.json').should_fail "ERROR: /environments/x.json: No such file or directory\n"
      end

      it 'knife show -z /nodes/x.json fails with an error' do
        knife('show -z /nodes/x.json').should_fail "ERROR: /nodes/x.json: No such file or directory\n"
      end

      it 'knife show -z /roles/x.json fails with an error' do
        knife('show -z /roles/x.json').should_fail "ERROR: /roles/x.json: No such file or directory\n"
      end

      it 'knife show -z /users/x.json fails with an error' do
        knife('show -z /users/x.json').should_fail "ERROR: /users/x.json: No such file or directory\n"
      end
    end

    context 'PUT /TYPE/NAME' do
      file 'empty.json', {}

      it 'knife raw -z -i empty.json -m PUT /clients/x fails with 404' do
        knife("raw -z -i #{path_to('empty.json')} -m PUT /clients/x").should_fail /404/
      end

      it 'knife raw -z -i empty.json -m PUT /data/x/y fails with 404' do
        knife("raw -z -i #{path_to('empty.json')} -m PUT /data/x/y").should_fail /404/
      end

      it 'knife raw -z -i empty.json -m PUT /environments/x fails with 404' do
        knife("raw -z -i #{path_to('empty.json')} -m PUT /environments/x").should_fail /404/
      end

      it 'knife raw -z -i empty.json -m PUT /nodes/x fails with 404' do
        knife("raw -z -i #{path_to('empty.json')} -m PUT /nodes/x").should_fail /404/
      end

      it 'knife raw -z -i empty.json -m PUT /roles/x fails with 404' do
        knife("raw -z -i #{path_to('empty.json')} -m PUT /roles/x").should_fail /404/
      end

      it 'knife raw -z -i empty.json -m PUT /users/x fails with 404' do
        knife("raw -z -i #{path_to('empty.json')} -m PUT /users/x").should_fail /404/
      end
    end
  end
end


text:
import React from 'react';
import moment from 'moment';

let timeStyle = {
  time: '',
  style: ''
};

let divStyle = {color: 'green',  fontWeight: 'bold', fontSize: '90px', clear: 'both'};
let divStyle2 = {color: '#337ab7', textAlign: 'justify', clear: 'both'};
let divStyle3 = {color: '#FA6900', textAlign: 'justify', clear: 'both'};

class Event extends React.Component {
  constructor(props) {
   super(props);
    }

    dateCheck(date){
      let nowDate = new Date();

      let moment1 = new moment(new Date(nowDate));
      let moment2 = new moment(new Date(date));
      let diffInMilliSeconds = moment2.diff(moment1);
      let duration = moment.duration(diffInMilliSeconds);

      let days = duration.days().toString();

      let today = 'Idag!';
      let upComming = 'Days left : ' + days;
      let datePassed = 'Completed! ';
      let x = nowDate.toLocaleDateString('en-US');

    if (date === x)  {
      timeStyle = { time: today, style: divStyle };
    } else if (days.substring(0, 1) === '-') {
       timeStyle = { time: datePassed, style: divStyle3 };
    } else {
       timeStyle = { time: upComming, style: divStyle2 };
      }
    return timeStyle;
      }

  render() {

      let self = this;

      let sorted = this.props.events.sort(function(obj1, obj2) {
      	return new Date(obj2.date) - new Date(obj1.date);
  });

      let eventList = sorted.map(function(event, i){
      timeStyle = self.dateCheck(event.date);
      return

                          {event.name}

                           {timeStyle.time}

;
    });
    return (

Choose Event

                {eventList}

    );
  }
}

export default Event;
Event.propTypes = {
 handleEventClick: React.PropTypes.any,
 events: React.PropTypes.array
};


text:
.. EN-Revision: none
.. _zend.view.helpers.initial.headstyle:

L'aide de vue HeadStyle
=======================

L'élément HTML *<style>* est utilisé pour inclure des feuilles de styles *CSS* à l'intérieur de l'élément
HTML *<head>*.

.. note::

   **Utilisez HeadLink pour lier des fichiers CSS externes**

   :ref:`HeadLink <zend.view.helpers.initial.headlink>` devrait être utilisé pour inclure des feuilles de styles
   externes. *HeadStyle* ne devrait être utilisé que si vous souhaitez définir des feuilles de styles internes.

L'aide de vue *HeadStyle* supporte les méthodes suivantes pour l'ajout et le paramétrage des déclarations de
feuilles de styles :

- ``appendStyle($content, $attributes = array())``

- ``offsetSetStyle($index, $content, $attributes = array())``

- ``prependStyle($content, $attributes = array())``

- ``setStyle($content, $attributes = array())``

Dans tous les cas, ``$content`` est le contenu des déclarations *CSS*. ``$attributes`` sont les attributs
additionnels que vous pouvez fournir à la balise *style*: "lang", "title", "media", ou "dir" sont autorisés.

.. note::

   **Paramétrez des commentaires conditionnels**

   *HeadStyle* vous permet d'englober vos balises de style avec des commentaires conditionnels, ce qui permet de
   les masquer pour des navigateurs spécifiques. Pour ajouter les balises conditionnelles, fournissez le
   paramètre *conditional* en tant que partie du paramètre ``$attrs`` lors de l'appel de la méthode.

   .. _zend.view.helpers.initial.headstyle.conditional:

   .. rubric:: HeadStyle avec des commentaires conditionnels

   .. code-block:: php
      :linenos:

      // adding scripts
      $this->headStyle()->appendStyle($styles, array('conditional' => 'lt IE 7'));

*HeadStyle* permet aussi la capture des déclarations de style ; ceci peut être utile si vous voulez créer des
déclarations par programme, et ensuite les placer à un autre endroit. L'utilisation de cette fonctionnalité est
montrée dans un exemple ci-dessous.

Enfin, vous pouvez utiliser la méthode ``headStyle()`` pour ajouter rapidement des éléments de déclarations ;
la signature de la méthode est ``headStyle($content$placement = 'APPEND', $attributes = array())``. ``$placement``
peut être "APPEND", "PREPEND", ou "SET".

*HeadStyle* surcharge chacune des méthodes ``append()``, ``offsetSet()``, ``prepend()``, et ``set()`` pour imposer
l'utilisation des méthodes spéciales listées ci-dessus. En interne, il stocke chaque élément sous la forme
d'un *stdClass*, qui est ensuite sérialisé en utilisant la méthode ``itemToString()``. Ceci vous permet de
réaliser des vérifications sur les éléments de la pile, et optionnellement modifier ces éléments en modifiant
simplement l'objet retourné.

L'aide *HeadStyle* est une implémentation concrète de l'aide :ref:`Placeholder
<zend.view.helpers.initial.placeholder>`.

.. note::

   **UTF-8 encoding used by default**

   By default, Zend Framework uses *UTF-8* as its default encoding, and, specific to this case, ``Zend_View`` does
   as well. Character encoding can be set differently on the view object itself using the ``setEncoding()`` method
   (or the the ``encoding`` instantiation parameter). However, since ``Zend\View\Interface`` does not define
   accessors for encoding, it's possible that if you are using a custom view implementation with this view helper,
   you will not have a ``getEncoding()`` method, which is what the view helper uses internally for determining the
   character set in which to encode.

   If you do not want to utilize *UTF-8* in such a situation, you will need to implement a ``getEncoding()`` method
   in your custom view implementation.

.. _zend.view.helpers.initial.headstyle.basicusage:

.. rubric:: Utilisation basique de l'aide HeadStyle

Vous pouvez spécifier une nouvelle balise de style à n'importe quel moment :

.. code-block:: php
   :linenos:

   // ajout de styles
   $this->headStyle()->appendStyle($styles);

L'ordre est très important avec les *CSS*; vous pouvez devoir assurer que les déclarations soient chargées dans
un ordre spécifique dû à l'ordre de la cascade ; employez les diverses directives "append", "prepend", et
"offsetSet" pour faciliter cette tâche :

.. code-block:: php
   :linenos:

   // Mettre les styles dans le bon ordre

   // - placer à un offset particulier
   $this->headStyle()->offsetSetStyle(100, $stylesPerso);

   // - placer à la fin
   $this->headStyle()->appendStyle($stylesFinaux);

   // - placer au début
   $this->headStyle()->prependStyle($stylesInitiaux);

Quand vous êtes finalement prêt à afficher toutes les déclarations de styles dans votre script de layout,
faîtes un simple *echo* de l'aide :

.. code-block:: php
   :linenos:

   <?php echo $this->headStyle() ?>

.. _zend.view.helpers.initial.headstyle.capture:

.. rubric:: Capturer les déclarations de style en utilisant l'aide HeadStyle

Parfois vous devez produire des déclarations de styles *CSS* par programme. Même si vous pouvez employer la
concaténation de chaînes, les "heredocs", ou tout autre équivalent, il est souvent plus facile de faire juste la
création des styles et de les entourer par des balises *PHP*. *HeadStyle* vous permet de le faire, et capture
ainsi l'élément dans la pile :

.. code-block:: php
   :linenos:

   <?php $this->headStyle()->captureStart() ?>
   body {
       background-color: <?php echo $this->bgColor ?>;
   }
   <?php $this->headStyle()->captureEnd() ?>

Les suppositions suivantes sont considérées :

- Les déclarations de styles sont ajoutées à la pile. Si vous souhaitez qu'elles remplacent la pile ou qu'elles
  soient ajoutées en début de pile, vous devez fournir "SET" ou "PREPEND", en tant que premier argument de
  ``captureStart()``.

- Si vous souhaitez spécifier un quelconque attribut additionnel pour la balise *<style>*, fournissez-le sous la
  forme d'un tableau en deuxième argument de ``captureStart()``.


text:
require 'net/http'
require 'json'
require 'base64'

#
# Sendpulse REST API Ruby class
#
# Documentation
# https://login.sendpulse.com/manual/rest-api/
# https://sendpulse.com/api
#
class SendpulseApi

  #
  # Sendpulse API constructor
  #
  # @param [Fixnum] user_id
  # @param [String] secret
  # @param [String] protocol
  # @param [String] token
  # @raise [Exception]
  #
  def initialize(user_id, secret, protocol = 'https', token = '')
    raise 'Empty ID or SECRET' if user_id.to_s.empty? || secret.to_s.empty?

    @url = "#{protocol}://api.sendpulse.com"
    @user_id = user_id
    @secret = secret
    @protocol = protocol
    @refresh_token = 0
    @token = token

    if @token.nil? || @token.empty?
      raise 'Could not connect to api, check your ID and SECRET' unless refresh_token
    end

  end

  #
  # Refresh token
  #
  # @return [Boolean]
  #
  def refresh_token
    @refresh_token += 1

    data = {
        grant_type: 'client_credentials',
        client_id: @user_id,
        client_secret: @secret
    }

    request_data = send_request('oauth/access_token', 'POST', data, false)

    if !request_data.nil? && request_data[:data]['access_token']
      @token = request_data[:data]['access_token']
      @refresh_token = 0
    else
      return false
    end

    true
  end
  private :refresh_token

  #
  # Get token
  #
  # @return [String]
  #
  def get_token
    @token
  end

  #
  # Get serialized string
  #
  # @param [Mixed] data
  # @return [String]
  #
  def serialize(data)
    JSON.generate(data)
  end
  private :serialize

  #
  # Get unserialized data
  #
  # @param [String] data
  # @return [Mixed]
  #
  def unserialize(data)
    JSON.parse(data)
  end
  private :unserialize

  #
  # Form and send request to API service
  #
  # @param [String] path
  # @param [String] method
  # @param [Hash] data
  # @param [Boolean] use_token
  # @return [Hash]
  #
  def send_request(path, method = 'GET', data = {}, use_token = true)

    request_data = {}

    uri = URI.parse("#{@url}/#{path}")

    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true if @protocol == 'https'

    token = {}
    token.merge!( 'authorization' => "Bearer #{@token}" ) if use_token

    case method
      when 'POST'
        request = Net::HTTP::Post.new(uri.request_uri, token)
        request.set_form_data(data)
      when 'PUT'
        request = Net::HTTP::Put.new(uri.request_uri, token)
        request.set_form_data(data)
      when 'DELETE'
        request = Net::HTTP::Delete.new(uri.request_uri, token)
        request.set_form_data(data)
      else
        request = Net::HTTP::Get.new(uri.request_uri, token)
    end

    begin
      response = http.request(request)
      if response.code.to_i == 401 && @refresh_token == 0
        refresh_token
        return send_request(path, method, data, use_token)
      else
        request_data[:data] = JSON.parse(response.body)
        request_data[:http_code] = response.code
      end
    rescue Exception => e
      puts "Exception \n  message: #{e.message} \n  backtrace: #{e.backtrace}"
    end

    handle_result(request_data)
  end
  private :send_request

  #
  # Process results
  #
  # @param [String] custom_message
  # @return [Hash]
  #
  def handle_error (custom_message = nil)
    data = { is_error: true }
    data[:message] = custom_message unless custom_message.nil?
    data
  end
  private :handle_error

  #
  # Process errors
  #
  # @param [Hash] data
  # @return [Hash]
  #
  def handle_result (data)
    unless data[:http_code].to_i == 200
      data[:is_error] = true
    end
    data
  end
  private :handle_result

  #
  # Create address book
  #
  # @param [String] book_name
  # @return [Hash]
  #
  def create_address_book(book_name)
    handle_error('Empty book name') if book_name.to_s.empty?
    data = { bookName: book_name }
    send_request('addressbooks', 'POST', data)
  end

  #
  # Edit address book name
  #
  # @param [Fixnum] id
  # @param [String] new_name
  # @return [Hash]
  #
  def edit_address_book(id, new_name)
    return handle_error('Empty new name or book id') if id.to_i <= 0 || new_name.to_s.empty?
    data = { name: new_name }
    send_request("addressbooks/#{id}", 'PUT', data)
  end

  #
  # Remove address book
  #
  # @param [Fixnum] id
  # @return [Hash]
  #
  def remove_address_book(id)
    return handle_error('Empty book id') unless id.to_i > 0
    send_request("addressbooks/#{id}", 'DELETE')
  end

  #
  # Get list of address books
  #
  # @param [Fixnum] limit
  # @param [Fixnum] offset
  # @return [Hash]
  #
  def list_address_books(limit = nil, offset = nil)
    data = {}
    data.merge!({limit: limit}) unless limit.nil?
    data.merge!({offset: offset}) unless offset.nil?
    send_request('addressbooks', 'GET', data)
  end

  #
  # Get information about book
  #
  # @param [Fixnum] id
  # @return [Hash]
  #
  def get_book_info(id)
    return handle_error('Empty book id') unless id.to_i > 0
    send_request("addressbooks/#{id}")
  end

  #
  # List email addresses from book
  #
  # @param [Fixnum] id
  # @return [Hash]
  #
  def get_emails_from_book(id)
    return handle_error('Empty book id') unless id.to_i > 0
    send_request("addressbooks/#{id}/emails")
  end

  #
  # Add new emails to address book
  #
  # @param [Fixnum] book_id
  # @param [Hash] emails
  # @return [Hash]
  #
  def add_emails(book_id, emails)
    return handle_error('Empty book id or emails') if book_id.to_i <= 0 || emails.empty?
    data = { emails: serialize(emails) }
    send_request("addressbooks/#{book_id}/emails", 'POST', data)
  end

  #
  # Remove email addresses from book
  #
  # @param [Fixnum] book_id
  # @param [Hash] emails
  # @return [Hash]
  #
  def remove_emails(book_id, emails)
    return handle_error('Empty book id or emails') if book_id.to_i <= 0 || emails.empty?
    data = { emails: serialize(emails) }
    send_request("addressbooks/#{book_id}/emails", 'DELETE', data)
  end

  #
  # Get information about email address from book
  #
  # @param [Fixnum] book_id
  # @param [String] email
  # @return [Hash]
  #
  def get_email_info(book_id, email)
    return handle_error('Empty book id or email') if book_id.to_i <= 0 || email.to_s.empty?
    send_request("addressbooks/#{book_id}/emails/#{email}")
  end

  #
  # Get cost of campaign based on address book
  #
  # @param [Fixnum] book_id
  # @return [Hash]
  #
  def campaign_cost(book_id)
    return handle_error('Empty book id') unless book_id.to_i > 0
    send_request("addressbooks/#{book_id}/cost")
  end

  #
  # Get list of campaigns
  #
  # @param [Fixnum] limit
  # @param [Fixnum] offset
  # @return [Hash]
  #
  def list_campaigns(limit = nil, offset = nil)
    data = {}
    data.merge!({limit: limit}) unless limit.nil?
    data.merge!({offset: offset}) unless offset.nil?
    send_request('campaigns', 'GET', data)
  end

  #
  # Get information about campaign
  #
  # @param [Fixnum] id
  # @return [Hash]
  #
  def get_campaign_info(id)
    return handle_error('Empty campaign id') unless id.to_i > 0
    send_request("campaigns/#{id}")
  end

  #
  # Get campaign statistic by countries
  #
  # @param [Fixnum] id
  # @return [Hash]
  #
  def campaign_stat_by_countries(id)
    return handle_error('Empty campaign id') unless id.to_i > 0
    send_request("campaigns/#{id}/countries")
  end

  #
  # Get campaign statistic by referrals
  #
  # @param [Fixnum] id
  # @return [Hash]
  #
  def campaign_stat_by_referrals(id)
    return handle_error('Empty campaign id') unless id.to_i > 0
    send_request("campaigns/#{id}/referrals")
  end

  #
  # Create new campaign
  #
  # @param [String] sender_name
  # @param [String] sender_email
  # @param [String] subject
  # @param [String] body
  # @param [Fixnum] book_id
  # @param [String] name
  # @param [String] attachments
  # @return [Hash]
  #
  def create_campaign(sender_name, sender_email, subject, body, book_id, name = '', attachments = '')
    if sender_name.empty? || sender_email.empty? || subject.empty? || body.empty? || book_id.to_i <= 0
      return handle_error('Not all data.')
    end
    attachments = serialize(attachments) unless attachments.empty?
    data = {
        sender_name: sender_name,
        sender_email: sender_email,
        subject: subject,
        body: Base64.encode64(body),
        list_id: book_id,
        name: name,
        attachments: attachments
    }
    send_request('campaigns', 'POST', data)
  end

  #
  # Cancel campaign
  #
  # @param [Fixnum] id
  # @return [Hash]
  #
  def cancel_campaign(id)
    return handle_error('Empty campaign id') unless id.to_i > 0
    send_request("campaigns/#{id}", 'DELETE')
  end

  #
  # List all senders
  #
  # @return [Hash]
  #
  def list_senders
    send_request('senders')
  end

  #
  # Cancel Add new sender
  #
  # @param [String] sender_name
  # @param [String] sender_email
  # @return [Hash]
  #
  def add_sender(sender_name, sender_email)
    return handle_error('Empty book sender name or sender email') if sender_name.to_s.empty? || sender_email.to_s.empty?
    data = {
        email: sender_email,
        name: sender_name
    }
    send_request('senders', 'POST', data)
  end

  #
  # Remove sender
  #
  # @param [String] email
  # @return [Hash]
  #
  def remove_sender(email)
    return handle_error('Empty email') if email.to_s.empty?
    data = { email: email }
    send_request('senders', 'DELETE', data)
  end

  #
  # Activate sender using code
  #
  # @param [String] email
  # @param [String] code
  # @return [Hash]
  #
  def activate_sender(email, code)
    return handle_error('Empty email or activation code') if email.to_s.empty? || code.to_s.empty?
    data = { code: code }
    send_request("senders/#{email}/code", 'POST', data)
  end

  #
  # Request mail with activation code
  #
  # @param [String] email
  # @return [Hash]
  #
  def get_sender_activation_mail(email)
    return handle_error('Empty email') if email.to_s.empty?
    send_request("senders/#{email}/code")
  end

  #
  # Get global information about email
  #
  # @param [String] email
  # @return [Hash]
  #
  def get_email_global_info(email)
    return handle_error('Empty email') if email.to_s.empty?
    send_request("emails/#{email}")
  end

  #
  # Remove email from all books
  #
  # @param [String] email
  # @return [Hash]
  #
  def remove_email_from_all_books(email)
    return handle_error('Empty email') if email.to_s.empty?
    send_request("emails/#{email}", 'DELETE')
  end

  #
  # Get email statistic by all campaigns
  #
  # @param [String] email
  # @return [Hash]
  #
  def email_stat_by_campaigns(email)
    return handle_error('Empty email') if email.to_s.empty?
    send_request("emails/#{email}/campaigns")
  end

  #
  # Get all emails from blacklist
  #
  # @return [Hash]
  #
  def get_black_list
    send_request('blacklist')
  end

  #
  # Add email to blacklist
  #
  # @param [String] emails
  # @param [String] comment
  # @return [Hash]
  #
  def add_to_black_list(emails, comment = '')
    return handle_error('Empty emails') if emails.to_s.empty?
    data = {
        emails: Base64.encode64(emails),
        comment: comment
    }
    send_request('blacklist', 'POST', data)
  end

  #
  # Remove emails from blacklist
  #
  # @param [String] emails
  # @return [Hash]
  #
  def remove_from_black_list(emails)
    return handle_error('Empty emails') if emails.to_s.empty?
    data = { emails: Base64.encode64(emails) }
    send_request('blacklist', 'DELETE', data)
  end

  #
  # Get balance
  #
  # @param [String] currency
  # @return [Hash]
  #
  def get_balance(currency = '')
    url = 'balance'
    url += '/' + currency.to_s.upcase unless currency.empty?
    send_request(url)
  end

  #
  # SMTP: get list of emails
  #
  # @param [Fixnum] limit
  # @param [Fixnum] offset
  # @param [String] from_date
  # @param [String] to_date
  # @param [String] sender
  # @param [String] recipient
  # @return [Hash]
  #
  def smtp_list_emails(limit = 0, offset = 0, from_date = '', to_date = '', sender = '', recipient = '')
    data = {
        limit: limit,
        offset: offset,
        from_date: from_date,
        to_date: to_date,
        sender: sender,
        recipient: recipient
    }
    send_request('/smtp/emails', 'GET', data)
  end

  #
  # SMTP: add emails to unsubscribe list
  #
  # @param [Fixnum] id
  # @return [Hash]
  #
  def smtp_get_email_info_by_id(id)
    return handle_error('Empty id') if id.to_s.empty?
    send_request("smtp/emails/#{id}")
  end

  #
  # SMTP: remove emails from unsubscribe list
  #
  # @param [Hash] emails
  # @return [Hash]
  #
  def smtp_unsubscribe_emails(emails)
    return handle_error('Empty emails') if emails.empty?
    data = { emails: serialize(emails) }
    send_request('smtp/unsubscribe', 'POST', data)
  end

  #
  # SMTP: remove emails from unsubscribe list
  #
  # @param [Hash] emails
  # @return [Hash]
  #
  def smtp_remove_from_unsubscribe(emails)
    return handle_error('Empty emails') if emails.empty?
    data = { emails: serialize(emails) }
    send_request('smtp/unsubscribe', 'DELETE', data)
  end

  #
  # SMTP: get list of IP
  #
  # @return [Hash]
  #
  def smtp_list_ip
    send_request('smtp/ips')
  end

  #
  # SMTP: get list of allowed domains
  #
  # @return [Hash]
  #
  def smtp_list_allowed_domains
    send_request('smtp/domains')
  end

  #
  # SMTP: add new domain
  #
  # @param [String] email
  # @return [Hash]
  #
  def smtp_add_domain(email)
    return handle_error('Empty email') if email.to_s.empty?
    data = { email: email }
    send_request('smtp/domains', 'POST', data)
  end

  #
  # SMTP: verify domain
  #
  # @param [String] email
  # @return [Hash]
  #
  def smtp_verify_domain(email)
    return handle_error('Empty email') if email.to_s.empty?
    send_request("smtp/domains/#{email}")
  end

  #
  # SMTP: send mail
  #
  # @param [Hash] email
  # @return [Hash]
  #
  def smtp_send_mail(email)
    return handle_error('Empty email') if email.empty?
    email[:html] = Base64.encode64(email[:html])
    data = { email: serialize(email) }
    send_request('smtp/emails', 'POST', data)
  end

end