text:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta content="Apache Forrest" name="Generator">
<meta name="Forrest-version" content="0.8">
<meta name="Forrest-skin-name" content="pelt">
<title>Fair Scheduler</title>
<link type="text/css" href="skin/basic.css" rel="stylesheet">
<link media="screen" type="text/css" href="skin/screen.css" rel="stylesheet">
<link media="print" type="text/css" href="skin/print.css" rel="stylesheet">
<link type="text/css" href="skin/profile.css" rel="stylesheet">

<link rel="shortcut icon" href="images/favicon.ico">

Apache > Hadoop > Core

<form action="http://www.google.com/search" method="get" class="roundtopsmall">
<input value="hadoop.apache.org" name="sitesearch" type="hidden"><input onFocus="getBlank (this, 'Search the site with google');" size="25" name="q" id="query" type="text" value="Search the site with google">
                    <input name="Search" value="Search" type="submit">
</form>

Project

Wiki

MapReduce 0.21 Documentation

Getting Started

Overview

MapReduce Tutorial

Hadoop Streaming

Guides

DistCp

Vaidya

Hadoop Archives

Gridmix

Schedulers

Capacity Scheduler

Fair Scheduler

Miscellaneous

API Docs

API Changes

Wiki

FAQ

Release Notes

Change Log

        PDF

Fair Scheduler

Purpose

Introduction

Installation

Configuration

Scheduler Parameters in mapred-site.xml

Allocation File (fair-scheduler.xml)

 Administration

Purpose

This document describes the Fair Scheduler, a pluggable
        MapReduce scheduler for Hadoop which provides a way to share
        large clusters.

Introduction

Fair scheduling is a method of assigning resources to jobs
        such that all jobs get, on average, an equal share of resources
        over time. When there is a single job running, that job uses the
        entire cluster. When other jobs are submitted, tasks slots that
        free up are assigned to the new jobs, so that each job gets
        roughly the same amount of CPU time. Unlike the default Hadoop
        scheduler, which forms a queue of jobs, this lets short jobs finish
        in reasonable time while not starving long jobs. It is also an easy
        way to share a cluster between multiple of users.
        Fair sharing can also work with job priorities - the priorities are
        used as weights to determine the fraction of total compute time that
        each job gets.

        The fair scheduler organizes jobs into pools, and
        divides resources fairly between these pools. By default, there is a
        separate pool for each user, so that each user gets an equal share
        of the cluster. It is also possible to set a job's pool based on the
        user's Unix group or any jobconf property.
        Within each pool, jobs can be scheduled using either fair sharing or
        first-in-first-out (FIFO) scheduling.

        In addition to providing fair sharing, the Fair Scheduler allows
        assigning guaranteed minimum shares to pools, which is useful
        for ensuring that certain users, groups or production applications
        always get sufficient resources. When a pool contains jobs, it gets
        at least its minimum share, but when the pool does not need its full
        guaranteed share, the excess is split between other pools.

        If a pool's minimum share is not met for some period of time, the
        scheduler optionally supports preemption of jobs in other
        pools. The pool will be allowed to kill tasks from other pools to make
        room to run. Preemption can be used to guarantee
        that "production" jobs are not starved while also allowing
        the Hadoop cluster to also be used for experimental and research jobs.
        In addition, a pool can also be allowed to preempt tasks if it is
        below half of its fair share for a configurable timeout (generally
        set larger than the minimum share preemption timeout).
        When choosing tasks to kill, the fair scheduler picks the
        most-recently-launched tasks from over-allocated jobs,
        to minimize wasted computation.
        Preemption does not cause the preempted jobs to fail, because Hadoop
        jobs tolerate losing tasks; it only makes them take longer to finish.

        The Fair Scheduler can limit the number of concurrent
        running jobs per user and per pool. This can be useful when a
        user must submit hundreds of jobs at once, or for ensuring that
        intermediate data does not fill up disk space on a cluster when too many
        concurrent jobs are running.
        Setting job limits causes jobs submitted beyond the limit to wait
        until some of the user/pool's earlier jobs finish.
        Jobs to run from each user/pool are chosen in order of priority and then
        submit time.

        Finally, the Fair Scheduler can limit the number of concurrent
        running tasks per pool. This can be useful when jobs have a
        dependency on an external service like a database or web
        service that could be overloaded if too many map or reduce
        tasks are run at once.

Installation

        To run the fair scheduler in your Hadoop installation, you need to put
        it on the CLASSPATH. The easiest way is to copy the
        hadoop-*-fairscheduler.jar from
        HADOOP_HOME/build/contrib/fairscheduler to HADOOP_HOME/lib.
        Alternatively you can modify HADOOP_CLASSPATH to include this jar, in
        HADOOP_CONF_DIR/hadoop-env.sh

       You will also need to set the following property in the Hadoop config
       file  HADOOP_CONF_DIR/mapred-site.xml to have Hadoop use
       the fair scheduler:

<property>
  <name>mapreduce.jobtracker.taskscheduler</name>
  <value>org.apache.hadoop.mapred.FairScheduler</value>
</property>

        Once you restart the cluster, you can check that the fair scheduler
        is running by going to http://<jobtracker URL>/scheduler
        on the JobTracker's web UI. A "job scheduler administration" page should
        be visible there. This page is described in the Administration section.

        If you wish to compile the fair scheduler from source, run  ant
        package in your HADOOP_HOME directory. This will build
        build/contrib/fair-scheduler/hadoop-*-fairscheduler.jar.

Configuration

        The Fair Scheduler contains configuration in two places -- algorithm
        parameters are set in HADOOP_CONF_DIR/mapred-site.xml, while
        a separate XML file called the allocation file,
        located by default in
        HADOOP_CONF_DIR/fair-scheduler.xml, is used to configure
        pools, minimum shares, running job limits and preemption timeouts.
        The allocation file is reloaded periodically at runtime,
        allowing you to change pool settings without restarting
        your Hadoop cluster.

        For a minimal installation, to just get equal sharing between users,
        you will not need to edit the allocation file.

Scheduler Parameters in mapred-site.xml

          The following parameters can be set in mapred-site.xml
          to affect the behavior of the fair scheduler:

Basic Parameters

Name	Description

            mapred.fairscheduler.preemption

            Boolean property for enabling preemption. Default: false.

            mapred.fairscheduler.pool

            Specify the pool that a job belongs in.
            If this is specified then mapred.fairscheduler.poolnameproperty is ignored.

            mapred.fairscheduler.poolnameproperty

            Specify which jobconf property is used to determine the pool that a
            job belongs in. String, default: mapreduce.job.user.name
            (i.e. one pool for each user).
            Another useful value is group.name to create a
            pool per Unix group.
            mapred.fairscheduler. poolnameproperty is used only for jobs in which
            mapred.fairscheduler.pool is not explicitly set.

            mapred.fairscheduler.allocation.file

            Can be used to have the scheduler use a different allocation file
            than the default one (HADOOP_CONF_DIR/fair-scheduler.xml).
            Must be an absolute path to the allocation file.

Advanced Parameters

Name	Description

            mapred.fairscheduler.sizebasedweight

            Take into account job sizes in calculating their weights for fair
            sharing. By default, weights are only based on job priorities.
            Setting this flag to true will make them based on the size of the
            job (number of tasks needed) as well,though not linearly
            (the weight will be proportional to the log of the number of tasks
            needed). This lets larger jobs get larger fair shares while still
            providing enough of a share to small jobs to let them finish fast.
            Boolean value, default: false.

            mapred.fairscheduler.preemption.only.log

            This flag will cause the scheduler to run through the preemption
            calculations but simply log when it wishes to preempt a task,
            without actually preempting the task.
            Boolean property, default: false.
            This property can be useful for
            doing a "dry run" of preemption before enabling it to make sure
            that you have not set timeouts too aggressively.
            You will see preemption log messages in your JobTracker's output
            log (HADOOP_LOG_DIR/hadoop-jobtracker-*.log).
            The messages look as follows:

Should preempt 2 tasks for job_20090101337_0001: tasksDueToMinShare = 2, tasksDueToFairShare = 0

            mapred.fairscheduler.update.interval

            Interval at which to update fair share calculations. The default
            of 500ms works well for clusters with fewer than 500 nodes,
            but larger values reduce load on the JobTracker for larger clusters.
            Integer value in milliseconds, default: 500.

            mapred.fairscheduler.preemption.interval

            Interval at which to check for tasks to preempt. The default
            of 15s works well for timeouts on the order of minutes.
            It is not recommended to set timeouts much smaller than this
            amount, but you can use this value to make preemption computations
            run more often if you do set such timeouts. A value of less than
            5s will probably be too small, however, as it becomes less than
            the inter-heartbeat interval.
            Integer value in milliseconds, default: 15000.

            mapred.fairscheduler.weightadjuster

          An extension point that lets you specify a class to adjust the
          weights of running jobs. This class should implement the
          WeightAdjuster interface. There is currently one example
          implementation - NewJobWeightBooster, which increases the
          weight of jobs for the first 5 minutes of their lifetime to let
          short jobs finish faster. To use it, set the weightadjuster
          property to the full class name,
          org.apache.hadoop.mapred.NewJobWeightBooster.
          NewJobWeightBooster itself provides two parameters for setting the
          duration and boost factor.

mapred.newjobweightbooster.factor
            Factor by which new jobs weight should be boosted.
            Default is 3.

mapred.newjobweightbooster.duration
            Boost duration in milliseconds. Default is 300000 for 5 minutes.

            mapred.fairscheduler.loadmanager

            An extension point that lets you specify a class that determines
            how many maps and reduces can run on a given TaskTracker. This class
            should implement the LoadManager interface. By default the task caps
            in the Hadoop config file are used, but this option could be used to
            make the load based on available memory and CPU utilization for example.

            mapred.fairscheduler.taskselector

          An extension point that lets you specify a class that determines
          which task from within a job to launch on a given tracker. This can be
          used to change either the locality policy (e.g. keep some jobs within
          a particular rack) or the speculative execution algorithm (select
          when to launch speculative tasks). The default implementation uses
          Hadoop's default algorithms from JobInProgress.

