text:
from __future__ import unicode_literals
from __future__ import absolute_import

__author__ = "czerwin@scalyr.com"

if False:  # NOSONAR
    from typing import Dict
    from types import ModuleType

import inspect
import os
import sys
import time
import random
import hashlib
from threading import Lock

import six

import scalyr_agent.scalyr_logging as scalyr_logging
from scalyr_agent.json_lib.objects import ArrayOfStrings

from scalyr_agent.config_util import (
    convert_config_param,
    get_config_from_env,
    BadConfiguration,
)
from scalyr_agent.util import StoppableThread

log = scalyr_logging.getLogger(__name__)

# Maximum value we will use for random sleep before first sample gathering.
# This way we guard against a potentially very large sleep which would be used for monitors
# configured with very large sample intervals.
MAX_INITIAL_GATHER_SAMPLE_SLEEP_SECS = 40

# Minimum value for initial sample gather sleep for monitors which use very large sample gather
# interval.
MIN_INITIAL_GATHER_SAMPLE_SLEEP_SECS = 15

class ScalyrMonitor(StoppableThread):
    """The default number of seconds between gathering a sample.  This is the global default, which should
    be set from the configuration file.
    """

    DEFAULT_SAMPLE_INTERVAL_SECS = 30.0

    """The base class for all monitors used by the agent.

    An instance of a monitor will be created for every reference to this module in the "monitors"
    section in the agent.json configuration file.  The monitor will be
    executed in its own thread and will be expected to send all output to
    provided Loggers.  Do not used stdout, stderr.

    Public attributes:  (must be updated in derived constructor)
        log_config:  A dict containing the log configuration object that
            should be used to configure the agent to copy the log generated
            by this module.  It has the same format as the entries in the
            "logs" section in agent.json.  In particular, the module
            can use this to specify the path of the log file where all emitted metric values
            from this monitor will be sent (using self._logger), set attributes to
            associate with all log lines generated by the module, specify a parser
            for the log, as well as set sampling rules.

            Note, if the "path" field in "log_config" is not absolute, it will be resolved relative to the
            directory specified by the "agent_log_path" option in the configuration file.
        disabled:  A boolean indicating if this module instance should be
            run.
    """

    def __init__(
        self, monitor_config, logger, sample_interval_secs=None, global_config=None
    ):
        """Constructs an instance of the monitor.

        It is optional for derived classes to override this method.  The can instead
        override _initialize which is invoked during initialization.
        TODO:  Determine which approach is preferred by developers and recommend that.

        If a derived class overrides __init__, they must invoke this method in the override method.

        This method will set default values for all public attributes (log_config, disabled, etc).  These
        may be overwritten by the derived class.

        The derived classes must raise an Exception (or something derived from Exception)
        in this method if the provided configuration is invalid or if there is any other
        error known at this time preventing the module from running.

        @param monitor_config: A dict containing the configuration information for this module instance from the
            configuration file. The only valid values are strings, ints, longs, floats, and booleans.
        @param logger: The logger to use for output.
        @param sample_interval_secs: The interval in seconds to wait between gathering samples.  If None, it will
            set the value from the ``sample_interval`` field in the monitor_config if present, or the default
            interval time for all monitors in ``DEFAULT_SAMPLE_INTERVAL_SECS``.  Generally, you should probably
            pass None here and allow the value to be taken from the configuration files.
        @param global_config: the global configuration object.  Monitors can use or ignore this as necessary
        """
        # The logger instance that this monitor should use to report all information and metric values.
        self._logger = logger
        self.monitor_name = monitor_config["module"]

        # Includes just the monitor module name. For example, if the full module name is
        # "scalyr_agent.builtin_monitors.symlink_file_monitor", module name would be
        # "symlink_file_monitor"
        self.monitor_module_name = self.monitor_name.split(".")[-1]
        # NOTE: In case there is only one monitor configured without "id" attribute defined, the
        # value will be set to empty string. In case there are multiple monitor configs defined, but
        # the user doesn't explicitly set "id" attribute for those, config index (number) will be
        # used.
        self.monitor_id = str(monitor_config.get("id", "") or "default")
        # Short hash of this monitor instance which is unique across all the monitors
        self.short_hash = hashlib.sha256(
            self.monitor_name.encode("utf-8") + b":" + self.monitor_id.encode("utf-8")
        ).hexdigest()[:10]

        # Holds raw monitor name without the part which are specific to monitor instances
        if "." in monitor_config["module"]:
            split = monitor_config["module"].split(".")
            self.raw_monitor_name = split[-1]
        else:
            self.raw_monitor_name = monitor_config["module"]

        # save the global config
        self._global_config = global_config

        # The MonitorConfig object created from the config for this monitor instance.
        self._config = MonitorConfig(monitor_config, monitor_module=self.monitor_name)
        log_path = self.monitor_name.split(".")[-1] + ".log"
        self.disabled = False
        # TODO: For now, just leverage the logic in the loggers for naming this monitor.  However,
        # we should have it be more dynamic where the monitor can override it.
        if logger.component.find("monitor:") == 0:
            self.monitor_name = logger.component[8:]
        else:
            self.monitor_name = logger.component
        self.log_config = {
            "path": log_path,
        }
        # This lock protects all variables that can be access by other threads, reported_lines,
        # emitted_lines, and errors.  It does not protect _run_state since that already has its own lock.
        self.__lock = Lock()
        self.__reported_lines = 0
        self.__errors = 0

        # Set the time between samples for this monitor.  We prefer configuration values over the values
        # passed into the constructor.
        if sample_interval_secs is not None:
            self._sample_interval_secs = sample_interval_secs
        else:
            self._sample_interval_secs = self._config.get(
                "sample_interval",
                convert_to=float,
                default=ScalyrMonitor.DEFAULT_SAMPLE_INTERVAL_SECS,
            )

        self.__metric_log_open = False

        # These variables control the rate limiter on how fast we can write to the metric log.
        # The first one is the average number of bytes that can be written per second.  This is the bucket fill rate
        # in the "leaky bucket" algorithm used to calculate the rate limit.  Derived classes may change this.
        self._log_write_rate = self._config.get(
            "monitor_log_write_rate", convert_to=int, default=2000
        )
        # This is the maximum size of a write burst to the log.  This is the bucket size in the "leaky bucket" algorithm
        # used to calculate the rate limit.  Derived classes may change this.
        self._log_max_write_burst = self._config.get(
            "monitor_log_max_write_burst", convert_to=int, default=100000
        )
        # This is the number of seconds between waiting to flush the metric log (if there are pending bytes that
        # need to be flushed to disk).  If this is greater than zero, then it will reduce the amount of disk
        # flushing, but at the cost of possible loss of data if the agent shutdowns down unexpectantly.
        self._log_flush_delay = self._config.get(
            "monitor_log_flush_delay", convert_to=float, default=0.0, min_value=0
        )

        # List of metrics name which shouldn't be logged and sent to Scalyr
        self._metric_name_blacklist = self._config.get(
            "metric_name_blacklist", convert_to=ArrayOfStrings, default=[]
        )

        # List of metric names for which per second rates should be calculated in the agent
        self._calculate_rate_metric_name = self._config.get(
            "calculate_rate_metric_names", convert_to=ArrayOfStrings, default=[]
        )

        # If true, will adjust the sleep time between gather_sample calls by the time spent in gather_sample, rather
        # than sleeping the full sample_interval_secs time.
        self._adjust_sleep_by_gather_time = False
        self._initialize()

        StoppableThread.__init__(self, name="metric thread")

    def get_stop_agent_on_failure(self):
        """
        Returns boolean value which indicates that the agent can not run without this monitor and
        has to fail if monitor fails.
        """
        try:
            return self._config["stop_agent_on_failure"]
        except KeyError:
            return False

    @property
    def uid(self):
        """
        Return unique id for this monitor.

        Unique ID is composed of the monitor name and the id specified in the monitor local config.
        """
        return (
            self._config["module"] + "-" + str(self._config.get("id", "default"))
            or "default"
        )

    def _initialize(self):
        """Can be overridden by derived classes to perform initialization functions before the monitor is run.

        This is meant to allow derived monitors to perform some initialization and configuration validation
        without having to override the __init__ method (and be responsible for passing all of the arguments
        to the super class).

        The derived classes must raise an Exception (or something derived from Exception)
        in this method if the provided configuration is invalid or if there is any other
        error known at this time preventing the module from running.

        NOTE: This will be called everytime the agent script is run, including when *stopping* the agent.
        Therefore it is not the best place to do things like create sockets/open files etc.

        @param global_config: the global configuration object.  Monitors can use or ignore this as necessary
        """
        pass

    @property
    def module_name(self):
        """Returns the name of the module that will run this monitor."""
        return self._config["module"]

    def reported_lines(self):
        """Returns the number of metric lines emitted to the metric log for this monitor.

        This is calculated by counting how many times the logger instance on this monitor's report_values
        method was invoked and all the times any logger has logged anything with metric_log_for_monitor set
        to this monitor.
        """
        self.__lock.acquire()
        result = self.__reported_lines
        self.__lock.release()
        return result

    def errors(self):
        """Returns the number of errors experienced by the monitor as it is running.

        For monitors just implementing the gather_sample method, this will be the number of times
        that invocation raised an exception.  If a monitor overrides the run method, then it is up to
        them to increment the errors as appropriate using increment_counter.
        """
        self.__lock.acquire()
        result = self.__errors
        self.__lock.release()
        return result

    def increment_counter(self, reported_lines=0, errors=0):
        """Increment some of the counters pertaining to the performance of this monitor."""
        self.__lock.acquire()
        self.__reported_lines += reported_lines
        self.__errors += errors
        self.__lock.release()

    def config_from_monitors(self, manager):
        """
        Called directly before running the `run` method.
        This method passes in the module manager object to a monitor before
        it runs so that the monitor can query the monitor about other monitors
        that exist.
        In order to prevent circular references, callees should *not* retain a
        reference to the manager object
        """
        pass

    def _get_initial_sleep_delay(self):
        # type: () -> int
        """
        Return initial sleep delay for this monitor.

        We sleep this number of seconds before first sample gathering.

        By default (on agent start up and when reloading the config and restarting the monitors),
        all the monitors are started at the same time, which means that all the monitors with the
        same sample gather interval will run at the same time.

        To avoid this and potential larger load spike when running many monitors on lower powered
        devices, we sleep random number of seconds before first sample gather interval for each
        monitor.

        This way we spread a potential short load spike during sample gathering across a longer time
        frame.
        """
        # NOTE: self._global_config will be None when using scalyr_agent/run_monitor.py script with
        # -c flag
        if not self._global_config:
            return 0

        if not self._global_config.global_monitor_sample_interval_enable_jitter:
            return 0

        sample_interval_secs = self._sample_interval_secs

        if sample_interval_secs >= MAX_INITIAL_GATHER_SAMPLE_SLEEP_SECS:
            min_jitter_secs = MIN_INITIAL_GATHER_SAMPLE_SLEEP_SECS
            max_jitter_secs = MAX_INITIAL_GATHER_SAMPLE_SLEEP_SECS
        else:
            # min sleep time is 2/10 of the sample interval and max is 8/10
            min_jitter_secs = round((sample_interval_secs / 10) * 2)
            max_jitter_secs = round((sample_interval_secs / 10) * 8)

        random_jitter_secs = random.randint(min_jitter_secs, max_jitter_secs)
        return random_jitter_secs

    def run(self):
        """Begins executing the monitor, writing metric output to logger.

        Implements the business logic for this monitor.  This method will
        be invoked by the agent on its own thread.  This method should
        only return if the monitor instance should no longer be executed or
        if the agent is shutting down.

        The default implementation of this method will invoke the
        "gather_sample" once every sample_period time, emitting the returned
        dict to logger.  Derived classes may override this method if they
        wish.

        This method should use "self._logger" to report any output.  It should use
        "self._logger.emit_value" to report any metric values generated by the monitor
        plugin.  See the documentation for 'scalyr_logging.AgentLogger.emit_value' method for more details.
        """
        # noinspection PyBroadException
        try:
            # To avoid all the monitors with the same sample interval running at the same time,
            # we add random sleep delay before the first same gathering.
            initial_sleep_delay = self._get_initial_sleep_delay()

            if initial_sleep_delay >= 1:
                self._sleep_but_awaken_if_stopped(initial_sleep_delay)
                self._logger.debug(
                    "Sleeping %s seconds before first sample gather interval"
                    % (initial_sleep_delay)
                )

            while not self._is_thread_stopped():
                sample_interval = self._sample_interval_secs

                # noinspection PyBroadException
                adjustment = 0
                try:
                    start_time = time.time()
                    self.gather_sample()
                    if self._adjust_sleep_by_gather_time:
                        adjustment = min(time.time() - start_time, sample_interval)
                except Exception:
                    self._logger.exception(
                        "Failed to gather sample due to the following exception"
                    )
                    self.increment_counter(errors=1)

                self._sleep_but_awaken_if_stopped(sample_interval - adjustment)

            self._logger.info("Monitor has finished")
        except Exception:
            # TODO:  Maybe remove this catch here and let the higher layer catch it.  However, we do not
            # right now join on the monitor threads, so no one would catch it.  We should change that.
            self._logger.exception(
                "Monitor died from due to exception:", error_code="failedMonitor"
            )

    def get_extra_server_attributes(self):
        """Derived classes may optionally return a dict of server attributes to be added to the main config
        server attributes.  Keys already defined by server attributes or other monitors will be dropped with a warning.

        You must ensure that this method is thread-safe as it will be invoked by a different thread than the monitor
        itself.

        @return: A dict or None
        """
        return None

    def get_user_agent_fragment(self):
        """Derived classes may optionally return a string fragment to be appended to the User-Agent header for all
        data sent to Scalyr.  Note: User-Agent augmentation applies to all data (not restricted to data from this
        monitor).

        You must ensure that this method is thread-safe as it will be invoked by a different thread (MonitorsManager).

        @return: A string fragment or None (Empty strings are treated as None)
        """
        return None

    def gather_sample(self):
        """Derived classes should implement this method to gather a data sample for this monitor plugin
        and report it.

        If the default "run" method implementation is not overridden, then
        derived classes must implement this method to actual perform the
        monitor-specific work to gather whatever information it should be
        collecting.

        It is expected that the derived class will report any gathered metric samples
        by using the 'emit_value' method on self._logger.  They may invoke that method
        multiple times in a single 'gather_sample' call to report multiple metrics.
        See the documentation for 'scalyr_logging.AgentLogger.emit_value' method for more details.

        Any exceptions raised by this method will be reported as an error but will
        not stop execution of the monitor.
        """
        pass

    def set_sample_interval(self, secs):
        """Sets the number of seconds between calls to gather_sample when running.

        This must be invoked before the monitor is started.

        @param secs: The number of seconds, which can be fractional.
        """
        self._sample_interval_secs = secs

    def set_log_watcher(self, log_watcher):
        """Provides a log_watcher object that monitors can use to add/remove log files"""
        pass

    def _get_log_rotation_configuration(self):
        """Gets the log rotation backup count and maximum byte settings from the monitor config,
        and if not specified by the monitor config then from the global config
        @return: A tuple containing the log_rotation_backup_count and the log_rotation_max_bytes
                 for this monitor.
        """

        rotation_count = self._config.get("log_rotation_backup_count")
        if rotation_count is None:
            # Sometimes global_config can be null if derived monitor did not pass one in.
            if self._global_config is not None:
                rotation_count = self._global_config.log_rotation_backup_count
            else:
                rotation_count = 2

        max_bytes = self._config.get("log_rotation_max_bytes")
        if max_bytes is None:
            if self._global_config is not None:
                max_bytes = self._global_config.log_rotation_max_bytes
            else:
                max_bytes = 20 * 1024 * 1024

        return (int(rotation_count), int(max_bytes))

    def open_metric_log(self):
        """Opens the logger for this monitor.

        This must be invoked before the monitor is started."""
        backup_count, max_bytes = self._get_log_rotation_configuration()

        self._logger.openMetricLogForMonitor(
            self.log_config["path"],
            self,
            max_bytes=max_bytes,
            backup_count=backup_count,
            max_write_burst=self._log_max_write_burst,
            log_write_rate=self._log_write_rate,
            flush_delay=self._log_flush_delay,
        )
        self.__metric_log_open = True
        return True

    def close_metric_log(self):
        """Closes the logger for this monitor.

        This must be invoked after the monitor has been stopped."""
        if self.__metric_log_open:
            self._logger.closeMetricLog()
            self.__metric_log_open = False

    def get_calculate_rate_metric_names(self):
        """
        Return a list of metric names for this monitor for which rate should be calculated on the
        agent side.

        This method can either return value which is read from the monitor config or it can obtain
        a list of those metric names dynamically (e.g. from the OpenMetrics metric schema / type or
        similar).
        """
        return self._calculate_rate_metric_name

    # 2->TODO '_is_stopped' name is reserved in python3
    def _is_thread_stopped(self):
        """Returns whether or not the "stop" method has been invoked."""
        return not self._run_state.is_running()

    def _sleep_but_awaken_if_stopped(self, time_to_sleep):
        """Sleeps for the specified amount of seconds or until the stop() method on this instance is invoked, whichever
         comes first.

        @param time_to_sleep: The number of seconds to sleep.

        @return: True if the stop() has been invoked.
        """
        return self._run_state.sleep_but_awaken_if_stopped(time_to_sleep)

