use a non-fuerte path

use a non-fuerte path

#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.

# Uncomment this to turn on verbose mode.
export DH_VERBOSE=1
export DH_OPTIONS=-v
export CMAKE_PREFIX_PATH="@(INSTALL_PREFIX)"
CMAKE_FLAGS = \
	-DCMAKE_BUILD_TYPE=Release \
	-DUSE_ROS=ON
%:
	dh  $@@

override_dh_auto_configure:
	dh_auto_configure -Scmake -- \
		-DCMAKE_INSTALL_PREFIX="@(INSTALL_PREFIX)" \
		-DCMAKE_PREFIX_PATH="@(INSTALL_PREFIX)" \
		$(CMAKE_FLAGS)

override_dh_auto_test:
	echo -- Running tests. Even if one of them fails the build is not canceled.
	-cat /proc/meminfo
	-cat /proc/cpuinfo
	dh_auto_test || true

#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.

# Uncomment this to turn on verbose mode.
export DH_VERBOSE=1
export DH_OPTIONS=-v
export CMAKE_PREFIX_PATH="/opt/ros/fuerte"
CMAKE_FLAGS = \
	-DCMAKE_BUILD_TYPE=Release \
	-DUSE_ROS=ON
%:
	dh  $@@

override_dh_auto_configure:
	dh_auto_configure -Scmake -- \
		-DCMAKE_INSTALL_PREFIX="/opt/ros/fuerte" \
		-DCMAKE_PREFIX_PATH="/opt/ros/fuerte" \
		$(CMAKE_FLAGS)

override_dh_auto_test:
	echo -- Running tests. Even if one of them fails the build is not canceled.
	-cat /proc/meminfo
	-cat /proc/cpuinfo
	dh_auto_test || true


cmake: explicitly define ROS_PACKAGE_NAME

... in case the user does not depend on rosconsole, which does it
otherwise.