Allocation File (fair-scheduler.xml)

        The allocation file configures minimum shares, running job
        limits, weights and preemption timeouts for each pool.
        Only users/pools whose values differ from the defaults need to be
        explicitly configured in this file.
        The allocation file is located in
        HADOOP_HOME/conf/fair-scheduler.xml.
        It can contain the following types of elements:

pool elements, which configure each pool.
        These may contain the following sub-elements:

minMaps and minReduces,
            to set the pool's minimum share of task slots.

maxMaps and maxReduces, to set the
            pool's maximum concurrent task slots.

schedulingMode, the pool's internal scheduling mode,
          which can be fair for fair sharing or fifo for
          first-in-first-out.

maxRunningJobs,
          to limit the number of jobs from the
          pool to run at once (defaults to infinite).

weight, to share the cluster
          non-proportionally with other pools. For example, a pool with weight 2.0 will get a 2x higher share than other pools. The default weight is 1.0.

minSharePreemptionTimeout, the
            number of seconds the pool will wait before
            killing other pools' tasks if it is below its minimum share
            (defaults to infinite).

user elements, which may contain a
        maxRunningJobs element to limit
        jobs. Note that by default, there is a pool for each
        user, so per-user limits are not necessary.

poolMaxJobsDefault, which sets the default running
        job limit for any pools whose limit is not specified.

userMaxJobsDefault, which sets the default running
        job limit for any users whose limit is not specified.

defaultMinSharePreemptionTimeout,
        which sets the default minimum share preemption timeout
        for any pools where it is not specified.

fairSharePreemptionTimeout,
        which sets the preemption timeout used when jobs are below half
        their fair share.

defaultPoolSchedulingMode, which sets the default scheduling
        mode (fair or fifo) for pools whose mode is
        not specified.

        Pool and user elements only required if you are setting
        non-default values for the pool/user. That is, you do not need to
        declare all users and all pools in your config file before running
        the fair scheduler. If a user or pool is not listed in the config file,
        the default values for limits, preemption timeouts, etc will be used.

        An example allocation file is given below :

<?xml version="1.0"?>
<allocations>
  <pool name="sample_pool">
    <minMaps>5</minMaps>
    <minReduces>5</minReduces>
    <maxMaps>25</maxMaps>
    <maxReduces>25</maxReduces>
    <minSharePreemptionTimeout>300</minSharePreemptionTimeout>
  </pool>
  <mapreduce.job.user.name="sample_user">
    <maxRunningJobs>6</maxRunningJobs>
  </user>
  <userMaxJobsDefault>3</userMaxJobsDefault>
  <fairSharePreemptionTimeout>600</fairSharePreemptionTimeout>
</allocations>

        This example creates a pool sample_pool with a guarantee of 5 map
        slots and 5 reduce slots. The pool also has a minimum share preemption
        timeout of 300 seconds (5 minutes), meaning that if it does not get its
        guaranteed share within this time, it is allowed to kill tasks from
        other pools to achieve its share. The pool has a cap of 25 map and 25
        reduce slots, which means that once 25 tasks are running, no more will
        be scheduled even if the pool's fair share is higher.
        The example also limits the number of running jobs
        per user to 3, except for sample_user, who can run 6 jobs concurrently.
        Finally, the example sets a fair share preemption timeout of 600 seconds
        (10 minutes). If a job is below half its fair share for 10 minutes, it
        will be allowed to kill tasks from other jobs to achieve its share.
        Note that the preemption settings require preemption to be
        enabled in mapred-site.xml as described earlier.

        Any pool not defined in the allocation file will have no guaranteed
        capacity and no preemption timeout. Also, any pool or user with no max
        running jobs set in the file will be allowed to run an unlimited
        number of jobs.

 Administration

      The fair scheduler provides support for administration at runtime
      through two mechanisms:

      It is possible to modify minimum shares, limits, weights, preemption
      timeouts and pool scheduling modes at runtime by editing the allocation
      file. The scheduler will reload this file 10-15 seconds after it
      sees that it was modified.

     Current jobs, pools, and fair shares  can be examined through the
     JobTracker's web interface, at
     http://<JobTracker URL>/scheduler.
     On this interface, it is also possible to modify jobs' priorities or
     move jobs from one pool to another and see the effects on the fair
     shares (this requires JavaScript).

      The following fields can be seen for each job on the web interface:

Submitted - Date and time job was submitted.

JobID, User, Name - Job identifiers as on the standard
     web UI.

Pool - Current pool of job. Select another value to move job to
     another pool.

Priority - Current priority. Select another value to change the
     job's priority

Maps/Reduces Finished: Number of tasks finished / total tasks.

Maps/Reduces Running: Tasks currently running.

Map/Reduce Fair Share: The average number of task slots that this
     job should have at any given time according to fair sharing. The actual
     number of tasks will go up and down depending on how much compute time
     the job has had, but on average it will get its fair share amount.

     In addition, it is possible to view an "advanced" version of the web
     UI by going to http://<JobTracker URL>/scheduler?advanced.
     This view shows two more columns:

Maps/Reduce Weight: Weight of the job in the fair sharing
     calculations. This depends on priority and potentially also on
     job size and job age if the sizebasedweight and
     NewJobWeightBooster are enabled.

        Copyright ©
         2009 The Apache Software Foundation.


text:
package flow

import (
	"github.com/skydive-project/skydive/filters"
	"github.com/skydive-project/skydive/topology/graph"
)

func NewFilterForNodeTIDs(uuids []string) *filters.Filter {
	return filters.NewFilterForIds(uuids, "NodeTID", "ANodeTID", "BNodeTID")
}

func NewFilterForNodes(nodes []*graph.Node) *filters.Filter {
	var ids []string
	for _, node := range nodes {
		if t, ok := node.Metadata()["TID"]; ok {
			ids = append(ids, t.(string))
		}
	}
	return NewFilterForNodeTIDs(ids)
}

func NewFilterForFlowSet(flowset *FlowSet) *filters.Filter {
	ids := make([]string, len(flowset.Flows))
	for i, flow := range flowset.Flows {
		ids[i] = string(flow.UUID)
	}
	return filters.NewFilterForIds(ids, "UUID")
}

redpajama_set_name: RedPajamaGithub


text:
import { Router } from 'express'

import models from 'models'
import Cruds from 'cruds'

export default () => {
  let Universe = models.Universe
  let router = Router()
  let cruds = Cruds()

  router.use('/universe', cruds(Universe))

  return router
}


text:
<?xml version="1.0" encoding="UTF-8"?>

<!--

  Copyright 2003 - 2016 The eFaps Team

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

-->

<install xmlns="http://www.efaps.org/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.efaps.org/xsd http://www.efaps.org/xsd/eFaps_1.0.xsd">
    <application>eFapsApp-Accounting</application>
    <dependencies>
        <dependency order="0">
            <groupId>org.efaps</groupId>
            <artifactId>efaps-kernel-install</artifactId>
            <version>8.0.0-SNAPSHOT</version>
        </dependency>
        <dependency order="1">
            <groupId>org.efaps</groupId>
            <artifactId>efaps-webapp-install</artifactId>
            <version>8.0.0-SNAPSHOT</version>
        </dependency>
        <dependency order="2">
            <groupId>org.efaps.apps</groupId>
            <artifactId>contacts</artifactId>
            <version>8.0.0-SNAPSHOT</version>
        </dependency>
        <dependency order="3">
            <groupId>org.efaps.apps</groupId>
            <artifactId>commons</artifactId>
            <version>8.0.0-SNAPSHOT</version>
        </dependency>
        <dependency order="4">
            <groupId>org.efaps.apps</groupId>
            <artifactId>products</artifactId>
            <version>8.0.0-SNAPSHOT</version>
        </dependency>
        <dependency order="5">
            <groupId>org.efaps.apps</groupId>
            <artifactId>sales</artifactId>
            <version>8.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <version number="1" reloadCache="false" login="true" compile="true">
        <description>Install ERP-Accounting Basic Modul.</description>
        <script type="groovy">
            import java.io.File;
            import java.util.UUID;
            import org.efaps.admin.runlevel.RunLevel;
            import org.efaps.admin.user.JAASSystem;
            import org.efaps.admin.user.Role;
            import org.efaps.db.Context;
            import org.efaps.db.QueryBuilder;
            import org.efaps.db.InstanceQuery;
            import org.efaps.esjp.admin.ui.UIUpdate;
            import org.efaps.esjp.data.ObjectImport;
            import org.efaps.esjp.admin.user.RoleUpdate;

            EFAPS_LOGGER.info("Importing Data for eFapsApp-Accounting");

            RunLevel.init("shell");
            RunLevel.execute();

            //its not possible to import CostTextPosition due to Company

            UIUpdate update = new UIUpdate();

            <!-- connect the Accounting_ERP_CurrencyTree_Rate_Menu_Action_Create Menu to the ERP_CurrencyTree_Rate_Menu_Action menu -->
            update.add2Menu("d9480319-83fb-45ae-9a0b-877271acc034", "590181bd-a12f-4969-b403-5dc68d5089ef", -1);

            <!-- connect the Accounting_Sales_TaxTree_Account Menu to the Sales_TaxTree menu -->
            update.add2Menu("bc6cce90-6292-40ec-85c4-81c0e2110ae7", "d40d45b3-b2a1-45e8-ae72-fc991cb945f7", -1);

            <!-- connect the Accounting_Sales_PaymentDocTree_Transaction Sales_PaymentScheduleTree  -->
            update.add2Menu("4d17bb1a-51ef-4a2d-a511-052b1a88def3", "60732b90-3b07-4ca4-af15-6fb0712c8670", -1);

            <!-- connect the Accounting_Sales_PaymentDocTree_Transaction  Sales_PaymentSupplierOutTree -->
            update.add2Menu("4d17bb1a-51ef-4a2d-a511-052b1a88def3", "9e1ea83a-7670-47ee-9a73-134f07ef3585", -1);

            <!-- connect the Accounting_Sales_Document_PLEReport to Sales_Document_ReportMyDesk menu -->
            update.add2Menu("0bbae7f9-a7ae-4569-a08f-083930135f12", "218a4858-af25-4ad8-8a28-7283cd629766", -1);

            <!-- Accounting_Accounting, Admin_Help_MainMenu -->
            update.add2Help("906bd8c4-2e7f-4234-936b-6a1ee74bdf37", "dead549e-5cc6-49f9-9a79-8e33aa139f6d", -1);

            <!-- add to Accounting_Admin role -->
            RoleUpdate rolUp = new RoleUpdate("c687443f-e47e-4689-8a51-7eacdeac1e09");
            <!-- Sales_IncomingDetractionMyDesk -->
            rolUp.addUI("43f18157-a158-4426-8082-e7f4ce4851ed");
            <!-- Sales_IncomingRetentionMyDesk -->
            rolUp.addUI("ef7ab984-44aa-45de-ba12-148ee783ba43");
            <!-- Sales_IncomingDetractionMyDesk_Menu_Action_CreatePaymentDetractionOut -->
            rolUp.addUI("f21aa796-f233-41f3-b0dc-dc9fff2f4892");

            <!-- add to Accounting_Manager role -->
            rolUp = new RoleUpdate("757f9274-acd0-416a-a336-20470409e8af");
            <!-- Sales_IncomingDetractionMyDesk -->
            rolUp.addUI("43f18157-a158-4426-8082-e7f4ce4851ed");
            <!-- Sales_IncomingRetentionMyDesk -->
            rolUp.addUI("ef7ab984-44aa-45de-ba12-148ee783ba43");
            <!-- Sales_IncomingDetractionMyDesk_Menu_Action_CreatePaymentDetractionOut -->
            rolUp.addUI("f21aa796-f233-41f3-b0dc-dc9fff2f4892");

            <!-- add to Accounting_Executive role -->
            rolUp = new RoleUpdate("fc3af4de-83c9-4165-b466-5478329847eb");
            <!-- Sales_IncomingDetractionMyDesk -->
            rolUp.addUI("43f18157-a158-4426-8082-e7f4ce4851ed");
            <!-- Sales_IncomingRetentionMyDesk -->
            rolUp.addUI("ef7ab984-44aa-45de-ba12-148ee783ba43");
            <!-- Sales_IncomingDetractionMyDesk_Menu_Action_CreatePaymentDetractionOut -->
            rolUp.addUI("f21aa796-f233-41f3-b0dc-dc9fff2f4892");

        </script>
    </version>