def load_monitor_class(module_name, additional_python_paths):
    """Loads the ScalyrMonitor class from the specified module and return it.

    This examines the module, locates the first class derived from ScalyrMonitor (there should only be one),
    and returns it.

    @param module_name: The name of the module
    @param additional_python_paths: A list of paths (separate by os.pathsep) to add to the PYTHONPATH when
        instantiating the module in case it needs to read other packages.

    @type module_name: six.text_type
    @type additional_python_paths: six.text_type

    @return: A tuple containing the class for the monitor and the MonitorInformation object for it.
    @rtype: (class, MonitorInformation)
    """

    original_path = list(sys.path)

    # Add in the additional paths.
    if additional_python_paths is not None and len(additional_python_paths) > 0:
        for x in additional_python_paths.split(os.pathsep):
            sys.path.append(x)

    MonitorInformation.set_monitor_info(module_name)
    # Load monitor.
    try:
        module = __import__(module_name)
        # If this a package name (contains periods) then we have to walk down
        # the subparts to get the actual module we wanted.
        for n in module_name.split(".")[1:]:
            module = getattr(module, n)

        # Now find any class that derives from ScalyrMonitor
        for attr in module.__dict__:
            value = getattr(module, attr)
            if not inspect.isclass(value):
                continue
            if "ScalyrMonitor" in six.text_type(value.__bases__):
                description = value.__doc__
                if description:
                    description = description.strip()

                MonitorInformation.set_monitor_info(
                    module_name, description=description
                )
                return value, MonitorInformation.get_monitor_info(module_name)

        return None, None
    finally:
        # Be sure to reset the PYTHONPATH
        sys.path = original_path

