Add build_discard snippet to launcher job. (#630)

Although we've set a launcher job retention policy matching the other ci_* jobs that policy is not enabled because the launcher job was not using that data.

<?xml version='1.0' encoding='UTF-8'?>
<project>
  <actions/>
  <description>
    Launches a build of the CI job for each supported platform with the same set of parameters.
    Use of RTI Connext will always be disabled on aarch64 jobs.
  </description>
  <keepDependencies>false</keepDependencies>
  <properties>
@[if build_discard]@
@(SNIPPET(
    'property_build-discard',
    days_to_keep=build_discard['days_to_keep'],
    num_to_keep=build_discard['num_to_keep'],
))@
@[end if]@
    <com.sonyericsson.rebuild.RebuildSettings plugin="rebuild@@1.31">
      <autoRebuild>false</autoRebuild>
      <rebuildDisabled>false</rebuildDisabled>
    </com.sonyericsson.rebuild.RebuildSettings>
    <org.jenkinsci.plugins.requeuejob.RequeueJobProperty plugin="jobrequeue@@1.1">
      <requeueJob>true</requeueJob>
    </org.jenkinsci.plugins.requeuejob.RequeueJobProperty>
@(SNIPPET(
    'property_parameter-definition',
    ci_scripts_default_branch=ci_scripts_default_branch,
    default_repos_url=default_repos_url,
    supplemental_repos_url=supplemental_repos_url,
    ignore_rmw_default=ignore_rmw_default,
    use_connext_debs_default=use_connext_debs_default,
    use_isolated_default=use_isolated_default,
    ubuntu_distro=ubuntu_distro,
    ros_distro=ros_distro,
    colcon_mixin_url=colcon_mixin_url,
    cmake_build_type=cmake_build_type,
    build_args_default=build_args_default,
    test_args_default=test_args_default,
    compile_with_clang_default=compile_with_clang_default,
    enable_coverage_default=enable_coverage_default,
    os_name=None,
))@
  </properties>
  <scm class="hudson.scm.NullSCM"/>
  <assignedNode>@(label_expression)</assignedNode>
  <canRoam>false</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
    <hudson.plugins.groovy.SystemGroovy plugin="groovy@@2.2">
      <source class="hudson.plugins.groovy.StringSystemScriptSource">
        <script plugin="script-security@@1.70">
          <script>// PREDICT TRIGGERED BUILDS AND GENERATE MARKDOWN FOR BUILD STATUS

import jenkins.model.Jenkins

def predict_build_number(job_name) {
  p = Jenkins.instance.getItemByFullName(job_name)
  if (!p) {
    return 0
  }
  build_number = p.getNextBuildNumber()
  if (p.isInQueue()) {
    // assuming the queued builds don't get cancelled
    for (item in Jenkins.instance.getQueue().getItems()) {
      if (item.task.getName() == job_name) {
        build_number += 1
      }
    }
  }
  return build_number
}

build_numbers = [:]
@[for os_name in os_specific_data.keys()]@
build_numbers["@(os_name)"] = predict_build_number("ci_@(os_name)")
@[end for]@

for (item in build_numbers) {
  name = item.key[0].toUpperCase() + item.key[1..-1].toLowerCase()
  if (name == "Osx") {
    name = "macOS"
  }
  job_name = "ci_${item.key}"
  build_number = item.value
  println "* ${name} [![Build Status](http://ci.ros2.org/buildStatus/icon?job=${job_name}&build=${build_number})](http://ci.ros2.org/job/${job_name}/${build_number}/)"
}
</script>
          <sandbox>false</sandbox>
        </script>
      </source>
    </hudson.plugins.groovy.SystemGroovy>
  </builders>
  <publishers>
@[for os_name, os_data in os_specific_data.items()]@
    <hudson.plugins.parameterizedtrigger.BuildTrigger plugin="parameterized-trigger@@2.35.2">
      <configs>
        <hudson.plugins.parameterizedtrigger.BuildTriggerConfig>
          <configs>
            <hudson.plugins.parameterizedtrigger.CurrentBuildParameters/>
@[  if os_name in ['linux-aarch64']]@
            <hudson.plugins.parameterizedtrigger.BooleanParameters>
              <configs>
                <hudson.plugins.parameterizedtrigger.BooleanParameterConfig>
                  <name>CI_USE_CONNEXTDDS</name>
                  <value>false</value>
                </hudson.plugins.parameterizedtrigger.BooleanParameterConfig>
              </configs>
            </hudson.plugins.parameterizedtrigger.BooleanParameters>
@[  end if]@
@[  if os_name in ['windows', 'windows-metal']]@
            <hudson.plugins.parameterizedtrigger.BooleanParameters>
              <configs>
                <hudson.plugins.parameterizedtrigger.BooleanParameterConfig>
                  <name>CI_ISOLATED</name>
                  <value>@(os_data['use_isolated_default'])</value>
                </hudson.plugins.parameterizedtrigger.BooleanParameterConfig>
              </configs>
            </hudson.plugins.parameterizedtrigger.BooleanParameters>
@[  end if]@
          </configs>
          <projects>@(os_data['job_name'])</projects>
          <condition>SUCCESS</condition>
          <triggerWithNoParameters>false</triggerWithNoParameters>
          <triggerFromChildProjects>false</triggerFromChildProjects>
        </hudson.plugins.parameterizedtrigger.BuildTriggerConfig>
      </configs>
    </hudson.plugins.parameterizedtrigger.BuildTrigger>
@[end for]@
  </publishers>
  <buildWrappers/>
</project>

<?xml version='1.0' encoding='UTF-8'?>
<project>
  <actions/>
  <description>
    Launches a build of the CI job for each supported platform with the same set of parameters.
    Use of RTI Connext will always be disabled on aarch64 jobs.
  </description>
  <keepDependencies>false</keepDependencies>
  <properties>
    <com.sonyericsson.rebuild.RebuildSettings plugin="rebuild@@1.31">
      <autoRebuild>false</autoRebuild>
      <rebuildDisabled>false</rebuildDisabled>
    </com.sonyericsson.rebuild.RebuildSettings>
    <org.jenkinsci.plugins.requeuejob.RequeueJobProperty plugin="jobrequeue@@1.1">
      <requeueJob>true</requeueJob>
    </org.jenkinsci.plugins.requeuejob.RequeueJobProperty>
@(SNIPPET(
    'property_parameter-definition',
    ci_scripts_default_branch=ci_scripts_default_branch,
    default_repos_url=default_repos_url,
    supplemental_repos_url=supplemental_repos_url,
    ignore_rmw_default=ignore_rmw_default,
    use_connext_debs_default=use_connext_debs_default,
    use_isolated_default=use_isolated_default,
    ubuntu_distro=ubuntu_distro,
    ros_distro=ros_distro,
    colcon_mixin_url=colcon_mixin_url,
    cmake_build_type=cmake_build_type,
    build_args_default=build_args_default,
    test_args_default=test_args_default,
    compile_with_clang_default=compile_with_clang_default,
    enable_coverage_default=enable_coverage_default,
    os_name=None,
))@
  </properties>
  <scm class="hudson.scm.NullSCM"/>
  <assignedNode>@(label_expression)</assignedNode>
  <canRoam>false</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
    <hudson.plugins.groovy.SystemGroovy plugin="groovy@@2.2">
      <source class="hudson.plugins.groovy.StringSystemScriptSource">
        <script plugin="script-security@@1.70">
          <script>// PREDICT TRIGGERED BUILDS AND GENERATE MARKDOWN FOR BUILD STATUS

import jenkins.model.Jenkins

def predict_build_number(job_name) {
  p = Jenkins.instance.getItemByFullName(job_name)
  if (!p) {
    return 0
  }
  build_number = p.getNextBuildNumber()
  if (p.isInQueue()) {
    // assuming the queued builds don't get cancelled
    for (item in Jenkins.instance.getQueue().getItems()) {
      if (item.task.getName() == job_name) {
        build_number += 1
      }
    }
  }
  return build_number
}

build_numbers = [:]
@[for os_name in os_specific_data.keys()]@
build_numbers["@(os_name)"] = predict_build_number("ci_@(os_name)")
@[end for]@

for (item in build_numbers) {
  name = item.key[0].toUpperCase() + item.key[1..-1].toLowerCase()
  if (name == "Osx") {
    name = "macOS"
  }
  job_name = "ci_${item.key}"
  build_number = item.value
  println "* ${name} [![Build Status](http://ci.ros2.org/buildStatus/icon?job=${job_name}&build=${build_number})](http://ci.ros2.org/job/${job_name}/${build_number}/)"
}
</script>
          <sandbox>false</sandbox>
        </script>
      </source>
    </hudson.plugins.groovy.SystemGroovy>
  </builders>
  <publishers>
@[for os_name, os_data in os_specific_data.items()]@
    <hudson.plugins.parameterizedtrigger.BuildTrigger plugin="parameterized-trigger@@2.35.2">
      <configs>
        <hudson.plugins.parameterizedtrigger.BuildTriggerConfig>
          <configs>
            <hudson.plugins.parameterizedtrigger.CurrentBuildParameters/>
@[  if os_name in ['linux-aarch64']]@
            <hudson.plugins.parameterizedtrigger.BooleanParameters>
              <configs>
                <hudson.plugins.parameterizedtrigger.BooleanParameterConfig>
                  <name>CI_USE_CONNEXTDDS</name>
                  <value>false</value>
                </hudson.plugins.parameterizedtrigger.BooleanParameterConfig>
              </configs>
            </hudson.plugins.parameterizedtrigger.BooleanParameters>
@[  end if]@
@[  if os_name in ['windows', 'windows-metal']]@
            <hudson.plugins.parameterizedtrigger.BooleanParameters>
              <configs>
                <hudson.plugins.parameterizedtrigger.BooleanParameterConfig>
                  <name>CI_ISOLATED</name>
                  <value>@(os_data['use_isolated_default'])</value>
                </hudson.plugins.parameterizedtrigger.BooleanParameterConfig>
              </configs>
            </hudson.plugins.parameterizedtrigger.BooleanParameters>
@[  end if]@
          </configs>
          <projects>@(os_data['job_name'])</projects>
          <condition>SUCCESS</condition>
          <triggerWithNoParameters>false</triggerWithNoParameters>
          <triggerFromChildProjects>false</triggerFromChildProjects>
        </hudson.plugins.parameterizedtrigger.BuildTriggerConfig>
      </configs>
    </hudson.plugins.parameterizedtrigger.BuildTrigger>
@[end for]@
  </publishers>
  <buildWrappers/>
</project>


Add macros for min severity to not compile out (#60)

* Add macros for min severity to not compile out

This was broken because it was referencing enum values

* Move _NONE to another sentence

// generated from rcutils/resource/logging_macros.h.em

// Copyright 2017 Open Source Robotics Foundation, Inc.
//
// 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.

/*! \file */

#ifndef RCUTILS__LOGGING_MACROS_H_
#define RCUTILS__LOGGING_MACROS_H_

#include "rcutils/logging.h"

#include <stdio.h>
#include <stdlib.h>

#if __cplusplus
extern "C"
{
#endif

// These are used for compiling out logging macros lower than a minimum severity.
#define RCUTILS_LOG_MIN_SEVERITY_DEBUG 0
#define RCUTILS_LOG_MIN_SEVERITY_INFO 1
#define RCUTILS_LOG_MIN_SEVERITY_WARN 2
#define RCUTILS_LOG_MIN_SEVERITY_ERROR 3
#define RCUTILS_LOG_MIN_SEVERITY_FATAL 4
#define RCUTILS_LOG_MIN_SEVERITY_NONE 5

/**
 * \def RCUTILS_LOG_MIN_SEVERITY
 * Define RCUTILS_LOG_MIN_SEVERITY=RCUTILS_LOG_MIN_SEVERITY_[DEBUG|INFO|WARN|ERROR|FATAL]
 * in your build options to compile out anything below that severity.
 * Use RCUTILS_LOG_MIN_SEVERITY_NONE to compile out all macros.
 */
#ifndef RCUTILS_LOG_MIN_SEVERITY
#define RCUTILS_LOG_MIN_SEVERITY RCUTILS_LOG_MIN_SEVERITY_DEBUG
#endif

/**
 * \def RCUTILS_LOG_COND_NAMED
 * The logging macro all other logging macros call directly or indirectly.
 * \param severity The severity level
 * \param condition_before The condition macro(s) inserted before the log call
 * \param condition_after The condition macro(s) inserted after the log call
 * \param name The name of the logger
 * \param ... The format string, followed by the variable arguments for the format string
 */
#define RCUTILS_LOG_COND_NAMED(severity, condition_before, condition_after, name, ...) \
  { \
    RCUTILS_LOGGING_AUTOINIT \
    static rcutils_log_location_t __rcutils_logging_location = {__func__, __FILE__, __LINE__}; \
    condition_before \
    if (severity >= g_rcutils_logging_severity_threshold) { \
      rcutils_log(&__rcutils_logging_location, severity, name, __VA_ARGS__); \
    } \
    condition_after \
  }

///@@{
/**
 * \def RCUTILS_LOG_CONDITION_EMPTY
 * An empty macro which can be used as a placeholder for `condition_before`
 * and `condition_after` which doesn't affect the logging call.
 */
#define RCUTILS_LOG_CONDITION_EMPTY
///@@}

/** @@name Macros for the `once` condition which ignores all subsequent log
 * calls except the first one.
 */
///@@{
/**
 * \def RCUTILS_LOG_CONDITION_ONCE_BEFORE
 * A macro initializing and checking the `once` condition.
 */
#define RCUTILS_LOG_CONDITION_ONCE_BEFORE \
  { \
    static int __rcutils_logging_once = 0; \
    if (RCUTILS_UNLIKELY(0 == __rcutils_logging_once)) { \
      __rcutils_logging_once = 1;
/**
 * \def RCUTILS_LOG_CONDITION_ONCE_AFTER
 * A macro finalizing the `once` condition.
 */
#define RCUTILS_LOG_CONDITION_ONCE_AFTER } \
  }
///@@}

/** @@name Macros for the `expression` condition which ignores the log calls
 * when the expression evaluates to false.
 */
///@@{
/**
 * \def RCUTILS_LOG_CONDITION_EXPRESSION_BEFORE
 * A macro checking the `expression` condition.
 */
#define RCUTILS_LOG_CONDITION_EXPRESSION_BEFORE(expression) \
  if (expression) {
/**
 * \def RCUTILS_LOG_CONDITION_EXPRESSION_AFTER
 * A macro finalizing the `expression` condition.
 */
#define RCUTILS_LOG_CONDITION_EXPRESSION_AFTER }
///@@}

/** @@name Macros for the `function` condition which ignores the log calls
 * when the function returns false.
 */
///@@{
/// The filter function signature.
/**
 * \return true to log the message, false to ignore the message
 */
typedef bool (* RclLogFilter)();
/**
 * \def RCUTILS_LOG_CONDITION_FUNCTION_BEFORE
 * A macro checking the `function` condition.
 */
#define RCUTILS_LOG_CONDITION_FUNCTION_BEFORE(function) \
  if ((*function)()) {
/**
 * \def RCUTILS_LOG_CONDITION_FUNCTION_AFTER
 * A macro finalizing the `function` condition.
 */
#define RCUTILS_LOG_CONDITION_FUNCTION_AFTER }
///@@}

/** @@name Macros for the `skipfirst` condition which ignores the first log
 * call but processes all subsequent calls.
 */
///@@{
/**
 * \def RCUTILS_LOG_CONDITION_SKIPFIRST_BEFORE
 * A macro initializing and checking the `skipfirst` condition.
 */
#define RCUTILS_LOG_CONDITION_SKIPFIRST_BEFORE \
  { \
    static bool __rcutils_logging_first = true; \
    if (RCUTILS_UNLIKELY(true == __rcutils_logging_first)) { \
      __rcutils_logging_first = false; \
    } else {
/**
 * \def RCUTILS_LOG_CONDITION_SKIPFIRST_AFTER
 * A macro finalizing the `skipfirst` condition.
 */
#define RCUTILS_LOG_CONDITION_SKIPFIRST_AFTER } \
  }
///@@}

/** @@name Macros for the `throttle` condition which ignores log calls if the
 * last logged message is not longer ago than the specified duration.
 */
///@@{
/**
 * \def RCUTILS_LOG_CONDITION_THROTTLE_BEFORE
 * A macro initializing and checking the `throttle` condition.
 */
#define RCUTILS_LOG_CONDITION_THROTTLE_BEFORE(time_source_type, duration) { \
    static rcutils_duration_value_t __rcutils_logging_duration = RCUTILS_MS_TO_NS((rcutils_duration_value_t)duration); \
    static rcutils_time_point_value_t __rcutils_logging_last_logged = 0; \
    rcutils_time_point_value_t __rcutils_logging_now = 0; \
    bool __rcutils_logging_condition = true; \
    if (rcutils_steady_time_now(&__rcutils_logging_now) != RCUTILS_RET_OK) { \
      rcutils_log( \
        &__rcutils_logging_location, RCUTILS_LOG_SEVERITY_ERROR, "", \
        "%s() at %s:%d getting current steady time failed\n", \
        __func__, __FILE__, __LINE__); \
    } else { \
      __rcutils_logging_condition = __rcutils_logging_now >= __rcutils_logging_last_logged + __rcutils_logging_duration; \
    } \
 \
    if (RCUTILS_LIKELY(__rcutils_logging_condition)) { \
      __rcutils_logging_last_logged = __rcutils_logging_now;

/**
 * \def RCUTILS_LOG_CONDITION_THROTTLE_AFTER
 * A macro finalizing the `throttle` condition.
 */
#define RCUTILS_LOG_CONDITION_THROTTLE_AFTER } \
  }
///@@}

@{
import sys
sys.path.insert(0, rcutils_module_path)
from rcutils.logging import feature_combinations
from rcutils.logging import get_macro_arguments
from rcutils.logging import get_macro_parameters
from rcutils.logging import get_suffix_from_features
from rcutils.logging import severities
}@
@[for severity in severities]@
/** @@name Logging macros for severity @(severity).
 */
///@@{
#if (RCUTILS_LOG_MIN_SEVERITY > RCUTILS_LOG_MIN_SEVERITY_@(severity))
// empty logging macros for severity @(severity) when being disabled at compile time
@[ for feature_combination in feature_combinations]@
@{suffix = get_suffix_from_features(feature_combination)}@
/// Empty logging macro due to the preprocessor definition of RCUTILS_LOG_MIN_SEVERITY.
# define RCUTILS_LOG_@(severity)@(suffix)(@(''.join([p + ', ' for p in get_macro_parameters(feature_combination).keys()]))format, ...)
@[ end for]@

#else
@[ for feature_combination in feature_combinations]@
@{suffix = get_suffix_from_features(feature_combination)}@
/**
 * \def RCUTILS_LOG_@(severity)@(suffix)
 * Log a message with severity @(severity)@
@[ if feature_combinations[feature_combination].doc_lines]@
 with the following conditions:
@[ else]@
.
@[ end if]@
@[ for doc_line in feature_combinations[feature_combination].doc_lines]@
 * @(doc_line)
@[ end for]@
@[ for param_name, doc_line in feature_combinations[feature_combination].params.items()]@
 * \param @(param_name) @(doc_line)
@[ end for]@
 * \param ... The format string, followed by the variable arguments for the format string
 */
# define RCUTILS_LOG_@(severity)@(suffix)(@(''.join([p + ', ' for p in get_macro_parameters(feature_combination).keys()]))...) \
  RCUTILS_LOG_COND_NAMED( \
    RCUTILS_LOG_SEVERITY_@(severity), \
    @(''.join([str(a) + ', ' for a in get_macro_arguments(feature_combination)]))\
    __VA_ARGS__)
@[ end for]@
#endif
///@@}

@[end for]@
#if __cplusplus
}
#endif

#endif  // RCUTILS__LOGGING_MACROS_H_

// generated from rcutils/resource/logging_macros.h.em

// Copyright 2017 Open Source Robotics Foundation, Inc.
//
// 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.

/*! \file */

#ifndef RCUTILS__LOGGING_MACROS_H_
#define RCUTILS__LOGGING_MACROS_H_

#include "rcutils/logging.h"

#include <stdio.h>
#include <stdlib.h>

#if __cplusplus
extern "C"
{
#endif

/**
 * \def RCUTILS_LOG_MIN_SEVERITY
 * Define RCUTILS_LOG_MIN_SEVERITY=RCUTILS_LOG_SEVERITY_[DEBUG|INFO|WARN|ERROR|FATAL]
 * in your build options to compile out anything below that severity.
 */
#ifndef RCUTILS_LOG_MIN_SEVERITY
#define RCUTILS_LOG_MIN_SEVERITY RCUTILS_LOG_SEVERITY_DEBUG
#endif

/**
 * \def RCUTILS_LOG_COND_NAMED
 * The logging macro all other logging macros call directly or indirectly.
 * \param severity The severity level
 * \param condition_before The condition macro(s) inserted before the log call
 * \param condition_after The condition macro(s) inserted after the log call
 * \param name The name of the logger
 * \param ... The format string, followed by the variable arguments for the format string
 */
#define RCUTILS_LOG_COND_NAMED(severity, condition_before, condition_after, name, ...) \
  { \
    RCUTILS_LOGGING_AUTOINIT \
    static rcutils_log_location_t __rcutils_logging_location = {__func__, __FILE__, __LINE__}; \
    condition_before \
    if (severity >= g_rcutils_logging_severity_threshold) { \
      rcutils_log(&__rcutils_logging_location, severity, name, __VA_ARGS__); \
    } \
    condition_after \
  }

///@@{
/**
 * \def RCUTILS_LOG_CONDITION_EMPTY
 * An empty macro which can be used as a placeholder for `condition_before`
 * and `condition_after` which doesn't affect the logging call.
 */
#define RCUTILS_LOG_CONDITION_EMPTY
///@@}

/** @@name Macros for the `once` condition which ignores all subsequent log
 * calls except the first one.
 */
///@@{
/**
 * \def RCUTILS_LOG_CONDITION_ONCE_BEFORE
 * A macro initializing and checking the `once` condition.
 */
#define RCUTILS_LOG_CONDITION_ONCE_BEFORE \
  { \
    static int __rcutils_logging_once = 0; \
    if (RCUTILS_UNLIKELY(0 == __rcutils_logging_once)) { \
      __rcutils_logging_once = 1;
/**
 * \def RCUTILS_LOG_CONDITION_ONCE_AFTER
 * A macro finalizing the `once` condition.
 */
#define RCUTILS_LOG_CONDITION_ONCE_AFTER } \
  }
///@@}

/** @@name Macros for the `expression` condition which ignores the log calls
 * when the expression evaluates to false.
 */
///@@{
/**
 * \def RCUTILS_LOG_CONDITION_EXPRESSION_BEFORE
 * A macro checking the `expression` condition.
 */
#define RCUTILS_LOG_CONDITION_EXPRESSION_BEFORE(expression) \
  if (expression) {
/**
 * \def RCUTILS_LOG_CONDITION_EXPRESSION_AFTER
 * A macro finalizing the `expression` condition.
 */
#define RCUTILS_LOG_CONDITION_EXPRESSION_AFTER }
///@@}

/** @@name Macros for the `function` condition which ignores the log calls
 * when the function returns false.
 */
///@@{
/// The filter function signature.
/**
 * \return true to log the message, false to ignore the message
 */
typedef bool (* RclLogFilter)();
/**
 * \def RCUTILS_LOG_CONDITION_FUNCTION_BEFORE
 * A macro checking the `function` condition.
 */
#define RCUTILS_LOG_CONDITION_FUNCTION_BEFORE(function) \
  if ((*function)()) {
/**
 * \def RCUTILS_LOG_CONDITION_FUNCTION_AFTER
 * A macro finalizing the `function` condition.
 */
#define RCUTILS_LOG_CONDITION_FUNCTION_AFTER }
///@@}

/** @@name Macros for the `skipfirst` condition which ignores the first log
 * call but processes all subsequent calls.
 */
///@@{
/**
 * \def RCUTILS_LOG_CONDITION_SKIPFIRST_BEFORE
 * A macro initializing and checking the `skipfirst` condition.
 */
#define RCUTILS_LOG_CONDITION_SKIPFIRST_BEFORE \
  { \
    static bool __rcutils_logging_first = true; \
    if (RCUTILS_UNLIKELY(true == __rcutils_logging_first)) { \
      __rcutils_logging_first = false; \
    } else {
/**
 * \def RCUTILS_LOG_CONDITION_SKIPFIRST_AFTER
 * A macro finalizing the `skipfirst` condition.
 */
#define RCUTILS_LOG_CONDITION_SKIPFIRST_AFTER } \
  }
///@@}

/** @@name Macros for the `throttle` condition which ignores log calls if the
 * last logged message is not longer ago than the specified duration.
 */
///@@{
/**
 * \def RCUTILS_LOG_CONDITION_THROTTLE_BEFORE
 * A macro initializing and checking the `throttle` condition.
 */
#define RCUTILS_LOG_CONDITION_THROTTLE_BEFORE(time_source_type, duration) { \
    static rcutils_duration_value_t __rcutils_logging_duration = RCUTILS_MS_TO_NS((rcutils_duration_value_t)duration); \
    static rcutils_time_point_value_t __rcutils_logging_last_logged = 0; \
    rcutils_time_point_value_t __rcutils_logging_now = 0; \
    bool __rcutils_logging_condition = true; \
    if (rcutils_steady_time_now(&__rcutils_logging_now) != RCUTILS_RET_OK) { \
      rcutils_log( \
        &__rcutils_logging_location, RCUTILS_LOG_SEVERITY_ERROR, "", \
        "%s() at %s:%d getting current steady time failed\n", \
        __func__, __FILE__, __LINE__); \
    } else { \
      __rcutils_logging_condition = __rcutils_logging_now >= __rcutils_logging_last_logged + __rcutils_logging_duration; \
    } \
 \
    if (RCUTILS_LIKELY(__rcutils_logging_condition)) { \
      __rcutils_logging_last_logged = __rcutils_logging_now;

/**
 * \def RCUTILS_LOG_CONDITION_THROTTLE_AFTER
 * A macro finalizing the `throttle` condition.
 */
#define RCUTILS_LOG_CONDITION_THROTTLE_AFTER } \
  }
///@@}

@{
import sys
sys.path.insert(0, rcutils_module_path)
from rcutils.logging import feature_combinations
from rcutils.logging import get_macro_arguments
from rcutils.logging import get_macro_parameters
from rcutils.logging import get_suffix_from_features
from rcutils.logging import severities
}@
@[for severity in severities]@
/** @@name Logging macros for severity @(severity).
 */
///@@{
#if (RCUTILS_LOG_MIN_SEVERITY > RCUTILS_LOG_SEVERITY_@(severity))
// empty logging macros for severity @(severity) when being disabled at compile time
@[ for feature_combination in feature_combinations]@
@{suffix = get_suffix_from_features(feature_combination)}@
/// Empty logging macro due to the preprocessor definition of RCUTILS_LOG_MIN_SEVERITY.
# define RCUTILS_LOG_@(severity)@(suffix)(@(''.join([p + ', ' for p in get_macro_parameters(feature_combination).keys()]))format, ...)
@[ end for]@

#else
@[ for feature_combination in feature_combinations]@
@{suffix = get_suffix_from_features(feature_combination)}@
/**
 * \def RCUTILS_LOG_@(severity)@(suffix)
 * Log a message with severity @(severity)@
@[ if feature_combinations[feature_combination].doc_lines]@
 with the following conditions:
@[ else]@
.
@[ end if]@
@[ for doc_line in feature_combinations[feature_combination].doc_lines]@
 * @(doc_line)
@[ end for]@
@[ for param_name, doc_line in feature_combinations[feature_combination].params.items()]@
 * \param @(param_name) @(doc_line)
@[ end for]@
 * \param ... The format string, followed by the variable arguments for the format string
 */
# define RCUTILS_LOG_@(severity)@(suffix)(@(''.join([p + ', ' for p in get_macro_parameters(feature_combination).keys()]))...) \
  RCUTILS_LOG_COND_NAMED( \
    RCUTILS_LOG_SEVERITY_@(severity), \
    @(''.join([str(a) + ', ' for a in get_macro_arguments(feature_combination)]))\
    __VA_ARGS__)
@[ end for]@
#endif
///@@}

@[end for]@
#if __cplusplus
}
#endif

#endif  // RCUTILS__LOGGING_MACROS_H_


updated hostnames

updated hostnames

#!/bin/bash

# DO NOT REMOVE THIS BLOCK UNLESS YOU DON'T WANT TO USE CUSTOM SCRIPTS
@[if DEVELSPACE]@
export ROSWSS_SCRIPTS="@(PROJECT_SOURCE_DIR)/scripts:$ROSWSS_SCRIPTS"
@[else]@
export ROSWSS_SCRIPTS="@(CMAKE_INSTALL_PREFIX)/@(CATKIN_PACKAGE_SHARE_DESTINATION)/scripts:$ROSWSS_SCRIPTS"
@[end if]@

# SET HERE YOUR WORKSPACE PREFIX
export ROSWSS_PREFIX="thor"
export ROSWSS_ROOT_RELATIVE_PATH="../.."

# SETUP YOUR ENVIRONMENT HERE
export ONBOARD_LAUNCH_PKG="thor_mang_onboard_launch"
export GAZEBO_LAUNCH_PKG="thor_mang_gazebo"
export GAZEBO_LAUNCH_FILE="start_all.launch"
export GAZEBO_LAUNCH_W_ONBOARD_FILE="start_onboard_all.launch"
export GAZEBO_WORLDS_PKG="thor_mang_gazebo"
export AUTOSTART_LAUNCH_PKG="thor_mang_robot_bringup"
export ROBOT_MASTER_HOSTNANE="motion"
export ROBOT_HOSTNAMES="motion perception onboard"
export ROBOT_USER="thor"

# THOR SPECIFIC EXPORTS
export GAZEBO_MODEL_PATH=$WS_ROOT/src/thor/thor_mang_simulation/thor_mang_gazebo/models
export THOR_MOTION_HOSTNAME="motion"
export THOR_PERCEPTION_HOSTNAME="perception"
export THOR_ONBOARD_HOSTNAME="perception"

# THOR PCs/LAUNCHES
add_remote_pc "motion" "motion" "motion" "roslaunch thor_mang_onboard_launch motion.launch"
add_remote_pc "perception" "perception" "perception" "export ROS_MASTER_URI=http://thor-motion:11311; export ROS_IP=192.168.1.11; roslaunch thor_mang_onboard_launch perception.launch"
add_remote_pc "onboard" "motion" "onboard" "export ROS_MASTER_URI=http://thor-motion:11311; export ROS_IP=192.168.1.11; roslaunch thor_mang_onboard_launch onboard.launch"

# Custom completion scripts
add_completion "ui" "_ui_complete"

#!/bin/bash

# DO NOT REMOVE THIS BLOCK UNLESS YOU DON'T WANT TO USE CUSTOM SCRIPTS
@[if DEVELSPACE]@
export ROSWSS_SCRIPTS="@(PROJECT_SOURCE_DIR)/scripts:$ROSWSS_SCRIPTS"
@[else]@
export ROSWSS_SCRIPTS="@(CMAKE_INSTALL_PREFIX)/@(CATKIN_PACKAGE_SHARE_DESTINATION)/scripts:$ROSWSS_SCRIPTS"
@[end if]@

# SET HERE YOUR WORKSPACE PREFIX
export ROSWSS_PREFIX="thor"
export ROSWSS_ROOT_RELATIVE_PATH="../.."

# SETUP YOUR ENVIRONMENT HERE
export ONBOARD_LAUNCH_PKG="thor_mang_onboard_launch"
export GAZEBO_LAUNCH_PKG="thor_mang_gazebo"
export GAZEBO_LAUNCH_FILE="start_all.launch"
export GAZEBO_LAUNCH_W_ONBOARD_FILE="start_onboard_all.launch"
export GAZEBO_WORLDS_PKG="thor_mang_gazebo"
export AUTOSTART_LAUNCH_PKG="thor_mang_robot_bringup"
export ROBOT_MASTER_HOSTNANE="thor-motion"
export ROBOT_HOSTNAMES="thor-motion thor-perception thor-onboard"
export ROBOT_USER="thor"

# THOR SPECIFIC EXPORTS
export GAZEBO_MODEL_PATH=$WS_ROOT/src/thor/thor_mang_simulation/thor_mang_gazebo/models
export THOR_MOTION_HOSTNAME="motion"
export THOR_PERCEPTION_HOSTNAME="perception"
export THOR_ONBOARD_HOSTNAME="perception"

# THOR PCs/LAUNCHES
add_remote_pc "motion" "motion" "motion" "roslaunch thor_mang_onboard_launch motion.launch"
add_remote_pc "perception" "perception" "perception" "export ROS_MASTER_URI=http://thor-motion:11311; export ROS_IP=192.168.1.11; roslaunch thor_mang_onboard_launch perception.launch"
add_remote_pc "onboard" "motion" "onboard" "export ROS_MASTER_URI=http://thor-motion:11311; export ROS_IP=192.168.1.11; roslaunch thor_mang_onboard_launch onboard.launch"

# Custom completion scripts
add_completion "ui" "_ui_complete"


Refactor defaultAvatar so that there is only one copy of the call to DefaultGraphics so that using its callback is simpler.

/*  Sirikata
 *  default.em
 *
 *  Copyright (c) 2011, Ewen Cheslack-Postava
 *  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 Sirikata 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.
 */

// A sane, simple, default. Only includes functionality from libraries.
system.require('std/shim/restore/simpleStorage.em');

std.simpleStorage.setScript(
    function()
    {
        system.require('std/shim/restore/persistService.em');
        system.require('std/script/scriptable.em');
        system.require('std/movement/movable.em');
        system.require('std/graphics/default.em');

        scriptable = new std.script.Scriptable();
        movable = new std.movement.Movable(true); // Self only

        var init = function() {
            simulator = new std.graphics.DefaultGraphics(system.self, 'ogregraphics');
        };

        if (system.self == system)
        {
            //if do not have a connected presence
            system.onPresenceConnected(
                function(pres) {
                    init();
                    system.onPresenceConnected(function(){});
                }
            );
        }
        else
        {
            //already have a connected presence, use it.
            init();
        }

    }, false);

/*  Sirikata
 *  default.em
 *
 *  Copyright (c) 2011, Ewen Cheslack-Postava
 *  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 Sirikata 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.
 */

// A sane, simple, default. Only includes functionality from libraries.
system.require('std/shim/restore/simpleStorage.em');

std.simpleStorage.setScript(
    function()
    {
        system.require('std/shim/restore/persistService.em');
        system.require('std/script/scriptable.em');
        system.require('std/movement/movable.em');
        system.require('std/graphics/default.em');

        scriptable = new std.script.Scriptable();
        movable = new std.movement.Movable(true); // Self only

        if (system.self == system)
        {
            //if do not have a connected presence
            system.onPresenceConnected(
                function(pres) {
                    simulator = new std.graphics.DefaultGraphics(pres, 'ogregraphics');
                    system.onPresenceConnected(function(){});
                }
            );
        }
        else
        {
            //already have a connected presence, use it.
            simulator = new std.graphics.DefaultGraphics(system.self, 'ogregraphics');
        }

    }, false);


Fixed key modifiers on freeRotate.

Fixed key modifiers on freeRotate.

/*  Sirikata
 *  default.em
 *
 *  Copyright (c) 2011, Ewen Cheslack-Postava
 *  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 Sirikata 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.
 */

system.require('graphics.em');
system.require('std/movement/pursue.em');
system.require('std/script/scripter.em');
system.require('inputbinding.em');
system.require('drag/move.em');
system.require('drag/rotate.em');
system.require('drag/scale.em');
system.require('std/graphics/chat.em');
system.require('std/graphics/physics.em');
system.require('std/graphics/propertybox.em');
system.require('std/graphics/presenceList.em');
system.require('std/graphics/setMesh.em');

(
function() {

    var ns = std.graphics;

    /** @namespace
     *  The DefaultGraphics class just contains some sane defaults for
     *  interaction, allowing you to get a decent, baseline client
     *  that only requires built-in functionality. You still define
     *  the presence and which underlying graphics system to use, but
     *  this class takes care of defining all other UI and interaction.
     */
    std.graphics.DefaultGraphics = function(pres, name, cb) {
        this._pres = pres;
        this._simulator = new std.graphics.Graphics(pres, name, std.core.bind(this.finishedGraphicsInit, this, cb), true);
    };
    std.graphics.DefaultGraphics.prototype.finishedGraphicsInit = function(cb, gfx) {
        // assert(gfx == this._simulator);
        this._cameraMode = 'first';

        this._selected = null;
        this._loadingUIs = 0;

        var ui_finish_cb = std.core.bind(this.finishedUIInit, this, cb);
        this._loadingUIs++; this._scripter = new std.script.Scripter(this, ui_finish_cb);
        this._loadingUIs++; this._chat = new std.graphics.Chat(this._pres, this._simulator, ui_finish_cb);
        this._loadingUIs++; this._physics = new std.graphics.PhysicsProperties(this._simulator, ui_finish_cb);
        this._loadingUIs++; this._propertybox = new std.propertybox.PropertyBox(this, ui_finish_cb);
        this._loadingUIs++; this._presenceList = new std.graphics.PresenceList(this._pres, this._simulator, this._scripter, ui_finish_cb);
        this._loadingUIs++; this._setMesh = new std.graphics.SetMesh(this._simulator, ui_finish_cb);
    };
    std.graphics.DefaultGraphics.prototype.finishedUIInit = function(cb) {
        this._loadingUIs--;
        if (this._loadingUIs > 0) return;

        this._simulator.hideLoadScreen();

        this._moverot = new std.movement.MoveAndRotate(this._pres, std.core.bind(this.updateCameraOffset, this), 'rotation');

        this._draggers = {
            move: new std.graphics.MoveDragHandler(this._simulator),
            rotate: new std.graphics.RotateDragHandler(this._simulator),
            scale: new std.graphics.ScaleDragHandler(this._simulator)
        };

        this._binding = new std.graphics.InputBinding();
        this._simulator.inputHandler.onAnything = std.core.bind(this._binding.dispatch, this._binding);

        this._binding.addAction('quit', std.core.bind(this._simulator.quit, this._simulator));
        this._binding.addAction('screenshot', std.core.bind(this._simulator.screenshot, this._simulator));
        this._binding.addAction('toggleSuspend', std.core.bind(this._simulator.toggleSuspend, this._simulator));
        this._binding.addAction('scriptSelectedObject', std.core.bind(this.scriptSelectedObject, this));
        this._binding.addAction('scriptSelf', std.core.bind(this.scriptSelf, this));
        this._binding.addAction('togglePropertyBox', std.core.bind(this.togglePropertyBox, this));

        this._binding.addAction('toggleChat', std.core.bind(this.toggleChat, this));

        this._binding.addAction('reorientSelf', std.core.bind(this.reorientSelf, this));

        this._binding.addAction('togglePhysicsProperties', std.core.bind(this._physics.toggle, this._physics));
        this._binding.addAction('togglePresenceList', std.core.bind(this._presenceList.toggle, this._presenceList));
        this._binding.addAction('toggleSetMesh', std.core.bind(this._setMesh.toggle, this._setMesh));

        this._binding.addAction('toggleCameraMode', std.core.bind(this.toggleCameraMode, this));

        this._binding.addAction('actOnObject', std.core.bind(this.actOnObject, this));

        this._binding.addToggleAction('moveForward', std.core.bind(this.moveSelf, this, new util.Vec3(0, 0, -1)), 1, -1);
        this._binding.addToggleAction('moveBackward', std.core.bind(this.moveSelf, this, new util.Vec3(0, 0, 1)), 1, -1);
        this._binding.addToggleAction('moveLeft', std.core.bind(this.moveSelf, this, new util.Vec3(-1, 0, 0)), 1, -1);
        this._binding.addToggleAction('moveRight', std.core.bind(this.moveSelf, this, new util.Vec3(1, 0, 0)), 1, -1);
        this._binding.addToggleAction('moveUp', std.core.bind(this.moveSelf, this, new util.Vec3(0, 1, 0)), 1, -1);
        this._binding.addToggleAction('moveDown', std.core.bind(this.moveSelf, this, new util.Vec3(0, -1, 0)), 1, -1);

        this._binding.addToggleAction('rotateUp', std.core.bind(this.rotateSelf, this, new util.Vec3(1, 0, 0)), 1, -1);
        this._binding.addToggleAction('rotateDown', std.core.bind(this.rotateSelf, this, new util.Vec3(-1, 0, 0)), 1, -1);
        this._binding.addToggleAction('rotateLeft', std.core.bind(this.rotateSelf, this, new util.Vec3(0, 1, 0)), 1, -1);
        this._binding.addToggleAction('rotateRight', std.core.bind(this.rotateSelf, this, new util.Vec3(0, -1, 0)), 1, -1);

        this._binding.addFloat2Action('pickObject', std.core.bind(this.pickObject, this));

        this._binding.addAction('updatePhysicsProperties', std.core.bind(this.updatePhysicsProperties, this));

        this._binding.addAction('startMoveDrag', std.core.bind(this.startDrag, this, this._draggers.move));
        this._binding.addAction('startRotateDrag', std.core.bind(this.startDrag, this, this._draggers.rotate));
        this._binding.addAction('startScaleDrag', std.core.bind(this.startDrag, this, this._draggers.scale));
        this._binding.addAction('forwardMousePressToDragger', std.core.bind(this.forwardMousePressToDragger, this));
        this._binding.addAction('forwardMouseDragToDragger', std.core.bind(this.forwardMouseDragToDragger, this));
        this._binding.addAction('updatePropertyBox', std.core.bind(this.updatePropertyBox, this));
        this._binding.addAction('forwardMouseReleaseToDragger', std.core.bind(this.forwardMouseReleaseToDragger, this));
        this._binding.addAction('stopDrag', std.core.bind(this.stopDrag, this));

        this._binding.addAction('startFreeRotate', std.core.bind(this.startFreeRotate, this));
        this._binding.addAction('freeRotateDrag', std.core.bind(this.freeRotateDrag, this));
        this._binding.addAction('freeRotateRelease', std.core.bind(this.freeRotateRelease, this));

        /** Bindings are an *ordered* list of keys and actions. Keys
         *  are a combination of the type of event, the primary key
         *  for the event (key or mouse button), and modifiers.
         *  Modifiers are tricky to handle. You can specify a string
         *  indicating which to filter on. If you omit the string, it
         *  is equivalent to 'none'. The special values '*' and 'any'
         *  are equivalent and will match any modifier, i.e. the event
         *  will always be triggered. There isn't support
         *  for matching combinations of modifiers.
         */
        var bindings = [
            { key: ['button-pressed', 'escape'], action: 'quit' },
            { key: ['button-pressed', 'i'], action: 'screenshot' },
            { key: ['button-pressed', 'm'], action: 'toggleSuspend' },
            { key: ['button-pressed', 's', 'alt' ], action: 'scriptSelectedObject' },
            { key: ['button-pressed', 's', 'ctrl' ], action: 'scriptSelf' },

            { key: ['button-pressed', 'c', 'ctrl' ], action: 'toggleChat' },
            { key: ['button-pressed', 'p', 'ctrl' ], action: 'togglePhysicsProperties' },
            { key: ['button-pressed', 'p', 'alt' ], action: 'togglePropertyBox' },
            { key: ['button-pressed', 'l', 'ctrl' ], action: 'togglePresenceList' },
            { key: ['button-pressed', 'j', 'ctrl' ], action: 'toggleSetMesh' },

            { key: ['button-pressed', 't'], action: 'reorientSelf' },

            { key: ['mouse-click', 2], action: 'pickObject' },
            { key: ['mouse-click', 2], action: 'scriptSelectedObject' },
            { key: ['button-pressed', 'return'], action: 'actOnObject' },

            { key: ['button-pressed', 'c' ], action: 'toggleCameraMode' },

            { key: ['button', 'w' ], action: 'moveForward' },
            { key: ['button', 'up' ], action: 'moveForward' },
            { key: ['button', 's' ], action: 'moveBackward' },
            { key: ['button', 'down' ], action: 'moveBackward' },
            { key: ['button', 'a' ], action: 'moveLeft' },
            { key: ['button', 'd' ], action: 'moveRight' },
            { key: ['button', 'q' ], action: 'moveUp' },
            { key: ['button', 'z' ], action: 'moveDown' },

            { key: ['button', 'up', 'shift' ], action: 'rotateUp' },
            { key: ['button', 'down', 'shift' ], action: 'rotateDown' },
            { key: ['button', 'left' ], action: 'rotateLeft' },
            { key: ['button', 'right' ], action: 'rotateRight' },

            { key: ['mouse-press', 1 ], action: 'pickObject' },

            { key: ['mouse-press', 1 ], action: 'updatePhysicsProperties' },

            // Note that the ordering of registration here is critical.
            { key: ['mouse-press', 1, 'none' ], action: 'startMoveDrag' },
            { key: ['mouse-press', 1, 'ctrl' ], action: 'startRotateDrag' },
            { key: ['mouse-press', 1, 'alt' ], action: 'startScaleDrag' },
            { key: ['mouse-press', 1, '*'], action: 'forwardMousePressToDragger' },
            { key: ['mouse-press', 1, '*'], action: 'updatePropertyBox' },
            { key: ['mouse-drag', 1, '*'], action: 'forwardMouseDragToDragger' },
            { key: ['mouse-release', 1, '*'], action: 'forwardMouseReleaseToDragger' },
            { key: ['mouse-release', 1, '*'], action: 'stopDrag' },
            { key: ['mouse-press', 3, 'none' ], action: 'startFreeRotate' },
            { key: ['mouse-drag', 3, 'none'], action: 'freeRotateDrag' },
            { key: ['mouse-release', 3, 'none'], action: 'freeRotateRelease' }
        ];

        this._binding.addBindings(bindings);

        if (cb && typeof(cb) === "function")
            cb(this);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.simulator = function() {
        return this._simulator;
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.invoke = function() {
        // Just forward manual invoke commands directly
        return this._simulator.invoke.apply(this._simulator, arguments);
    };

    /** Request that the given URL be added as a module in the UI. */
    std.graphics.DefaultGraphics.prototype.addGUIModule = function(name, url, cb) {
        return this._simulator.addGUIModule(name, url, cb);
    };

    /** Request that the given script text be added as a module in the UI. */
    std.graphics.DefaultGraphics.prototype.addGUITextModule = function(name, js_text, cb) {
        return this._simulator.addGUITextModule(name, js_text, cb);
    };

    //by default how to scale translational velocity from keypresses.  (movement
    //is agonizingly slow if just set this to 1.  I really recommend 5.)
    /** @public */
    std.graphics.DefaultGraphics.prototype.defaultVelocityScaling = 5;
    //by default how to scale rotational velocity from keypresses
    /** @public */
    std.graphics.DefaultGraphics.prototype.defaultRotationalVelocityScaling = .5;

    /** @function */
    std.graphics.DefaultGraphics.prototype.toggleChat = function() {
        this._chat.toggle();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.scriptSelf = function() {
        this._scripter.script(system.self);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.togglePropertyBox = function() {
        this._propertybox.TogglePropertyBox();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.scriptSelectedObject = function() {
        if (this._selected == null)
            return;
        this._presenceList.addObject(this._selected.toString(), 'Scripted');
        this._scripter.script(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.toggleCameraMode = function(evt) {
        this._cameraMode = this._cameraMode == 'first' ? 'third' : 'first';
        this._simulator.setCameraMode(this._cameraMode);
        this.updateCameraOffset();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.updateCameraOffset = function(evt) {
        if (this._cameraMode == 'third') {
            var orient = this._pres.getOrientation();
            this._simulator.setCameraOffset(orient.mul(<0, 1.5, 4>));
        }
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.moveSelf = function(dir, val) {
        this._moverot.move(dir, this.defaultVelocityScaling * val);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.rotateSelf = function(about, val) {
        this._moverot.rotate(about, this.defaultRotationalVelocityScaling * val);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.pickObject = function(x, y) {
        if (this._selected) {
            this._simulator.bbox(this._selected, false);
            this._selected = null;
        }

        var clicked = this._simulator.pick(x, y);
        if (clicked) {
            this._selected = clicked;
            this._simulator.bbox(this._selected, true);
        }
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.actOnObject = function(evt) {
        if (this._selected)
            { 'action' : 'touch' } >> this._selected >> [];
    }

    /** @function */
    std.graphics.DefaultGraphics.prototype.updatePhysicsProperties = function() {
        // Update even if not selected so display can be disabled
        this._physics.update(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.startDrag = function(dragger, evt) {
        if (this._selected)
            this._dragger = dragger;
        if (this._dragger)
            this._dragger.selected(this._selected, this._simulator.pickedPosition(), evt);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.forwardMousePressToDragger = function(evt) {
        if (this._dragger) this._dragger.onMousePress(evt);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.forwardMouseDragToDragger = function(evt) {
        if (this._dragger) this._dragger.onMouseDrag(evt);
        this._propertybox.HandleUpdateProperties(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.updatePropertyBox = function(evt) {
        this._propertybox.HandleUpdateProperties(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.forwardMouseReleaseToDragger = function(evt) {
        if (this._dragger) this._dragger.onMouseRelease(evt);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.stopDrag = function() {
        delete this._dragger;
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.startFreeRotate = function(evt) {
        this.startX = evt.x;
        this.startY = evt.y;
        this.startOrientation = this._pres.getOrientation();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.freeRotateDrag = function(evt) {
        if (this.startX == null || this.startY == null)
            return;

        var SCALE = 1;
        var dx = evt.x - this.startX;
        var dy = evt.y - this.startY;
        var dXAngle = dx * SCALE;
        var dYAngle = dy * SCALE;
        var newQuat = this.startOrientation
            .mul(new util.Quaternion(<0, 1, 0>, -dXAngle))
            .mul(new util.Quaternion(<1, 0, 0>, dYAngle));
        this._pres.setOrientation(newQuat);
        this.updateCameraOffset();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.freeRotateRelease = function(evt) {
        this.startX = null;
        this.startY = null;
        this.startOrientation = null;
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.reorientSelf = function(evt) {
        this._pres.setOrientation(util.Quaternion.fromLookAt(
            this._pres.getOrientation().zAxis().scale(-1), <0, 1, 0>));
        this.updateCameraOffset();
    }

})();

/*  Sirikata
 *  default.em
 *
 *  Copyright (c) 2011, Ewen Cheslack-Postava
 *  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 Sirikata 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.
 */

system.require('graphics.em');
system.require('std/movement/pursue.em');
system.require('std/script/scripter.em');
system.require('inputbinding.em');
system.require('drag/move.em');
system.require('drag/rotate.em');
system.require('drag/scale.em');
system.require('std/graphics/chat.em');
system.require('std/graphics/physics.em');
system.require('std/graphics/propertybox.em');
system.require('std/graphics/presenceList.em');
system.require('std/graphics/setMesh.em');

(
function() {

    var ns = std.graphics;

    /** @namespace
     *  The DefaultGraphics class just contains some sane defaults for
     *  interaction, allowing you to get a decent, baseline client
     *  that only requires built-in functionality. You still define
     *  the presence and which underlying graphics system to use, but
     *  this class takes care of defining all other UI and interaction.
     */
    std.graphics.DefaultGraphics = function(pres, name, cb) {
        this._pres = pres;
        this._simulator = new std.graphics.Graphics(pres, name, std.core.bind(this.finishedGraphicsInit, this, cb), true);
    };
    std.graphics.DefaultGraphics.prototype.finishedGraphicsInit = function(cb, gfx) {
        // assert(gfx == this._simulator);
        this._cameraMode = 'first';

        this._selected = null;
        this._loadingUIs = 0;

        var ui_finish_cb = std.core.bind(this.finishedUIInit, this, cb);
        this._loadingUIs++; this._scripter = new std.script.Scripter(this, ui_finish_cb);
        this._loadingUIs++; this._chat = new std.graphics.Chat(this._pres, this._simulator, ui_finish_cb);
        this._loadingUIs++; this._physics = new std.graphics.PhysicsProperties(this._simulator, ui_finish_cb);
        this._loadingUIs++; this._propertybox = new std.propertybox.PropertyBox(this, ui_finish_cb);
        this._loadingUIs++; this._presenceList = new std.graphics.PresenceList(this._pres, this._simulator, this._scripter, ui_finish_cb);
        this._loadingUIs++; this._setMesh = new std.graphics.SetMesh(this._simulator, ui_finish_cb);
    };
    std.graphics.DefaultGraphics.prototype.finishedUIInit = function(cb) {
        this._loadingUIs--;
        if (this._loadingUIs > 0) return;

        this._simulator.hideLoadScreen();

        this._moverot = new std.movement.MoveAndRotate(this._pres, std.core.bind(this.updateCameraOffset, this), 'rotation');

        this._draggers = {
            move: new std.graphics.MoveDragHandler(this._simulator),
            rotate: new std.graphics.RotateDragHandler(this._simulator),
            scale: new std.graphics.ScaleDragHandler(this._simulator)
        };

        this._binding = new std.graphics.InputBinding();
        this._simulator.inputHandler.onAnything = std.core.bind(this._binding.dispatch, this._binding);

        this._binding.addAction('quit', std.core.bind(this._simulator.quit, this._simulator));
        this._binding.addAction('screenshot', std.core.bind(this._simulator.screenshot, this._simulator));
        this._binding.addAction('toggleSuspend', std.core.bind(this._simulator.toggleSuspend, this._simulator));
        this._binding.addAction('scriptSelectedObject', std.core.bind(this.scriptSelectedObject, this));
        this._binding.addAction('scriptSelf', std.core.bind(this.scriptSelf, this));
        this._binding.addAction('togglePropertyBox', std.core.bind(this.togglePropertyBox, this));

        this._binding.addAction('toggleChat', std.core.bind(this.toggleChat, this));

        this._binding.addAction('reorientSelf', std.core.bind(this.reorientSelf, this));

        this._binding.addAction('togglePhysicsProperties', std.core.bind(this._physics.toggle, this._physics));
        this._binding.addAction('togglePresenceList', std.core.bind(this._presenceList.toggle, this._presenceList));
        this._binding.addAction('toggleSetMesh', std.core.bind(this._setMesh.toggle, this._setMesh));

        this._binding.addAction('toggleCameraMode', std.core.bind(this.toggleCameraMode, this));

        this._binding.addAction('actOnObject', std.core.bind(this.actOnObject, this));

        this._binding.addToggleAction('moveForward', std.core.bind(this.moveSelf, this, new util.Vec3(0, 0, -1)), 1, -1);
        this._binding.addToggleAction('moveBackward', std.core.bind(this.moveSelf, this, new util.Vec3(0, 0, 1)), 1, -1);
        this._binding.addToggleAction('moveLeft', std.core.bind(this.moveSelf, this, new util.Vec3(-1, 0, 0)), 1, -1);
        this._binding.addToggleAction('moveRight', std.core.bind(this.moveSelf, this, new util.Vec3(1, 0, 0)), 1, -1);
        this._binding.addToggleAction('moveUp', std.core.bind(this.moveSelf, this, new util.Vec3(0, 1, 0)), 1, -1);
        this._binding.addToggleAction('moveDown', std.core.bind(this.moveSelf, this, new util.Vec3(0, -1, 0)), 1, -1);

        this._binding.addToggleAction('rotateUp', std.core.bind(this.rotateSelf, this, new util.Vec3(1, 0, 0)), 1, -1);
        this._binding.addToggleAction('rotateDown', std.core.bind(this.rotateSelf, this, new util.Vec3(-1, 0, 0)), 1, -1);
        this._binding.addToggleAction('rotateLeft', std.core.bind(this.rotateSelf, this, new util.Vec3(0, 1, 0)), 1, -1);
        this._binding.addToggleAction('rotateRight', std.core.bind(this.rotateSelf, this, new util.Vec3(0, -1, 0)), 1, -1);

        this._binding.addFloat2Action('pickObject', std.core.bind(this.pickObject, this));

        this._binding.addAction('updatePhysicsProperties', std.core.bind(this.updatePhysicsProperties, this));

        this._binding.addAction('startMoveDrag', std.core.bind(this.startDrag, this, this._draggers.move));
        this._binding.addAction('startRotateDrag', std.core.bind(this.startDrag, this, this._draggers.rotate));
        this._binding.addAction('startScaleDrag', std.core.bind(this.startDrag, this, this._draggers.scale));
        this._binding.addAction('forwardMousePressToDragger', std.core.bind(this.forwardMousePressToDragger, this));
        this._binding.addAction('forwardMouseDragToDragger', std.core.bind(this.forwardMouseDragToDragger, this));
        this._binding.addAction('updatePropertyBox', std.core.bind(this.updatePropertyBox, this));
        this._binding.addAction('forwardMouseReleaseToDragger', std.core.bind(this.forwardMouseReleaseToDragger, this));
        this._binding.addAction('stopDrag', std.core.bind(this.stopDrag, this));

        this._binding.addAction('startFreeRotate', std.core.bind(this.startFreeRotate, this));
        this._binding.addAction('freeRotateDrag', std.core.bind(this.freeRotateDrag, this));
        this._binding.addAction('freeRotateRelease', std.core.bind(this.freeRotateRelease, this));

        /** Bindings are an *ordered* list of keys and actions. Keys
         *  are a combination of the type of event, the primary key
         *  for the event (key or mouse button), and modifiers.
         *  Modifiers are tricky to handle. You can specify a string
         *  indicating which to filter on. If you omit the string, it
         *  is equivalent to 'none'. The special values '*' and 'any'
         *  are equivalent and will match any modifier, i.e. the event
         *  will always be triggered. There isn't support
         *  for matching combinations of modifiers.
         */
        var bindings = [
            { key: ['button-pressed', 'escape'], action: 'quit' },
            { key: ['button-pressed', 'i'], action: 'screenshot' },
            { key: ['button-pressed', 'm'], action: 'toggleSuspend' },
            { key: ['button-pressed', 's', 'alt' ], action: 'scriptSelectedObject' },
            { key: ['button-pressed', 's', 'ctrl' ], action: 'scriptSelf' },

            { key: ['button-pressed', 'c', 'ctrl' ], action: 'toggleChat' },
            { key: ['button-pressed', 'p', 'ctrl' ], action: 'togglePhysicsProperties' },
            { key: ['button-pressed', 'p', 'alt' ], action: 'togglePropertyBox' },
            { key: ['button-pressed', 'l', 'ctrl' ], action: 'togglePresenceList' },
            { key: ['button-pressed', 'j', 'ctrl' ], action: 'toggleSetMesh' },

            { key: ['button-pressed', 't'], action: 'reorientSelf' },

            { key: ['mouse-click', 2], action: 'pickObject' },
            { key: ['mouse-click', 2], action: 'scriptSelectedObject' },
            { key: ['button-pressed', 'return'], action: 'actOnObject' },

            { key: ['button-pressed', 'c' ], action: 'toggleCameraMode' },

            { key: ['button', 'w' ], action: 'moveForward' },
            { key: ['button', 'up' ], action: 'moveForward' },
            { key: ['button', 's' ], action: 'moveBackward' },
            { key: ['button', 'down' ], action: 'moveBackward' },
            { key: ['button', 'a' ], action: 'moveLeft' },
            { key: ['button', 'd' ], action: 'moveRight' },
            { key: ['button', 'q' ], action: 'moveUp' },
            { key: ['button', 'z' ], action: 'moveDown' },

            { key: ['button', 'up', 'shift' ], action: 'rotateUp' },
            { key: ['button', 'down', 'shift' ], action: 'rotateDown' },
            { key: ['button', 'left' ], action: 'rotateLeft' },
            { key: ['button', 'right' ], action: 'rotateRight' },

            { key: ['mouse-press', 1 ], action: 'pickObject' },

            { key: ['mouse-press', 1 ], action: 'updatePhysicsProperties' },

            // Note that the ordering of registration here is critical.
            { key: ['mouse-press', 1, 'none' ], action: 'startMoveDrag' },
            { key: ['mouse-press', 1, 'ctrl' ], action: 'startRotateDrag' },
            { key: ['mouse-press', 1, 'alt' ], action: 'startScaleDrag' },
            { key: ['mouse-press', 1, '*'], action: 'forwardMousePressToDragger' },
            { key: ['mouse-press', 1, '*'], action: 'updatePropertyBox' },
            { key: ['mouse-drag', 1, '*'], action: 'forwardMouseDragToDragger' },
            { key: ['mouse-release', 1, '*'], action: 'forwardMouseReleaseToDragger' },
            { key: ['mouse-release', 1, '*'], action: 'stopDrag' },
            { key: ['mouse-press', 3, 'none' ], action: 'startFreeRotate' },
            { key: ['mouse-drag', 3, '*'], action: 'freeRotateDrag' },
            { key: ['mouse-release', 3, '*'], action: 'freeRotateRelease' }
        ];

        this._binding.addBindings(bindings);

        if (cb && typeof(cb) === "function")
            cb(this);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.simulator = function() {
        return this._simulator;
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.invoke = function() {
        // Just forward manual invoke commands directly
        return this._simulator.invoke.apply(this._simulator, arguments);
    };

    /** Request that the given URL be added as a module in the UI. */
    std.graphics.DefaultGraphics.prototype.addGUIModule = function(name, url, cb) {
        return this._simulator.addGUIModule(name, url, cb);
    };

    /** Request that the given script text be added as a module in the UI. */
    std.graphics.DefaultGraphics.prototype.addGUITextModule = function(name, js_text, cb) {
        return this._simulator.addGUITextModule(name, js_text, cb);
    };

    //by default how to scale translational velocity from keypresses.  (movement
    //is agonizingly slow if just set this to 1.  I really recommend 5.)
    /** @public */
    std.graphics.DefaultGraphics.prototype.defaultVelocityScaling = 5;
    //by default how to scale rotational velocity from keypresses
    /** @public */
    std.graphics.DefaultGraphics.prototype.defaultRotationalVelocityScaling = .5;

    /** @function */
    std.graphics.DefaultGraphics.prototype.toggleChat = function() {
        this._chat.toggle();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.scriptSelf = function() {
        this._scripter.script(system.self);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.togglePropertyBox = function() {
        this._propertybox.TogglePropertyBox();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.scriptSelectedObject = function() {
        if (this._selected == null)
            return;
        this._presenceList.addObject(this._selected.toString(), 'Scripted');
        this._scripter.script(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.toggleCameraMode = function(evt) {
        this._cameraMode = this._cameraMode == 'first' ? 'third' : 'first';
        this._simulator.setCameraMode(this._cameraMode);
        this.updateCameraOffset();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.updateCameraOffset = function(evt) {
        if (this._cameraMode == 'third') {
            var orient = this._pres.getOrientation();
            this._simulator.setCameraOffset(orient.mul(<0, 1.5, 4>));
        }
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.moveSelf = function(dir, val) {
        this._moverot.move(dir, this.defaultVelocityScaling * val);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.rotateSelf = function(about, val) {
        this._moverot.rotate(about, this.defaultRotationalVelocityScaling * val);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.pickObject = function(x, y) {
        if (this._selected) {
            this._simulator.bbox(this._selected, false);
            this._selected = null;
        }

        var clicked = this._simulator.pick(x, y);
        if (clicked) {
            this._selected = clicked;
            this._simulator.bbox(this._selected, true);
        }
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.actOnObject = function(evt) {
        if (this._selected)
            { 'action' : 'touch' } >> this._selected >> [];
    }

    /** @function */
    std.graphics.DefaultGraphics.prototype.updatePhysicsProperties = function() {
        // Update even if not selected so display can be disabled
        this._physics.update(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.startDrag = function(dragger, evt) {
        if (this._selected)
            this._dragger = dragger;
        if (this._dragger)
            this._dragger.selected(this._selected, this._simulator.pickedPosition(), evt);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.forwardMousePressToDragger = function(evt) {
        if (this._dragger) this._dragger.onMousePress(evt);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.forwardMouseDragToDragger = function(evt) {
        if (this._dragger) this._dragger.onMouseDrag(evt);
        this._propertybox.HandleUpdateProperties(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.updatePropertyBox = function(evt) {
        this._propertybox.HandleUpdateProperties(this._selected);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.forwardMouseReleaseToDragger = function(evt) {
        if (this._dragger) this._dragger.onMouseRelease(evt);
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.stopDrag = function() {
        delete this._dragger;
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.startFreeRotate = function(evt) {
        this.startX = evt.x;
        this.startY = evt.y;
        this.startOrientation = this._pres.getOrientation();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.freeRotateDrag = function(evt) {
        var SCALE = 1;
        var dx = evt.x - this.startX;
        var dy = evt.y - this.startY;
        var dXAngle = dx * SCALE;
        var dYAngle = dy * SCALE;
        var newQuat = this.startOrientation
            .mul(new util.Quaternion(<0, 1, 0>, -dXAngle))
            .mul(new util.Quaternion(<1, 0, 0>, dYAngle));
        this._pres.setOrientation(newQuat);
        this.updateCameraOffset();
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.freeRotateRelease = function(evt) {
        this.startX = null;
        this.startY = null;
        this.startOrientation = null;
    };

    /** @function */
    std.graphics.DefaultGraphics.prototype.reorientSelf = function(evt) {
        this._pres.setOrientation(util.Quaternion.fromLookAt(
            this._pres.getOrientation().zAxis().scale(-1), <0, 1, 0>));
        this.updateCameraOffset();
    }

})();


Reintegrate with ros/rosdistro repo Context https://github.com/ros2/rosdistro/issues/492

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
))@
@(TEMPLATE(
    'snippet/from_base_image.Dockerfile.em',
    template_packages=template_packages,
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
    base_image=base_image,
    maintainer_name=maintainer_name,
))@
@(TEMPLATE(
    'snippet/setup_tzdata.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
))@
@{
template_dependencies = [
    'dirmngr',
    'gnupg2',
    'lsb-release',
]
# add 'python3-pip' to 'template_dependencies' if pip dependencies are declared
if 'pip3_install' in locals():
    if isinstance(pip3_install, list) and pip3_install != []:
        template_dependencies.append('python3-pip')
}@
@(TEMPLATE(
    'snippet/install_upstream_package_list.Dockerfile.em',
    packages=template_dependencies,
    upstream_packages=upstream_packages if 'upstream_packages' in locals() else [],
))@
@
# setup ros2 keys
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 421C365BD9FF1F717815A3895523BAEEB01FA116

# setup sources.list
RUN echo "deb http://packages.ros.org/ros2/ubuntu `lsb_release -sc` main" > /etc/apt/sources.list.d/ros2-latest.list

# install bootstrap tools
RUN apt-get update && apt-get install --no-install-recommends -y \
    python3-rosdep \
    python3-rosinstall \
    python3-vcstools \
    && rm -rf /var/lib/apt/lists/*

# setup environment
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8

# bootstrap rosdep
RUN rosdep init \
    && rosdep update

@[if 'pip3_install' in locals()]@
@[  if pip3_install]@
# install python packages
RUN pip3 install -U \
    @(' \\\n    '.join(pip3_install))@

@[  end if]@
@[end if]@

# install ros2 packages
ENV ROS_DISTRO @ros2distro_name
RUN apt-get update && apt-get install -y \
    @(' \\\n    '.join(ros2_packages))@  \
    && rm -rf /var/lib/apt/lists/*

@[if 'entrypoint_name' in locals()]@
@[  if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
# setup entrypoint
COPY ./@entrypoint_file /

ENTRYPOINT ["/@entrypoint_file"]
@[  end if]@
@[end if]@
@{
cmds = [
'bash',
]
}@
CMD ["@(' && '.join(cmds))"]

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
))@
@(TEMPLATE(
    'snippet/from_base_image.Dockerfile.em',
    template_packages=template_packages,
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
    base_image=base_image,
    maintainer_name=maintainer_name,
))@
@(TEMPLATE(
    'snippet/setup_tzdata.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
))@
@{
template_dependencies = [
    'dirmngr',
    'gnupg2',
    'lsb-release',
]
# add 'python3-pip' to 'template_dependencies' if pip dependencies are declared
if 'pip3_install' in locals():
    if isinstance(pip3_install, list) and pip3_install != []:
        template_dependencies.append('python3-pip')
}@
@(TEMPLATE(
    'snippet/install_upstream_package_list.Dockerfile.em',
    packages=template_dependencies,
    upstream_packages=upstream_packages if 'upstream_packages' in locals() else [],
))@
@
# setup ros2 keys
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 421C365BD9FF1F717815A3895523BAEEB01FA116

# setup sources.list
RUN echo "deb http://packages.ros.org/ros2/ubuntu `lsb_release -sc` main" > /etc/apt/sources.list.d/ros2-latest.list

# install bootstrap tools
RUN apt-get update && apt-get install --no-install-recommends -y \
    python3-rosdep \
    python3-rosinstall \
    python3-vcstools \
    && rm -rf /var/lib/apt/lists/*

# setup environment
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8

# bootstrap rosdep
ENV ROSDISTRO_INDEX_URL https://raw.githubusercontent.com/ros2/rosdistro/ros2/index.yaml
RUN rosdep init \
    && rosdep update

@[if 'pip3_install' in locals()]@
@[  if pip3_install]@
# install python packages
RUN pip3 install -U \
    @(' \\\n    '.join(pip3_install))@

@[  end if]@
@[end if]@

# install ros2 packages
ENV ROS_DISTRO @ros2distro_name
RUN apt-get update && apt-get install -y \
    @(' \\\n    '.join(ros2_packages))@  \
    && rm -rf /var/lib/apt/lists/*

@[if 'entrypoint_name' in locals()]@
@[  if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
# setup entrypoint
COPY ./@entrypoint_file /

ENTRYPOINT ["/@entrypoint_file"]
@[  end if]@
@[end if]@
@{
cmds = [
'bash',
]
}@
CMD ["@(' && '.join(cmds))"]


install pytest-rerunfailures for colcon --retest-until-pass (#824)

# generated from @template_name

@(TEMPLATE(
    'snippet/from_base_image.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
))@

VOLUME ["/var/cache/apt/archives"]

ENV DEBIAN_FRONTEND noninteractive

@(TEMPLATE(
    'snippet/old_release_set.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
))@

@(TEMPLATE(
    'snippet/setup_locale.Dockerfile.em',
    timezone=timezone,
))@

RUN useradd -u @uid -l -m buildfarm

@(TEMPLATE(
    'snippet/setup_nvidia_docker2.Dockerfile.em'
))@

@(TEMPLATE(
    'snippet/add_distribution_repositories.Dockerfile.em',
    distribution_repository_keys=distribution_repository_keys,
    distribution_repository_urls=distribution_repository_urls,
    os_name=os_name,
    os_code_name=os_code_name,
    add_source=False,
))@

@(TEMPLATE(
    'snippet/add_additional_repositories.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
))@

@(TEMPLATE(
    'snippet/add_wrapper_scripts.Dockerfile.em',
    wrapper_scripts=wrapper_scripts,
))@

# automatic invalidation once every day
RUN echo "@today_str"

@(TEMPLATE(
    'snippet/install_python3.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
))@

RUN python3 -u /tmp/wrapper_scripts/apt.py update-install-clean -q -y git python3-yaml

@[if build_tool == 'colcon']@
RUN python3 -u /tmp/wrapper_scripts/apt.py update-install-clean -q -y python3-pip
@# colcon-core.package_identification.python needs at least setuptools 30.3.0
@# pytest-rerunfailures enables usage of --retest-until-pass
RUN pip3 install -U setuptools pytest-rerunfailures
@[end if]@
@[if ros_version == 2]@
RUN python3 -u /tmp/wrapper_scripts/apt.py update-install-clean -q -y ros-@(rosdistro_name)-ros-workspace
@[end if]@
RUN python3 -u /tmp/wrapper_scripts/apt.py update-install-clean -q -y ccache

@(TEMPLATE(
    'snippet/set_environment_variables.Dockerfile.em',
    environment_variables=build_environment_variables,
))@

@(TEMPLATE(
    'snippet/install_dependencies.Dockerfile.em',
    dependencies=dependencies,
    dependency_versions=dependency_versions,
))@

@(TEMPLATE(
    'snippet/install_dependencies_from_file.Dockerfile.em',
    install_lists=install_lists,
))@

@[if run_abichecker]@
RUN python3 -u /tmp/wrapper_scripts/apt.py update-install-clean -q -y abi-compliance-checker python3 python3-catkin-pkg-modules python3-pip
RUN pip3 install -U auto_abi_checker
@[end if]@

# After all dependencies are installed, update ccache symlinks.
# This command is supposed to be invoked whenever a new compiler is installed
# but that isn't happening. So we invoke it here to make sure all compilers are
# picked up.
# TODO(nuclearsandwich) add link to Debian bug report when one is opened.
RUN which update-ccache-symlinks >/dev/null 2>&1 && update-ccache-symlinks

USER buildfarm
ENTRYPOINT ["sh", "-c"]
@{
cmd = \
    'PATH=/usr/lib/ccache:$PATH' + \
    ' PYTHONPATH=/tmp/ros_buildfarm:$PYTHONPATH python3 -u'
if not testing:
    cmd += \
        ' /tmp/ros_buildfarm/scripts/devel/build_and_install.py' + \
        ' --rosdistro-name ' + rosdistro_name + \
        ' --ros-version ' + str(ros_version) + \
        ' --clean-before'
    if run_abichecker:
        cmd += ' --run-abichecker'
else:
    cmd += \
        ' /tmp/ros_buildfarm/scripts/devel/build_and_test.py' + \
        ' --rosdistro-name %s' % rosdistro_name + \
        ' --ros-version ' + str(ros_version)
    if require_gpu_support:
        cmd += ' --require-gpu-support'
cmd += \
    ' --build-tool ' + build_tool + \
    ' --workspace-root ' + workspace_root + \
    ' --parent-result-space' + ''.join([' %s/install_isolated' % (space) for space in parent_result_space])
if vars().get('build_tool_args'):
    cmd += ' --build-tool-args ' + ' '.join(build_tool_args)
if vars().get('build_tool_test_args'):
    cmd += ' --build-tool-test-args ' + ' '.join(
        a if ' ' not in a else '"%s"' % a for a in build_tool_test_args)
}@
CMD ["@(cmd.replace('"', '\\"'))"]

# generated from @template_name

@(TEMPLATE(
    'snippet/from_base_image.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
))@

VOLUME ["/var/cache/apt/archives"]

ENV DEBIAN_FRONTEND noninteractive

@(TEMPLATE(
    'snippet/old_release_set.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
))@

@(TEMPLATE(
    'snippet/setup_locale.Dockerfile.em',
    timezone=timezone,
))@

RUN useradd -u @uid -l -m buildfarm

@(TEMPLATE(
    'snippet/setup_nvidia_docker2.Dockerfile.em'
))@

@(TEMPLATE(
    'snippet/add_distribution_repositories.Dockerfile.em',
    distribution_repository_keys=distribution_repository_keys,
    distribution_repository_urls=distribution_repository_urls,
    os_name=os_name,
    os_code_name=os_code_name,
    add_source=False,
))@

@(TEMPLATE(
    'snippet/add_additional_repositories.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
    arch=arch,
))@

@(TEMPLATE(
    'snippet/add_wrapper_scripts.Dockerfile.em',
    wrapper_scripts=wrapper_scripts,
))@

# automatic invalidation once every day
RUN echo "@today_str"

@(TEMPLATE(
    'snippet/install_python3.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
))@

RUN python3 -u /tmp/wrapper_scripts/apt.py update-install-clean -q -y git python3-yaml

@[if build_tool == 'colcon']@
RUN python3 -u /tmp/wrapper_scripts/apt.py update-install-clean -q -y python3-pip
@# colcon-core.package_identification.python needs at least version 30.3.0
RUN pip3 install -U setuptools
@[end if]@
@[if ros_version == 2]@
RUN python3 -u /tmp/wrapper_scripts/apt.py update-install-clean -q -y ros-@(rosdistro_name)-ros-workspace
@[end if]@
RUN python3 -u /tmp/wrapper_scripts/apt.py update-install-clean -q -y ccache

@(TEMPLATE(
    'snippet/set_environment_variables.Dockerfile.em',
    environment_variables=build_environment_variables,
))@

@(TEMPLATE(
    'snippet/install_dependencies.Dockerfile.em',
    dependencies=dependencies,
    dependency_versions=dependency_versions,
))@

@(TEMPLATE(
    'snippet/install_dependencies_from_file.Dockerfile.em',
    install_lists=install_lists,
))@

@[if run_abichecker]@
RUN python3 -u /tmp/wrapper_scripts/apt.py update-install-clean -q -y abi-compliance-checker python3 python3-catkin-pkg-modules python3-pip
RUN pip3 install -U auto_abi_checker
@[end if]@

# After all dependencies are installed, update ccache symlinks.
# This command is supposed to be invoked whenever a new compiler is installed
# but that isn't happening. So we invoke it here to make sure all compilers are
# picked up.
# TODO(nuclearsandwich) add link to Debian bug report when one is opened.
RUN which update-ccache-symlinks >/dev/null 2>&1 && update-ccache-symlinks

USER buildfarm
ENTRYPOINT ["sh", "-c"]
@{
cmd = \
    'PATH=/usr/lib/ccache:$PATH' + \
    ' PYTHONPATH=/tmp/ros_buildfarm:$PYTHONPATH python3 -u'
if not testing:
    cmd += \
        ' /tmp/ros_buildfarm/scripts/devel/build_and_install.py' + \
        ' --rosdistro-name ' + rosdistro_name + \
        ' --ros-version ' + str(ros_version) + \
        ' --clean-before'
    if run_abichecker:
        cmd += ' --run-abichecker'
else:
    cmd += \
        ' /tmp/ros_buildfarm/scripts/devel/build_and_test.py' + \
        ' --rosdistro-name %s' % rosdistro_name + \
        ' --ros-version ' + str(ros_version)
    if require_gpu_support:
        cmd += ' --require-gpu-support'
cmd += \
    ' --build-tool ' + build_tool + \
    ' --workspace-root ' + workspace_root + \
    ' --parent-result-space' + ''.join([' %s/install_isolated' % (space) for space in parent_result_space])
if vars().get('build_tool_args'):
    cmd += ' --build-tool-args ' + ' '.join(build_tool_args)
if vars().get('build_tool_test_args'):
    cmd += ' --build-tool-test-args ' + ' '.join(
        a if ' ' not in a else '"%s"' % a for a in build_tool_test_args)
}@
CMD ["@(cmd.replace('"', '\\"'))"]


prepend ${PACKAGE_NAME} to all generated cmake targets

Otherwise multiple packages employing xacro's cmake macros will use the
same conflicting target name.
This is only an issue with catkin_make, which defines a single global
cmake namespace. The new catkin tools (or catkin_make_isolated) build
each package separately.

@[if DEVELSPACE]@
set(_xacro_py
  @(CMAKE_CURRENT_SOURCE_DIR)/scripts/xacro
  )
@[else]@
set(_xacro_py
  ${xacro_DIR}/../../../@(CATKIN_PACKAGE_BIN_DESTINATION)/xacro
  )
@[end if]@

add_custom_target(${PROJECT_NAME}_xacro_generated_to_devel_space_ ALL)

## xacro_add_xacro_file(<input> [<output>] [INORDER] [REMAP <arg> <arg> ...]
##                      [OUTPUT <variable>])
##
## Creates a command run xacro on <input> like so:
## xacro [--inorder] -o <output> <input> [<remap args>]
##
## If <output> was not specified, it is determined from <input> removing the suffix .xacro
## The absolute output file name is returned in variable <output>, which defaults to
## XACRO_OUTPUT_FILE.
##
## In order to actually build and install, you need to provide a custom target:
## foreach(xacro_file ${MY_XACRO_FILES})
##   xacro_add_xacro_file(${xacro_file} INORDER REMAP bar:=foo foo:=bar)
##   list(APPEND xacro_outputs ${XACRO_OUTPUT_FILE})
## endforeach()
## add_custom_target(xacro_target ALL DEPENDS ${xacro_outputs})
## xacro_install(xacro_target ${xacro_outputs} DESTINATION xml)
##
## Be aware, that xacro_install() is required to install into both, install and devel space.
## Normal install() only installs into install space!
##
## For conveniency, you might want to use xacro_add_files(), which does the same:
## xacro_add_files(${MY_XACRO_FILES} INORDER REMAP bar:=foo foo:=bar
##                 TARGET xacro_target INSTALL DESTINATION xml)
function(xacro_add_xacro_file input)
  # parse arguments
  set(options INORDER)
  set(oneValueArgs OUTPUT)
  set(multiValueArgs REMAP)
  cmake_parse_arguments(_XACRO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  ## process arguments
  # retrieve output file name
  if(_XACRO_UNPARSED_ARGUMENTS)
    # output file explicitly specified
    list(GET _XACRO_UNPARSED_ARGUMENTS 0 output)
    list(REMOVE_AT _XACRO_UNPARSED_ARGUMENTS 0)
    # any remaining unparsed args?
    if(_XACRO_UNPARSED_ARGUMENTS)
      message(WARNING "unknown arguments: ${_XACRO_UNPARSED_ARGUMENTS}")
    endif(_XACRO_UNPARSED_ARGUMENTS)
  else()
    # implicitly determine output file from input
    if(${input} MATCHES "(.*)[.]xacro$")
      set(output ${CMAKE_MATCH_1})
    else()
      message(FATAL_ERROR "no <output> specified for: " ${input})
    endif()
  endif()
  # message(STATUS "output: ${output}")

  # transform _XACRO_INORDER's BOOL value
  if(_XACRO_INORDER)
    set(_XACRO_INORDER "--inorder")
  else()
    unset(_XACRO_INORDER)
  endif()

  ## determine absolute output target location
  if(IS_ABSOLUTE ${output})
    set(abs_output ${output})
  else()
    set(abs_output ${CMAKE_CURRENT_BINARY_DIR}/${output})
  endif()
  # message(STATUS "abs_output: ${abs_output}")

  ## export abs_output to parent scope in variable ${_XACRO_OUTPUT}
  if(NOT _XACRO_OUTPUT)
    set(_XACRO_OUTPUT XACRO_OUTPUT_FILE)
  endif()
  set(${_XACRO_OUTPUT} ${abs_output} PARENT_SCOPE)

  ## Call out to xacro to determine dependencies
  message(STATUS "xacro: determining deps for: " ${input} " ...")
  execute_process(COMMAND ${_xacro_py} --deps ${input} ${_XACRO_REMAP}
    WORKING_DIRECTORY $(CMAKE_CURRENT_SOURCE_DIR)
    ERROR_VARIABLE _xacro_err
    OUTPUT_VARIABLE _xacro_deps_result
    OUTPUT_STRIP_TRAILING_WHITESPACE)
  if(_xacro_err)
    message(WARNING "failed to determine deps for: ${input}
${_xacro_err}")
  endif(_xacro_err)

  separate_arguments(_xacro_deps_result)

  ## command to actually call xacro
  add_custom_command(OUTPUT ${output}
    COMMAND ${CATKIN_ENV} ${_xacro_py} ${_XACRO_INORDER} -o ${abs_output} ${input} ${_XACRO_REMAP}
    DEPENDS ${input} ${_xacro_deps_result}
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    COMMENT "xacro: generating ${output} from ${input}"
    )
endfunction(xacro_add_xacro_file)

## xacro_install(<target> <output> [<output> ...] DESTINATION <path>)
##
## installs xacro-generated files both to devel and input space
## into ${CATKIN_PACKAGE_SHARE_DESTINATION}/<path>
function(xacro_install target)
  # parse arguments
  set(oneValueArgs DESTINATION)
  cmake_parse_arguments(_XACRO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  set(outputs ${_XACRO_UNPARSED_ARGUMENTS})

  ## rule to create target dir
  file(TO_CMAKE_PATH ${CATKIN_PACKAGE_SHARE_DESTINATION}/${_XACRO_DESTINATION} dest)
  file(TO_CMAKE_PATH ${CATKIN_DEVEL_PREFIX}/${dest} TARGET_DIR)
  add_custom_command(OUTPUT ${TARGET_DIR}
    COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET_DIR}
    COMMENT "creating dir ${TARGET_DIR}")

  ## process list of outputs
  foreach(output ${outputs})
    get_filename_component(tgt ${output} NAME)
    file(TO_CMAKE_PATH ${TARGET_DIR}/${tgt} tgt)
    list(APPEND tgts ${tgt})

    # rule to create devel space tgt
    add_custom_command(OUTPUT ${tgt}
      COMMAND ${CMAKE_COMMAND} -E copy ${output} ${tgt}
      DEPENDS ${TARGET_DIR} ${output}
      COMMENT "Copying to devel space: ${tgt}"
      )
  endforeach()

  ## rule to create devel space tgts
  add_custom_target(${PROJECT_NAME}_${target}_to_devel_space_ DEPENDS ${tgts})
  # add to main target _xacro_generated_to_devel_space_
  add_dependencies(${PROJECT_NAME}_xacro_generated_to_devel_space_
                   ${PROJECT_NAME}_${target}_to_devel_space_)

  ## normal install
  install(FILES ${outputs} DESTINATION ${dest})
endfunction(xacro_install)

## xacro_add_files(<file> [<file> ...] [INORDER] [REMAP <arg> <arg> ...]
##                 [TARGET <target>] [INSTALL [DESTINATION <path>]])
##
## create make <target> to generate xacro files
## and optionally install to ${CATKIN_PACKAGE_SHARE_DESTINATION}/<path>
## in devel and install space.
function(xacro_add_files)
  # parse arguments
  set(options INORDER INSTALL)
  set(oneValueArgs OUTPUT TARGET DESTINATION)
  set(multiValueArgs REMAP)
  cmake_parse_arguments(_XACRO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  ## process arguments
  # transform _XACRO_INORDER's BOOL value
  if(_XACRO_INORDER)
    set(_XACRO_INORDER "INORDER")
  else()
    unset(_XACRO_INORDER)
  endif()

  # prepare REMAP args (prepending REMAP)
  if(_XACRO_REMAP)
    set(_XACRO_REMAP REMAP ${_XACRO_REMAP})
  endif()

  # have INSTALL option, but no TARGET: fallback to default target
  if(_XACRO_INSTALL AND NOT _XACRO_TARGET)
    # message(STATUS "xacro: no TARGET specified, using default")
    set(_XACRO_TARGET _xacro_auto_generate)
  endif()

  foreach(input ${_XACRO_UNPARSED_ARGUMENTS})
    # call to main function
    xacro_add_xacro_file(${input} ${_XACRO_OUTPUT} ${_XACRO_INORDER} ${_XACRO_REMAP})
    list(APPEND outputs ${XACRO_OUTPUT_FILE})
  endforeach()

  if(outputs)
    # link to target
    add_custom_target(${PROJECT_NAME}_${_XACRO_TARGET} ALL DEPENDS ${outputs})

    # install?
    if(_XACRO_INSTALL)
      xacro_install(${_XACRO_TARGET} ${outputs} DESTINATION ${_XACRO_DESTINATION})
    endif(_XACRO_INSTALL)
  endif()
endfunction(xacro_add_files)

@[if DEVELSPACE]@
set(_xacro_py
  @(CMAKE_CURRENT_SOURCE_DIR)/scripts/xacro
  )
@[else]@
set(_xacro_py
  ${xacro_DIR}/../../../@(CATKIN_PACKAGE_BIN_DESTINATION)/xacro
  )
@[end if]@

add_custom_target(_xacro_generated_to_devel_space_ ALL)

## xacro_add_xacro_file(<input> [<output>] [INORDER] [REMAP <arg> <arg> ...]
##                      [OUTPUT <variable>])
##
## Creates a command run xacro on <input> like so:
## xacro [--inorder] -o <output> <input> [<remap args>]
##
## If <output> was not specified, it is determined from <input> removing the suffix .xacro
## The absolute output file name is returned in variable <output>, which defaults to
## XACRO_OUTPUT_FILE.
##
## In order to actually build and install, you need to provide a custom target:
## foreach(xacro_file ${MY_XACRO_FILES})
##   xacro_add_xacro_file(${xacro_file} INORDER REMAP bar:=foo foo:=bar)
##   list(APPEND xacro_outputs ${XACRO_OUTPUT_FILE})
## endforeach()
## add_custom_target(xacro_target ALL DEPENDS ${xacro_outputs})
## xacro_install(xacro_target ${xacro_outputs} DESTINATION xml)
##
## Be aware, that xacro_install() is required to install into both, install and devel space.
## Normal install() only installs into install space!
##
## For conveniency, you might want to use xacro_add_files(), which does the same:
## xacro_add_files(${MY_XACRO_FILES} INORDER REMAP bar:=foo foo:=bar
##                 TARGET xacro_target INSTALL DESTINATION xml)
function(xacro_add_xacro_file input)
  # parse arguments
  set(options INORDER)
  set(oneValueArgs OUTPUT)
  set(multiValueArgs REMAP)
  cmake_parse_arguments(_XACRO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  ## process arguments
  # retrieve output file name
  if(_XACRO_UNPARSED_ARGUMENTS)
    # output file explicitly specified
    list(GET _XACRO_UNPARSED_ARGUMENTS 0 output)
    list(REMOVE_AT _XACRO_UNPARSED_ARGUMENTS 0)
    # any remaining unparsed args?
    if(_XACRO_UNPARSED_ARGUMENTS)
      message(WARNING "unknown arguments: ${_XACRO_UNPARSED_ARGUMENTS}")
    endif(_XACRO_UNPARSED_ARGUMENTS)
  else()
    # implicitly determine output file from input
    if(${input} MATCHES "(.*)[.]xacro$")
      set(output ${CMAKE_MATCH_1})
    else()
      message(FATAL_ERROR "no <output> specified for: " ${input})
    endif()
  endif()
  # message(STATUS "output: ${output}")

  # transform _XACRO_INORDER's BOOL value
  if(_XACRO_INORDER)
    set(_XACRO_INORDER "--inorder")
  else()
    unset(_XACRO_INORDER)
  endif()

  ## determine absolute output target location
  if(IS_ABSOLUTE ${output})
    set(abs_output ${output})
  else()
    set(abs_output ${CMAKE_CURRENT_BINARY_DIR}/${output})
  endif()
  # message(STATUS "abs_output: ${abs_output}")

  ## export abs_output to parent scope in variable ${_XACRO_OUTPUT}
  if(NOT _XACRO_OUTPUT)
    set(_XACRO_OUTPUT XACRO_OUTPUT_FILE)
  endif()
  set(${_XACRO_OUTPUT} ${abs_output} PARENT_SCOPE)

  ## Call out to xacro to determine dependencies
  message(STATUS "xacro: determining deps for: " ${input} " ...")
  execute_process(COMMAND ${_xacro_py} --deps ${input} ${_XACRO_REMAP}
    WORKING_DIRECTORY $(CMAKE_CURRENT_SOURCE_DIR)
    ERROR_VARIABLE _xacro_err
    OUTPUT_VARIABLE _xacro_deps_result
    OUTPUT_STRIP_TRAILING_WHITESPACE)
  if(_xacro_err)
    message(WARNING "failed to determine deps for: ${input}
${_xacro_err}")
  endif(_xacro_err)

  separate_arguments(_xacro_deps_result)

  ## command to actually call xacro
  add_custom_command(OUTPUT ${output}
    COMMAND ${CATKIN_ENV} ${_xacro_py} ${_XACRO_INORDER} -o ${abs_output} ${input} ${_XACRO_REMAP}
    DEPENDS ${input} ${_xacro_deps_result}
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    COMMENT "xacro: generating ${output} from ${input}"
    )
endfunction(xacro_add_xacro_file)

## xacro_install(<target> <output> [<output> ...] DESTINATION <path>)
##
## installs xacro-generated files both to devel and input space
## into ${CATKIN_PACKAGE_SHARE_DESTINATION}/<path>
function(xacro_install target)
  # parse arguments
  set(oneValueArgs DESTINATION)
  cmake_parse_arguments(_XACRO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  set(outputs ${_XACRO_UNPARSED_ARGUMENTS})

  ## rule to create target dir
  file(TO_CMAKE_PATH ${CATKIN_PACKAGE_SHARE_DESTINATION}/${_XACRO_DESTINATION} dest)
  file(TO_CMAKE_PATH ${CATKIN_DEVEL_PREFIX}/${dest} TARGET_DIR)
  add_custom_command(OUTPUT ${TARGET_DIR}
    COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET_DIR}
    COMMENT "creating dir ${TARGET_DIR}")

  ## process list of outputs
  foreach(output ${outputs})
    get_filename_component(tgt ${output} NAME)
    file(TO_CMAKE_PATH ${TARGET_DIR}/${tgt} tgt)
    list(APPEND tgts ${tgt})

    # rule to create devel space tgt
    add_custom_command(OUTPUT ${tgt}
      COMMAND ${CMAKE_COMMAND} -E copy ${output} ${tgt}
      DEPENDS ${TARGET_DIR} ${output}
      COMMENT "Copying to devel space: ${tgt}"
      )
  endforeach()

  ## rule to create devel space tgts
  add_custom_target(${target}_to_devel_space_ DEPENDS ${tgts})
  # add to main target _xacro_generated_to_devel_space_
  add_dependencies(_xacro_generated_to_devel_space_ ${target}_to_devel_space_)

  ## normal install
  install(FILES ${outputs} DESTINATION ${dest})
endfunction(xacro_install)

## xacro_add_files(<file> [<file> ...] [INORDER] [REMAP <arg> <arg> ...]
##                 [TARGET <target>] [INSTALL [DESTINATION <path>]])
##
## create make <target> to generate xacro files
## and optionally install to ${CATKIN_PACKAGE_SHARE_DESTINATION}/<path>
## in devel and install space.
function(xacro_add_files)
  # parse arguments
  set(options INORDER INSTALL)
  set(oneValueArgs OUTPUT TARGET DESTINATION)
  set(multiValueArgs REMAP)
  cmake_parse_arguments(_XACRO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  ## process arguments
  # transform _XACRO_INORDER's BOOL value
  if(_XACRO_INORDER)
    set(_XACRO_INORDER "INORDER")
  else()
    unset(_XACRO_INORDER)
  endif()

  # prepare REMAP args (prepending REMAP)
  if(_XACRO_REMAP)
    set(_XACRO_REMAP REMAP ${_XACRO_REMAP})
  endif()

  # have INSTALL option, but no TARGET: fallback to default target
  if(_XACRO_INSTALL AND NOT _XACRO_TARGET)
    # message(STATUS "xacro: no TARGET specified, using default")
    set(_XACRO_TARGET _xacro_auto_generate)
  endif()

  foreach(input ${_XACRO_UNPARSED_ARGUMENTS})
    # call to main function
    xacro_add_xacro_file(${input} ${_XACRO_OUTPUT} ${_XACRO_INORDER} ${_XACRO_REMAP})
    list(APPEND outputs ${XACRO_OUTPUT_FILE})
  endforeach()

  if(outputs)
    # link to target
    add_custom_target(${_XACRO_TARGET} ALL DEPENDS ${outputs})

    # install?
    if(_XACRO_INSTALL)
      xacro_install(${_XACRO_TARGET} ${outputs} DESTINATION ${_XACRO_DESTINATION})
    endif(_XACRO_INSTALL)
  endif()
endfunction(xacro_add_files)