</install>


text:
from __future__ import absolute_import, division

import collections
import copy
import logging
import threading
import time

from kafka.vendor import six

from kafka import errors as Errors
from kafka.metrics.measurable import AnonMeasurable
from kafka.metrics.stats import Avg, Max, Rate
from kafka.protocol.produce import ProduceRequest
from kafka.structs import TopicPartition
from kafka.version import __version__

log = logging.getLogger(__name__)

class Sender(threading.Thread):
    """
    The background thread that handles the sending of produce requests to the
    Kafka cluster. This thread makes metadata requests to renew its view of the
    cluster and then sends produce requests to the appropriate nodes.
    """
    DEFAULT_CONFIG = {
        'max_request_size': 1048576,
        'acks': 1,
        'retries': 0,
        'request_timeout_ms': 30000,
        'guarantee_message_order': False,
        'client_id': 'kafka-python-' + __version__,
        'api_version': (0, 8, 0),
    }

    def __init__(self, client, metadata, accumulator, metrics, **configs):
        super(Sender, self).__init__()
        self.config = copy.copy(self.DEFAULT_CONFIG)
        for key in self.config:
            if key in configs:
                self.config[key] = configs.pop(key)

        self.name = self.config['client_id'] + '-network-thread'
        self._client = client
        self._accumulator = accumulator
        self._metadata = client.cluster
        self._running = True
        self._force_close = False
        self._topics_to_add = set()
        self._sensors = SenderMetrics(metrics, self._client, self._metadata)

    def run(self):
        """The main run loop for the sender thread."""
        log.debug("Starting Kafka producer I/O thread.")

        # main loop, runs until close is called
        while self._running:
            try:
                self.run_once()
            except Exception:
                log.exception("Uncaught error in kafka producer I/O thread")

        log.debug("Beginning shutdown of Kafka producer I/O thread, sending"
                  " remaining records.")

        # okay we stopped accepting requests but there may still be
        # requests in the accumulator or waiting for acknowledgment,
        # wait until these are completed.
        while (not self._force_close
               and (self._accumulator.has_unsent()
                    or self._client.in_flight_request_count() > 0)):
            try:
                self.run_once()
            except Exception:
                log.exception("Uncaught error in kafka producer I/O thread")

        if self._force_close:
            # We need to fail all the incomplete batches and wake up the
            # threads waiting on the futures.
            self._accumulator.abort_incomplete_batches()

        try:
            self._client.close()
        except Exception:
            log.exception("Failed to close network client")

        log.debug("Shutdown of Kafka producer I/O thread has completed.")

    def run_once(self):
        """Run a single iteration of sending."""
        while self._topics_to_add:
            self._client.add_topic(self._topics_to_add.pop())

        # get the list of partitions with data ready to send
        result = self._accumulator.ready(self._metadata)
        ready_nodes, next_ready_check_delay, unknown_leaders_exist = result

        # if there are any partitions whose leaders are not known yet, force
        # metadata update
        if unknown_leaders_exist:
            log.debug('Unknown leaders exist, requesting metadata update')
            self._metadata.request_update()

        # remove any nodes we aren't ready to send to
        not_ready_timeout = float('inf')
        for node in list(ready_nodes):
            if not self._client.is_ready(node):
                log.debug('Node %s not ready; delaying produce of accumulated batch', node)
                self._client.maybe_connect(node, wakeup=False)
                ready_nodes.remove(node)
                not_ready_timeout = min(not_ready_timeout,
                                        self._client.connection_delay(node))

        # create produce requests
        batches_by_node = self._accumulator.drain(
            self._metadata, ready_nodes, self.config['max_request_size'])

        if self.config['guarantee_message_order']:
            # Mute all the partitions drained
            for batch_list in six.itervalues(batches_by_node):
                for batch in batch_list:
                    self._accumulator.muted.add(batch.topic_partition)

        expired_batches = self._accumulator.abort_expired_batches(
            self.config['request_timeout_ms'], self._metadata)
        for expired_batch in expired_batches:
            self._sensors.record_errors(expired_batch.topic_partition.topic, expired_batch.record_count)

        self._sensors.update_produce_request_metrics(batches_by_node)
        requests = self._create_produce_requests(batches_by_node)
        # If we have any nodes that are ready to send + have sendable data,
        # poll with 0 timeout so this can immediately loop and try sending more
        # data. Otherwise, the timeout is determined by nodes that have
        # partitions with data that isn't yet sendable (e.g. lingering, backing
        # off). Note that this specifically does not include nodes with
        # sendable data that aren't ready to send since they would cause busy
        # looping.
        poll_timeout_ms = min(next_ready_check_delay * 1000, not_ready_timeout)
        if ready_nodes:
            log.debug("Nodes with data ready to send: %s", ready_nodes) # trace
            log.debug("Created %d produce requests: %s", len(requests), requests) # trace
            poll_timeout_ms = 0

        for node_id, request in six.iteritems(requests):
            batches = batches_by_node[node_id]
            log.debug('Sending Produce Request: %r', request)
            (self._client.send(node_id, request, wakeup=False)
                 .add_callback(
                     self._handle_produce_response, node_id, time.time(), batches)
                 .add_errback(
                     self._failed_produce, batches, node_id))

        # if some partitions are already ready to be sent, the select time
        # would be 0; otherwise if some partition already has some data
        # accumulated but not ready yet, the select time will be the time
        # difference between now and its linger expiry time; otherwise the
        # select time will be the time difference between now and the
        # metadata expiry time
        self._client.poll(timeout_ms=poll_timeout_ms)

    def initiate_close(self):
        """Start closing the sender (won't complete until all data is sent)."""
        self._running = False
        self._accumulator.close()
        self.wakeup()

    def force_close(self):
        """Closes the sender without sending out any pending messages."""
        self._force_close = True
        self.initiate_close()

    def add_topic(self, topic):
        # This is generally called from a separate thread
        # so this needs to be a thread-safe operation
        # we assume that checking set membership across threads
        # is ok where self._client._topics should never
        # remove topics for a producer instance, only add them.
        if topic not in self._client._topics:
            self._topics_to_add.add(topic)
            self.wakeup()

    def _failed_produce(self, batches, node_id, error):
        log.debug("Error sending produce request to node %d: %s", node_id, error) # trace
        for batch in batches:
            self._complete_batch(batch, error, -1, None)

    def _handle_produce_response(self, node_id, send_time, batches, response):
        """Handle a produce response."""
        # if we have a response, parse it
        log.debug('Parsing produce response: %r', response)
        if response:
            batches_by_partition = dict([(batch.topic_partition, batch)
                                         for batch in batches])

            for topic, partitions in response.topics:
                for partition_info in partitions:
                    if response.API_VERSION < 2:
                        partition, error_code, offset = partition_info
                        ts = None
                    else:
                        partition, error_code, offset, ts = partition_info
                    tp = TopicPartition(topic, partition)
                    error = Errors.for_code(error_code)
                    batch = batches_by_partition[tp]
                    self._complete_batch(batch, error, offset, ts)

            if response.API_VERSION > 0:
                self._sensors.record_throttle_time(response.throttle_time_ms, node=node_id)

        else:
            # this is the acks = 0 case, just complete all requests
            for batch in batches:
                self._complete_batch(batch, None, -1, None)

    def _complete_batch(self, batch, error, base_offset, timestamp_ms=None):
        """Complete or retry the given batch of records.

        Arguments:
            batch (RecordBatch): The record batch
            error (Exception): The error (or None if none)
            base_offset (int): The base offset assigned to the records if successful
            timestamp_ms (int, optional): The timestamp returned by the broker for this batch
        """
        # Standardize no-error to None
        if error is Errors.NoError:
            error = None

        if error is not None and self._can_retry(batch, error):
            # retry
            log.warning("Got error produce response on topic-partition %s,"
                        " retrying (%d attempts left). Error: %s",
                        batch.topic_partition,
                        self.config['retries'] - batch.attempts - 1,
                        error)
            self._accumulator.reenqueue(batch)
            self._sensors.record_retries(batch.topic_partition.topic, batch.record_count)
        else:
            if error is Errors.TopicAuthorizationFailedError:
                error = error(batch.topic_partition.topic)

            # tell the user the result of their request
            batch.done(base_offset, timestamp_ms, error)
            self._accumulator.deallocate(batch)
            if error is not None:
                self._sensors.record_errors(batch.topic_partition.topic, batch.record_count)

        if getattr(error, 'invalid_metadata', False):
            self._metadata.request_update()

        # Unmute the completed partition.
        if self.config['guarantee_message_order']:
            self._accumulator.muted.remove(batch.topic_partition)

    def _can_retry(self, batch, error):
        """
        We can retry a send if the error is transient and the number of
        attempts taken is fewer than the maximum allowed
        """
        return (batch.attempts < self.config['retries']
                and getattr(error, 'retriable', False))

    def _create_produce_requests(self, collated):
        """
        Transfer the record batches into a list of produce requests on a
        per-node basis.

        Arguments:
            collated: {node_id: [RecordBatch]}

        Returns:
            dict: {node_id: ProduceRequest} (version depends on api_version)
        """
        requests = {}
        for node_id, batches in six.iteritems(collated):
            requests[node_id] = self._produce_request(
                node_id, self.config['acks'],
                self.config['request_timeout_ms'], batches)
        return requests

    def _produce_request(self, node_id, acks, timeout, batches):
        """Create a produce request from the given record batches.

        Returns:
            ProduceRequest (version depends on api_version)
        """
        produce_records_by_partition = collections.defaultdict(dict)
        for batch in batches:
            topic = batch.topic_partition.topic
            partition = batch.topic_partition.partition

            buf = batch.records.buffer()
            produce_records_by_partition[topic][partition] = buf

        kwargs = {}
        if self.config['api_version'] >= (0, 11):
            version = 3
            kwargs = dict(transactional_id=None)
        elif self.config['api_version'] >= (0, 10):
            version = 2
        elif self.config['api_version'] == (0, 9):
            version = 1
        else:
            version = 0
        return ProduceRequest[version](
            required_acks=acks,
            timeout=timeout,
            topics=[(topic, list(partition_info.items()))
                    for topic, partition_info
                    in six.iteritems(produce_records_by_partition)],
            **kwargs
        )

    def wakeup(self):
        """Wake up the selector associated with this send thread."""
        self._client.wakeup()

    def bootstrap_connected(self):
        return self._client.bootstrap_connected()