def define_config_option(
    monitor_module,
    option_name,
    option_description,
    required_option=False,
    max_value=None,
    min_value=None,
    convert_to=None,
    default=None,
    env_aware=False,
    env_name=None,
):
    """Defines a configuration option for the specified monitor.

    Once this is invoked, any validation rules supplied here are applied to all MonitorConfig objects created
    with the same monitor name.

    Note, this overwrites any previously defined rules for this configuration option.

    @param monitor_module:  The module the monitor is defined in.  This must be the same name that will be supplied
        for any MonitorConfig instances for this monitor.
    @param option_name: The name of the option field.
    @param required_option: If True, then this is option considered to be required and when the configuration
        is parsed for the monitor, a BadMonitorConfiguration exception if the field is not present.
    @param convert_to: If not None, then will convert the value for the option to the specified type. Only int,
        bool, float, long, and six.text_type are supported. If the type conversion cannot be done, a
        BadMonitorConfiguration exception is raised during configuration parsing. The only true conversions allowed are
        those from six.text_type value to other types such as int, bool, long, float. Trivial conversions are allowed
        from int, long to float, but not the other way around. Additionally, any primitive type can be converted to
        six.text_type.
    @param default: The value to assign to the option if the option is not present in the configuration. This is
        ignored if 'required_option' is True.
    @param max_value: If not None, the maximum allowed value for option. Raises a BadMonitorConfiguration if the
        value is greater during configuration parsing.
    @param min_value: If not None, the minimum allowed value for option. Raises a BadMonitorConfiguration if the
        value is less than during configuration parsing.
    @param env_aware: If True and not defined in config file, look for presence of environment variable.
    @param env_name: If provided, will use this name to lookup the environment variable.  Otherwise, use
        scalyr_<field> as the environment variable name.
        Note: A non-empty value also automatically implies env_aware as True, regardless of it's value.
    """
    option = ConfigOption()
    option.option_name = option_name
    option.description = option_description
    option.required_option = required_option
    option.max_value = max_value
    option.min_value = min_value
    option.convert_to = convert_to
    option.default = default
    option.env_aware = env_aware
    option.env_name = env_name

    MonitorInformation.set_monitor_info(monitor_module, option=option)
    return None

def define_metric(
    monitor_module,
    metric_name,
    description,
    extra_fields=None,
    unit=None,
    cumulative=False,
    category=None,
):
    """Defines description information for a metric with the specified name and extra fields.

    This will overwrite previous metric information recorded for the same ``metric_name`` and ``extra_fields``.

    Currently, this information is only used when creating documentation pages for the monitor.  Not all of the fields
    are used but will be used in the future.

    @param monitor_module:  The module name for the monitor this metric is defined in.
    @param metric_name: The name of the metric.
    @param description: The description of the metric.
    @param extra_fields: A dict describing the extra fields that are recorded with this metric.  It maps from the
        extra field name to the values that the description apply to.
    @param unit: A string describing the units of the value.  For now, this should be 'sec' or 'bytes'.  You may also
        include a colon after the unit with a scale factor.  For example, 'sec:.01' indicates the value represents
        1/100ths of a second.  You may also specify 'milliseconds', which is mapped to 'sec:.001'
    @param cumulative: True if the metric records the sum all metric since the monitored process began.  For example,
        it could be the sum of all request sizes received by a server.  In this case, calculating the difference between
        two values for the metric is the same as calculating the rate of non-accumulated metric.
    @param category: The category of the metric.  Each category will get its own table when printing the documentation.
        This should be used when there are many metrics and they need to be broken down into smaller groups.

    @type monitor_module: six.text_type
    @type metric_name: six.text_type
    @type description: six.text_type
    @type extra_fields: dict
    @type unit: six.text_type
    @type cumulative: bool
    @type category: six.text_type
    """

    info = MetricDescription()
    info.metric_name = metric_name
    info.description = description
    info.extra_fields = extra_fields
    info.unit = unit
    info.cumulative = cumulative
    info.category = category
    MonitorInformation.set_monitor_info(monitor_module, metric=info)

def define_log_field(monitor_module, field_name, field_description):
    """Defines a field that can be parsed from the log lines generated by the specified monitor.

    Note, this overwrites any previously defined rules for this log field.

    @param monitor_module:  The module the monitor is defined in.  This must be the same name that will be supplied
        for any MonitorConfig instances for this monitor.
    @param field_name: The name of the log field.
    @param field_description: The description for the log field.

    """
    log_field = LogFieldDescription()
    log_field.field = field_name
    log_field.description = field_description

    MonitorInformation.set_monitor_info(monitor_module, log_field=log_field)

    return None

class MonitorInformation(object):
    """Encapsulates all the descriptive information that can be gather for a particular monitor.

    This is generally used to create documentation pages for the monitor.
    """

    def __init__(self, monitor_module):
        self.__monitor_module = monitor_module
        self.__description = None
        # Maps from option name to the ConfigOption object that describes it.
        self.__options = {}
        # Maps from metric name with extra fields to the MetricDescription object that describes it.
        self.__metrics = {}
        # Maps from log field name to the LogFieldDescription object that describes it.
        self.__log_fields = {}
        # A counter used to determine insert sort order.
        self.__counter = 0

    @property
    def monitor_module(self):
        """Returns the module the monitor is defined in.

        @return: The module the monitor is defined in.
        @rtype: six.text_type
        """
        return self.__monitor_module

    @property
    def description(self):
        """Returns a description for the monitor using markdown.

        @return: The description
        @rtype: six.text_type
        """
        return self.__description

    @property
    def config_options(self):
        """Returns the configuration options for this monitor.

        @return: A list of the options
        @rtype: list of ConfigOption
        """
        return sorted(
            six.itervalues(self.__options), key=self.__get_insert_sort_position
        )

    @property
    def metrics(self):
        """Returns descriptions for the metrics recorded by this monitor.

        @return: A list of metric descriptions
        @rtype: list of MetricDescription
        """
        return sorted(
            six.itervalues(self.__metrics), key=self.__get_insert_sort_position
        )

    @property
    def log_fields(self):
        """Returns the log fields that are parsed from the log lines generated by this monitor.

        @return: A list of the log fields.
        @rtype: list of LogFieldDescription
        """
        return sorted(
            six.itervalues(self.__log_fields), key=self.__get_insert_sort_position
        )

    def __get_insert_sort_position(self, item):
        """Returns the key to use for sorting the item by its insert position.

        This relies on the 'sort_pos' attribute added to all ConfigOption, MetricDescription, and
        LogFieldDescription objects when added to a monitor's information.

        @param item: The object
        @type item: object

        @return: The insert position of the item
        @rtype: int
        """
        return getattr(item, "sort_pos")

    __monitor_info__ = {}  # type: Dict[ModuleType, MonitorInformation]

    @staticmethod
    def set_monitor_info(
        monitor_module, description=None, option=None, metric=None, log_field=None
    ):
        """Sets information for the specified monitor.

        @param monitor_module: The module the monitor is defined in.
        @param description: If not None, sets the description for the monitor, using markdown.
        @param option: If not None, adds the specified configuration option to the monitor's information.
        @param metric: If not None, adds the specified metric description to the monitor's information.
        @param log_field: If not None, adds the specified log field description to the monitor's information.

        @type monitor_module: six.text_type
        @type description: six.text_type
        @type option: ConfigOption
        @type metric: MetricDescription
        @type log_field: LogFieldDescription
        """
        if monitor_module not in MonitorInformation.__monitor_info__:
            MonitorInformation.__monitor_info__[monitor_module] = MonitorInformation(
                monitor_module
            )

        info = MonitorInformation.__monitor_info__[monitor_module]
        if description is not None:
            info.__description = description

        # Increment the counter we use to recorder insert order.
        info.__counter += 1

        if option is not None:
            info.__options[option.option_name] = option
            # Stash a position attribute to capture what the insert order was for the options.
            setattr(option, "sort_pos", info.__counter)

        if metric is not None:
            if metric.extra_fields is None:
                info.__metrics[metric.metric_name] = metric
            else:
                # If there are extra fields, we use that as part of the key name to store the metric under to
                # avoid collisions with the same metric but different extra fields registered.
                info.__metrics[
                    "%s%s" % (metric.metric_name, six.text_type(metric.extra_fields))
                ] = metric
            # Stash a position attribute to capture what the insert order was for the metrics.
            setattr(metric, "sort_pos", info.__counter)

        if log_field is not None:
            info.__log_fields[log_field.field] = log_field
            # Stash a position attribute to capture what the insert order was for the log fields.
            setattr(log_field, "sort_pos", info.__counter)

    @staticmethod
    def get_monitor_info(monitor_module):
        """Returns the MonitorInformation object for the monitor defined in ``monitor_module``.

        @param monitor_module: The module the monitor is defined in.
        @type monitor_module: six.text_type

        @return: The information for the specified monitor, or none if it has not been loaded.
        @rtype: MonitorInformation
        """
        if monitor_module in MonitorInformation.__monitor_info__:
            return MonitorInformation.__monitor_info__[monitor_module]
        else:
            return None

    def __repr__(self):
        return "<MonitorInformation monitor_module=%s,metrics=%s>" % (
            self.__monitor_module,
            self.__metrics,
        )