add_definitions(-DROS_PACKAGE_NAME=\"${PROJECT_NAME}\")

#
# Add a Catch executable target.
#
# An executable target is created with the source files, it is linked
# against Catch. It is also registered as dependency of the run_tests target.
#
# :param target: the target name
# :type target: string
# :param source_files: a list of source files used to build the test
#   executable
# :type source_files: list of strings
#
function(catch_add_test target)
	add_executable(${target}
		${ARGN}
		@(DEVELSPACE ? (PROJECT_SOURCE_DIR + "/src") : CATKIN_PACKAGE_SHARE_DESTINATION)/meta_info.cpp
	)

	target_link_libraries(${target}
		@(DEVELSPACE ? CATKIN_DEVEL_PREFIX : CMAKE_INSTALL_PREFIX)/lib/libcatch_ros_standalone.so
	)

	if(TARGET ${target})
		# make sure the target is built before running tests
		add_dependencies(tests ${target})

		get_target_property(_target_path ${target} RUNTIME_OUTPUT_DIRECTORY)
		set(cmd "${_target_path}/${target} -r ros_junit -o ${CATKIN_TEST_RESULTS_DIR}/${PROJECT_NAME}/catch-${target}.xml")
		catkin_run_tests_target("catch" ${target} "catch-${target}.xml" COMMAND ${cmd} DEPENDENCIES ${target})
	endif()
endfunction()

#
# Add a Catch rostest executable target.
#
# An executable target is created with the source files, it is linked
# against Catch.
# In contrast to catch_add_test, this function links against a main() function
# which also calls ros::init(). Also, the test is not registered with the
# run_tests target, because it is expected that you use the test inside of
# a rostest.
#
# :param target: the target name
# :type target: string
# :param source_files: a list of source files used to build the test
#   executable
# :type source_files: list of strings
#
function(catch_add_rostest_node target)
	add_executable(${target}
		${ARGN}
		@(DEVELSPACE ? (PROJECT_SOURCE_DIR + "/src") : CATKIN_PACKAGE_SHARE_DESTINATION)/meta_info.cpp
	)

	target_link_libraries(${target}
		@(DEVELSPACE ? CATKIN_DEVEL_PREFIX : CMAKE_INSTALL_PREFIX)/lib/libcatch_ros_rostest.so
	)
endfunction()


fold format argument into varargs

fold format argument into varargs

// 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

// Provide the compiler with branch prediction information
#ifndef WIN32
/**
 * \def RCUTILS_LIKELY
 * Instruct the compiler to optimize for the case where the argument equals 1.
 */
# define RCUTILS_LIKELY(x) __builtin_expect((x), 1)
/**
 * \def RCUTILS_UNLIKELY
 * Instruct the compiler to optimize for the case where the argument equals 0.
 */
# define RCUTILS_UNLIKELY(x) __builtin_expect((x), 0)
#else
/**
 * \def RCUTILS_LIKELY
 * No op since Windows doesn't support providing branch prediction information.
 */
# define RCUTILS_LIKELY(x) (x)
/**
 * \def RCUTILS_UNLIKELY
 * No op since Windows doesn't support providing branch prediction information.
 */
# define RCUTILS_UNLIKELY(x) (x)
#endif

/**
 * \def RCUTILS_LOGGING_AUTOINIT
 * \brief Initialize the rcl logging library.
 * Usually it is unnecessary to call the macro directly.
 * All logging macros ensure that this has been called once.
 */
#define RCUTILS_LOGGING_AUTOINIT \
  if (RCUTILS_UNLIKELY(!g_rcl_logging_initialized)) { \
    rcl_logging_initialize(); \
  }

/**
 * \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 format The format string
 * \param ... The variable arguments for the format strings
 */
#define RCUTILS_LOG_COND_NAMED(severity, condition_before, condition_after, name, ...) \
  { \
    RCUTILS_LOGGING_AUTOINIT \
    static rcl_log_location_t __rcutils_logging_location = {__func__, __FILE__, __LINE__}; \
    condition_before \
    if (severity >= g_rcl_logging_severity_threshold) { \
      rcl_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) { \
      rcl_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 } \
  }
///@@}

@{
severities = ('DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL')

from collections import OrderedDict
default_args = OrderedDict((
  ('condition_before', 'RCUTILS_LOG_CONDITION_EMPTY'),
  ('condition_after', 'RCUTILS_LOG_CONDITION_EMPTY'),
  ('name', '""'),
))

name_params = OrderedDict((
  ('name', 'The name of the logger'),
))
name_args = {'name': 'name'}

once_args = {
  'condition_before': 'RCUTILS_LOG_CONDITION_ONCE_BEFORE',
  'condition_after': 'RCUTILS_LOG_CONDITION_ONCE_AFTER'}
name_doc_lines = [
  'All subsequent log calls except the first one are being ignored.']

expression_params = OrderedDict((
  ('expression', 'The expression determining if the message should be logged'),
))
expression_args = {
  'condition_before': 'RCUTILS_LOG_CONDITION_EXPRESSION_BEFORE(expression)',
  'condition_after': 'RCUTILS_LOG_CONDITION_EXPRESSION_AFTER'}
expression_doc_lines = [
  'Log calls are being ignored when the expression evaluates to false.']

function_params = OrderedDict((
  ('function', 'The functions return value determines if the message should be logged'),
))
function_args = {
  'condition_before': 'RCUTILS_LOG_CONDITION_FUNCTION_BEFORE(function)',
  'condition_after': 'RCUTILS_LOG_CONDITION_FUNCTION_AFTER'}
function_doc_lines = [
  'Log calls are being ignored when the function returns false.']

skipfirst_args = {
  'condition_before': 'RCUTILS_LOG_CONDITION_SKIPFIRST_BEFORE',
  'condition_after': 'RCUTILS_LOG_CONDITION_SKIPFIRST_AFTER'}
skipfirst_doc_lines = [
  'The first log call is being ignored but all subsequent calls are being processed.']

throttle_params = OrderedDict((
  ('time_source_type', 'The time source type of the time to be used'),
  ('duration', 'The duration of the throttle interval'),
))
throttle_args = {
  'condition_before': 'RCUTILS_LOG_CONDITION_THROTTLE_BEFORE(time_source_type, duration)',
  'condition_after': 'RCUTILS_LOG_CONDITION_THROTTLE_AFTER'}
throttle_doc_lines = [
  'Log calls are being ignored if the last logged message is not longer ago than the specified duration.']

class Feature(object):
  __slots__ = ('params', 'args', 'doc_lines')
  def __init__(self, *, params=None, args=None, doc_lines=None):
    if params is None:
      params = {}
    self.params = params
    if args is None:
      args = {}
    self.args = args
    if doc_lines is None:
      doc_lines = []
    self.doc_lines = doc_lines

feature_combinations = OrderedDict((
  ('', Feature()),
  ('_NAMED', Feature(
    params=name_params,
    args=name_args)),
  ('_ONCE', Feature(
    params=None,
    args=once_args,
    doc_lines=name_doc_lines)),
  ('_ONCE_NAMED', Feature(
    params=name_params,
    args={**once_args, **name_args},
    doc_lines=name_doc_lines)),
  ('_EXPRESSION', Feature(
    params=expression_params,
    args=expression_args,
    doc_lines=expression_doc_lines)),
  ('_EXPRESSION_NAMED', Feature(
    params=OrderedDict((*expression_params.items(), *name_params.items())),
    args={**expression_args, **name_args},
    doc_lines=expression_doc_lines + name_doc_lines)),
  ('_FUNCTION', Feature(
    params=function_params,
    args=function_args,
    doc_lines=function_doc_lines)),
  ('_FUNCTION_NAMED', Feature(
    params=OrderedDict((*function_params.items(), *name_params.items())),
    args={**function_args, **name_args},
    doc_lines=function_doc_lines + name_doc_lines)),
  ('_SKIPFIRST', Feature(
    params=None,
    args=skipfirst_args,
    doc_lines=skipfirst_doc_lines)),
  ('_SKIPFIRST_NAMED', Feature(
    params=name_params,
    args={**skipfirst_args, **name_args},
    doc_lines=skipfirst_doc_lines)),
  ('_THROTTLE', Feature(
    params=throttle_params,
    args=throttle_args,
    doc_lines=throttle_doc_lines)),
  ('_SKIPFIRST_THROTTLE', Feature(
    params=throttle_params,
    args={
      'condition_before': ' '.join([
        throttle_args['condition_before'],
        skipfirst_args['condition_before']]),
      'condition_after': ' '.join([
        throttle_args['condition_after'], skipfirst_args['condition_after']]),
    },
    doc_lines=skipfirst_doc_lines + throttle_doc_lines)),
  ('_THROTTLE_NAMED', Feature(
    params=OrderedDict((*throttle_params.items(), *name_params.items())),
    args={**throttle_args, **name_args},
    doc_lines=throttle_doc_lines)),
  ('_SKIPFIRST_THROTTLE_NAMED', Feature(
    params=OrderedDict((*throttle_params.items(), *name_params.items())),
    args={
      **{
        'condition_before': ' '.join([
          throttle_args['condition_before'],
          skipfirst_args['condition_before']]),
        'condition_after': ' '.join([
          throttle_args['condition_after'],
          skipfirst_args['condition_after']]),
      }, **name_args
    },
    doc_lines=skipfirst_doc_lines + throttle_doc_lines)),
))

def get_macro_parameters(suffix):
  return ''.join([p + ', ' for p in feature_combinations[suffix].params.keys()])

def get_macro_arguments(suffix):
  args = []
  for k, default_value in default_args.items():
    value = feature_combinations[suffix].args.get(k, default_value)
    args.append(value)
  return ''.join([a + ', ' for a in args])
}@
@[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 suffix in feature_combinations]@
/// Empty logging macro due to the preprocessor definition of RCUTILS_LOG_MIN_SEVERITY.
# define RCUTILS_LOG_@(severity)@(suffix)(@(get_macro_parameters(suffix))format, ...)
@[ end for]@

#else
@[ for suffix in feature_combinations]@
/**
 * \def RCUTILS_LOG_@(severity)@(suffix)
 * Log a message with severity @(severity)@
@[ if feature_combinations[suffix].doc_lines]@
 with the following conditions:
@[ else]@
.
@[ end if]@
@[ for doc_line in feature_combinations[suffix].doc_lines]@
 * @(doc_line)
@[ end for]@
@[ for param_name, doc_line in feature_combinations[suffix].params.items()]@
 * \param @(param_name) @(doc_line)
@[ end for]@
 * \param format The format string
 * \param ... The variable arguments for the format strings
 */
# define RCUTILS_LOG_@(severity)@(suffix)(@(get_macro_parameters(suffix))...) \
  RCUTILS_LOG_COND_NAMED( \
    RCUTILS_LOG_SEVERITY_@(severity), \
    @(get_macro_arguments(suffix))\
    __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

// Provide the compiler with branch prediction information
#ifndef WIN32
/**
 * \def RCUTILS_LIKELY
 * Instruct the compiler to optimize for the case where the argument equals 1.
 */
# define RCUTILS_LIKELY(x) __builtin_expect((x), 1)
/**
 * \def RCUTILS_UNLIKELY
 * Instruct the compiler to optimize for the case where the argument equals 0.
 */
# define RCUTILS_UNLIKELY(x) __builtin_expect((x), 0)
#else
/**
 * \def RCUTILS_LIKELY
 * No op since Windows doesn't support providing branch prediction information.
 */
# define RCUTILS_LIKELY(x) (x)
/**
 * \def RCUTILS_UNLIKELY
 * No op since Windows doesn't support providing branch prediction information.
 */
# define RCUTILS_UNLIKELY(x) (x)
#endif

/**
 * \def RCUTILS_LOGGING_AUTOINIT
 * \brief Initialize the rcl logging library.
 * Usually it is unnecessary to call the macro directly.
 * All logging macros ensure that this has been called once.
 */
#define RCUTILS_LOGGING_AUTOINIT \
  if (RCUTILS_UNLIKELY(!g_rcl_logging_initialized)) { \
    rcl_logging_initialize(); \
  }

/**
 * \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 format The format string
 * \param ... The variable arguments for the format strings
 */
#define RCUTILS_LOG_COND_NAMED(severity, condition_before, condition_after, name, format, ...) \
  { \
    RCUTILS_LOGGING_AUTOINIT \
    static rcl_log_location_t __rcutils_logging_location = {__func__, __FILE__, __LINE__}; \
    condition_before \
    if (severity >= g_rcl_logging_severity_threshold) { \
      rcl_log(&__rcutils_logging_location, severity, name, format, ## __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) { \
      rcl_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 } \
  }
///@@}

@{
severities = ('DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL')

from collections import OrderedDict
default_args = OrderedDict((
  ('condition_before', 'RCUTILS_LOG_CONDITION_EMPTY'),
  ('condition_after', 'RCUTILS_LOG_CONDITION_EMPTY'),
  ('name', '""'),
))

name_params = OrderedDict((
  ('name', 'The name of the logger'),
))
name_args = {'name': 'name'}

once_args = {
  'condition_before': 'RCUTILS_LOG_CONDITION_ONCE_BEFORE',
  'condition_after': 'RCUTILS_LOG_CONDITION_ONCE_AFTER'}
name_doc_lines = [
  'All subsequent log calls except the first one are being ignored.']

expression_params = OrderedDict((
  ('expression', 'The expression determining if the message should be logged'),
))
expression_args = {
  'condition_before': 'RCUTILS_LOG_CONDITION_EXPRESSION_BEFORE(expression)',
  'condition_after': 'RCUTILS_LOG_CONDITION_EXPRESSION_AFTER'}
expression_doc_lines = [
  'Log calls are being ignored when the expression evaluates to false.']

function_params = OrderedDict((
  ('function', 'The functions return value determines if the message should be logged'),
))
function_args = {
  'condition_before': 'RCUTILS_LOG_CONDITION_FUNCTION_BEFORE(function)',
  'condition_after': 'RCUTILS_LOG_CONDITION_FUNCTION_AFTER'}
function_doc_lines = [
  'Log calls are being ignored when the function returns false.']

skipfirst_args = {
  'condition_before': 'RCUTILS_LOG_CONDITION_SKIPFIRST_BEFORE',
  'condition_after': 'RCUTILS_LOG_CONDITION_SKIPFIRST_AFTER'}
skipfirst_doc_lines = [
  'The first log call is being ignored but all subsequent calls are being processed.']

throttle_params = OrderedDict((
  ('time_source_type', 'The time source type of the time to be used'),
  ('duration', 'The duration of the throttle interval'),
))
throttle_args = {
  'condition_before': 'RCUTILS_LOG_CONDITION_THROTTLE_BEFORE(time_source_type, duration)',
  'condition_after': 'RCUTILS_LOG_CONDITION_THROTTLE_AFTER'}
throttle_doc_lines = [
  'Log calls are being ignored if the last logged message is not longer ago than the specified duration.']

class Feature(object):
  __slots__ = ('params', 'args', 'doc_lines')
  def __init__(self, *, params=None, args=None, doc_lines=None):
    if params is None:
      params = {}
    self.params = params
    if args is None:
      args = {}
    self.args = args
    if doc_lines is None:
      doc_lines = []
    self.doc_lines = doc_lines

feature_combinations = OrderedDict((
  ('', Feature()),
  ('_NAMED', Feature(
    params=name_params,
    args=name_args)),
  ('_ONCE', Feature(
    params=None,
    args=once_args,
    doc_lines=name_doc_lines)),
  ('_ONCE_NAMED', Feature(
    params=name_params,
    args={**once_args, **name_args},
    doc_lines=name_doc_lines)),
  ('_EXPRESSION', Feature(
    params=expression_params,
    args=expression_args,
    doc_lines=expression_doc_lines)),
  ('_EXPRESSION_NAMED', Feature(
    params=OrderedDict((*expression_params.items(), *name_params.items())),
    args={**expression_args, **name_args},
    doc_lines=expression_doc_lines + name_doc_lines)),
  ('_FUNCTION', Feature(
    params=function_params,
    args=function_args,
    doc_lines=function_doc_lines)),
  ('_FUNCTION_NAMED', Feature(
    params=OrderedDict((*function_params.items(), *name_params.items())),
    args={**function_args, **name_args},
    doc_lines=function_doc_lines + name_doc_lines)),
  ('_SKIPFIRST', Feature(
    params=None,
    args=skipfirst_args,
    doc_lines=skipfirst_doc_lines)),
  ('_SKIPFIRST_NAMED', Feature(
    params=name_params,
    args={**skipfirst_args, **name_args},
    doc_lines=skipfirst_doc_lines)),
  ('_THROTTLE', Feature(
    params=throttle_params,
    args=throttle_args,
    doc_lines=throttle_doc_lines)),
  ('_SKIPFIRST_THROTTLE', Feature(
    params=throttle_params,
    args={
      'condition_before': ' '.join([
        throttle_args['condition_before'],
        skipfirst_args['condition_before']]),
      'condition_after': ' '.join([
        throttle_args['condition_after'], skipfirst_args['condition_after']]),
    },
    doc_lines=skipfirst_doc_lines + throttle_doc_lines)),
  ('_THROTTLE_NAMED', Feature(
    params=OrderedDict((*throttle_params.items(), *name_params.items())),
    args={**throttle_args, **name_args},
    doc_lines=throttle_doc_lines)),
  ('_SKIPFIRST_THROTTLE_NAMED', Feature(
    params=OrderedDict((*throttle_params.items(), *name_params.items())),
    args={
      **{
        'condition_before': ' '.join([
          throttle_args['condition_before'],
          skipfirst_args['condition_before']]),
        'condition_after': ' '.join([
          throttle_args['condition_after'],
          skipfirst_args['condition_after']]),
      }, **name_args
    },
    doc_lines=skipfirst_doc_lines + throttle_doc_lines)),
))

def get_macro_parameters(suffix):
  return ''.join([p + ', ' for p in feature_combinations[suffix].params.keys()])

def get_macro_arguments(suffix):
  args = []
  for k, default_value in default_args.items():
    value = feature_combinations[suffix].args.get(k, default_value)
    args.append(value)
  return ''.join([a + ', ' for a in args])
}@
@[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 suffix in feature_combinations]@
/// Empty logging macro due to the preprocessor definition of RCUTILS_LOG_MIN_SEVERITY.
# define RCUTILS_LOG_@(severity)@(suffix)(@(get_macro_parameters(suffix))format, ...)
@[ end for]@

#else
@[ for suffix in feature_combinations]@
/**
 * \def RCUTILS_LOG_@(severity)@(suffix)
 * Log a message with severity @(severity)@
@[ if feature_combinations[suffix].doc_lines]@
 with the following conditions:
@[ else]@
.
@[ end if]@
@[ for doc_line in feature_combinations[suffix].doc_lines]@
 * @(doc_line)
@[ end for]@
@[ for param_name, doc_line in feature_combinations[suffix].params.items()]@
 * \param @(param_name) @(doc_line)
@[ end for]@
 * \param format The format string
 * \param ... The variable arguments for the format strings
 */
# define RCUTILS_LOG_@(severity)@(suffix)(@(get_macro_parameters(suffix))format, ...) \
  RCUTILS_LOG_COND_NAMED( \
    RCUTILS_LOG_SEVERITY_@(severity), \
    @(get_macro_arguments(suffix))\
    format, ## __VA_ARGS__)
@[ end for]@
#endif
///@@}

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

#endif  // RCUTILS__LOGGING_MACROS_H_


Can now display messages from simpleInput without taking any input.

if (typeof(std.core.SimpleInput) != 'undefined')
    throw new Error('Error in std.core.SimpleInput.  May only import once.');

(function ()
 {
     var knownUsed = [];

     var SIMPLE_INPUT_MOD_NAME = 'SimpleInput';
     var haveInited = false;
     var guiMod = simulator._simulator.addGUITextModule(
         SIMPLE_INPUT_MOD_NAME,
         getSimpleInputGUIText(),
         function()
         {
             haveInited = true;
             guiMod.bind('responseReceived',
                         respReceivedFunc);
         }
     );

     function respReceivedFunc(forWhom,response)
     {
         if ((!(forWhom in knownUsed)) ||
             (knownUsed[forWhom] == null))
         {
             throw new Error('\nWarning in simple input: ' +
                             'recevied response for '      +
                             forWhom.toString() + ' when ' +
                             'have no record for it.\n');

         }

         var inputter = knownUsed[forWhom];
         knownUsed[forWhom] = null;
         inputter.cb(response);
     }

     /**
      @param {int} type what type of simple input going to provide
      (See std.core.SimpleInput.SELECT_LIST and
      std.core.SimpleInput.ENTER_TEXT as examples

      @param {string} message what message gets written at the top of
      the input.

      @param {function} cb Takes a single argument -- the value of
      what was selected.

      @param additional (optional)

        if ENTER_TEXT is selected, then this should be undefined.

        if SELECT_LIST is entered as type, then this should be an
        arrray of tuples.  The first element of each tuple should
        contain the text that gets displayed to the user next to the
        option.  The second element should contain a code that gets
        passed back to cb so that the scripter knows what was
        selected.  Code must be text.

        if NO_INPUT is entered as type, then just display message
        without getting any response back.
      */
     std.core.SimpleInput = function(type, message, cb, additional)
     {
         if (!haveInited)
             throw new Error('Error.  GUI still initializing.  Please wait.');

         this.type       = type;
         this.message    = message;
         this.cb         = cb;
         this.additional = additional;

         if ((type == std.core.SimpleInput.SELECT_LIST) &&
             (typeof(this.additional) == 'undefined'))
         {
             throw new Error ('Error constructing SimpleInput.  If given ' +
                              'a list input, should be given additional '  +
                              'labels.');
         }

         this.indexUsed = addToKnownUsed(this);

         var callFunc = '';
         if (type == std.core.SimpleInput.SELECT_LIST)
             callFunc = 'simpleInputSelectList';
         else if (type == std.core.SimpleInput.ENTER_TEXT)
             callFunc = 'simpleInputSelectText';
         else if (type == std.core.SimpleInput.NO_INPUT)
             callFunc = 'simpleInputNoInput';
         else
             throw new Error ('Error: please select a valid type ' +
                              'for SimpleInput');

         guiMod.call(callFunc,message,this.indexUsed,additional);
     };

     /*** Types of simple input to get  ***/
     //note: if add to any additional ones of these, then
     //must also add to if-else if statement in constructor
     //of SimpleInput
     std.core.SimpleInput.SELECT_LIST = 0;
     std.core.SimpleInput.ENTER_TEXT  = 1;
     //used just to display a message, not to get any user response
     //from.
     std.core.SimpleInput.NO_INPUT = 2;

     std.core.SimpleInput.ready = function()
     {
         return haveInited;
     };

     /**
      We want to recycle the divs,etc. associ
      */
     function addToKnownUsed(simpleInputObject)
     {
         var indexToUse = null;
         for (var s in knownUsed)
         {
             if (knownUsed[s] == null)
             {
                 indexToUse = s;
                 break;
             }
         }

         //could not find empty index.  Create new element
         if (indexToUse == null)
         {
             knownUsed.push(null);
             indexToUse = knownUsed.length - 1;
         }
         knownUsed[indexToUse] = simpleInputObject;
         return indexToUse;
     }

     function getSimpleInputGUIText()
     {
         var returner = "sirikata.ui('" + SIMPLE_INPUT_MOD_NAME + "',";
         returner += 'function(){ ';

         returner += @

         var newcsslink =
             $("<link />").attr({rel:'stylesheet', type:'text/css', href:'../scripting/prompt.css'});
	 $("head").append(newcsslink);

         //keeps track of all open windows requiring input events.
         var existingWindows = { };

         function generateDivIDFromInputID(inputID)
         {
             return 'simpleInputID__' + inputID.toString();
         }

         function newWindow(htmlForWindow,simpleInputID)
         {
             var newWindowID = generateDivIDFromInputID(simpleInputID);
             $('
'   +
               htmlForWindow   +
               '
' //end div at top.
              ).attr({id:newWindowID,title:'simpleInput'}).appendTo('body');

             var inputWindow = new sirikata.ui.window(
                 '#' + newWindowID,
                 {
	             autoOpen: true,
	             height: 'auto',
	             width: 300,
                     height: 300,
                     position: 'right'
                 }
             );
             inputWindow.show();
             existingWindows[newWindowID] = [inputWindow,simpleInputID];
         }

         simpleInputSubmit = function(simpleInputID)
         {
             var returner = '';
             //first check to see if we got the value for a text element
             var textInputID = generateSimpleInputOptionID(simpleInputID);
             var textInput = $('#' + textInputID);
             if (textInput.length > 0)
             {
                 //means that we got a text input
                 returner =textInput.val();
             }
             else
             {
                 var radioInput = $('input:radio[name=' +
                                    textInputID +']:checked');
                 if (radioInput.length > 0)
                     returner = radioInput.val();
             }

             //automtaically handles case of noinput type of input by
             //passing undefined as responseReceived
             sirikata.event('responseReceived',simpleInputID,returner);

             delete existingWindows[simpleInputID];
             //actually remove the window from view after its question has been answered.
             var inputID = generateDivIDFromInputID(simpleInputID);
             $('#'+inputID).remove();
         };

         function generateSubmitButtonHtml(simpleInputID)
         {
             var htmlToDisplay = '';
             htmlToDisplay += '<button ' +
                 'onclick="simpleInputSubmit(' + simpleInputID.toString() +
                 ')">';

             htmlToDisplay += 'Submit';
             htmlToDisplay += '</button>';

             return htmlToDisplay;
         }

         simpleInputSelectList =
             function(message,simpleInputID,additional)
         {
             var htmlInsert = message + '
';
             var radName = generateSimpleInputOptionID(simpleInputID);
             for (var s in additional)
             {
                 htmlInsert += '<input type=radio name="' +
                     radName + '" value="' + additional[s][1] +
                     '"></input>' + additional[s][0];
                 htmlInsert += '
';
             }
             htmlInsert += generateSubmitButtonHtml(simpleInputID);
             newWindow(htmlInsert,simpleInputID);
         };

         function generateSimpleInputOptionID(inputID)
         {
             return 'simpleInputIDOption__' + inputID.toString();
         }

         simpleInputNoInput = function (message,simpleInputID)
         {
             var htmlInsert = message + '
';
             htmlInsert += generateSubmitButtonHtml(simpleInputID);
             newWindow(htmlInsert,simpleInputID);
         };

         simpleInputSelectText = function(message,simpleInputID)
         {
             var htmlInsert = message + '
';
             htmlInsert += '<input id="'                      +
                 generateSimpleInputOptionID(simpleInputID)   +
                 '"></input>
';
             htmlInsert += generateSubmitButtonHtml(simpleInputID);
             newWindow(htmlInsert,simpleInputID);

             //handles enter submitting text
             var handleEnterHit = function(evt)
             {
                 //13 represents keycode for enter, submits whatever's in
                 //the text box if user hits enter.
                 if (evt.keyCode == 13)
                     simpleInputSubmit(simpleInputID);
             };

             //copied from chat.js
             var register_area = document.getElementById(
                 generateSimpleInputOptionID(simpleInputID));
             register_area.onkeyup = handleEnterHit;
         };
         @;

         returner += '});';
         return returner;
     }

 }
)();

if (typeof(std.core.SimpleInput) != 'undefined')
    throw new Error('Error in std.core.SimpleInput.  May only import once.');

(function ()
 {
     var knownUsed = [];

     var SIMPLE_INPUT_MOD_NAME = 'SimpleInput';
     var haveInited = false;
     var guiMod = simulator._simulator.addGUITextModule(
         SIMPLE_INPUT_MOD_NAME,
         getSimpleInputGUIText(),
         function()
         {
             haveInited = true;
             guiMod.bind('responseReceived',
                         respReceivedFunc);
         }
     );

     function respReceivedFunc(forWhom,response)
     {
         if ((!(forWhom in knownUsed)) ||
             (knownUsed[forWhom] == null))
         {
             throw new Error('\nWarning in simple input: ' +
                             'recevied response for '      +
                             forWhom.toString() + ' when ' +
                             'have no record for it.\n');

         }

         var inputter = knownUsed[forWhom];
         knownUsed[forWhom] = null;
         inputter.cb(response);
     }

     /**
      @param {int} type what type of simple input going to provide
      (See std.core.SimpleInput.SELECT_LIST and
      std.core.SimpleInput.ENTER_TEXT as examples

      @param {string} message what message gets written at the top of
      the input.

      @param {function} cb Takes a single argument -- the value of
      what was selected.

      @param additional (optional)

        if ENTER_TEXT is selected, then this should be undefined.

        if SELECT_LIST is entered as type, then this should be an
        arrray of tuples.  The first element of each tuple should
        contain the text that gets displayed to the user next to the
        option.  The second element should contain a code that gets
        passed back to cb so that the scripter knows what was
        selected.  Code must be text.
      */
     std.core.SimpleInput = function(type, message, cb, additional)
     {
         if (!haveInited)
             throw new Error('Error.  GUI still initializing.  Please wait.');

         this.type       = type;
         this.message    = message;
         this.cb         = cb;
         this.additional = additional;

         if ((type == std.core.SimpleInput.SELECT_LIST) &&
             (typeof(this.additional) == 'undefined'))
         {
             throw new Error ('Error constructing SimpleInput.  If given ' +
                              'a list input, should be given additional '  +
                              'labels.');
         }

         this.indexUsed = addToKnownUsed(this);

         var callFunc = '';
         if (type == std.core.SimpleInput.SELECT_LIST)
             callFunc = 'simpleInputSelectList';
         else if (type == std.core.SimpleInput.ENTER_TEXT)
             callFunc = 'simpleInputSelectText';
         else
             throw new Error ('Error: please select a valid type ' +
                              'for SimpleInput');

         guiMod.call(callFunc,message,this.indexUsed,additional);
     };

     /*** Types of simple input to get  ***/
     //note: if add to any additional ones of these, then
     //must also add to if-else if statement in constructor
     //of SimpleInput
     std.core.SimpleInput.SELECT_LIST = 0;
     std.core.SimpleInput.ENTER_TEXT  = 1;

     std.core.SimpleInput.ready = function()
     {
         return haveInited;
     };

     /**
      We want to recycle the divs,etc. associ
      */
     function addToKnownUsed(simpleInputObject)
     {
         var indexToUse = null;
         for (var s in knownUsed)
         {
             if (knownUsed[s] == null)
             {
                 indexToUse = s;
                 break;
             }
         }

         //could not find empty index.  Create new element
         if (indexToUse == null)
         {
             knownUsed.push(null);
             indexToUse = knownUsed.length - 1;
         }
         knownUsed[indexToUse] = simpleInputObject;
         return indexToUse;
     }

     function getSimpleInputGUIText()
     {
         var returner = "sirikata.ui('" + SIMPLE_INPUT_MOD_NAME + "',";
         returner += 'function(){ ';

         returner += @

         var newcsslink =
             $("<link />").attr({rel:'stylesheet', type:'text/css', href:'../scripting/prompt.css'});
	 $("head").append(newcsslink);

         //keeps track of all open windows requiring input events.
         var existingWindows = { };

         function generateDivIDFromInputID(inputID)
         {
             return 'simpleInputID__' + inputID.toString();
         }

         function newWindow(htmlForWindow,simpleInputID)
         {
             var newWindowID = generateDivIDFromInputID(simpleInputID);
             $('
'   +
               htmlForWindow   +
               '
' //end div at top.
              ).attr({id:newWindowID,title:'simpleInput'}).appendTo('body');

             var inputWindow = new sirikata.ui.window(
                 '#' + newWindowID,
                 {
	             autoOpen: true,
	             height: 'auto',
	             width: 300,
                     height: 300,
                     position: 'right'
                 }
             );
             inputWindow.show();
             existingWindows[newWindowID] = [inputWindow,simpleInputID];
         }

         simpleInputSubmit = function(simpleInputID)
         {
             var returner = null;
             //first check to see if we got the value for a text element
             var textInputID = generateSimpleInputOptionID(simpleInputID);
             var textInput = $('#' + textInputID);
             if (textInput.length > 0)
             {
                 //means that we got a text input
                 returner =textInput.val();
             }
             else
             {
                 var radioInput = $('input:radio[name=' +
                                    textInputID +']:checked');
                 if (radioInput.length > 0)
                     returner = radioInput.val();
             }

             if (returner === null)
             {
                 sirikata.log('error','In simpleInput, selecting ' +
                              'an input that does not exist.');
             }
             else
             {
                 sirikata.event('responseReceived',simpleInputID,returner);
             }

             delete existingWindows[simpleInputID];
             //actually remove the window from view after its question has been answered.
             var inputID = generateDivIDFromInputID(simpleInputID);
             $('#'+inputID).remove();
         };

         function generateSubmitButtonHtml(simpleInputID)
         {
             var htmlToDisplay = '';
             htmlToDisplay += '<button ' +
                 'onclick="simpleInputSubmit(' + simpleInputID.toString() +
                 ')">';

             htmlToDisplay += 'Submit';
             htmlToDisplay += '</button>';

             return htmlToDisplay;
         }

         simpleInputSelectList =
             function(message,simpleInputID,additional)
         {
             var htmlInsert = message + '
';
             var radName = generateSimpleInputOptionID(simpleInputID);
             for (var s in additional)
             {
                 htmlInsert += '<input type=radio name="' +
                     radName + '" value="' + additional[s][1] +
                     '"></input>' + additional[s][0];
                 htmlInsert += '
';
             }
             htmlInsert += generateSubmitButtonHtml(simpleInputID);
             newWindow(htmlInsert,simpleInputID);
         };

         function generateSimpleInputOptionID(inputID)
         {
             return 'simpleInputIDOption__' + inputID.toString();
         }

         simpleInputSelectText = function(message,simpleInputID)
         {
             var htmlInsert = message + '
';
             htmlInsert += '<input id="'                      +
                 generateSimpleInputOptionID(simpleInputID)   +
                 '"></input>
';
             htmlInsert += generateSubmitButtonHtml(simpleInputID);
             newWindow(htmlInsert,simpleInputID);

             //handles enter submitting text
             var handleEnterHit = function(evt)
             {
                 //13 represents keycode for enter, submits whatever's in
                 //the text box if user hits enter.
                 if (evt.keyCode == 13)
                     simpleInputSubmit(simpleInputID);
             };

             //copied from chat.js
             var register_area = document.getElementById(
                 generateSimpleInputOptionID(simpleInputID));
             register_area.onkeyup = handleEnterHit;
         };
         @;

         returner += '});';
         return returner;
     }

 }
)();


Change dexter.em file for v0.10.4

Change dexter.em file for v0.10.4

/*
 **********************************************************************************************************************
 * Copyright (c) 2014 Samsung Electronics, Inc.,
 * 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.
 *
 * 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 HOLDER 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.
 * -------------------------------------------------------------------------------------------------------------------
 * Version : 0.10.4
 * -------------------------------------------------------------------------------------------------------------------
 * Add Key Assignments :
 *   - markDexterDefectToFalseAlarm() : to mark defect status as a false alarm  (async: 3~5 sec)
 *   - runDexterForCurrentFile() : to execute static anlaysis without eding and saving a file
 **********************************************************************************************************************
*/

// INITIALIZE GLOBAL VARIABLES
macro initDexterGlobalVariables()
{
	if(g_dexterConfig != "g_dexterConfig"){
		stop;
	}

	global g_dexterRunning;
	global g_dexterConfig;			// property for dexter configuration such as dexter home, src/header dirs, etc.
	global g_updateCount;			// current updated count for the statusbar
	global g_dexterInitialized;		// 1: initialized,  0: not initialized
	global g_maxUpdateCount;		// the count of the statusbar's update that used for checking the result of Dexter
	global g_dexterPrefix;			// Prefix string for tooltip of bookmark
	global g_lastFinished;			// last static analysis time(filename:long value)
	global g_showResultMsgDialog;	// 1: show,  0: hide
	global g_waitDexterResult;		// 1: wait(synchronously),  0: no wait(asynchronously)
	global g_analysisWhenOpen;		// 1: analysis when open, 0: not analysis when open a file(default)
	global g_functionList;
	global g_dexterPath;			// dexter daemon installation path

	g_dexterRunning = 1;
	g_maxUpdateCount = 6;
	g_updateCount = 0;
	g_dexterInitialized = 0;
	g_dexterPrefix = "[Dexter] ";
	g_lastFinished = "";
	g_showResultMsgDialog = 0;
	g_waitDexterResult = 0;
	g_analysisWhenOpen = 0;
	g_functionList = "";

	g_dexterConfig.sourceDirRegKey = "sourceDirRegKey"
	g_dexterConfig.headerDirRegKey = "headerDirRegKey"
	g_dexterConfig.dexterHomeRegKey = "dexterHomeRegKey"
	g_dexterConfig.dexterInstallationPathRegKey = "dexterInstallationPathRegKey"
	g_dexterConfig.sourceEncodingRegKey = "sourceEncodingRegKey"

	g_dexterRunning = GetReg("g_dexterRunning");
	if(g_dexterRunning == nil){
		g_dexterRunning = 1;
	}

	g_showResultMsgDialog = GetReg("g_showResultMsgDialog");
	if(g_showResultMsgDialog == nil){
		g_showResultMsgDialog = 0;
	}

	g_waitDexterResult = GetReg("g_waitDexterResult");
	if(g_waitDexterResult == nil){
		g_waitDexterResult = 0;
	}

	g_analysisWhenOpen = GetReg("g_analysisWhenOpen");
	if(g_analysisWhenOpen == nil){
		g_analysisWhenOpen = 0;
	}
}

//===================================================
// EVENTS
//===================================================
event AppStart()
{
	initDexter();
}

event AppShutdown()
{
	if(g_dexterConfig == "g_dexterConfig"){
		stop;
	}

	closeDexter();
}

event ProjectOpen(sProject)
{
	initDexter();

	g_dexterConfig.projectName = getCurrentProjectName();
	g_dexterConfig.sourceDir = "";
	g_dexterConfig.headerDir = "";

	SetReg(g_dexterConfig.sourceDirRegKey, "");
	SetReg(g_dexterConfig.headerDirRegKey, "")
}

event StatusbarUpdate(sMessage)
{
	if(g_dexterInitialized != 1){
		return;
	}
	if(g_dexterRunning != 1){
		return;
	}

	if(sMessage[0] != "L"){
		return;
	}

	addBookmarkToCurFile();
	g_updateCount = 0;
}
event DocumentOpen(sFile)
{
	if(g_dexterInitialized != 1 || g_dexterRunning != 1){
		stop;
	}

	if(g_analysisWhenOpen == 1){
		runDexter(sFile);
	}
	stop;
}

event DocumentSaveComplete(sFile) // synchronously
//event DocumentChanged(sFile)  // asynchronously
{

	runDexter(sFile);
	stop;
}

//===================================================
//  MACROS - INITIALIZE
//===================================================
macro initDexter()
{
	initDexterGlobalVariables();

	initDexterHome();
	if(g_dexterConfig.dexterHome == nil){
		error("g_dexterConfig.dexterHomeRegKey is null in initDexter()");
		stop;
	}

	g_dexterConfig.sourceEncoding = GetReg("sourceEncodingRegkey");
	if(g_dexterConfig.sourceEncoding == "nil" || g_dexterConfig.sourceEncoding == ""){
		g_dexterConfig.sourceEncoding = "UTF-8";
		SetReg("sourceEncodingRegkey", "UTF-8");
	}

	g_dexterConfig.sourceEncoding = GetReg(g_dexterConfig.sourceEncodingRegKey)

	g_dexterPath = GetReg(g_dexterConfig.dexterInstallationPathRegKey);
	if(g_dexterPath != nil && g_dexterPath != "g_dexterPath"){
		g_dexterDaemon = GetReg("g_dexterDaemon");
		if(g_dexterDaemon == nil || g_dexterDaemon == "g_dexterDaemon" || g_dexterDaemon == 0){
			RunCmdLine(g_dexterPath # "\\dexter.exe", g_dexterPath, 0);
		}
	} else {
		error("Dexter Initialized failed");
		Msg("You have to run Dexter Daemon first. If you didn't install, please install it first.");
		stop;
	}

	g_dexterConfig.sourceDir = GetReg(g_dexterConfig.sourceDirRegKey)
	g_dexterConfig.headerDir = GetReg(g_dexterConfig.headerDirRegKey)

	g_dexterInitialized = 1;
	info("Dexter Initialized successfully");

	//removeDexterConfigReg()  // use this for debugging
}

macro initDexterHome()
{
	g_dexterConfig.dexterHome = GetReg(g_dexterConfig.dexterHomeRegKey)
}

macro closeDexter()
{
	SetReg("g_showResultMsgDialog", g_showResultMsgDialog);
	SetReg("g_waitDexterResult", g_waitDexterResult);
	SetReg("g_dexterRunning", g_dexterRunning);
	SetReg("g_analysisWhenOpen", g_analysisWhenOpen);
	closeLogFile();
}

//===================================================
//  MAIN MACROS - for shortcuts
//===================================================
/* Run Static Analysis with using Dexter */
macro runDexterForCurrentFile()
{
	runDexter(getCurrentFilePath());
}

macro runDexter(sFile)
{
	checkAndStopDexterInitialize();

	if(sFile == nil || sFile == "sFile"){
		stop;
	}

	if(isSupportedFile(sFile) != 1){
		info("can't run dexter because the file is not supporting : " # sFile);
		stop;
	}

	if(sFile == nil || sFile == "sFile" || isSupportedFile(sFile) != 1 || g_dexterInitialized != 1){
		error("can't run dexter because dexter is not initialized : " # sFile);
		stop;
	}

	g_dexterDaemon = GetReg("g_dexterDaemon");
	if(g_dexterDaemon == nil || g_dexterDaemon == "g_dexterDaemon" || g_dexterDaemon == 0){
		RunCmdLine(g_dexterPath # "\\dexter.exe", g_dexterPath, 0);
	}

	saveModifiedFunctionList();
	createDexterConfFile();
}

/* Dexter HOME and Source Encoding Setting : User Asking */
macro setupDexter()
{
	checkAndStopDexterInitialize();

	if(g_dexterConfig.dexterHome == nil) {
		g_dexterConfig.dexterHome = Ask ("Enter Dexter Home Path (eg. C:\\dexter_1.0.3)")
		SetReg(g_dexterConfig.dexterHomeRegKey, g_dexterConfig.dexterHome);
	} else {
		while(1) {
			homeMsg = "Current Dexter home path is " # g_dexterConfig.dexterHome # ". Do you want change the path?  (Y:N)"
			StartMsg(homeMsg)
			answer = GetChar();
			EndMsg();

			if("Y" == toupper(answer)){
				g_dexterConfig.dexterHome = Ask("Enter Dexter Home Path (eg. C:\\dexter_v1.0.3). Previous value is " # g_dexterConfig.dexterHome)
				SetReg(g_dexterConfig.dexterHomeRegKey, g_dexterConfig.dexterHome);
				break;
			} else if("N" == toupper(answer)) {
				break;
			}
		}
	}

	if(g_dexterConfig.sourceEncoding == nil) {
		g_dexterConfig.sourceEncoding = Ask ("Enter source code encoding (eq. UTF-8)")
		// TODO : check encoding pattern
		SetReg(g_dexterConfig.sourceEncodingRegKey, g_dexterConfig.sourceEncoding)
	} else {
		while(1) {
			encodingMsg = "Current source code encoding is " # g_dexterConfig.sourceEncoding # ". Do you want change Encoding? (Y:N)"
			StartMsg(encodingMsg)
			answer = GetChar();
			EndMsg();

			if("Y" == toupper(answer)) {
				g_dexterConfig.sourceEncoding = Ask ("Enter source code encoding (eq. UTF-8)")
				// TODO : check encoding pattern
				SetReg(g_dexterConfig.sourceEncodingRegKey, g_dexterConfig.sourceEncoding)
				break;
			} else if("N" == toupper(answer)) {
				break;
			}
		}
	}
}

/* Set Source directory */
macro setDexterSourceDir()
{
	checkAndStopDexterInitialize();

	g_dexterConfig.sourceDir = GetReg(g_dexterConfig.sourceDirRegKey)
	g_dexterConfig.headerDir = GetReg(g_dexterConfig.headerDirRegKey)

	ynErrorMsg = "Error: You can enter only 'Y' or 'N'. Macro will be terminated."

	enterMsg = "Enter source directory (eq. C:\\Prj\\src)"
	if(g_dexterConfig.sourceDir == nil) {
		g_dexterConfig.sourceDir = Ask (enterMsg)
		SetReg(g_dexterConfig.sourceDirRegKey, g_dexterConfig.sourceDir)
	} else {
		while(1) {
			qMsg = "Current source directory is " # g_dexterConfig.sourceDir # ". Do you want change Directory? (Y:N)"
			StartMsg(qMsg)
			answer = GetChar();
			EndMsg();

			if("Y" == toupper(answer)) {
				g_dexterConfig.sourceDir = Ask (enterMsg)
				SetReg(g_dexterConfig.sourceDirRegKey, g_dexterConfig.sourceDir)
				break;
			} else if("N" == toupper(answer)) {
				break;
			}
		}
	}
}

/* Set Header directory */
macro setDexterHeaderDir()
{
	checkAndStopDexterInitialize();

	g_dexterConfig.headerDir = GetReg(g_dexterConfig.headerDirRegKey)

	ynErrorMsg = "Error: You can enter only 'Y' or 'N'. Macro will be terminated."

	enterMsg = "Enter header file directory, if you have (eq. C:\\Prj\\inc)"
	qMsg = "none";
	if(g_dexterConfig.headerDir == nil) {
		qMsg = "No header file directory is registered. Do you want add Directory? (Y:N)"
	} else {
		qMsg = "Current header directory is " # g_dexterConfig.headerDir # ". Do you want change Directory? (Y:N:D to delete)"
	}

	while(1) {
		StartMsg(qMsg)
		answer = GetChar();
		EndMsg();

		if("Y" == toupper(answer)) {
			g_dexterConfig.headerDir = Ask (enterMsg)
			SetReg(g_dexterConfig.headerDirRegKey, g_dexterConfig.headerDir)
			break;
		} else if("D" == toupper(answer)) {
			g_dexterConfig.headerDir = ""
			SetReg(g_dexterConfig.headerDirRegKey, "")
			break;
		} else if("N" == toupper(answer)) {
			break;
		}
	}
}

macro toggleShowDexterMsgDialog()
{
	if(g_showResultMsgDialog == 0){
		g_showResultMsgDialog = 1;
		Msg("Dexter Result Message Dialog : ON");
	} else {
		g_showResultMsgDialog = 0;
		Msg("Dexter Result Message Dialog : OFF");
	}

	stop;
}

macro toggleWaitForDexterResult()
{
	if(g_waitDexterResult == 0){
		g_waitDexterResult = 1;
		Msg("Waiting Dexter Result(Sync) : ON");
	} else {
		g_waitDexterResult = 0;
		Msg("Waiting Dexter Result(Sync) : OFF");
	}

	stop;
}

macro toggleDexterRunning()
{
	if(g_DexterRunning == 0){
		g_DexterRunning = 1;
		Msg("Dexter Static Analysis : ON");
	} else {
		g_DexterRunning = 0;
		Msg("Dexter Static Analysis : OFF");
	}

	stop;
}

macro toggleAnalysisWhenOpen()
{
	if(g_analysisWhenOpen== 0){
		g_analysisWhenOpen= 1;
		Msg("Dexter Static Analysis When opening a file : ON");
	} else {
		g_waitDexterResult = 0;
		Msg("Dexter Static Analysis When opening a file : OFF");
	}

	stop;
}

macro markDexterDefectToFalseAlarm()
{
	checkAndStopDexterInitialize();

	if(g_dexterInitialized != 1){
		stop;
	}

	var hResultFile;
	var resultFilePath;
	var lineStr;
	var resultCount;

	resultFilePath = getResultFilePathForCurrentFile();
	if(resultFilePath == nil || resultFilePath == ""){
		stop;
	}

	hResultFile = OpenBuf(resultFilePath);
	if(hResultFile == hNil){
		error("there is no result file to dismiss : " # resultFilePath);
		stop;
	}
	resultCount = GetBufLineCount(hResultFile) - 1;
	if(resultCount <= 0){
		warn("there is no defect info");
		CloseBuf(hResultFile);
		stop;
	}

	var hCurFile;
	hCurFile = GetCurrentBuf();
	if(hCurFile == hNil){
		Msg("there is no open/target file");
		stop;
	}

	var curLine;
	curLine = GetBufLnCur(hCurFile) + 1;

	if(curLine <= 0){
		warn("invalid current line number : " # curLine);
		stop;
	}
	var defect;
	var answer;
	while(--resultCount >= 0){
		lineStr = GetBufLine(hResultFile, resultCount);
		defect = splitDefectMessage(lineStr);

		if(defect.line == curLine){
			while(1){
				StartMsg("Do you want to mark the defect as FALSE ALARM? (Y : N) "
					# defect.checkerCode # defect.line);
				answer = GetChar();
				EndMsg();

				if(answer == "Y" || answer == "y"){
					createDefectFilterFile(defect, hCurFile, curLine);
					removeBookmark(defect);
					DelBufLine(hResultFile, resultCount);
					SetBufDirty(hResultFile, True);
					SaveBuf(hResultFile);
					SetBufDirty(hResultFile, True);
					break;
				} else if(answer == "N" || answer == "n"){
					break;
				}
			}
		}
	}
	CloseBuf(hResultFile);
}

//===================================================
//  SUB MACROS - not for shortcuts
//===================================================
macro createDexterConfFile()
{
	if(g_dexterInitialized != 1){
		stop;
	}

	// project handle
	var hprj;
	var projDir;
	var hFile;

	hprj = GetCurrentProj();
	projDir = GetProjDir(hprj);
	hFile = GetCurrentBuf();
	if(hFile == hNil){
		Msg("There is no open/target file to analyze");
		stop;
	}

	var resultFileFullPath;
	resultFileFullPath = getResultFilePathForCurrentFile();

	if(resultFileFullPath == nil || resultFileFullPath == ""){
		Msg("can't make result file full path in createDexterConfFile()");
		stop;
	}

	var hConfbuf;
	var confFile;
	var requestTime;
	var contents;
	var functionList;
	initDexterHome();
	confFile = g_dexterConfig.dexterHome # "\\bin\\daemon\\dexter_daemon_cfg.json"
	hConfbuf = OpenBuf(confFile);

	if(hConfbuf == hNil){
		hConfbuf = NewBuf(confFile);
		if(hConfbuf == hNil){
			Msg("Invalid Dexter configuration file(Open Error) : " # confFile);
			stop;
		}
	}
	requestTime = getCurrentTimeString();

	contents = "{";
	contents = contents # "\t\"requestTime\":\"" # requestTime # "\",";
	contents = contents # "\t\"resultFileFullPath\":\"" # resultFileFullPath # "\",";
	contents = contents # "\t\"projectName\":\"" # getCurrentProjectName() # "\",";
	contents = contents # "\t\"projectFullPath\":\"" # projDir # "\",";
	contents = contents # "\t\"sourceEncoding\":\"" # g_dexterConfig.sourceEncoding # "\",";

	if(g_dexterConfig.sourceDir == nil || g_dexterConfig.sourceDir == ""){
//		contents = contents # "\t\"sourceDir\":[],";
	} else {
		contents = contents # "\t\"sourceDir\":[\"" # g_dexterConfig.sourceDir # "\"],";
	}

	if(g_dexterConfig.headerDir == nil || g_dexterConfig.headerDir == ""){
		contents = contents # "\t\"headerDir\":[],";
	} else {
		contents = contents # "\t\"headerDir\":[\"" # g_dexterConfig.headerDir # "\"],";
	}

	contents = contents # "\t\"fileName\":[\"" # GetBufName(hFile) # "\"],";
	contents = contents # "\t\"type\":\"FILE\",";
	contents = contents # "\t\"functionList\":[" # g_functionList # "]";
	contents = contents # "}";

	emptyFileContent(hConfbuf, 0);
	AppendBufLine(hConfbuf, contents);
	SaveBuf(hConfbuf);
	CloseBuf(hConfbuf);
}
macro saveModifiedFunctionList(){

	var firstRevisionLine;
	var changeCount;
	var functionName;
	var curSymbol;

	hwnd = GetCurrentWnd();
	hbuf = GetCurrentBuf();

	currentLine  = 0;

	changeCount = 0;
	firstRevisionLine = 0;

	g_functionList= "";
	currentLn = GetWndSelLnFirst (hwnd);
	currentIch =GetWndSelIchFirst(hwnd);
	vert = GetWndVertScroll (hwnd);
	wndsel = GetWndSel(hwnd);
	//msg();
	while(1){

		Go_To_Next_Change;
		if(changeCount == 0){
			firstRevisionLine = GetBufLnCur(hbuf);
		}else if( isNavigatedLine(hbuf,changeCount,firstRevisionLine) == true){
			break;
		}
		changeCount = changeCount +1;

		curSymbol = GetCurSymbol();
		symbolLocation = GetSymbolLocation(curSymbol);
		if( symbolLocation == "" ){

		}else if(symbolLocation.Type == "Function" || symbolLocation.Type == "Method"){
			functionName = SymbolLeafName(symbolLocation);

			addFunctionNameIfNotExist(functionName);
		}
	}
	if(g_functionList !=""){
	g_functionList = strtrunc(g_functionList,strlen(g_functionList)-1);
	}
	SetBufIns(hbuf,currentLn,currentIch);
	ScrollWndToLine(hwnd,vert);

}
macro isNavigatedLine(hbuf, count,firstRevisionLine){

	var currentLine;
	currentLine = GetBufLnCur(hbuf);
	if(count>=1 && currentLine == firstRevisionLine){
		return true;
	}
	return false;

}
macro addFunctionNameIfNotExist(functionName){
	var index;
	var functionListLength;
	var compareFunctionName;
	var frontIndex;
	var backIndex;

	index = 0;
	frontIndex = 0;
	backIndex = 0;
	functionListLength = strlen(g_functionList);

	while(index<functionListLength){
		if(g_functionList[index] == ","){
				backIndex = index;
				compareFunctionName = strmid(g_functionList,frontIndex+1,backIndex-1);
				if(compareFunctionName == functionName){
				return;
				}
			frontIndex = index +1;
		}
		index = index +1;
	}

	g_functionList = g_functionList # "\"" #  functionName # "\"" # ",";

}

macro createPlatzKeywordFile()
{
	if(g_dexterInitialized != 1){
		stop;
	}
	var keyword;
	var hFile;

	hFile = GetCurrentBuf();
	if(hFile == hNil){
		Msg("There is no open/target File to search");
		stop;
	}
	keyword = GetKeywordFromCurrentLine(hFile);
	if(keyword == nil){
		Msg("There is no target keyword to search. Please move your insertion cursor and restart search macro");
		stop;
	}

	var hKeywordBuf;
	var keywordFile;
	var requestTime;
	var contents;

	initDexterHome();
	keywordFile = g_dexterConfig.dexterHome # "\\bin\\daemon\\platz_keyword.json"
	hKeywordBuf = OpenBuf(keywordFile);

	if(hKeywordBuf == hNil){
		hKeywordBuf = NewBuf(keywordFile);
		if(hKeywordBuf == hNil){
			Msg("Invalid Platz Keyword file(Open Error) : " # keywordFile);
			stop;
		}
	}
	requestTime = getCurrentTimeString();

	contents = "{";
	contents = contents # "\t\"keyword\":\"" # keyword # "\"";
	contents = contents # "}";
	emptyFileContent(hKeywordBuf, 0);
	AppendBufLine(hKeywordBuf, contents);
	SaveBuf(hKeywordBuf);
	CloseBuf(hKeywordBuf);
}

macro GetKeywordFromCurrentLine(hbuf)
{
	var currentCursorIndex;
	var current
	var index;
	var currentLineNumber;
	var currentLineText;
	var firstCharIndex;
	var lastCharIndex;
	var keyword;

	hwnd = GetCurrentWnd();
	currentLineNumber = GetWndSelLnFirst(hwnd);
	currentLineText = GetBufLine(hbuf,currentLineNumber);
	currentCursorIndex = GetWndSelIchFirst(hwnd);
	index = currentCursorIndex;

	if(checkAllowedChar(currentLineText[index]) == 0){
		msg("[Dexter] You have to move your cursor on a character.");
		stop;
	}

	firstCharIndex = index;
	while(index--){
		if(checkAllowedChar(currentLineText[index]) == 0){
			firstCharIndex = index+1;
			break;
		}
	}

	index = currentCursorIndex;
	lastCharIndex = index;
	while(index++){
		if(checkAllowedChar(currentLineText[index]) == 0){
			lastCharIndex = index-1;
			break;
		}
	}

	keyword = strmid(currentLineText,firstCharIndex,lastCharIndex+1);
	return keyword;

}

macro checkAllowedChar(char){
	var asciiNum;
	if(char ==Nil){
		return 0;
	}
	asciiNum  =  AsciiFromChar(char);
	if(asciiNum == 95 || asciiNum == 36){
		return 1;
	}
	if(asciiNum >= 65 && asciiNum <=90){

		return 1;
	}
	if(asciiNum >=97 && asciiNum <=122){
		return 1;
	}
	if(asciiNum >=48 && asciiNum <=57){
		return 1;
	}
	return 0;

}

macro createDefectFilterFile(defect, hFile, curLine)
{
	var hFilterBuf;
	var filterFile;

	initDexterHome();
	filterFile = g_dexterConfig.dexterHome # "\\filter\\defect-filter.json"

	hFilterBuf = OpenBuf(filterFile);

	if(hFilterBuf == hNil){
		hFilterBuf = NewBuf(filterFile);
		if(hFilterBuf == hNil){
			debug("Invalid Dexter filter file(Open/Create Error) : " # filterFile);
			stop;
		}
	}

	if(!isBufRW(hFilterBuf)){
		debug("buf cannot read write");
		emptyFileContent(hFilterBuf, 1);
	}

	var filterContent;
	filterContent = "{";
	filterContent = filterContent # "\t\"fid\":0,";
	filterContent = filterContent # "\t\"isActive\":true,";
	filterContent = filterContent # "\t\"checkerCode\":\"" # defect.checkerCode # "\",";
	filterContent = filterContent # "\t\"className\":\"" # defect.className # "\",";
	filterContent = filterContent # "\t\"methodName\":\"" # defect.methodName # "\",";
	filterContent = filterContent # "\t\"toolName\":\"" # defect.toolName # "\",";
	filterContent = filterContent # "\t\"language\":\"" # defect.language # "\",";
	filterContent = filterContent # "\t\"modulePath\":\"" # defect.modulePath # "\",";
	filterContent = filterContent # "\t\"fileName\":\"" # getCurrentFileName() # "\",";
	filterContent = filterContent # "\t\"line\":\"" # curLine # "\"";
	filterContent = filterContent # "}";

	AppendBufLine(hFilterBuf, filterContent);
	SaveBuf(hFilterBuf);
 	CloseBuf(hFilterBuf);
}

macro isSupportedFile(sFile)
{
	length = strlen(sFile) ;
    bPt = length - 3;
    ePt = length;

    if(bPt < 0 || ePt < 0 || bPt > length || ePt > length){
    	return 0;
    }
	ext1 = tolower(strmid(sFile, bPt, ePt));

	length = strlen(sFile);
   	bPt = length - 1;
   	ePt = length;

    if(bPt < 0 || ePt < 0 || bPt > length || ePt > length){
    	return 0;
    }
   	ext2 = tolower(strmid(sFile, bPt, ePt));

	if(ext1 != "cpp" && ext1 != "hpp" && ext2 != "c" && ext2 != "h")
	{
		return 0;
	}

	return 1;
}

/* for Debugging */
macro removeDexterConfigReg()
{
	g_dexterConfig.dexterHome = ""
	g_dexterConfig.sourceEncoding = ""
	g_dexterConfig.sourceDir = ""
	g_dexterConfig.headerDir = ""

	SetReg("dexterHomeRegKey", "")
	SetReg("headerDirRegKey", "")
	SetReg("sourceDirRegKey", "")
	SetReg("sourceEncodingRegKey", "")

	stop;
}

/* Return resultFileFullPath for current file. If error, return nil */
macro getResultFilePathForCurrentFile()
{
	checkAndStopDexterInitialize();

	var resultFolder;
	var hprj;
	var prjDir;
	var prjName;
	var hFile;
	var fileName;
	var bP;
	var eP;
	var fLength;
	var filePathFromPrj;

	resultFolder = g_dexterConfig.dexterHome # "\\result\\daemon\\";

	hprj = GetCurrentProj ();
	if(hprj == hNil){
		return nil;
	}

	prjDir = GetProjDir(hprj);
	prjName = GetCurrentProjectName();
	hFile = GetCurrentBuf();

	if(hFile == hNil){
		Msg("cann't open current file to created result file path");
		return nil;
		Stop;
	}

	fileName = GetBufName(hFile);

	// for v1.11
	eP = strlen(fileName);
	if(hasPrefix(fileName, prjDir) == 0 && eP > 3){
		if(fileName[1] == ":"){
			bP = 3;
			filePathFromPrj = strmid(fileName, bP, eP);
			return resultFolder # filePathFromPrj;
		} else {
			return resultFolder # fileName;
		}
	} else {
		bP = strlen(prjDir);
		fLength = eP;
		if(bP < 0 || eP < 0 || bP > fLength || eP > fLength){
			if(fileName[1] == ":"){
				bP = 3;
				filePathFromPrj = strmid(fileName, bP, eP);
				return resultFolder # filePathFromPrj;
			} else {
				return resultFolder # fileName;
			}
		} else {
			filePathFromPrj = strmid(fileName, bP, eP);
			filePathFromPrj = prjName # filePathFromPrj;
			return resultFolder # filePathFromPrj;
		}
	}
}

macro addBookmarkToCurFile()
{
	checkAndStopDexterInitialize();
	initDexterHome();

	var resultFilePath;
	var hResultFile;
	var currentFilePath;

	resultFilePath = getResultFilePathForCurrentFile();

	if(resultFilePath == nil || resultFilePath == ""){
		return;
	}

	hResultFile = OpenBuf(resultFilePath);
	if(hResultFile != hNil){
		// 2. check if analysis is over
		var errorCount;
		var endLineStr;
		errorCount = GetBufLineCount(hResultFile) - 1; // errorCount -1 : because the last line is for "E|" message

		endLineStr = GetBufLine(hResultFile, errorCount);

		if(endLineStr[0] != "E" || g_lastFinished == endLineStr){
			CloseBuf(hResultFile);
			stop;
		}
		g_lastFinished = endLineStr;

		// 3. remove old bookmarks and add new bookmarks for defects
		var hBuf;
		hBuf = GetCurrentBuf();
		if(hBuf != hNil && IsBufRW(hBuf) == False){ // read only file
			Msg("[Dexter] Cannot add bookmark(s) of defects into the current file due to read-only state.");
			stop;
		}

		removeAllDexterBookmarkForCurrentFile();
		currentFilePath = getCurrentFilePath();
		addDexterBookmarks(hResultFile, errorCount, currentFilePath);
		CloseBuf(hResultFile);
		stop;
	}
}

macro removeAllDexterBookmarkForCurrentFile()
{
	debug("S:removeAllDexterBookmarksForCurrentFile");
	var count;
	var index;
	var bookmark;
	var fileName;

	fileName = getCurrentFilePath();

	count = BookmarksCount();
	index = 0;
	while(index < count){
		bookmark = BookmarksItem(index);

		if(bookmark.File == fileName && hasPrefix(bookmark.Name, g_dexterPrefix) == 1){
			BookmarksDelete(bookmark.Name);
			count = BookmarksCount();
		} else {
			index++;
		}
	}
	debug("E:removeAllDexterBookmarksForCurrentFile");
}

macro removeBookmark(defect)
{
	var defectMsg;
	defectMsg = createDefectMessage(defect);
	BookmarksDelete(defectMsg);
}

macro addDexterBookmarks(hResultFile, errorCount, currentFileName)
{
	debug("S:addDexterBookmarks");
	var lineMsg;
	var lineStr;
	var defect;
	var totalErrorCount;
	totalErrorCount = errorCount;

	lineMsg = "";

	while(--errorCount >= 0){
		lineStr = GetBufLine(hResultFile, errorCount);
		defect = splitDefectMessage(lineStr);

		if(defect.fail != 1){
			var defectMsg;
			defectMsg = createDefectMessage(defect);

			if(defect.line <= 0){
				BookmarksAdd(defectMsg, currentFileName, 1, 1);
			} else {
				BookmarksAdd(defectMsg, currentFileName, defect.line-1, 1);
			}

			lineMsg = lineMsg # defect.line # " ";
		}
	}

	if(g_showResultMsgDialog == 1) {
		if(totalErrorCount > 0){
			Msg("[Dexter Result] You have " # totalErrorCount # " defect(s) in " # currentFileName # " file. Line(s): " # lineMsg);
		} else {
			Msg("[Dexter Result] You have no defects in " # currentFileName # " file.";
		}
	}

	debug("E:addDexterBookmarks");
	stop;
}

macro createDefectMessage(defect)
{
	var defectMsg;
	defectMsg = g_dexterPrefix # defect.fileName # ":" # defect.severityCode # ":"
# defect.checkerCode # ":" # defect.line # ":" # " " # defect.message;

	return defectMsg;
}

macro splitDefectMessage(message)
{
	var defect;
	var size;

	size = strlen(message);
	if(message == nil || size == 0){
		defect.fail = 1;
		return defect;
	}

	var index;
	var foundColon;
	var curColumn;

	index = 0;
	foundColon = 0;

	defect.line = "";
	defect.checkerCode = "";
	defect.toolName = "";
	defect.language = "";
	defect.modulePath = "";
	defect.fileName = "";
	defect.className = "";
	defect.methodName = "";
	defect.severityCode = "";
	defect.message = "";

	curColumn = 0;
	while(index < size){
		if(message[index] == ":"){
			curColumn ++;
			foundColon = 1;
			index++;
		}

		if(message[index] == ":"){
			continue;
		}

		if(curColumn == 0){
			defect.line = defect.line # message[index];
		} else if(curColumn == 1){
			defect.checkerCode = defect.CheckerCode # message[index];
		} else if(curColumn == 2){
			defect.toolName = defect.toolName # message[index];
		} else if(curColumn == 3){
			defect.language = defect.language # message[index];
		} else if(curColumn == 4){
			defect.modulePath = defect.modulePath # message[index];
		} else if(curColumn == 5){
			defect.fileName = defect.fileName # message[index];
		} else if(curColumn == 6){
			defect.className = defect.className # message[index];
		} else if(curColumn == 7){
			defect.methodName = defect.methodName # message[index];
		} else if(curColumn == 8){
			defect.severityCode = defect.severityCode # message[index];
		} else {
			length = strlen(message);
			if(index > length){
				defect.message = "";
			} else {
				defect.message = strmid(message,index, length);
			}
			break;
		}

		index++;
	}

	if(foundColon == 0){
		defect.fail = 1;
		return defect;
	}

	defect.fail = 0;
	return defect;
}

macro addDefectBookmarkSync()
{
   	var tryCount;
   	var loopCount;

   	tryCount = 500;

    while(--tryCount > 0)
    {
    	addBookmarkToCurFile();

		// waiting...
	    loopCount = 10000;
    	while(loopCount-- > 0){	}
    }

    stop;
}

macro checkAndStopDexterInitialize()
{
	if(g_dexterConfig == nil || g_dexterConfig == "g_dexterConfig"){
		Msg("You have to enable the feature 'Event Handling', then rerun Source Insight: 'Menu > Options > Preferences > General > Enablie event handlers' option. If you enabled, please just rerun Source Insight, again");
		stop;
	}
}

//===================================================
// UTILITIES
//===================================================
macro getCurrentFilePath()
{
	var hBuf;

	hBuf = GetCurrentBuf();
	if(hBuf == hNil){
		return "";
	} else {
		return GetBufName(hBuf);
	}
}

/* return only current file name without path information */
macro getCurrentFileName()
{
	var curFilePath;
	var reverseName;
	var length;
	var fileName;

	curFilePath = getCurrentFilePath();
	if(curFilePath == nil || curFilePath == ""){
		return "";
	}

	fileName = "";
	reverseName = "";
	length = strlen(curFilePath);
	index = length;

	while(--index >= 0){
		if(curFilePath[index] == "\\"){
			break;
		} else {
			reverseName = reverseName # curFilePath[index];
		}
	}

	length = strlen(reverseName);
	index = length;
	while(--index >= 0){
		fileName = fileName # reverseName[index];
	}

	return fileName;
}

/* Return yyyyMMddhhmmssSSS */
macro getCurrentTimeString()
{
	var now;
	var nowStr;

	now = GetSysTime(0);

	nowStr = now.Year;

	nowStr = addZeroForDate(nowStr, now.Month);
	nowStr = addZeroForDate(nowStr, now.Day);
	nowStr = addZeroForDate(nowStr, now.Hour);
	nowStr = addZeroForDate(nowStr, now.Minute);
	nowStr = addZeroForDate(nowStr, now.Second);
	nowStr = addZeroForTreeDigits(nowStr, now.Milliseconds);

	return nowStr;
}

/* Return yyyyMMdd */
macro getCurrentDateString()
{
	var now;
	var nowStr;

	now = GetSysTime(0);

	nowStr = now.Year;

	nowStr = addZeroForDate(nowStr, now.Month);
	nowStr = addZeroForDate(nowStr, now.Day);

	return nowStr;
}

macro addZeroForDate(baseStr, newStr)
{
	if(newStr < 10){
		baseStr = baseStr # "0" # newStr;
	} else {
		baseStr = baseStr # newStr;
	}

	return baseStr;
}

macro addZeroForTreeDigits(baseStr, newStr)
{
	if(newStr >= 0 && newStr < 10){
		baseStr = baseStr # "0" # newStr;
	} else if(newStr >= 10 && newStr < 100){
		baseStr = baseStr # "00" # newStr;
	} else {
		baseStr = baseStr # newStr;
	}

	return baseStr;
}

/* this macro exists because built-in ClearBuf() doesn't work well */
macro emptyFileContent(hBuf, isSave)
{
	if(hBuf != hNil){
		line = GetBufLineCount(hBuf);

		while(--line >= 0){
			DelBufLine(hBuf, line);
		}

		ClearBuf(hBuf);

		if(isSave == 1){
			SaveBuf(hBuf);
		}
	}
}

/* If has searchStr, return 1, or return 0 */
macro hasPrefix(baseStr, searchStr)
{
	size = strlen(searchStr);

	index = 0;
	while(index < size){
		if(baseStr[index] != searchStr[index]){
			return 0;
		}

		index++;
	}

	return 1;
}

/* return only current project name without path information */
macro getCurrentProjectName()
{
	var hprj;
	var prjName;

	hprj = GetCurrentProj();
	if(hprj == hNil){
		return "";
	}

	prjName = GetProjName(hprj);

	var index;
	index = strlen(prjName);

	var reverseName;

	while(--index >= 0)
	{
		if(prjName[index] == "\\"){
			break;
		} else {
			reverseName = reverseName # prjName[index];
		}
	}

	var onlyProjectName;

	index = strlen(reverseName);
	while(--index >= 0){
		onlyProjectName = onlyProjectName # reverseName[index];
	}

	return onlyProjectName;
}

macro error(s)
{
	log("[E]", s);
}

macro warn(s)
{
	log("[W]", s);
}

macro info(s)
{
	log("[I]", s);
}

macro debug(s)
{
	log("[D]", s);
}

macro log(prefix, s)
{
	/*
	checkAndStopDexterInitialize();

	var hLogBuf;
	var sLogFile;

	sLogFile = g_dexterConfig.dexterHome # "\\log\\sourceinsight.log";
	hLogBuf = GetBufHandle(sLogFile)

	if(hLogBuf == hNil){
		hLogBuf = OpenBuf(sLogFile);
		if(hLogBuf == hNil){
			return;
		}
	}

	AppendBufLine(hLogBuf, prefix # " " # getCurrentTimeString() # " : " # s);
	SaveBuf(hLogBuf);
	*/
}

macro closeLogFile()
{
	sLogFile = g_dexterConfig.dexterHome # "\\log\\sourceinsight.log";
	hLogBuf = GetBufHandle(sLogFile)

	if(hLogBuf != hNil){
		CloseBuf(hLogBuf);
	}
}


remove copy-n-paste obsolete parts of the template

Signed-off-by: Mikael Arguedas <a16f295d1139a1392bb19262902c32cf3e999ce4@gmail.com>

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
))@
ARG FROM_IMAGE=@base_image
FROM $FROM_IMAGE
@(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 [],
))@

@(TEMPLATE(
    'snippet/setup_ros_sources.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
    ros2distro_name='rolling',
    rosdistro_name='',
    ros_version=ros_version,
    testing_repo=True,
))@

@(TEMPLATE(
    'snippet/install_ros_bootstrap_tools.Dockerfile.em',
    ros_version=ros_version,
))@

# setup environment
ENV ROS_DISTRO @ros2distro_name
@[if 'env_before' in locals()]@
@[  for env_var, env_val in env_before.items()]@
ENV @(env_var) @(env_val)
@[  end for]@

@[end if]@
@[if 'ros2_repo_packages' in locals()]@
@[  if ros2_repo_packages]@
# install packages from the ROS repositories
RUN apt-get update && apt-get install -y --no-install-recommends \
    @(' \\\n    '.join(sorted(ros2_repo_packages)))@  \
    && rm -rf /var/lib/apt/lists/*

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

@[  end if]@
@[end if]@
# bootstrap rosdep
@[if 'rosdep' in locals()]@
@[  if 'rosdistro_index_url' in rosdep]@
ENV ROSDISTRO_INDEX_URL @(rosdep['rosdistro_index_url'])
@[  end if]@
@[end if]@
RUN rosdep init \
    && rosdep update --rosdistro $ROS_DISTRO

@(TEMPLATE(
    'snippet/setup_colcon_mixin_metadata.Dockerfile.em',
))@

@[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,
))@
ARG FROM_IMAGE=@base_image
FROM $FROM_IMAGE
@(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 [],
))@

@(TEMPLATE(
    'snippet/setup_ros_sources.Dockerfile.em',
    os_name=os_name,
    os_code_name=os_code_name,
    ros2distro_name='rolling',
    rosdistro_name='',
    ros_version=ros_version,
    testing_repo=True,
))@

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

@(TEMPLATE(
    'snippet/install_ros_bootstrap_tools.Dockerfile.em',
    ros_version=ros_version,
))@

@[if 'ros2_repo_packages' in locals()]@
@[  if ros2_repo_packages]@
# install packages from the ROS repositories
RUN apt-get update && apt-get install -y --no-install-recommends \
    @(' \\\n    '.join(sorted(ros2_repo_packages)))@  \
    && rm -rf /var/lib/apt/lists/*

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

@[  end if]@
@[end if]@
@(TEMPLATE(
    'snippet/check_pytest_regression.Dockerfile.em',
))@
@
# bootstrap rosdep
@[if 'rosdep' in locals()]@
@[  if 'rosdistro_index_url' in rosdep]@
ENV ROSDISTRO_INDEX_URL @(rosdep['rosdistro_index_url'])
@[  end if]@
@[end if]@
RUN rosdep init \
    && rosdep update

@(TEMPLATE(
    'snippet/setup_colcon_mixin_metadata.Dockerfile.em',
))@

@[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))"]


Moving ros distro EVN to preserve more cache ros images will be able to share additional layers (about 90MB)

@(TEMPLATE(
    'snippet/add_generated_comment.Dockerfile.em',
    user_name=user_name,
    tag_name=tag_name,
    source_template_name=template_name,
    now_str=now_str,
))@
@(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 Dirk Thomas dthomas+buildfarm@@osrfoundation.org

# setup environment
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
@[if 'packages' in locals()]@
@[if packages]@

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

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

# setup keys
RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys 421C365BD9FF1F717815A3895523BAEEB01FA116

# setup sources.list
RUN echo "deb http://packages.ros.org/ros/@os_name @os_code_name main" > /etc/apt/sources.list.d/ros-latest.list

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

# bootstrap rosdep
RUN rosdep init \
    && rosdep update

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

# setup entrypoint
COPY ./ros_entrypoint.sh /

@[if 'entrypoint_name' in locals()]@
@[if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
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,
    now_str=now_str,
))@
@(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 Dirk Thomas dthomas+buildfarm@@osrfoundation.org

# setup environment
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8
@[if 'packages' in locals()]@
@[if packages]@

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

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

# setup keys
RUN apt-key adv --keyserver ha.pool.sks-keyservers.net --recv-keys 421C365BD9FF1F717815A3895523BAEEB01FA116

# setup sources.list
RUN echo "deb http://packages.ros.org/ros/@os_name @os_code_name main" > /etc/apt/sources.list.d/ros-latest.list

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

# bootstrap rosdep
RUN rosdep init \
    && rosdep update

# install ros packages
RUN apt-get update && apt-get install -y \
    @(' \\\n    '.join(ros_packages))@  \
    && rm -rf /var/lib/apt/lists/*

# setup entrypoint
COPY ./ros_entrypoint.sh /

@[if 'entrypoint_name' in locals()]@
@[if entrypoint_name]@
@{
entrypoint_file = entrypoint_name.split('/')[-1]
}@
ENTRYPOINT ["/@entrypoint_file"]
@[end if]@
@[end if]@
@{
cmds = [
'bash',
]
}@
CMD ["@(' && '.join(cmds))"]