class SenderMetrics(object):

    def __init__(self, metrics, client, metadata):
        self.metrics = metrics
        self._client = client
        self._metadata = metadata

        sensor_name = 'batch-size'
        self.batch_size_sensor = self.metrics.sensor(sensor_name)
        self.add_metric('batch-size-avg', Avg(),
                        sensor_name=sensor_name,
                        description='The average number of bytes sent per partition per-request.')
        self.add_metric('batch-size-max', Max(),
                        sensor_name=sensor_name,
                        description='The max number of bytes sent per partition per-request.')

        sensor_name = 'compression-rate'
        self.compression_rate_sensor = self.metrics.sensor(sensor_name)
        self.add_metric('compression-rate-avg', Avg(),
                        sensor_name=sensor_name,
                        description='The average compression rate of record batches.')

        sensor_name = 'queue-time'
        self.queue_time_sensor = self.metrics.sensor(sensor_name)
        self.add_metric('record-queue-time-avg', Avg(),
                        sensor_name=sensor_name,
                        description='The average time in ms record batches spent in the record accumulator.')
        self.add_metric('record-queue-time-max', Max(),
                        sensor_name=sensor_name,
                        description='The maximum time in ms record batches spent in the record accumulator.')

        sensor_name = 'produce-throttle-time'
        self.produce_throttle_time_sensor = self.metrics.sensor(sensor_name)
        self.add_metric('produce-throttle-time-avg', Avg(),
                        sensor_name=sensor_name,
                        description='The average throttle time in ms')
        self.add_metric('produce-throttle-time-max', Max(),
                        sensor_name=sensor_name,
                        description='The maximum throttle time in ms')

        sensor_name = 'records-per-request'
        self.records_per_request_sensor = self.metrics.sensor(sensor_name)
        self.add_metric('record-send-rate', Rate(),
                        sensor_name=sensor_name,
                        description='The average number of records sent per second.')
        self.add_metric('records-per-request-avg', Avg(),
                        sensor_name=sensor_name,
                        description='The average number of records per request.')

        sensor_name = 'bytes'
        self.byte_rate_sensor = self.metrics.sensor(sensor_name)
        self.add_metric('byte-rate', Rate(),
                        sensor_name=sensor_name,
                        description='The average number of bytes sent per second.')

        sensor_name = 'record-retries'
        self.retry_sensor = self.metrics.sensor(sensor_name)
        self.add_metric('record-retry-rate', Rate(),
                        sensor_name=sensor_name,
                        description='The average per-second number of retried record sends')

        sensor_name = 'errors'
        self.error_sensor = self.metrics.sensor(sensor_name)
        self.add_metric('record-error-rate', Rate(),
                        sensor_name=sensor_name,
                        description='The average per-second number of record sends that resulted in errors')

        sensor_name = 'record-size-max'
        self.max_record_size_sensor = self.metrics.sensor(sensor_name)
        self.add_metric('record-size-max', Max(),
                        sensor_name=sensor_name,
                        description='The maximum record size across all batches')
        self.add_metric('record-size-avg', Avg(),
                        sensor_name=sensor_name,
                        description='The average maximum record size per batch')

        self.add_metric('requests-in-flight',
                        AnonMeasurable(lambda *_: self._client.in_flight_request_count()),
                        description='The current number of in-flight requests awaiting a response.')

        self.add_metric('metadata-age',
                        AnonMeasurable(lambda _, now: (now - self._metadata._last_successful_refresh_ms) / 1000),
                        description='The age in seconds of the current producer metadata being used.')

    def add_metric(self, metric_name, measurable, group_name='producer-metrics',
                   description=None, tags=None,
                   sensor_name=None):
        m = self.metrics
        metric = m.metric_name(metric_name, group_name, description, tags)
        if sensor_name:
            sensor = m.sensor(sensor_name)
            sensor.add(metric, measurable)
        else:
            m.add_metric(metric, measurable)

    def maybe_register_topic_metrics(self, topic):

        def sensor_name(name):
            return 'topic.{0}.{1}'.format(topic, name)

        # if one sensor of the metrics has been registered for the topic,
        # then all other sensors should have been registered; and vice versa
        if not self.metrics.get_sensor(sensor_name('records-per-batch')):

            self.add_metric('record-send-rate', Rate(),
                            sensor_name=sensor_name('records-per-batch'),
                            group_name='producer-topic-metrics.' + topic,
                            description= 'Records sent per second for topic ' + topic)

            self.add_metric('byte-rate', Rate(),
                            sensor_name=sensor_name('bytes'),
                            group_name='producer-topic-metrics.' + topic,
                            description='Bytes per second for topic ' + topic)

            self.add_metric('compression-rate', Avg(),
                            sensor_name=sensor_name('compression-rate'),
                            group_name='producer-topic-metrics.' + topic,
                            description='Average Compression ratio for topic ' + topic)

            self.add_metric('record-retry-rate', Rate(),
                            sensor_name=sensor_name('record-retries'),
                            group_name='producer-topic-metrics.' + topic,
                            description='Record retries per second for topic ' + topic)

            self.add_metric('record-error-rate', Rate(),
                            sensor_name=sensor_name('record-errors'),
                            group_name='producer-topic-metrics.' + topic,
                            description='Record errors per second for topic ' + topic)

    def update_produce_request_metrics(self, batches_map):
        for node_batch in batches_map.values():
            records = 0
            total_bytes = 0
            for batch in node_batch:
                # register all per-topic metrics at once
                topic = batch.topic_partition.topic
                self.maybe_register_topic_metrics(topic)

                # per-topic record send rate
                topic_records_count = self.metrics.get_sensor(
                    'topic.' + topic + '.records-per-batch')
                topic_records_count.record(batch.record_count)

                # per-topic bytes send rate
                topic_byte_rate = self.metrics.get_sensor(
                    'topic.' + topic + '.bytes')
                topic_byte_rate.record(batch.records.size_in_bytes())

                # per-topic compression rate
                topic_compression_rate = self.metrics.get_sensor(
                    'topic.' + topic + '.compression-rate')
                topic_compression_rate.record(batch.records.compression_rate())

                # global metrics
                self.batch_size_sensor.record(batch.records.size_in_bytes())
                if batch.drained:
                    self.queue_time_sensor.record(batch.drained - batch.created)
                self.compression_rate_sensor.record(batch.records.compression_rate())
                self.max_record_size_sensor.record(batch.max_record_size)
                records += batch.record_count
                total_bytes += batch.records.size_in_bytes()

            self.records_per_request_sensor.record(records)
            self.byte_rate_sensor.record(total_bytes)

    def record_retries(self, topic, count):
        self.retry_sensor.record(count)
        sensor = self.metrics.get_sensor('topic.' + topic + '.record-retries')
        if sensor:
            sensor.record(count)

    def record_errors(self, topic, count):
        self.error_sensor.record(count)
        sensor = self.metrics.get_sensor('topic.' + topic + '.record-errors')
        if sensor:
            sensor.record(count)

    def record_throttle_time(self, throttle_time_ms, node=None):
        self.produce_throttle_time_sensor.record(throttle_time_ms)