class ConfigOption(object):
    """Simple object to hold the fields for a single configuration option."""

    def __init__(self):
        # The name of the option.
        self.option_name = None
        # The description of the option.
        self.description = None
        # True if the option is required.
        self.required_option = False
        # The maximum value allowed value for the option if any.
        self.max_value = None
        # The minimum value allowed value for the option if any.
        self.min_value = None
        # The primitive type to convert the value to.
        self.convert_to = None
        # The default value, if any.
        self.default = None
        # Whether to look in the environment for a fallback value if not defined in config file
        self.env_aware = False
        # Customer environment variable name (instead of SCALYR_<option_name>
        self.env_name = None

    def __repr__(self):
        return "%s %s %s" % (self.option_name, self.env_aware, self.env_name)

class MetricDescription(object):
    """Simple object to hold fields describing a monitor's metric."""

    def __init__(self):
        # The name of the metric.
        self.metric_name = None
        # The description for the metric.
        self.description = None
        # A dict containing a map of the extra fields included in the metric along with the format for the values.
        self.extra_fields = None
        # A string describing the units of the value.  For now, this should be 'sec' or 'bytes'.  You may also include
        # a colon after the unit with a scale factor.  For example, 'sec:.01' indicates the value represents 1/100ths
        # of a second.  You may also specify 'milliseconds', which is mapped to 'sec:.001'.
        self.unit = None
        # True if the metric records the sum all metric since the monitored process began.  For example, it could be
        # the sum of all the latencies for all requested received by the server.
        self.cumulative = False
        # The category for this metric.  This needs only to be supplied if the metric list is long for a particular
        # monitor.
        self.category = None

    def __repr__(self):
        return (
            "<MetricDescription metric_name=%s,unit=%s,cumulative=%s,extra_fields=%s>"
            % (self.metric_name, self.unit, self.cumulative, str(self.extra_fields))
        )

class LogFieldDescription(object):
    """Simple object to hold fields describing the entries that are parsed from a log line produced by the monitor."""

    def __init__(self):
        # The name of the field in the log line.
        self.field = None
        # The meaning of the field.
        self.description = None

class MonitorConfig(object):
    """Encapsulates configuration parameters for a single monitor instance and includes helper utilities to
    validate configuration values.

    This supports most of the operators and methods that dict supports, but has additional support to allow
    Monitor developers to easily validate configuration values.  See the get method for more details.

    This abstraction does not support any mutator operations.  The configuration is read-only.
    """

    def __init__(self, content=None, monitor_module=None):
        """Initializes MonitorConfig.

        @param content: A dict containing the key/values pairs to use.
        @param monitor_module: The module containing the monitor.  This must be the same as what was previously
            used for 'define_config_option' for any options registered for this monitor.
        """
        self.__map = {}
        self.__monitor_module = monitor_module
        self._environment_aware_map = {}

        if content is not None:
            for x in content:
                self.__map[x] = content[x]

        info = MonitorInformation.get_monitor_info(monitor_module)
        if info is not None:
            for x in info.config_options:

                # Config option is environment aware if either of the following are Truthy
                env_aware = x.env_aware or x.env_name
                if env_aware:
                    env_name = x.env_name or ("SCALYR_%s" % x.option_name.upper())
                    self._environment_aware_map[x.option_name] = env_name
                    defined_in_env = env_name in os.environ
                else:
                    defined_in_env = False

                if (
                    x.required_option
                    or x.default is not None
                    or x.option_name in self.__map
                    or defined_in_env
                ):
                    self.__map[x.option_name] = self.get(
                        x.option_name,
                        required_field=x.required_option,
                        max_value=x.max_value,
                        min_value=x.min_value,
                        convert_to=x.convert_to,
                        default=x.default,
                        report_conflicting_environment_value=True,
                    )

    def __len__(self):
        """Returns the number of keys in the JsonObject"""
        return len(self.__map)

    def get(
        self,
        field,
        required_field=False,
        max_value=None,
        min_value=None,
        convert_to=None,
        default=None,
        report_conflicting_environment_value=False,
    ):
        """Returns the value for the requested field.

        If the value is not set via config file, also look for it in the environment.

        This method will optionally apply some validation rules as indicated by the optional arguments.  If any
        of these validation operations fail, then a BadMonitorConfiguration exception is raised.  Monitor developers are
        encouraged to catch this exception at their layer.

        @param field: The name of the field.
        @param required_field: If True, then will raise a BadMonitorConfiguration exception if the field is not
            present.
        @param convert_to: If not None, then will convert the value for the field to the specified type. Only int,
            bool, float, long, and six.text_type are supported. If the type conversion cannot be done, a
            BadMonitorConfiguration exception is raised. The only conversions allowed are those mapped out in
            ALLOWED_CONVERSIONS. Trivial conversions are allowed from int, long to
            float, but not the other way around. Additionally, any primitive type can be converted to six.text_type.
            six.text_type can be converted to complex types such as ArrayOfStrings, JsonArray, JsonObject as long as
            they can be correctly parsed.
        @param default: The value to return if the field is not present in the configuration. This is ignored if
            'required_field' is True.
        @param max_value: If not None, the maximum allowed value for field. Raises a BadMonitorConfiguration if the
            value is greater.
        @param min_value: If not None, the minimum allowed value for field. Raises a BadMonitorConfiguration if the
            value is less than.
        @param report_conflicting_environment_value: If True, disallows overriding via environment variable.

        @return: The value
        @raise BadMonitorConfiguration: If any of the conversion or required rules are violated.
        """
        try:
            result = self.__map.get(field)
            if (
                result is not None
                and convert_to is not None
                and type(result) != convert_to
            ):
                result = convert_config_param(field, result, convert_to)

            # Param not found in config file, so check environment
            if result is None or report_conflicting_environment_value:
                envar_name = self._environment_aware_map.get(field)
                logger = None
                if report_conflicting_environment_value:
                    logger = log
                envar_val = get_config_from_env(
                    field,
                    envar_name,
                    convert_to=convert_to,
                    logger=logger,
                    param_val=result,
                    monitor_name=self.__monitor_module,
                )
                if result is None:
                    result = envar_val

            # Required field not found in environment nor in config
            if result is None:
                if required_field and field not in self.__map:
                    raise BadMonitorConfiguration(
                        'Missing required field "%s"' % field, field
                    )
                result = self.__map.get(field, default)

            if result is None:
                return result

            # Perform conversion again in case both config-file and environment values were absent and the default
            # value requires conversion.
            if convert_to is not None and not issubclass(convert_to, type(result)):
                result = convert_config_param(field, result, convert_to)

            if max_value is not None and result > max_value:
                raise BadMonitorConfiguration(
                    'Value of %s in field "%s" is invalid; maximum is %s'
                    % (six.text_type(result), field, six.text_type(max_value)),
                    field,
                )

            if min_value is not None and result < min_value:
                raise BadMonitorConfiguration(
                    'Value of %s in field "%s" is invalid; minimum is %s'
                    % (six.text_type(result), field, six.text_type(min_value)),
                    field,
                )

            return result
        except BadConfiguration as e:
            raise BadMonitorConfiguration(message=e.message, field=e.field)

    def __iter__(self):
        return six.iterkeys(self.__map)

    def iteritems(self):
        """Returns an iterator over the items (key/value tuple) for this object."""
        return six.iteritems(self.__map)

    def itervalues(self):
        """Returns an iterator over the values for this object."""
        return six.itervalues(self.__map)

    def iterkeys(self):
        """Returns an iterator over the keys for this object."""
        return six.iterkeys(self.__map)

    def items(self):
        """Returns a list of items (key/value tuple) for this object."""
        return list(self.__map.items())

    def values(self):
        """Returns a list of values for this object."""
        return list(self.__map.values())

    def keys(self):
        """Returns a list keys for this object."""
        return list(self.__map.keys())

    def __getitem__(self, field):
        if field not in self:
            raise KeyError('The missing field "%s" in monitor config.' % field)
        return self.__map[field]

    def copy(self):
        result = MonitorConfig()
        result.__map = self.__map.copy()
        return result

    def __contains__(self, key):
        """Returns True if the JsonObject contains a value for key."""
        return key in self.__map

    def __eq__(self, other):
        if other is None:
            return False
        if type(self) is not type(other):
            return False
        assert isinstance(other.__map, dict)
        return self.__map == other.__map

    def __ne__(self, other):
        return not self.__eq__(other)

class BadMonitorConfiguration(Exception):
    """Exception indicating a bad monitor configuration, such as missing a required field."""

    def __init__(self, message, field):
        self.message = message
        self.field = field
        Exception.__init__(self, message)

class UnsupportedSystem(Exception):
    """Exception indicating a particular monitor is not supported on this system."""

    def __init__(self, monitor_name, message):
        """Constructs an instance of the exception.

        @param monitor_name: The name of the monitor
        @param message: A message indicating what require was violated, such as requires Python version 2.6 or greater.
        """
        Exception.__init__(self, message)
        self.monitor_name = monitor_name