text:
/**
 *      iobroker radar Adapter
 *      (c) 2016- <frankjoke@hotmail.com>
 *      MIT License
 */
/* eslint-env node,es6 */
// jshint node:true, esversion:6, strict:global, undef:true, unused:true
"use strict";
const utils = require(__dirname + '/lib/utils'); // Get common adapter utils
const adapter = utils.Adapter('radar');
const btbindir = __dirname + '\\bin\\bluetoothview\\';

const util = require('util');
const http = require('http');
const xml2js = require('xml2js');
const ping = require('ping');
const fs = require('fs');
const dns = require('dns');
//const noble =     require('noble'); // will be loaded later because not all machines will have it working
var noble = null;
const exec = require('child_process').exec;

function _O(obj, level) {
    return util.inspect(obj, false, level || 2, false).replace(/\n/g, ' ');
}

// function _J(str) { try { return JSON.parse(str); } catch (e) { return {'error':'JSON Parse Error of:'+str}}}
function _N(fun) {
    return setTimeout.apply(null, [fun, 0].concat(Array.prototype.slice.call(arguments, 1)));
} // move fun to next schedule keeping arguments
function _D(l, v) {
    adapter.log.debug(l);
    return v === undefined ? l : v;
}

function _I(l, v) {
    adapter.log.info(l);
    return v === undefined ? l : v;
}

function _W(l, v) {
    adapter.log.warn(l);
    return v === undefined ? l : v;
}

function wait(time, arg) {
    return new Promise(res => setTimeout(res, time, arg));
}

function pSeriesP(obj, promfn, delay) { // fun gets(item) and returns a promise
    delay = delay || 0;
    let p = Promise.resolve();
    const nv = [],
        f = (k) => p = p.then(() => promfn(k).then(res => wait(delay, nv.push(res))));
    for (let item of obj)
        f(item);
    return p.then(() => nv);
}
/*
function pSeriesInP(obj,promfn,delay) { // fun gets(key,obj) and returns a promise
    delay = delay || 0;
    let p = Promise.resolve();
    const   nv = [],
            f = (k) => p = p.then(() => promfn(k,obj).then(res => wait(delay,nv.push(res))));
    for(let item in obj)
        f(item);
    return p.then(() => nv);
}

function pSeriesF(obj,fun,delay) { // fun gets(item) and returns a value
    delay = delay || 0;
    let p = Promise.resolve();
    const   nv = [],
            f = (k) => p = p.then(() => Promise.resolve(fun(k)).then(res => wait(delay,nv.push(res))));
    for(let item of obj)
        f(item);
    return p.then(() => nv);
}
*/
function c2pP(f) {
    //    _D(`c2pP: ${_O(f)}`);
    return function () {
        const args = Array.prototype.slice.call(arguments);
        return new Promise((res, rej) => {
            args.push((err, result) => (err && _N(rej, err)) || _N(res, result));
            f.apply(this, args);
        });
    };
}

function c1pP(f) {
    return function () {
        const args = Array.prototype.slice.call(arguments);
        return new Promise((res) => {
            args.push((result) => _N(res, result));
            f.apply(this, args);
        });
    };
}
/*
function pRetryP(nretry, fn, arg) {
    return fn(arg).catch(err => {
        if (nretry <= 0)
            throw err;
        return pRetryP(nretry - 1, fn,arg);
    });
}

function pRepeatP(nretry, fn, arg) {
    return fn(arg).then(() => Promise.reject()).catch(err => {
        if (nretry <= 0)
            return Promise.resolve();
        return pRepeatP(nretry - 1, fn,arg);
    });
}

*/

const P = {};

function makePs() {
    P.getObjectList = c2pP(adapter.objects.getObjectList);
    P.getForeignObject = c2pP(adapter.getForeignObject);
    P.setForeignObject = c2pP(adapter.setForeignObject);
    P.getForeignObjects = c2pP(adapter.getForeignObjects);
    P.getForeignState = c2pP(adapter.getForeignState);
    P.getState = c2pP(adapter.getState);
    P.setState = c2pP(adapter.setState);
    P.getObject = c2pP(adapter.getObject);
    P.deleteState = c2pP(adapter.deleteState);
    P.delObject = c2pP(adapter.delObject);
    P.setObject = c2pP(adapter.setObject);
    P.createState = c2pP(adapter.createState);
    P.extendObject = c2pP(adapter.extendObject);
}

var isStopping = false;
const scanList = new Map();
var scanDelay = 30 * 1000; // in ms = 30 sec
var scanTimer = null;
var printerDelay = 100;
var printerCount = 0;
var delayAway = 10;
var countHere = 0;
var whoHere = [];
var host = null;

function stop(dostop) {
    isStopping = true;
    if (scanTimer)
        clearInterval(scanTimer);
    scanTimer = null;
    _W('Adapter disconnected and stopped with '+dostop);
    //    if (dostop)
    //        process.exit();
    //        adapter.stop();
}

adapter.on('message', obj => processMessage(obj));

adapter.on('ready', () => main(makePs()));

adapter.on('unload', () => stop(false));

function processMessage(obj) {
    if (obj && obj.command) {
        _D(`process Message ${_O(obj)}`);
        switch (obj.command) {
            case 'ping':
                {
                    // Try to connect to mqtt broker
                    if (obj.callback && obj.message) {
                        ping.probe(obj.message, {
                            log: adapter.log.debug
                        }, function (err, result) {
                            adapter.sendTo(obj.from, obj.command, res, obj.callback);
                        });
                    }
                    break;
                }
        }
    }
    adapter.getMessage(function (err, obj) {
        if (obj) {
            processMessage(obj);
        }
    });
}

const objects = new Map();

function makeState(id, value, ack) {
    ack = ack === undefined || !!ack;
    if (objects.has(id))
        return P.setState(id, value, ack);
    _D(`Make State ${id} and set value to '${_O(value)}'`) ///TC
    var st = {
        common: {
            name: id, // You can add here some description
            read: true,
            write: false,
            state: 'state',
            role: 'value',
            type: typeof value
        },
        type: 'state',
        _id: id
    };
    if (id.endsWith('Percent'))
        st.common.unit = "%";
    return P.extendObject(id, st)
        .then(x => {
            objects.set(id, x);
            return P.setState(id, value, ack);
        })
        .catch(err => _D(`MS ${_O(err)}:=extend`, id));

}

var nobleRunning = null;

function myNoble(len) {
    function stopNoble(idf) {
        if (nobleRunning)
            clearTimeout(nobleRunning);
        if (!noble)
            return {};
        nobleRunning = null;
        noble.removeAllListeners('discover');
        noble.stopScanning();
        //        _D(util.format('Noble found %j',idf));
        return idf;
    }

    _D(`Noble= ${_O(noble)} start ${len}`);

    let idf = {};
    if (nobleRunning) clearTimeout(nobleRunning);
    nobleRunning = null;

    if (!noble) return Promise.resolve({});
    if (isStopping) return Promise.reject('Stopping.')
    if (noble.state !== 'poweredOn') return Promise.reject('Noble not powered ON!');

    return new Promise((res, rej) => {
        noble.on('discover', function (per) {
            if (isStopping)
                return res(stopNoble(idf));

            var idt = (per.advertisement && per.advertisement.localName) ? per.advertisement.localName : "NaN";
            idf[per.address.toUpperCase()] = {
                address: per.address,
                name: idt,
                rssi: per.rssi
            };
        });

        noble.startScanning([], true);
        nobleRunning = setTimeout(() => res(stopNoble(idf)), len);
    }).catch(err => _I(`Noble scan Err ${_O(err)}`, err, noble = null));
}

function pExec(command) {
    const istest = command.startsWith('!');
    return new Promise((resolve, reject) => {
        exec(istest ? command.slice(1) : command, (error, stdout, stderr) => {
            if (istest && error) {
                error[stderr] = stderr;
                return reject(error);
            }
            resolve(stdout);
        });
    });
}

function pGet(url, retry) {
    //    _I(`pGet retry(${retry}): ${url}`);
    return (new Promise((resolve, reject) => {
        //        _I(`pGet retry(${retry}): ${url}`);
        http.get(url, (res) => {
            let statusCode = res.statusCode;
            let contentType = res.headers['content-type'];
            //            _D(`res: ${statusCode}, ${contentType}`);
            let error = null;
            if (statusCode !== 200) {
                error = new Error(`Request Failed. Status Code: ${statusCode}`);
                //              } else if (!/^application\/json/.test(contentType)) {
                //                error = new Error(`Invalid content-type. Expected application/json but received ${contentType}`);
            }
            if (error) {
                res.resume(); // consume response data to free up memory
                return reject(error);
            }

            res.setEncoding('utf8');
            let rawData = '';
            res.on('data', (chunk) => rawData += chunk);
            res.on('end', () => _N(resolve, rawData));
        }).on('error', (e) => _N(reject, e));
    })).catch(err => {
        if (!(retry > 0)) throw err;
        return wait(100, retry - 1).then(a => pGet(url, a));
    });
}

var doFping = true;
var doHci = true;
var doBtv = true;
var doMac = true;
var doUwz = null;

function xmlParseString(body) {
    function parseNumbers(str) {
        if (!isNaN(str))
            str = str % 1 === 0 ? parseInt(str) : parseFloat(str);
        return str;
    }

    function tagnames(item) {
        let all = item.split(':');
        item = (all.length === 2) ? all[1] : all[0];
        //            _I(`Tag: all: ${_O(all)} became ${item}`);
        return item;
    }
    return (c2pP(new xml2js.Parser({
            explicitArray: false,
            trim: true,
            tagNameProcessors: [tagnames],
            //                attrNameProcessors: [tagnames],
            valueProcessors: [parseNumbers]
        })
        .parseString))(body);
}