text:
module Saxxy

  class CallbackArray < Array
    def <<(obj)
      super(obj)
      @add_callback.call(obj) if @add_callback
      self
    end

    def >>(obj)
      delete(obj)
      @remove_callback.call(obj) if @remove_callback
      self
    end

    def on_remove(&block)
      @remove_callback = block
      self
    end

    def on_add(&block)
      @add_callback = block
      self
    end
  end

end

redpajama_set_name: RedPajamaGithub


text:
<?php
namespace GoogleAPI\Contrib\Analytics;
use GoogleAPI\Service\apiModel;

class ProfileChildLink extends apiModel {
    public $href;
    public $type;
    public function setHref($href) {
        $this->href = $href;
    }
    public function getHref() {
        return $this->href;
    }
    public function setType($type) {
        $this->type = $type;
    }
    public function getType() {
        return $this->type;
    }
}


text:
/*
 * This file is available under and governed by the GNU General Public
 * License version 2 only, as published by the Free Software Foundation.
 * However, the following notice accompanied the original version of this
 * file:
 *
 * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 *  * Neither the name of JSR-310 nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package test.java.time.chrono;

import static org.junit.Assert.assertNotNull;

import java.time.chrono.Chronology;
import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;
import org.junit.Test;

/**
 * Tests that a custom Chronology is available via the ServiceLoader.
 * The CopticChronology is configured via META-INF/services/java.time.chrono.Chronology.
 */
public class TestServiceLoader {

    @Test
    public void test_copticServiceLoader() {
        Map<String, Chronology> chronos = new HashMap<>();
        // Android-changed: This test assumes that the system classloader sees all test classes.
        // That assumption is untrue, when run in CTS. Use this class's classloader instead.
        ServiceLoader<Chronology> loader = ServiceLoader.load(Chronology.class,
                getClass().getClassLoader());
        for (Chronology chrono : loader) {
            chronos.put(chrono.getId(), chrono);
        }
        assertNotNull("CopticChronology not found", chronos.get("Coptic"));
    }

}


text:
### Exception handlers
Code used: [Base class](../examples/src/Number.php)|[Test case](../examples/tests/NumberTest.php)

In the last part we talked about writing your test and the usage of asserts. Your test case should look something
like this:
```php
<?php

namespace Test\App;

use App\Number;
use PHPUnit\Framework\TestCase;

class NumberTest extends TestCase
{
    /**
     * Number increment test
     */
    public function testIncrement()
    {
        $numberClass = new Number();

        $this->assertEquals(2, $numberClass->increment(1));
    }
}
```

This test only covers the things that you expect to happen, but if you want to write a good test you should also
cover the things that you don't want to happen. What if a string gets passed to the function, should it accept it or
should it throw an exception. The current version of the code does not accept strings, if you do pass a string it should
throw a `TypeError`. Exceptions and errors can be tested using the `expectException` method from the `TestCase` class
provided by PHPUnit. So lets add that line of code to our current test:

```php
<?php

namespace Test\App;

use App\Number;
use PHPUnit\Framework\TestCase;

class NumberTest extends TestCase
{
    /**
     * Number increment test
     */
    public function testIncrement()
    {
        $numberClass = new Number();

        $this->assertEquals(2, $numberClass->increment(1));

        // add exception handler
        $this->expectException(\TypeError::class);
        $numberClass->increment("x");
    }
}
```

Thats it, exception handlers arn't that complicated. The next part will cover the usage of `DataProviders`.

[PREVIOUS](./part_1.md) | [NEXT](./part_3.md)


text:
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Runtime.Serialization;

using Microsoft.Samples.Debugging.Native;
using Microsoft.Samples.Debugging.Native.Private;

namespace Microsoft.Samples.Debugging.Native
{

    /// <summary>
    /// Serves as global hook to register a platform-specific allocator for a Context.
    /// This provides extensions an easy way to get a CONTEXT for the current platform.
    /// </summary>
    [CLSCompliant(true)]
    public static class NativeContextAllocator
    {
        /// <summary>
        /// Allocate a context for the current platform
        /// </summary>
        /// <returns>Newly allocated platform specific context, determined by SetDefaultAllocator</returns>
        /// <exception cref="InvalidOperationException">Throws if no default allocator is set </exception>
        static public INativeContext Allocate()
        {
            if (s_fpAllocator == null)
            {
                throw new InvalidOperationException("No default allocator set.");
            }
            return s_fpAllocator();
        }

        /// <summary>
        /// Set the allocator used by Alloc
        /// </summary>
        /// <param name="fp">delegate to function that will allocate the context</param>
        static public void SetDefaultAllocator(AllocatorFunction fp)
        {
            s_fpAllocator = fp;
        }

        static AllocatorFunction s_fpAllocator;

        /// <summary>
        /// Prototype for native context allocator function.
        /// </summary>
        /// <returns>new instance of a native context</returns>
        public delegate INativeContext AllocatorFunction();
    }

    /// <summary>
    /// Exposes raw contents of the Context in IContext. This locks the buffer. Dispose this object to unlock the buffer
    /// </summary>
    /// <remarks>The implementation behind the interface has a variety of ways to ensure the memory is safe to write to.
    /// The buffer may be in the native heap; or it may be to a pinned object in the managed heap
    /// This is primarily intended for writing to the context (by passing the buffer out to a pinvoke),
    /// but can also be a way to read the raw bytes.</remarks>
    [CLSCompliant(true)]
    public interface IContextDirectAccessor : IDisposable
    {
        /// <summary>
        /// The size of the buffer. This should be the same as INativeContext.Size.
        /// </summary>
        int Size { get; }

        /// <summary>
        /// A pointer to the raw buffer. The memory is pinned until this object is disposed. Check the context Flags
        /// to know which raw bytes are valid to be read.
        /// </summary>
        IntPtr RawBuffer { get; }
    }

    /// <summary>
    /// Interface to a context. This provides platform agnostic wrapper to a platform specific OS Context.
    /// </summary>
    [CLSCompliant(true)]
    public interface INativeContext :
        IEquatable<INativeContext>,
        IDisposable
    {
        #region Writing
        /// <summary>
        /// Used to lock the buffer and get a raw pointer to it.
        /// This is the only way to change the entire context at once.
        /// This is useful for pinvoking to native functions.
        /// </summary>
        /// <returns>context writer object</returns>
        /// <remarks>
        /// Expected usage would be (in C# syntax):
        /// <example>
        ///    IContext c = NativeContextAllocator.Alloc();
        ///    using(IContextWriter w = c.OpenForDirectAccess) { // context buffer is now locked
        ///       SomeNativeFunctionToGetThreadContext(w.RawBuffer, w.Size);
        ///    } // w is disposed, this unlocks the context buffer.
        /// </example>
        /// </remarks>
        IContextDirectAccessor OpenForDirectAccess();
        #endregion

        #region Geometry and writing
        /// <summary>
        /// Get Size in bytes. Size could change depending on the flags.
        /// </summary>
        int Size { get; }

        /// <summary>
        /// Get the flags associated with the context.
        /// </summary>
        /// <remarks>Flags are platform specific and generally indicate which parts of the context are valid.
        /// Flags will affect which registers are available (EnumerateRegisters), potentially the Size of the context,
        /// and how contexts are compared.
        /// Expanding the active flags means newly included registers have an uninitialized value.
        /// A context could be completely constructed late-bound by setting the Flags and then calling
        /// SetRegisterByName on each regsister
        ///
        /// This property must roundtrip.
        ///
        /// When setting the flags to a new value, the object may enforce certain contstraints(for example,
        /// it may ensure that certain mandatory flags stay present). To see if a the set occured exactly,
        /// reget the flags after setting them and compare with expected results.
        /// </remarks>
        int Flags { get; set; }

        #endregion

        #region Standard operations
        /// <summary>
        /// Get the instruction pointer (eip on x86)
        /// </summary>
        IntPtr InstructionPointer { get; }

        /// <summary>
        /// Get the stack pointer (esp on x86)
        /// </summary>
        IntPtr StackPointer { get; }

        /// <summary>
        /// Enable or disable the single-step flag in the context.
        /// </summary>
        /// <param name="enable">true to enable single-stepping, false to disable it</param>
        /// <exception cref="System.InvalidOperationException">Throws if the architecture doesn't support single-stepping.</exception>
        void SetSingleStepFlag(bool enable);

        /// <summary>
        /// Is the single step flag enabled?
        /// </summary>
        bool IsSingleStepFlagEnabled { get; }

        /// <summary>
        /// Create a new deep copy of this context.
        /// The copies are independent and can be modified without interfering with each other.
        /// </summary>
        /// <returns>copy of this context</returns>
        /// <remarks>Contexts can be large, so copying excessively would be expensive.</remarks>
        /// <example>
        /// INativeContext c1 = ...
        /// INativeContext c2 = c1.Clone();
        ///
        /// Assert(c1 != c2); // true, Clone gives different instances
        /// Assert(c1.Equals(c2)); // true
        /// Assert(c2.Equals(c1)); // true
        /// </example>
        INativeContext Clone();

        // <summary>
        // Implement IEquatable<T> to do value comparison of two contexts.
        // </summary>
        // <param name="other">non-null context to compare too</param>
        // <returns>true if equal, else false</returns>
        // <remarks>Comparison can't just do a bitwise comparison of the buffer. It needs to be aware of the <see cref="Flags"/>
        // property for each context, because if a portion of the context is missing, it could be random garbage.
        // Comparison does not modify either context object.</remarks>

        // bool IEquatable<T>.Equals(object other)  // inheritted from IEquatable<T>

        #endregion Standard operations

        #region Self Describing
        /// <summary>
        /// Get a simple string description of the CPU the context is for. A implementation may also provide a ToString()
        /// override to give more detail (eg, which flags are active)
        /// </summary>
        string Cpu { get; }

        /// <summary>
        /// Enumerate registers names (and their types) for late-bound access. Available registers depend on the flags.
        /// </summary>
        /// <returns>an enumeration of (name,type) pairs</returns>
        /// <remarks>An implementation does not need to include all registers on the context.
        /// The returned strings can be used with other by-name functions like <see cref="FindRegisterByName"/>
        /// and <see cref="SetRegisterByName"/>.</remarks>
        System.Collections.Generic.IEnumerable<String> EnumerateRegisters();

        /// <summary>
        /// Get a register by name
        /// </summary>
        /// <param name="name">Name of the registers. Lookup is case insensitive</param>
        /// <returns>value of register. Registers can be arbitrary types (uint32, double, long, etc), so this
        /// returns an object. Throws if name is not currently valid</returns>
        object FindRegisterByName(string name);

        /// <summary>
        /// Sets a register by name.
        /// </summary>
        /// <param name="name">Case-insensitive name of register to set. </param>
        /// <param name="value">value of register to set. Type of value must be convertable to type of the register</param>
        /// <exception cref="System.InvalidOperationException">Throws if no matching name or if register is not valid for the given Flags.</exception>
        void SetRegisterByName(string name, object value);

        #endregion Self Describing

    } // IContext

}


text:
require 'spec_helper'

cmdnova = '/usr/bin/nova --os-username admin --os-password adminpw  --os-tenant-name admin --os-auth-url http://192.168.0.201:35357/v2.0'

describe command(cmdnova + ' network-list') do
  its(:exit_status) { should eq(0) }
end

describe command(cmdnova + ' network-list') do
  its(:stdout) { should match(/10.10.1.0/) }
end

['nova-network'].each do |svcname|
  describe service(svcname) do
    it { should be_enabled }
    it { should be_running }
  end
end


text:
'use strict';

import _ from 'lodash';
import fs from 'fs';
import path from 'path';
import {List, Map, OrderedMap} from 'immutable';

const COMPONENT_REDUCER_MAP = {
	tooltip: 'tooltips',
	type: 'typography'
};

const REGEX_BOOTSTRAP_COMPONENT_NAME = /([\w\s]+)\n/;

export function initVariables(baseTheme, lexiconDirs) {
	const {srcDir, userDataPath} = lexiconDirs;

	const bootstrapVariables = mapBootstrapVariables(srcDir);

	const lexiconVariables = mapLexiconVariables(srcDir);

	let variables = _mergeVariables(bootstrapVariables, lexiconVariables);

	if (baseTheme === 'atlasTheme') {
		const atlasVariables = mapAtlasVariables(srcDir);

		variables = _mergeVariables(variables, atlasVariables);
	}

	const sourceVariables = variables;

	mapCustomVariables(userDataPath).forEach((variable, key) => {
		if (sourceVariables.has(key)) {
			let sourceVariable = variables.get(key);

			variables = variables.set(key, sourceVariable.set('value', variable.get('value')));
		}
	});

	return {
		sourceVariables: sourceVariables,
		variables: variables
	};
};

export function mapAtlasVariables(srcDir) {
	return _mapVariablesFromComponentArray(_getAtlasThemeComponents(srcDir), path.join(srcDir, 'scss/atlas-theme/variables'), 'lexicon');
};

export function mapBootstrapVariables(srcDir) {
	return _mapBootstrapVariablesFile(srcDir);
};

export function mapCustomVariables(userDataPath) {
	return mapVariablesFromFile(path.join(userDataPath, '_custom_variables.scss'), 'custom', '');
};

export function mapThemeVariables(themePath) {
	return mapVariablesFromFile(path.join(themePath, 'src/css/_aui_variables.scss'), 'theme', '');
};

export function mapLexiconVariables(srcDir) {
	return _mapVariablesFromComponentArray(_getLexiconBaseComponents(srcDir), path.join(srcDir, 'scss/lexicon-base/variables'), 'lexicon');
};

export function mapVariablesFromFile(filePath, group, component) {
	if (!filePath || !fs.existsSync(filePath)) {
		return OrderedMap();
	}

	let fileContents = fs.readFileSync(filePath, {
		encoding: 'utf8'
	});

	return _mapVariablesFromString(fileContents, group, component);
};

export function _getAtlasThemeComponents(srcDir) {
	return _getComponentArrayFromVariablesFile(path.join(srcDir, 'scss/atlas-theme/_variables.scss'));
};

export function _getComponentArrayFromVariablesFile(filePath) {
	let fileContents = fs.readFileSync(filePath, {
		encoding: 'utf8'
	});

	let regex = /\@import\s\"variables\/(.*)\"/;

	return _.reduce(fileContents.split('\n'), function(result, item, index) {
		let match = item.match(regex);

		if (match) {
			result.push(match[1]);
		}

		return result;
	}, []);
};

export function _getLexiconBaseComponents(srcDir) {
	return _getComponentArrayFromVariablesFile(path.join(srcDir, 'scss/lexicon-base/_variables.scss'));
};

export function _getReducedComponentName(component) {
	return COMPONENT_REDUCER_MAP[component] || component;
};

export function _mapBootstrapVariablesFile(srcDir) {
	let fileContents = fs.readFileSync(path.join(srcDir, 'scss/bootstrap/_variables.scss'), {
		encoding: 'utf8'
	});

	let fileSections = fileContents.split('//== ');

	let orderedMap = OrderedMap();

	_.forEach(fileSections, function(item, index) {
		if (index == 0) {
			return;
		}

		let name = item.match(REGEX_BOOTSTRAP_COMPONENT_NAME);

		if (name && name.length) {
			let componentName = _.kebabCase(name[1]);

			orderedMap = orderedMap.merge(_mapVariablesFromString(item, 'bootstrap', componentName));
		}
	});

	return orderedMap;
};

export function _mapVariablesFromComponentArray(componentArray, variablesDir, group) {
	let orderedMap = OrderedMap();

	_.forEach(componentArray, function(item, index) {
		let fileName = '_' + item + '.scss';

		let componentVariables = mapVariablesFromFile(path.join(variablesDir, fileName), group, item);

		orderedMap = orderedMap.merge(componentVariables);
	});

	return orderedMap;
};

export function _mapVariablesFromString(fileContents, group, component) {
	let orderedMap = OrderedMap();

	fileContents.replace(/(\$.*):[\s]*(.*);/g, function(match, variable, value) {
		value = _.trim(value.replace('!default', ''));

		orderedMap = orderedMap.set(variable, Map({
			component: _getReducedComponentName(component),
			group: group,
			name: variable,
			value: value
		}));
	});

	return orderedMap;
};

export function _mergeVariables(variables, targetVariables) {
	targetVariables.forEach((tragetVariable, key) => {
		if (variables.has(key)) {
			const modifiedVariable = variables.get(key).set('value', tragetVariable.get('value'));

			variables = variables.set(key, modifiedVariable);
		}
		else {
			variables = variables.set(key, tragetVariable);
		}
	});

	return variables;
};


text:
require 'ndr_support/password/constants'

module NdrSupport
  # Contains logic for checking and generating secure passwords,
  # in line with CESG guidelines.
  module Password
    include Constants

    extend self

    # Is the given `string` deemed a good password?
    # An additional `word_list` can be provided; its entries add only
    # minimally when considering the strength of `string`.
    #
    #   NdrSupport::Password.valid?('google password')    #=> false
    #   NdrSupport::Password.valid?(SecureRandom.hex(12)) #=> true
    #
    def valid?(string, word_list: [])
      string = prepare_string(string.to_s.dup)
      slug   = slugify(strip_common_words(string, word_list))

      meets_requirements?(slug)
    end

    # Generates a random #valid? password, using the 2048-word RFC1751 dictionary.
    # Optionally, specify `number_of_words` and/or `separator`.
    #
    #   NdrSupport::Password.generate #=> "sill quod okay phi"
    #   NdrSupport::Password.generate #=> "dint dale pew wane"
    #   NdrSupport::Password.generate #=> "rent jude ding gent"
    #
    #   NdrSupport::Password.generate(number_of_words: 6) #=> "dad bide thee glen road beam"
    #
    #   NdrSupport::Password.generate(separator: '-') #=> "jail-net-skim-cup"
    #
    # Raises a RuntimeError if a strong enough password was not produced:
    #
    #   NdrSupport::Password.generate(number_of_words: 1) #=>
    #     RuntimeError: Failed to generate a #valid? password!
    #
    def generate(number_of_words: 4, separator: ' ')
      attempts = 0

      loop do
        words = Array.new(number_of_words) do
          RFC1751_WORDS[SecureRandom.random_number(RFC1751_WORDS.length)].downcase
        end

        phrase = words.join(separator)
        return phrase if valid?(phrase)

        attempts += 1
        raise 'Failed to generate a #valid? password!' if attempts > 10
      end
    end

    private

    def meets_requirements?(string)
      string.length >= 6 && string.chars.uniq.length >= 5
    end

    def strip_common_words(string, common_words)
      common_words += COMMON_PASSWORDS

      # Try the longest common words first, in case some are substrings of others:
      common_words = common_words.sort_by(&:length).reverse

      common_words.each do |common_word|
        pattern = prepare_string(common_word)

        # Don't try to remove things that #slugify will be able to remove
        # at least as effectively: [#6950#note-12]
        next if slugify(pattern).length <= 2

        string.gsub!(pattern) { |word| word.chars.first + word.chars.last }
      end

      string
    end

    def slugify(string)
      input  = string.chars
      output = []

      until input.length.zero?
        sequence = [input.shift]
        sequence << input.shift while input.any? && no_added_value?(sequence.last, input.first)

        sequence.slice!(1..-2) # discard interior of sequence
        output.concat(sequence.uniq)
      end

      output.join
    end

    def no_added_value?(a, b)
      sequential?(a, b) || repeating?(a, b)
    end

    def repeating?(a, b)
      a == b
    end

    def sequential?(a, b, check_inverse: true)
      # avoid non-alphanumeric characters being considered for sequencing:
      # ';'.next #=> '<'
      return false unless sequencible?(a) && sequencible?(b)

      (a.next == b && b.length == 1) || (check_inverse && sequential?(b, a, check_inverse: false))
    end

    def sequencible?(string)
      /\A([a-z]|[0-9])\z/i =~ string
    end

    def prepare_string(string)
      string.downcase
    end
  end