function scanExtIP() {
    let oldip = "";
    let sameip = 0;

    function getIP(site) {
        return pGet(site, 2)
            .then(chunk => {
                const ip = chunk.trim();
                if (ip == oldip)
                    ++sameip;
                else
                    oldip = ip;
                return Promise.resolve(sameip);
            }, err => _I(`MyIP Error ${_O(err)}`, Promise.resolve(sameip)));
    }

    return getIP('http://icanhazip.com/?x=2')
        .then(() => getIP('http://wtfismyip.com/text'))
        .then(() => sameip < 1 ? getIP('http://nst.sourceforge.net/nst/tools/ip.php') : Promise.resolve(sameip))
        .then(() => P.getState('ExternalNetwork.IP4'))
        .then(x => x, err => Promise.resolve())
        .then(state => {
            if (state && state.val)
                state = state.val;
            if (oldip !== '' && state != oldip) {
                _I(`New IP address ${oldip}`, oldip);
            } else if (oldip === '') {
                return makeState('ExternalNetwork.status', _W(`Not connected to external network!`, 0));
            } else
                _D(`Same IP address ${oldip}`);
            return makeState('ExternalNetwork.IP4', oldip)
                .then(() => makeState('ExternalNetwork.status', ++sameip));
        }, err => _I(`scanExtIP error ${_O(err)}`, Promise.resolve()));
}

function scanECB(item) {
    let idn = item.id + '.';
    return pGet('http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml', 2)
        .then(body => xmlParseString(body))
        .then(ecb => makeState(idn + 'fromDate', ecb.Envelope.Cube.Cube['$'].time).then(() => ecb))
        .then(ecb => pSeriesP(ecb.Envelope.Cube.Cube.Cube, cur => {
            let ccur = cur['$'].currency;
            let rate = parseFloat(cur['$'].rate);
            if (item.ip.indexOf(ccur) < 0)
                return Promise.resolve();
            return makeState(idn + ccur, rate);
        }, 5))
        .catch(err => _I(`ECB error: ${_O(err)}`));
}

function scanHP(item) {

    let idn = item.id + '.';
    let colors = [];
    let below10 = [];
    //    _I(`should call ${item.ip} for printer data`);
    return pGet('http://' + item.ip + '/DevMgmt/ConsumableConfigDyn.xml', 2)
        .then(body => xmlParseString(body.trim()))
        //        .then(result => _I(`parser ${_O(result,3)}`,result))
        .then(result => result["ConsumableConfigDyn"] ? result["ConsumableConfigDyn"] : result)
        .then(result => pSeriesP(result["ConsumableInfo"], item => {
                //            _I(`parser ${_O(item)}`);
                if (item["ConsumableTypeEnum"] != "ink")
                    return Promise.resolve('No Ink');
                let p = "P" + item["ConsumableStation"],
                    lc = item["ConsumableLabelCode"],
                    idnc = idn + lc + '.',
                    d = item["Installation"] ? item["Installation"]["Date"] : null,
                    l = parseInt(item["ConsumablePercentageLevelRemaining"]),
                    ci = item["ConsumableIcon"],
                    s = ci["Shape"],
                    fc = ci["FillColor"],
                    rgb = fc["Blue"] | (fc["Green"] << 8) | (fc["Red"] << 16),
                    n = item["ConsumableSelectibilityNumber"];
                rgb = '#' + (0x1000000 + rgb).toString(16).slice(1);
                let ss = `${p} = ${lc},${d ? d + ',' : ''} ${l}%, ${n}, ${rgb}, ${s}`;
                colors.push(ss);
                if (l <= 10)
                    below10.push(lc);
                return makeState(idnc + 'fillPercent', l)
                    .then(res => makeState(idnc + 'color', rgb))
                    .then(res => makeState(idnc + 'text', ss));
            })
            .then(arg => makeState(idn + 'anyBelow10', below10.length > 0))
            .then(arg => makeState(_D(idn + 'whoBelow10'), below10.join(', ')))
            .then(arg => _D(`HP Printer inks found:${colors.length}`))
            .catch(err => _D(`HP Printer could not find info! Err: ${_O(err)}`)));
}

var oldWhoHere = null,
    bts = new Map(),
    ips = new Map(),
    vendors = new Map(),
    arps = {},
    unkn = {};

function checkArps(ip) {
    ip = ip.trim();
    if (arps[ip]) {
        delete arps[ip];
        return true;
    }
    return false;
}

function checkUnkn(ip) {
    ip = ip.trim().toUpperCase();
    if (arps[ip]) {
        delete arps[ip];
        return true;
    }
    return false;
}

function checkCache(item, cache, funP) {
    return new Promise((_res, _rej) => {
        if (cache.has(item))
            return _res(cache.get(item));
        funP(item).then(res => _res((cache.set(item, res), res)));
    });
}

function scanAll() {
    if (isStopping) // do not start scan if stopping...
        return;

    _D(`Would now start scan for devices! ${printerCount === 0 ? 'Would also scan for printer ink now!' : 'printerCount=' + printerCount}`);

    for (let item of scanList.values())
        item.ipHere = item.btHere = false;

    arps = {};
    unkn = {};

    return Promise.all([doBtv ?
        pExec(`${btbindir}bluetoothview /scomma ${btbindir}btf.txt`)
        .then(stdout => wait(300, stdout))
        .then(stdout => c2pP(fs.readFile)(`${btbindir}btf.txt`, 'utf8'))
        .then(data => wait(100, data))
        .then(data => {
            try {
                fs.unlinkSync(`${btbindir}btf.txt`);
            } catch (e) {
                return '';
            }
            return data;
        })
        .then(data => {
            for (let item of scanList.values())
                if (data.toUpperCase().indexOf(item.bluetooth) > 0) {
                    _D(`doBtv found  ${item.name}`);
                    item.btHere = true;
                }
        }) : wait(10),
        myNoble(scanDelay - 25000)
        .then(data => {
            let found = 0;
            for (let key of scanList.values()) {
                if (data[key.bluetooth]) {
                    delete data[key.bluetooth];
                    _D(`Noble found  ${key.name}`);
                    key.btHere = true;
                    ++found;
                }
            }
            return pSeriesP(Object.keys(data), (d) => {
                var e = data[d];
                //                _W(`process not found ${d} ${a}`);
                return checkCache(d, bts, mac => pGet('http://api.macvendors.com/' + mac).then(x => x.trim(), err => 'N/A'))
                    .then(x => e.vendor = x)
                    .then(() => unkn[d] = e)
                    //                    .then(() => _D(`Noble found also unknown: ${_O(e)}`))
                    .then(() => delete e['address']);
            });
        }, err => false),
        doMac ? pExec('arp-scan -lgq --retry=7')
        .then(res => res && res.match(/(\d*\.){3}\d*\s*([\dA-F]{2}\:){5}[\dA-F]{2}/gi))
        .then(res => pSeriesP(res, item => {
            const s = item.split('\t');
            s[1] = s[1].toUpperCase();
            return Promise.all([
                    checkCache(s[0], ips, ip => c2pP(dns.reverse)(ip).then(nam => nam, err => 'DNS N/A')).then(x => s.push(x)),
                    checkCache(s[1], vendors, mac => pGet('http://api.macvendors.com/' + mac).then(x => x.trim(), err => 'Vendor N/A')).then(x => s.push(x)),
                ])
                .then(() => {
                    for (let sl of scanList.values()) {
                        let here = false;
                        if (s[0] == sl.ip)
                            sl.ipHere = here = true;
                        if (sl.hasMAC)
                            for (let m of sl.hasMAC)
                                if (s[1] == m)
                                    sl.ipHere = here = true;
                        if (!here)
                            arps[s[0]] = s.slice(1).join('; ');
                    }
                    return s;
                })
                .catch(err => _D(`${_O(err)}`));
        }, 10)) : wait(5),
        pSeriesP(scanList.values(), item => {
            //            _D(`key ${key} obj ${_O(key)} = ${_O(obj[key])}`);
            let all = [];
            if (item.hasECB) {
                if (printerCount === 0)
                    all.push(scanECB(item));
            } else if (item.hasIP && !item.ipHere)
                if (item.ip.toUpperCase().startsWith('HTTP'))
                    all.push(pGet(item.ip).then(x => true, e => false).then(x => item.ipHere = x || item.ipHere));
                else
                    all.push(c1pP(ping.sys.probe)(item.ip)
                        .then(res => {
                            //                        _I(`${item.name}:${item.ip} = ${res}`);
                            if (!res && doFping)
                                return pExec('fping ' + item.ip)
                                    .then(stdout => / is alive/.test(stdout) || res, false);
                            return res;
                        })
                        .then(iph => {
                            //                        _I(`IP ${item.name}:${item.ip} = ${iph}`);
                            if (iph) {
                                item.ipHere = true;
                                if (item.printer && printerCount === 0)
                                    return scanHP(item);
                            }
                            return iph;
                        })
                    );

            /*
                        if (doMac && item.hasMAC)
                            all.push(pSeriesP(item.hasMAC, mac => pExec('arp-scan -lgq  --retry=5 --destaddr='+ mac)
                                .then(ret => {
                                    item.ipHere = item.ipHere || ret.toUpperCase().indexOf(mac)>0;
            //                        _I(`arp-scan for ${item.id}  ${item.ipHere} returned ${ret}`);
                                    return Promise.resolve();
                                })
                            ));
            */
            if (item.hasBT)
                checkUnkn(item.bluetooth);
            if (doHci && item.hasBT && !item.bluetooth.startsWith('7C:2F:80') && !item.btHere) {
                all.push(pExec('hcitool name ' + item.bluetooth)
                    .then(stdout => {
                        let bth = stdout > "";
                        if (bth) {
                            item.btname = stdout.trim();
                            item.btHere = true;
                            _D(`hcitool found ${item.name} as ${item.btname}`);
                        }
                        return bth;
                    }, err => false)
                    .then(bt => item.btHere = bt)
                    .then(bt => !bt ? wait(200)
                        .then(x => pExec('!l2ping -c1 ' + item.bluetooth))
                        .then(op => op, x => _D(x, pExec('!l2ping -c1 ' + item.bluetooth)))
                        .then(op => op.length > 0 ?
                            _D(`l2ping found ${item.name} with "${op}"`, (item.btHere = true)) :
                            _D(`l2ping for ${item.name} returned nothing!`, false),
                            x => _D(`l2ping for ${item.name} err: "${x}"`, false)) :
                        false)
                    .catch(x => x)
                    .then(x => wait(100))
                );
            }
            return Promise.all(all)
                .then(obj => item.name, err => _D(`err in ${item.name}: ${_O(err)}`));
        }, 50).then(res => res, err => _D(`err ${_O(err)}`, err))
    ]).then(res => {
        //            _D(`Promise all  returned ${res}  ${res}:${_O(res)}`);
        if (++printerCount >= printerDelay) ///TBC
            printerCount = 0;
        whoHere = [];
        let allhere = [];
        return pSeriesP(scanList.values(), (item) => {
                //            for(let item of scanList.values()) {
                //                _I(`item=${_O(item)}:`);
                const here = item.ipHere || item.btHere;
                let cnt = item.cnt === undefined ? -delayAway : parseInt(item.cnt);
                let anw = false;
                //                _I(`${item.name}:cnt=${cnt}, here=${here}`);
                if (item.hasECB)
                    return Promise.resolve();
                if (here) {
                    cnt = cnt < 0 ? 0 : cnt + 1;
                    anw = true;
                } else {
                    cnt = cnt > 0 ? -1 : cnt - 1;
                    anw = cnt >= -delayAway;
                }
                if (item.rip) {
                    if (Array.isArray(item.rip))
                        for (let ip of item.rip)
                            checkArps(ip);
                    else
                        checkArps(item.rip);
                }
                item.anwesend = anw;
                item.cnt = cnt;
                if (anw) {
                    allhere.push(item.id);
                    if (item.name == item.id)
                        whoHere.push(item.id);
                }
                _D(`${item.id}=${_O(item)}`);
                const idn = item.id;
                return makeState(idn + '.count', cnt)
                    .then(res => makeState(idn + '.here', anw))
                    .then(res => item.hasIP ? makeState(idn + '.ipHere', item.ipHere) : false)
                    .then(res => item.hasBT ? makeState(idn + '.btHere', item.btHere) : false);
            }).then(() => {
                countHere = whoHere.length;
                whoHere = whoHere.join(', ');
                if (oldWhoHere != whoHere) {
                    oldWhoHere = whoHere;
                    _I(`ScanAll: From all ${allhere.length} devices dedected ${countHere} are whoHere: ${whoHere}`);
                }
                allhere = allhere.join(', ');
                return makeState('countHere', countHere)
                    .then(res => makeState('allHere', allhere))
                    .then(res => makeState('whoHere', whoHere));
            }).then(() => _D(`Noble found unknown BT's: ${_O(unkn)}, unknown IP's: ${arps}`))
            .then(() => makeState('AllUnknownBTs', JSON.stringify(unkn)))
            .then(res => makeState('AllUnknownIPs', JSON.stringify(arps)));
    }, err => _W(`Scan devices returned error: ${_O(err)}`));
}

function isMacBt(str) {
    return /^([0-9A-F]{2}\:){5}[0-9A-F]{2}$/.test(str.trim().toUpperCase());
}

var ain = '',
    wlast = null,
    lang = '',
    numuwz = 0,
    delayuwz = 0,
    longuwz = false;

function getUWZ() {
    pGet('http://feed.alertspro.meteogroup.com/AlertsPro/AlertsProPollService.php?method=getWarning&language=de&areaID=' + doUwz)
        .then(body => JSON.parse(body))
        .then(data => {
            var w = data && data.results;
            if (!w)
                return Promise.reject('UWZ data err: ' + _O(data));
            //            _W(`${_O(w,5)}`);
            return w.map(i => (lang == 'de' ?
                (longuwz ? i.payload.translationsLongText.DE : i.payload.translationsShortText.DE) :
                (longuwz ? i.payload.longText : i.payload.shortText)) + (longuwz ? ': ' + i.payload.levelName : ''));
        })
        .then(w => {
            let wl = w.length,
                wt = w.join(numuwz < 0 ? '<br>\n' : '\n');
            wt = wt == '' ? "No warnings" : wt;
            if (wt != wlast) {
                wlast = wt;
                _I(`UWZ found the following (changed) warnings: ${wt}`);
                if (numuwz > 0) {
                    return pSeriesP(Object.keys(w), (x) => x < numuwz ? makeState('UWZ_Warnings.warning' + x, w[x]) : Promise.resolve())
                        .then(() => {
                            let n = wl,
                                l = [];

                            while (n < numuwz)
                                l.push(n++);
                            return pSeriesP(l, (x) => makeState('UWZ_Warnings.warning' + x, ''));
                        })
                } else
                    return makeState('UWZ_Warning', wlast);
            }
        })
        .catch(e => _W(`Error in getUWZ: ${e}`))
}

function main() {
    host = adapter.host;

    try {
        noble = require('noble');
    } catch (e) {
        _W(`Noble not available, Error: ${_O(e)}`);
        noble = null;
    }

    ain = adapter.name + '.' + adapter.instance + '.';

    if (!adapter.config.devices.length) {
        _W(`No to be scanned devices are configured for host ${host}! Will stop Adapter`);
        return stop(true);
    }

    if (!adapter.config.scandelay || parseInt(adapter.config.scandelay) < 30)
        adapter.config.scandelay = 30;
    scanDelay = adapter.config.scandelay * 1000;

    if (!adapter.config.delayaway || parseInt(adapter.config.delayaway) < 2)
        adapter.config.delayaway = 2;
    delayAway = adapter.config.delayaway;

    if (!adapter.config.printerdelay || parseInt(adapter.config.printerdelay) < 100)
        adapter.config.printerdelay = 100;
    printerDelay = adapter.config.printerdelay;

    _I(`radar set to scan every ${adapter.config.scandelay} sec and printers every ${printerDelay} scans.`);

    _I(`BT Bin Dir = '${btbindir}'`);

    pExec(`!${btbindir}bluetoothview /scomma ${btbindir}btf.txt`)
        .then(stdout => true, err => false)
        .then(result => {
            doBtv = result;
            return pExec('!fping 127.0.0.1').then(r => r, r => r)
        }).then(stdout => / is alive/.test(stdout), false)
        .then(result => {
            doFping = result;
            return pExec('!arp-scan -lgq').then(r => r, r => r)
        }).then(stdout => /[0-9] packets received/.test(stdout), false)
        .then(result => {
            doMac = result;
            return pExec('!hcitool name 12:34:56:78:90:ab');
        }).then(res => true, err => false)
        .then(res => {
            doHci = res;
            return pSeriesP(adapter.config.devices, item => {
                //                _I(`checking item ${_O(item)}`);
                if (item.name)
                    item.name = item.name.trim().replace(/[\s\.]/g, '_');
                if (!item.name || item.name.length < 2)
                    return Promise.resolve(_W(`Invalid item name '${_O(item.name)}', must be at least 2 letters long`));
                if (scanList.has(item.name))
                    return Promise.resolve(_W(`Double item name '${item.name}', names cannot be used more than once!`));
                item.id = item.name.endsWith('-') ? item.name.slice(0, -1) : item.name;
                item.ip = item.ip ? item.ip.trim() : '';
                item.macs = item.macs ? item.macs.trim().toUpperCase() : '';
                item.macs.split(',').forEach(val => {
                    const mac = val && (typeof val === 'string') ? val.trim() : null;
                    if (mac) {
                        if (isMacBt(mac))
                            item.hasMAC = item.hasMAC ? item.hasMAC.push(mac) : [mac];
                        else
                            _W(`invalid MAC address in ${item.name}: '${val}'`);
                    }
                });
                if (item.hasMAC && !doMac)
                    _W(`MAC addresses '${item.macs}' will not be scanned because no arp-scan is available!`)
                item.bluetooth = item.bluetooth ? item.bluetooth.trim().toUpperCase() : '';
                item.hasBT = isMacBt(item.bluetooth);
                if (item.bluetooth !== '' && !item.hasBT)
                    _W(`Invalid bluetooth address '${item.bluetooth}', 6 hex numbers separated by ':'`);
                item.printer = item.ip && item.name.startsWith('HP-');
                item.hasECB = item.ip && item.name.startsWith('ECB-');
                item.hasIP = item.ip && item.ip.length > 2;
                if (item.hasIP && !item.ip.toUpperCase().startsWith('HTTP')) {
                    if (!item.ip.match(/^(\d+\.){3}\d+/))
                        c2pP(dns.resolve)(item.ip).then(x => item.rip = x);
                    else
                        item.rip = item.ip;
                }
                if (!(item.hasIP || item.hasBT))
                    return Promise.resolve(_W(`Invalid Device should have IP or BT set ${_O(item)}`));
                scanList.set(item.name, item);
                _I(`Init item ${item.name} with ${_O(item)}`);
                return Promise.resolve(item.id);
            }, 50);
        }).then(() => parseInt(adapter.config.external) > 0 ? scanExtIP() : Promise.resolve())
        .then(() => P.getObjectList({
            include_docs: true
        }))
        .then(res => {
            var r = {};
            if (!adapter.config.delayuwz || parseInt(adapter.config.delayuwz) <= 0)
                return Promise.resolve(_I(`No UWZ warning because of Delay is ${adapter.config.delayuwz}`));
            delayuwz = parseInt(adapter.config.delayuwz);
            numuwz = parseInt(adapter.config.numuwz);
            longuwz = Boolean(adapter.config.longuwz)
            res.rows.map(i => r[i.doc._id] = i.doc)
            if (r['system.config'] && r['system.config'].common.language)
                lang = r['system.config'].common.language;
            if (r['system.config'] && r['system.config'].common.latitude) {
                adapter.config.latitude = parseFloat(r['system.config'].common.latitude);
                adapter.config.longitude = parseFloat(r['system.config'].common.longitude);
                return pGet(`http://feed.alertspro.meteogroup.com/AlertsPro/AlertsProPollService.php?method=lookupCoord&lat=${adapter.config.latitude}&lon=${adapter.config.longitude}`)
                    .then(res => JSON.parse(res)[0], e => _W(`Cpuld not get UWZ Area ID: ${e} for Laenge: ${adapter.config.longitude} Breite: ${adapter.config.latitude}`))
                    .then(res => doUwz = res && res.AREA_ID ? res.AREA_ID : null)
                    .then(() => getUWZ(), setInterval(getUWZ, parseInt(adapter.config.delayuwz) * 1000))
            } else return Promise.reject(_W('No geo location data found configured in admin to calculate UWZ AREA ID!'));
        }, err => doUwz = null)
        .then(res => {
            _I(`radar adapter initialized ${scanList.size} devices, ExternalNetwork = ${adapter.config.external}.`);
            _I(`radar set use of noble(${!!noble}), fping(${doFping}), doMac(${doMac}), doHci(${doHci}), doBtv(${doBtv}) and doUwz(${doUwz},${delayuwz},${numuwz},${lang},${longuwz}).`);
            scanTimer = setInterval(scanAll, scanDelay);
            if (parseInt(adapter.config.external) > 0)
                setInterval(scanExtIP, parseInt(adapter.config.external) * 1000);
            return scanAll(); // scan first time and generate states if they do not exist yet
        })
        .then(res => P.getObjectList({
            startkey: ain,
            endkey: ain + '\u9999'
        }))
        .then(res => pSeriesP(res.rows, item => { // clean all states which are not part of the list
            //            _I(`Check ${_O(item)}`);
            let id = item.id.slice(ain.length);
            if (objects.has(id))
                return Promise.resolve();
            //            _I(`Delete ${_O(item)}`);
            return P.deleteState(id)
                .then(x => _D(`Del State: ${id}`), err => _D(`Del State err: ${_O(err)}`)) ///TC
                .then(y => P.delObject(id))
                .then(x => _D(`Del Object: ${id}`), err => _D(`Del Object err: ${_O(err)}`)) ///TC
        }, 10))
        .catch(err => {
            _W(`radar initialization finished with error ${_O(err)}, will stop adapter!`);
            stop(true);
            throw err;
        })
        .then(x => _I('Adapter initialization finished!'));
}