end


text:
"use strict";
/**
 * A class that implements a simple Calculator
 */
var Calculator = (function () {
    function Calculator() {
    }
    /**
     * Adds the provided numbers and returns the result
     * @param a First number
     * @param b Second number
     */
    Calculator.prototype.add = function (a, b) {
        return a + b - 1;
    };
    /**
     * Subtracts second number from first number and returns the result
     * @param a First number
     * @param b Second number
     */
    Calculator.prototype.subtract = function (a, b) {
        return a - b;
    };
    /**
     * Multiplies the provided numbers and returns the result
     * @param a First number
     * @param b Second number
     */
    Calculator.prototype.multiply = function (a, b) {
        return a * b;
    };
    /**
     * Divides the first number by the second number and returns the result
     * @param a First number
     * @param b Second number
     */
    Calculator.prototype.divide = function (a, b) {
        return a / b;
    };
    return Calculator;
}());
exports.Calculator = Calculator;


text:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/weather_rigo_widget_4x2"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ImageView
        android:id="@+id/widget_backgroud"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_margin="1.0dip"
        android:scaleType="centerCrop" />

    <ImageView
        android:id="@+id/transparent_bg"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:clickable="false"
        android:focusable="false"
        android:scaleType="fitXY"
        android:src="@drawable/bg_widget_v"
        android:visibility="gone" />

    <ImageView
        android:id="@+id/loading_backgroud"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:scaleType="fitXY"
        android:visibility="gone" />

    <ImageView
        android:id="@+id/loading_logo"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:visibility="gone" />

    <TextView
        android:id="@id/loading"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:text="@string/widget_loading_tips"
        android:textSize="14.0dip"
        android:visibility="gone" />

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >

        <RelativeLayout
            android:id="@+id/date_time_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_marginLeft="8.0dip" >

            <ImageView
                android:id="@+id/time_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="14.0dip" />

            <LinearLayout
                android:id="@+id/date_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="4.0dip"
                android:layout_marginTop="14.0dip"
                android:layout_toRightOf="@id/time_view"
                android:orientation="vertical" >

                <TextView
                    android:id="@+id/time_a_view"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity="top"
                    android:paddingLeft="5.0dip"
                    android:shadowColor="#bf000000"
                    android:shadowDx="1.0"
                    android:shadowDy="1.0"
                    android:shadowRadius="3.0"
                    android:singleLine="true"
                    android:textColor="#ccffffff"
                    android:textSize="12.0dip" />

                <TextView
                    android:id="@+id/solor_date_view"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:shadowColor="#bf000000"
                    android:shadowDx="1.0"
                    android:shadowDy="1.0"
                    android:shadowRadius="3.0"
                    android:singleLine="true"
                    android:text=""
                    android:textColor="#ccffffff"
                    android:textSize="12.0dip" />

                <TextView
                    android:id="@+id/lunar_date_view"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:shadowColor="#bf000000"
                    android:shadowDx="1.0"
                    android:shadowDy="1.0"
                    android:shadowRadius="3.0"
                    android:singleLine="true"
                    android:text=""
                    android:textColor="#ccffffff"
                    android:textSize="12.0dip" />

                <TextView
                    android:id="@+id/festival_view"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:shadowColor="#bf000000"
                    android:shadowDx="1.0"
                    android:shadowDy="1.0"
                    android:shadowRadius="3.0"
                    android:singleLine="true"
                    android:text="N/A"
                    android:textColor="#ccffffff"
                    android:textSize="12.0dip"
                    android:visibility="invisible" />
            </LinearLayout>
        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/refresh_layout_view"
            android:layout_width="50.0dip"
            android:layout_height="50.0dip"
            android:layout_alignParentRight="true"
            android:layout_alignParentTop="true"
            android:layout_marginRight="4.0dip"
            android:gravity="right"
            android:paddingTop="5.0dip" >

            <FrameLayout
                android:id="@id/widget_fresh_progressbar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:visibility="gone" >

                <ProgressBar
                    style="@style/weather_widget_refresh_style"
                    android:layout_width="26.0dip"
                    android:layout_height="26.0dip" />
            </FrameLayout>

            <ImageView
                android:id="@+id/refresh_view"
                android:layout_width="26.0dip"
                android:layout_height="26.0dip"
                android:src="@drawable/refresh_27x27_1"
                android:visibility="invisible" />
        </RelativeLayout>

        <LinearLayout
            android:id="@id/weather_temperature_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentLeft="true"
            android:layout_marginBottom="8.0dip"
            android:layout_marginLeft="5.0dip"
            android:orientation="horizontal" >

            <RelativeLayout
                android:id="@+id/weather_view"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent" >

                <TextView
                    android:id="@id/weather_text_view"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_alignParentBottom="true"
                    android:layout_centerHorizontal="true"
                    android:gravity="center"
                    android:paddingLeft="1.0dip"
                    android:paddingRight="1.0dip"
                    android:shadowColor="#bf000000"
                    android:shadowDx="1.0"
                    android:shadowDy="1.0"
                    android:shadowRadius="3.0"
                    android:textColor="@android:color/white"
                    android:textSize="14.0dip" />

                <ImageView
                    android:id="@+id/weather_icon_view"
                    android:layout_width="40.0dip"
                    android:layout_height="40.0dip"
                    android:layout_above="@id/weather_text_view"
                    android:layout_centerInParent="true"
                    android:layout_marginBottom="6.0dip" />
            </RelativeLayout>

            <ImageView
                android:id="@+id/weather_divider_view"
                android:layout_width="2.0px"
                android:layout_height="60.0dip"
                android:layout_marginLeft="6.0dip"
                android:layout_marginTop="13.0dip"
                android:background="#99ffffff"
                android:visibility="invisible" />

            <RelativeLayout
                android:id="@id/temperature_pm_view"
                android:layout_width="wrap_content"
                android:layout_height="fill_parent"
                android:layout_marginLeft="6.0dip"
                android:gravity="bottom" >

                <RelativeLayout
                    android:id="@id/pm_view"
                    android:layout_width="wrap_content"
                    android:layout_height="22.0dip"
                    android:layout_alignParentBottom="true"
                    android:layout_marginLeft="6.0dip"
                    android:background="@drawable/bg_pm25_01"
                    android:minWidth="44.0dip"
                    android:orientation="horizontal"
                    android:visibility="gone" >

                    <TextView
                        android:id="@id/widget_pm_value_view"
                        style="@style/Shade"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="2.0dip"
                        android:layout_marginTop="5.0dip"
                        android:gravity="center_vertical"
                        android:singleLine="true"
                        android:text="60"
                        android:textColor="@android:color/white"
                        android:textSize="12.0dip" />

                    <ImageView
                        android:id="@id/widget_aqi_divider"
                        android:layout_width="1.0px"
                        android:layout_height="18.0dip"
                        android:layout_gravity="center_horizontal"
                        android:layout_marginLeft="2.0dip"
                        android:layout_marginRight="2.0dip"
                        android:layout_marginTop="6.0dip"
                        android:layout_toRightOf="@id/widget_pm_value_view"
                        android:background="#7bffffff" />

                    <TextView
                        android:id="@id/widget_pm_level_view"
                        style="@style/Shade"
                        android:layout_width="wrap_content"
                        android:layout_height="fill_parent"
                        android:layout_marginTop="5.0dip"
                        android:layout_toRightOf="@id/widget_aqi_divider"
                        android:gravity="center_vertical"
                        android:minWidth="14.0dip"
                        android:singleLine="true"
                        android:text="优"
                        android:textColor="@android:color/white"
                        android:textSize="12.0dip" />
                </RelativeLayout>

                <LinearLayout
                    android:id="@id/temperature_view"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_above="@id/pm_view"
                    android:layout_marginBottom="2.0dip"
                    android:orientation="horizontal" >

                    <RelativeLayout
                        android:id="@id/current_temperature_layout"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="bottom|left|center" >

                        <ImageView
                            android:id="@id/current_temperature_view"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_alignParentLeft="true" />

                        <ImageView
                            android:layout_width="8.0dip"
                            android:layout_height="8.0dip"
                            android:layout_alignParentRight="true"
                            android:layout_alignParentTop="true"
                            android:layout_marginLeft="2.0dip"
                            android:layout_marginTop="10.0dip"
                            android:visibility="gone" />
                    </RelativeLayout>

                    <LinearLayout
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="bottom|center"
                        android:orientation="vertical" >

                        <RelativeLayout
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_gravity="right"
                            android:layout_marginTop="5.0dip" >

                            <TextView
                                android:id="@id/high_temperature_view"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_alignParentLeft="true"
                                android:shadowColor="#bf000000"
                                android:shadowDx="1.0"
                                android:shadowDy="1.0"
                                android:shadowRadius="3.0"
                                android:textColor="@android:color/white"
                                android:textSize="14.0dip" />

                            <ImageView
                                android:layout_width="3.0dip"
                                android:layout_height="3.0dip"
                                android:layout_alignParentRight="true"
                                android:layout_alignParentTop="true"
                                android:layout_marginLeft="2.0dip"
                                android:layout_marginTop="3.0dip"
                                android:visibility="gone" />
                        </RelativeLayout>

                        <RelativeLayout
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_gravity="right" >

                            <TextView
                                android:id="@id/low_temperature_view"
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:layout_alignParentLeft="true"
                                android:shadowColor="#bf000000"
                                android:shadowDx="1.0"
                                android:shadowDy="1.0"
                                android:shadowRadius="3.0"
                                android:textColor="@android:color/white"
                                android:textSize="14.0dip" />

                            <ImageView
                                android:layout_width="3.0dip"
                                android:layout_height="3.0dip"
                                android:layout_alignParentRight="true"
                                android:layout_alignParentTop="true"
                                android:layout_marginLeft="3.0dip"
                                android:layout_marginTop="2.0dip"
                                android:visibility="gone" />
                        </RelativeLayout>
                    </LinearLayout>
                </LinearLayout>
            </RelativeLayout>
        </LinearLayout>

        <LinearLayout
            android:id="@+id/weather_location_layout"
            android:layout_width="140.0dip"
            android:layout_height="40.0dip"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginBottom="5.0dip"
            android:layout_marginRight="5.0dip"
            android:gravity="bottom|right|center"
            android:orientation="horizontal" >

            <TextView
                android:id="@id/location_view"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="1.0dip"
                android:ellipsize="end"
                android:gravity="center"
                android:lines="1"
                android:shadowColor="#bf000000"
                android:shadowDx="1.0"
                android:shadowDy="1.0"
                android:shadowRadius="3.0"
                android:textColor="@android:color/white"
                android:textSize="18.0dip" />

            <ImageView
                android:id="@+id/location_icon_view"
                android:layout_width="18.0dip"
                android:layout_height="18.0dip"
                android:layout_marginBottom="1.0dip"
                android:src="@drawable/current_loc_active_26x26"
                android:visibility="invisible" />
        </LinearLayout>
    </RelativeLayout>