text:
package com.spotify.heroic.cluster;

import com.google.common.collect.ImmutableList;
import com.spotify.heroic.dagger.PrimaryComponent;
import dagger.Component;
import eu.toolchain.async.AsyncFramework;
import eu.toolchain.async.AsyncFuture;
import java.net.URI;
import java.util.List;
import javax.inject.Inject;

public interface ClusterDiscoveryModule {
    ClusterDiscoveryComponent module(PrimaryComponent primary);

    static ClusterDiscoveryModule nullModule() {
        return primary -> DaggerClusterDiscoveryModule_NullComponent
            .builder()
            .primaryComponent(primary)
            .build();
    }

    @ClusterScope
    @Component(dependencies = PrimaryComponent.class)
    interface NullComponent extends ClusterDiscoveryComponent {
        @Override
        Null clusterDiscovery();
    }

    @ClusterScope
    class Null implements ClusterDiscovery {
        private final AsyncFramework async;

        @Inject
        public Null(AsyncFramework async) {
            this.async = async;
        }

        @Override
        public AsyncFuture<List<URI>> find() {
            return async.resolved(ImmutableList.of());
        }
    }
}


text:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="build" name="java-feature-set">

	<property environment="env" />
	<property name="debuglevel" value="source,lines,vars" />
	<property name="target" value="1.9" />
	<property name="source" value="1.9" />

	<path id="java-src.classpath">
		<pathelement location="bin" />
		<fileset dir="lib/">
			<include name="**/*.jar" />
		</fileset>
	</path>

	<target name="init" depends="cleanall">
		<mkdir dir="bin" />
		<copy includeemptydirs="false" todir="bin">
			<fileset dir="src">
				<exclude name="**/*.java" />
			</fileset>
		</copy>
	</target>

	<target name="clean">
		<echo message="==========================================================" />
		<echo message="CLEAN" />
		<echo message="==========================================================" />
		<delete dir="bin" />
	</target>

	<target depends="clean" name="cleanall" />
	<target depends="build-project" name="build" />

	<target depends="init" name="build-project">
		<echo message="==========================================================" />
		<echo message="Project[${ant.project.name}] Build file: ${ant.file}" />
		<echo message="Using Java version ${ant.java.version}." />
		<echo message="==========================================================" />
		<echo message="==========================================================" />
		<echo message="COMPILE" />
		<echo message="==========================================================" />
		<javac debug="true" debuglevel="${debuglevel}" destdir="bin" includeantruntime="false" source="${source}" target="${target}">
			<src path="src" />
			<classpath refid="java-src.classpath" />
		</javac>
		<echo message="==========================================================" />
		<echo message="CONFIG" />
		<echo message="==========================================================" />
		<copy file="src/main/resources/inbravo-version.txt" tofile="bin/inbravo-version.txt" overwrite="true" />
		<copy file="src/main/resources/inbravo-log4j.properties" tofile="bin/inbravo-log4j.properties" overwrite="true" />
		<echo message="==========================================================" />
		<echo message="JAR" />
		<echo message="==========================================================" />
		<jar destfile="inbravo.jar" basedir="bin" />
	</target>

	<target name="test">
		<java classname="com.inbravo.jdk8.InterfaceWithMainTest$MainClass" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="BinarySearch">
		<java classname="com.inbravo.ds.search.BinarySearch" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="BinaryTree">
		<java classname="com.inbravo.ds.tree.BinaryTree" failonerror="true" fork="yes">
			<arg line="PASSIVE ARCHIVE" />
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="BubbleSort">
		<java classname="com.inbravo.ds.sort.BubbleSort" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="Calculator">
		<java classname="com.inbravo.ds.sort.Calculator" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="DoubleEndedLinkList">
		<java classname="com.inbravo.ds.list.DoubleEndedLinkList" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="FileConv">
		<java classname="com.inbravo.ds.file.FileConv" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="JDBCTest">
		<java classname="com.inbravo.jdbc.JDBCTest" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="LinkedQueue">
		<java classname="com.inbravo.ds.queue.LinkedQueue" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="LinkStack">
		<java classname="com.inbravo.ds.stack.LinkStack" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="MailTest">
		<java classname="com.inbravo.mail.MailTest" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="PowerServiceClient">
		<java classname="com.inbravo.rmi.PowerServiceClient" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="PowerServiceImpl">
		<java classname="com.inbravo.rmi.PowerServiceImpl" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="Queue">
		<java classname="com.inbravo.ds.queue.Queue" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="ReverseTheWord">
		<java classname="com.inbravo.ds.stack.ReverseTheWord" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="SelectionSort">
		<java classname="com.inbravo.ds.sort.SelectionSort" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="Stack">
		<java classname="com.inbravo.ds.stack.Stack" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="StringHashTest">
		<java classname="com.inbravo.string.StringHashTest" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="StringTest">
		<java classname="com.inbravo.string.StringTest" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="VolatileTest">
		<java classname="com.inbravo.ds.concurrency.VolatileTest" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="ObjectSize" depends="build">
		<java classname="com.inbravo.memory.Memory" failonerror="true" fork="yes">
			<classpath refid="java-src.classpath" />
		</java>
	</target>

	<target name="deploy" depends="build">
		<scp file="inbravo.jar" password="impetus" todir="root@192.168.148.76:/root/amit/spark/" trust="true" />
	</target>

	<target name="inst-jar" depends="build-project">
		<echo message="==========================================================" />
		<echo message="INSTRUMENTATION JAR" />
		<echo message="==========================================================" />

		<jar destfile="inbravo-inst.jar" basedir="bin">
			<manifest>
				<attribute name="Premain-class" value="com.inbravo.memory.inst.InstrumentationAgent" />
				<attribute name="Agent-class" value="com.inbravo.memory.inst.InstrumentationAgent" />
			</manifest>
		</jar>
	</target>

</project>


text:
enum days {
    monday,
    tuesday,
    wednesday,
    thursday,
    friday,
    saturday,
    sunday
}

var weekendDay = days.saturday;
var daysOfMonth = days;
var daysOfYear: typeof days;


text:
#ifndef __datablock_h__
#define __datablock_h__

#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include "proto/rhizofs.pb-c.h"

/**
 * allocate a new datablock
 *
 * returns NULL on failure
 **/
Rhizofs__DataBlock * DataBlock_create();

/**
 * free all memory allocated by a datablock
 */
void DataBlock_destroy(Rhizofs__DataBlock * dblk);

/**
 * set the data of the datablock
 *
 * the data will not be modified or freed
 *
 * returns true on success and false on failure
 */
bool DataBlock_set_data(Rhizofs__DataBlock * dblk, const uint8_t * data,
        size_t len, Rhizofs__CompressionType compression);

/**
 * write the data stored in the datablock to the buffer "data"
 *
 * this function allocates the memory for "data" and the caller is
 * responsible to free it.
 *
 * returns the number of bytes of "data" or -1 on failure
 */
int DataBlock_get_data(Rhizofs__DataBlock * dblk, uint8_t ** data);

/**
 * write the data stored in the datablock to the buffer "data"
 *
 * expects "data" to be already allocated to the size of
 * dblk->size
 *
 * returns the number of bytes of "data" or -1 on failure
 */
int DataBlock_get_data_noalloc(Rhizofs__DataBlock * dblk, uint8_t * data, size_t len_data);

#endif