</RelativeLayout>


text:
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Trail = void 0;
const Utils_1 = require("../../../../Utils");
class Trail {
    constructor() {
        this.delay = 1;
        this.quantity = 1;
    }
    load(data) {
        if (data === undefined) {
            return;
        }
        if (data.delay !== undefined) {
            this.delay = data.delay;
        }
        if (data.quantity !== undefined) {
            this.quantity = data.quantity;
        }
        if (data.particles !== undefined) {
            this.particles = Utils_1.Utils.deepExtend({}, data.particles);
        }
    }
}
exports.Trail = Trail;


text:
package com.lb.launcher;

import com.lb.launcher.R;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;

public class AppsCustomizeTabHost extends FrameLayout implements LauncherTransitionable, Insettable  {
    static final String LOG_TAG = "AppsCustomizeTabHost";

    private static final String APPS_TAB_TAG = "APPS";
    private static final String WIDGETS_TAB_TAG = "WIDGETS";

    private AppsCustomizePagedView mPagedView;
    private View mContent;
    private boolean mInTransition = false;

    private final Rect mInsets = new Rect();

    public AppsCustomizeTabHost(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * Convenience methods to select specific tabs.  We want to set the content type immediately
     * in these cases, but we note that we still call setCurrentTabByTag() so that the tab view
     * reflects the new content (but doesn't do the animation and logic associated with changing
     * tabs manually).
     */
    void setContentTypeImmediate(AppsCustomizePagedView.ContentType type) {
        mPagedView.setContentType(type);
    }

    public void setCurrentTabFromContent(AppsCustomizePagedView.ContentType type) {
        setContentTypeImmediate(type);
    }

    @Override
    public void setInsets(Rect insets) {
        mInsets.set(insets);
        LayoutParams flp = (LayoutParams) mContent.getLayoutParams();
        flp.topMargin = insets.top;
        flp.bottomMargin = insets.bottom;
        flp.leftMargin = insets.left;
        flp.rightMargin = insets.right;
        mContent.setLayoutParams(flp);
    }

    /**
     * Setup the tab host and create all necessary tabs.
     */
    @Override
    protected void onFinishInflate() {
        mPagedView = (AppsCustomizePagedView) findViewById(R.id.apps_customize_pane_content);
        mContent = findViewById(R.id.content);
    }

    public String getContentTag() {
        return getTabTagForContentType(mPagedView.getContentType());
    }

    /**
     * Returns the content type for the specified tab tag.
     */
    public AppsCustomizePagedView.ContentType getContentTypeForTabTag(String tag) {
        if (tag.equals(APPS_TAB_TAG)) {
            return AppsCustomizePagedView.ContentType.Applications;
        } else if (tag.equals(WIDGETS_TAB_TAG)) {
            return AppsCustomizePagedView.ContentType.Widgets;
        }
        return AppsCustomizePagedView.ContentType.Applications;
    }

    /**
     * Returns the tab tag for a given content type.
     */
    public String getTabTagForContentType(AppsCustomizePagedView.ContentType type) {
        if (type == AppsCustomizePagedView.ContentType.Applications) {
            return APPS_TAB_TAG;
        } else if (type == AppsCustomizePagedView.ContentType.Widgets) {
            return WIDGETS_TAB_TAG;
        }
        return APPS_TAB_TAG;
    }

    /**
     * Disable focus on anything under this view in the hierarchy if we are not visible.
     */
    @Override
    public int getDescendantFocusability() {
        if (getVisibility() != View.VISIBLE) {
            return ViewGroup.FOCUS_BLOCK_DESCENDANTS;
        }
        return super.getDescendantFocusability();
    }

    void reset() {
        // Reset immediately
        mPagedView.reset();
    }

    void trimMemory() {
        mPagedView.trimMemory();
    }

    public void onWindowVisible() {
        if (getVisibility() == VISIBLE) {
            mContent.setVisibility(VISIBLE);
            // We unload the widget previews when the UI is hidden, so need to reload pages
            // Load the current page synchronously, and the neighboring pages asynchronously
            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage(), true);
            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
        }
    }
    @Override
    public ViewGroup getContent() {
        return mPagedView;
    }

    public boolean isInTransition() {
        return mInTransition;
    }

    /* LauncherTransitionable overrides */
    @Override
    public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
        mPagedView.onLauncherTransitionPrepare(l, animated, toWorkspace);
        mInTransition = true;

        if (toWorkspace) {
            // Going from All Apps -> Workspace
            setVisibilityOfSiblingsWithLowerZOrder(VISIBLE);
        } else {
            // Going from Workspace -> All Apps
            mContent.setVisibility(VISIBLE);

            // Make sure the current page is loaded (we start loading the side pages after the
            // transition to prevent slowing down the animation)
            // TODO: revisit this
            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());
        }
    }

    @Override
    public void onLauncherTransitionStart(Launcher l, boolean animated, boolean toWorkspace) {
        mPagedView.onLauncherTransitionStart(l, animated, toWorkspace);
    }

    @Override
    public void onLauncherTransitionStep(Launcher l, float t) {
        mPagedView.onLauncherTransitionStep(l, t);
    }

    @Override
    public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
        mPagedView.onLauncherTransitionEnd(l, animated, toWorkspace);
        mInTransition = false;

        if (!toWorkspace) {
            // Make sure adjacent pages are loaded (we wait until after the transition to
            // prevent slowing down the animation)
            mPagedView.loadAssociatedPages(mPagedView.getCurrentPage());

            // Opening apps, need to announce what page we are on.
            AccessibilityManager am = (AccessibilityManager)
                    getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
            if (am.isEnabled()) {
                // Notify the user when the page changes
                announceForAccessibility(mPagedView.getCurrentPageDescription());
            }

            // Going from Workspace -> All Apps
            // NOTE: We should do this at the end since we check visibility state in some of the
            // cling initialization/dismiss code above.
            setVisibilityOfSiblingsWithLowerZOrder(INVISIBLE);
        }
    }

    private void setVisibilityOfSiblingsWithLowerZOrder(int visibility) {
        ViewGroup parent = (ViewGroup) getParent();
        if (parent == null) return;

        View overviewPanel = ((Launcher) getContext()).getOverviewPanel();
        final int count = parent.getChildCount();
        if (!isChildrenDrawingOrderEnabled()) {
            for (int i = 0; i < count; i++) {
                final View child = parent.getChildAt(i);
                if (child == this) {
                    break;
                } else {
                    if (child.getVisibility() == GONE || child == overviewPanel) {
                        continue;
                    }
                    child.setVisibility(visibility);
                }
            }
        } else {
            throw new RuntimeException("Failed; can't get z-order of views");
        }
    }
}