text:
# Julia wrapper for header: /opt/ros/bouncy/include/rcutils/allocator.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function rcutils_get_zero_initialized_allocator()
    ccall((:rcutils_get_zero_initialized_allocator, librcutils), rcutils_allocator_t, ())
end

function rcutils_get_default_allocator()
    ccall((:rcutils_get_default_allocator, librcutils), rcutils_allocator_t, ())
end

function rcutils_allocator_is_valid(allocator)
    ccall((:rcutils_allocator_is_valid, librcutils), Bool, (Ptr{rcutils_allocator_t},), allocator)
end

function rcutils_reallocf(pointer, size::Csize_t, allocator)
    ccall((:rcutils_reallocf, librcutils), Ptr{Cvoid}, (Ptr{Cvoid}, Csize_t, Ptr{rcutils_allocator_t}), pointer, size, allocator)
end
# Julia wrapper for header: /opt/ros/bouncy/include/rcutils/error_handling.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function rcutils_get_zero_initialized_allocator()
    ccall((:rcutils_get_zero_initialized_allocator, librcutils), rcutils_allocator_t, ())
end

function rcutils_get_default_allocator()
    ccall((:rcutils_get_default_allocator, librcutils), rcutils_allocator_t, ())
end

function rcutils_allocator_is_valid(allocator)
    ccall((:rcutils_allocator_is_valid, librcutils), Bool, (Ptr{rcutils_allocator_t},), allocator)
end

function rcutils_reallocf(pointer, size::Csize_t, allocator)
    ccall((:rcutils_reallocf, librcutils), Ptr{Cvoid}, (Ptr{Cvoid}, Csize_t, Ptr{rcutils_allocator_t}), pointer, size, allocator)
end

function rcutils_error_state_copy(src, dst)
    ccall((:rcutils_error_state_copy, librcutils), rcutils_ret_t, (Ptr{rcutils_error_state_t}, Ptr{rcutils_error_state_t}), src, dst)
end

function rcutils_error_state_fini(error_state)
    ccall((:rcutils_error_state_fini, librcutils), Cvoid, (Ptr{rcutils_error_state_t},), error_state)
end

function rcutils_set_error_state(error_string, file, line_number::Csize_t, allocator::rcutils_allocator_t)
    ccall((:rcutils_set_error_state, librcutils), Cvoid, (Cstring, Cstring, Csize_t, rcutils_allocator_t), error_string, file, line_number, allocator)
end

function rcutils_error_is_set()
    ccall((:rcutils_error_is_set, librcutils), Bool, ())
end

function rcutils_get_error_state()
    ccall((:rcutils_get_error_state, librcutils), Ptr{rcutils_error_state_t}, ())
end

function rcutils_get_error_string()
    ccall((:rcutils_get_error_string, librcutils), Cstring, ())
end

function rcutils_get_error_string_safe()
    ccall((:rcutils_get_error_string_safe, librcutils), Cstring, ())
end

function rcutils_reset_error()
    ccall((:rcutils_reset_error, librcutils), Cvoid, ())
end
# Julia wrapper for header: /opt/ros/bouncy/include/rcl/node.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function rcutils_get_zero_initialized_allocator()
    ccall((:rcutils_get_zero_initialized_allocator, librcutils), rcutils_allocator_t, ())
end

function rcutils_get_default_allocator()
    ccall((:rcutils_get_default_allocator, librcutils), rcutils_allocator_t, ())
end

function rcutils_allocator_is_valid(allocator)
    ccall((:rcutils_allocator_is_valid, librcutils), Bool, (Ptr{rcutils_allocator_t},), allocator)
end

function rcutils_reallocf(pointer, size::Csize_t, allocator)
    ccall((:rcutils_reallocf, librcutils), Ptr{Cvoid}, (Ptr{Cvoid}, Csize_t, Ptr{rcutils_allocator_t}), pointer, size, allocator)
end

function rcutils_error_state_copy(src, dst)
    ccall((:rcutils_error_state_copy, librcutils), rcutils_ret_t, (Ptr{rcutils_error_state_t}, Ptr{rcutils_error_state_t}), src, dst)
end

function rcutils_error_state_fini(error_state)
    ccall((:rcutils_error_state_fini, librcutils), Cvoid, (Ptr{rcutils_error_state_t},), error_state)
end

function rcutils_set_error_state(error_string, file, line_number::Csize_t, allocator::rcutils_allocator_t)
    ccall((:rcutils_set_error_state, librcutils), Cvoid, (Cstring, Cstring, Csize_t, rcutils_allocator_t), error_string, file, line_number, allocator)
end

function rcutils_error_is_set()
    ccall((:rcutils_error_is_set, librcutils), Bool, ())
end

function rcutils_get_error_state()
    ccall((:rcutils_get_error_state, librcutils), Ptr{rcutils_error_state_t}, ())
end

function rcutils_get_error_string()
    ccall((:rcutils_get_error_string, librcutils), Cstring, ())
end

function rcutils_get_error_string_safe()
    ccall((:rcutils_get_error_string_safe, librcutils), Cstring, ())
end

function rcutils_reset_error()
    ccall((:rcutils_reset_error, librcutils), Cvoid, ())
end

function rcutils_get_zero_initialized_string_array()
    ccall((:rcutils_get_zero_initialized_string_array, librcutils/types), rcutils_string_array_t, ())
end

function rcutils_string_array_init(string_array, size::Csize_t, allocator)
    ccall((:rcutils_string_array_init, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_array_t}, Csize_t, Ptr{rcutils_allocator_t}), string_array, size, allocator)
end

function rcutils_string_array_fini(string_array)
    ccall((:rcutils_string_array_fini, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_array_t},), string_array)
end

function rcutils_get_zero_initialized_string_map()
    ccall((:rcutils_get_zero_initialized_string_map, librcutils/types), rcutils_string_map_t, ())
end

function rcutils_string_map_init(string_map, initial_capacity::Csize_t, allocator::rcutils_allocator_t)
    ccall((:rcutils_string_map_init, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Csize_t, rcutils_allocator_t), string_map, initial_capacity, allocator)
end

function rcutils_string_map_fini(string_map)
    ccall((:rcutils_string_map_fini, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t},), string_map)
end

function rcutils_string_map_get_capacity(string_map, capacity)
    ccall((:rcutils_string_map_get_capacity, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Ptr{Csize_t}), string_map, capacity)
end

function rcutils_string_map_get_size(string_map, size)
    ccall((:rcutils_string_map_get_size, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Ptr{Csize_t}), string_map, size)
end

function rcutils_string_map_reserve(string_map, capacity::Csize_t)
    ccall((:rcutils_string_map_reserve, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Csize_t), string_map, capacity)
end

function rcutils_string_map_clear(string_map)
    ccall((:rcutils_string_map_clear, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t},), string_map)
end

function rcutils_string_map_set(string_map, key, value)
    ccall((:rcutils_string_map_set, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Cstring, Cstring), string_map, key, value)
end

function rcutils_string_map_set_no_resize(string_map, key, value)
    ccall((:rcutils_string_map_set_no_resize, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Cstring, Cstring), string_map, key, value)
end

function rcutils_string_map_unset(string_map, key)
    ccall((:rcutils_string_map_unset, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Cstring), string_map, key)
end

function rcutils_string_map_key_exists(string_map, key)
    ccall((:rcutils_string_map_key_exists, librcutils/types), Bool, (Ptr{rcutils_string_map_t}, Cstring), string_map, key)
end

function rcutils_string_map_key_existsn(string_map, key, key_length::Csize_t)
    ccall((:rcutils_string_map_key_existsn, librcutils/types), Bool, (Ptr{rcutils_string_map_t}, Cstring, Csize_t), string_map, key, key_length)
end

function rcutils_string_map_get(string_map, key)
    ccall((:rcutils_string_map_get, librcutils/types), Cstring, (Ptr{rcutils_string_map_t}, Cstring), string_map, key)
end

function rcutils_string_map_getn(string_map, key, key_length::Csize_t)
    ccall((:rcutils_string_map_getn, librcutils/types), Cstring, (Ptr{rcutils_string_map_t}, Cstring, Csize_t), string_map, key, key_length)
end

function rcutils_string_map_get_next_key(string_map, key)
    ccall((:rcutils_string_map_get_next_key, librcutils/types), Cstring, (Ptr{rcutils_string_map_t}, Cstring), string_map, key)
end

function rcutils_string_map_copy(src_string_map, dst_string_map)
    ccall((:rcutils_string_map_copy, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Ptr{rcutils_string_map_t}), src_string_map, dst_string_map)
end

function rcutils_system_time_now(now)
    ccall((:rcutils_system_time_now, librcutils), rcutils_ret_t, (Ptr{rcutils_time_point_value_t},), now)
end

function rcutils_steady_time_now(now)
    ccall((:rcutils_steady_time_now, librcutils), rcutils_ret_t, (Ptr{rcutils_time_point_value_t},), now)
end

function rcutils_time_point_value_as_nanoseconds_string(time_point, str, str_size::Csize_t)
    ccall((:rcutils_time_point_value_as_nanoseconds_string, librcutils), rcutils_ret_t, (Ptr{rcutils_time_point_value_t}, Cstring, Csize_t), time_point, str, str_size)
end

function rcutils_time_point_value_as_seconds_string(time_point, str, str_size::Csize_t)
    ccall((:rcutils_time_point_value_as_seconds_string, librcutils), rcutils_ret_t, (Ptr{rcutils_time_point_value_t}, Cstring, Csize_t), time_point, str, str_size)
end

function rcutils_logging_initialize_with_allocator(allocator::rcutils_allocator_t)
    ccall((:rcutils_logging_initialize_with_allocator, librcutils), rcutils_ret_t, (rcutils_allocator_t,), allocator)
end

function rcutils_logging_initialize()
    ccall((:rcutils_logging_initialize, librcutils), rcutils_ret_t, ())
end

function rcutils_logging_shutdown()
    ccall((:rcutils_logging_shutdown, librcutils), rcutils_ret_t, ())
end

function rcutils_logging_severity_level_from_string(severity_string, allocator::rcutils_allocator_t, severity)
    ccall((:rcutils_logging_severity_level_from_string, librcutils), rcutils_ret_t, (Cstring, rcutils_allocator_t, Ptr{Cint}), severity_string, allocator, severity)
end

function rcutils_logging_get_output_handler()
    ccall((:rcutils_logging_get_output_handler, librcutils), rcutils_logging_output_handler_t, ())
end

function rcutils_logging_set_output_handler(_function::rcutils_logging_output_handler_t)
    ccall((:rcutils_logging_set_output_handler, librcutils), Cvoid, (rcutils_logging_output_handler_t,), _function)
end

function rcutils_logging_get_default_logger_level()
    ccall((:rcutils_logging_get_default_logger_level, librcutils), Cint, ())
end

function rcutils_logging_set_default_logger_level(level::Cint)
    ccall((:rcutils_logging_set_default_logger_level, librcutils), Cvoid, (Cint,), level)
end

function rcutils_logging_get_logger_level(name)
    ccall((:rcutils_logging_get_logger_level, librcutils), Cint, (Cstring,), name)
end

function rcutils_logging_get_logger_leveln(name, name_length::Csize_t)
    ccall((:rcutils_logging_get_logger_leveln, librcutils), Cint, (Cstring, Csize_t), name, name_length)
end

function rcutils_logging_set_logger_level(name, level::Cint)
    ccall((:rcutils_logging_set_logger_level, librcutils), rcutils_ret_t, (Cstring, Cint), name, level)
end

function rcutils_logging_logger_is_enabled_for(name, severity::Cint)
    ccall((:rcutils_logging_logger_is_enabled_for, librcutils), Bool, (Cstring, Cint), name, severity)
end

function rcutils_logging_get_logger_effective_level(name)
    ccall((:rcutils_logging_get_logger_effective_level, librcutils), Cint, (Cstring,), name)
end

# FIXME: handle variable args and comment back in
# function rcutils_logging_console_output_handler(location, severity::Cint, name, timestamp::rcutils_time_point_value_t, format, args)
#     ccall((:rcutils_logging_console_output_handler, librcutils), Cvoid, (Ptr{rcutils_log_location_t}, Cint, Cstring, rcutils_time_point_value_t, Cstring, Ptr{va_list}), location, severity, name, timestamp, format, args)
# end

function rcl_get_zero_initialized_arguments()
    ccall((:rcl_get_zero_initialized_arguments, librcl), rcl_arguments_t, ())
end

function rcl_parse_arguments(argc::Cint, argv, allocator::rcl_allocator_t, args_output)
    ccall((:rcl_parse_arguments, librcl), rcl_ret_t, (Cint, Ptr{Cstring}, rcl_allocator_t, Ptr{rcl_arguments_t}), argc, argv, allocator, args_output)
end

function rcl_arguments_get_count_unparsed(args)
    ccall((:rcl_arguments_get_count_unparsed, librcl), Cint, (Ptr{rcl_arguments_t},), args)
end

function rcl_arguments_get_unparsed(args, allocator::rcl_allocator_t, output_unparsed_indices)
    ccall((:rcl_arguments_get_unparsed, librcl), rcl_ret_t, (Ptr{rcl_arguments_t}, rcl_allocator_t, Ptr{Ptr{Cint}}), args, allocator, output_unparsed_indices)
end

function rcl_arguments_get_param_files_count(args)
    ccall((:rcl_arguments_get_param_files_count, librcl), Cint, (Ptr{rcl_arguments_t},), args)
end

function rcl_arguments_get_param_files(arguments, allocator::rcl_allocator_t, parameter_files)
    ccall((:rcl_arguments_get_param_files, librcl), rcl_ret_t, (Ptr{rcl_arguments_t}, rcl_allocator_t, Ptr{Ptr{Cstring}}), arguments, allocator, parameter_files)
end

function rcl_remove_ros_arguments(argv, args, allocator::rcl_allocator_t, nonros_argc, nonros_argv)
    ccall((:rcl_remove_ros_arguments, librcl), rcl_ret_t, (Ptr{Cstring}, Ptr{rcl_arguments_t}, rcl_allocator_t, Ptr{Cint}, Ptr{Ptr{Cstring}}), argv, args, allocator, nonros_argc, nonros_argv)
end

function rcl_arguments_copy(error_alloc::rcl_allocator_t, args, args_out)
    ccall((:rcl_arguments_copy, librcl), rcl_ret_t, (rcl_allocator_t, Ptr{rcl_arguments_t}, Ptr{rcl_arguments_t}), error_alloc, args, args_out)
end

function rcl_arguments_fini(args)
    ccall((:rcl_arguments_fini, librcl), rcl_ret_t, (Ptr{rcl_arguments_t},), args)
end

function rcl_get_global_arguments()
    ccall((:rcl_get_global_arguments, librcl), Ptr{rcl_arguments_t}, ())
end

function rcl_get_zero_initialized_node()
    ccall((:rcl_get_zero_initialized_node, librcl), rcl_node_t, ())
end

function rcl_node_init(node, name, namespace_, options)
    ccall((:rcl_node_init, librcl), rcl_ret_t, (Ptr{rcl_node_t}, Cstring, Cstring, Ptr{rcl_node_options_t}), node, name, namespace_, options)
end

function rcl_node_fini(node)
    ccall((:rcl_node_fini, librcl), rcl_ret_t, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_default_options()
    ccall((:rcl_node_get_default_options, librcl), rcl_node_options_t, ())
end

function rcl_node_options_copy(error_alloc::rcl_allocator_t, options, options_out)
    ccall((:rcl_node_options_copy, librcl), rcl_ret_t, (rcl_allocator_t, Ptr{rcl_node_options_t}, Ptr{rcl_node_options_t}), error_alloc, options, options_out)
end

function rcl_node_is_valid(node, error_msg_allocator)
    ccall((:rcl_node_is_valid, librcl), Bool, (Ptr{rcl_node_t}, Ptr{rcl_allocator_t}), node, error_msg_allocator)
end

function rcl_node_get_name(node)
    ccall((:rcl_node_get_name, librcl), Cstring, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_namespace(node)
    ccall((:rcl_node_get_namespace, librcl), Cstring, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_options(node)
    ccall((:rcl_node_get_options, librcl), Ptr{rcl_node_options_t}, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_domain_id(node, domain_id)
    ccall((:rcl_node_get_domain_id, librcl), rcl_ret_t, (Ptr{rcl_node_t}, Ptr{Csize_t}), node, domain_id)
end

function rcl_node_get_rmw_handle(node)
    ccall((:rcl_node_get_rmw_handle, librcl), Ptr{rmw_node_t}, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_rcl_instance_id(node)
    ccall((:rcl_node_get_rcl_instance_id, librcl), UInt64, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_graph_guard_condition(node)
    ccall((:rcl_node_get_graph_guard_condition, librcl), Ptr{Cvoid}, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_logger_name(node)
    ccall((:rcl_node_get_logger_name, librcl), Cstring, (Ptr{rcl_node_t},), node)
end
# Julia wrapper for header: /opt/ros/bouncy/include/rcl/rcl.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function rcutils_get_zero_initialized_allocator()
    ccall((:rcutils_get_zero_initialized_allocator, librcutils), rcutils_allocator_t, ())
end

function rcutils_get_default_allocator()
    ccall((:rcutils_get_default_allocator, librcutils), rcutils_allocator_t, ())
end

function rcutils_allocator_is_valid(allocator)
    ccall((:rcutils_allocator_is_valid, librcutils), Bool, (Ptr{rcutils_allocator_t},), allocator)
end

function rcutils_reallocf(pointer, size::Csize_t, allocator)
    ccall((:rcutils_reallocf, librcutils), Ptr{Cvoid}, (Ptr{Cvoid}, Csize_t, Ptr{rcutils_allocator_t}), pointer, size, allocator)
end

function rcutils_error_state_copy(src, dst)
    ccall((:rcutils_error_state_copy, librcutils), rcutils_ret_t, (Ptr{rcutils_error_state_t}, Ptr{rcutils_error_state_t}), src, dst)
end

function rcutils_error_state_fini(error_state)
    ccall((:rcutils_error_state_fini, librcutils), Cvoid, (Ptr{rcutils_error_state_t},), error_state)
end

function rcutils_set_error_state(error_string, file, line_number::Csize_t, allocator::rcutils_allocator_t)
    ccall((:rcutils_set_error_state, librcutils), Cvoid, (Cstring, Cstring, Csize_t, rcutils_allocator_t), error_string, file, line_number, allocator)
end

function rcutils_error_is_set()
    ccall((:rcutils_error_is_set, librcutils), Bool, ())
end

function rcutils_get_error_state()
    ccall((:rcutils_get_error_state, librcutils), Ptr{rcutils_error_state_t}, ())
end

function rcutils_get_error_string()
    ccall((:rcutils_get_error_string, librcutils), Cstring, ())
end

function rcutils_get_error_string_safe()
    ccall((:rcutils_get_error_string_safe, librcutils), Cstring, ())
end

function rcutils_reset_error()
    ccall((:rcutils_reset_error, librcutils), Cvoid, ())
end

function rcutils_get_zero_initialized_string_array()
    ccall((:rcutils_get_zero_initialized_string_array, librcutils/types), rcutils_string_array_t, ())
end

function rcutils_string_array_init(string_array, size::Csize_t, allocator)
    ccall((:rcutils_string_array_init, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_array_t}, Csize_t, Ptr{rcutils_allocator_t}), string_array, size, allocator)
end

function rcutils_string_array_fini(string_array)
    ccall((:rcutils_string_array_fini, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_array_t},), string_array)
end

function rcutils_get_zero_initialized_string_map()
    ccall((:rcutils_get_zero_initialized_string_map, librcutils/types), rcutils_string_map_t, ())
end

function rcutils_string_map_init(string_map, initial_capacity::Csize_t, allocator::rcutils_allocator_t)
    ccall((:rcutils_string_map_init, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Csize_t, rcutils_allocator_t), string_map, initial_capacity, allocator)
end

function rcutils_string_map_fini(string_map)
    ccall((:rcutils_string_map_fini, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t},), string_map)
end

function rcutils_string_map_get_capacity(string_map, capacity)
    ccall((:rcutils_string_map_get_capacity, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Ptr{Csize_t}), string_map, capacity)
end

function rcutils_string_map_get_size(string_map, size)
    ccall((:rcutils_string_map_get_size, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Ptr{Csize_t}), string_map, size)
end

function rcutils_string_map_reserve(string_map, capacity::Csize_t)
    ccall((:rcutils_string_map_reserve, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Csize_t), string_map, capacity)
end

function rcutils_string_map_clear(string_map)
    ccall((:rcutils_string_map_clear, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t},), string_map)
end

function rcutils_string_map_set(string_map, key, value)
    ccall((:rcutils_string_map_set, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Cstring, Cstring), string_map, key, value)
end

function rcutils_string_map_set_no_resize(string_map, key, value)
    ccall((:rcutils_string_map_set_no_resize, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Cstring, Cstring), string_map, key, value)
end

function rcutils_string_map_unset(string_map, key)
    ccall((:rcutils_string_map_unset, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Cstring), string_map, key)
end

function rcutils_string_map_key_exists(string_map, key)
    ccall((:rcutils_string_map_key_exists, librcutils/types), Bool, (Ptr{rcutils_string_map_t}, Cstring), string_map, key)
end

function rcutils_string_map_key_existsn(string_map, key, key_length::Csize_t)
    ccall((:rcutils_string_map_key_existsn, librcutils/types), Bool, (Ptr{rcutils_string_map_t}, Cstring, Csize_t), string_map, key, key_length)
end

function rcutils_string_map_get(string_map, key)
    ccall((:rcutils_string_map_get, librcutils/types), Cstring, (Ptr{rcutils_string_map_t}, Cstring), string_map, key)
end

function rcutils_string_map_getn(string_map, key, key_length::Csize_t)
    ccall((:rcutils_string_map_getn, librcutils/types), Cstring, (Ptr{rcutils_string_map_t}, Cstring, Csize_t), string_map, key, key_length)
end

function rcutils_string_map_get_next_key(string_map, key)
    ccall((:rcutils_string_map_get_next_key, librcutils/types), Cstring, (Ptr{rcutils_string_map_t}, Cstring), string_map, key)
end

function rcutils_string_map_copy(src_string_map, dst_string_map)
    ccall((:rcutils_string_map_copy, librcutils/types), rcutils_ret_t, (Ptr{rcutils_string_map_t}, Ptr{rcutils_string_map_t}), src_string_map, dst_string_map)
end

function rcutils_system_time_now(now)
    ccall((:rcutils_system_time_now, librcutils), rcutils_ret_t, (Ptr{rcutils_time_point_value_t},), now)
end

function rcutils_steady_time_now(now)
    ccall((:rcutils_steady_time_now, librcutils), rcutils_ret_t, (Ptr{rcutils_time_point_value_t},), now)
end

function rcutils_time_point_value_as_nanoseconds_string(time_point, str, str_size::Csize_t)
    ccall((:rcutils_time_point_value_as_nanoseconds_string, librcutils), rcutils_ret_t, (Ptr{rcutils_time_point_value_t}, Cstring, Csize_t), time_point, str, str_size)
end

function rcutils_time_point_value_as_seconds_string(time_point, str, str_size::Csize_t)
    ccall((:rcutils_time_point_value_as_seconds_string, librcutils), rcutils_ret_t, (Ptr{rcutils_time_point_value_t}, Cstring, Csize_t), time_point, str, str_size)
end

function rcutils_logging_initialize_with_allocator(allocator::rcutils_allocator_t)
    ccall((:rcutils_logging_initialize_with_allocator, librcutils), rcutils_ret_t, (rcutils_allocator_t,), allocator)
end

function rcutils_logging_initialize()
    ccall((:rcutils_logging_initialize, librcutils), rcutils_ret_t, ())
end

function rcutils_logging_shutdown()
    ccall((:rcutils_logging_shutdown, librcutils), rcutils_ret_t, ())
end

function rcutils_logging_severity_level_from_string(severity_string, allocator::rcutils_allocator_t, severity)
    ccall((:rcutils_logging_severity_level_from_string, librcutils), rcutils_ret_t, (Cstring, rcutils_allocator_t, Ptr{Cint}), severity_string, allocator, severity)
end

function rcutils_logging_get_output_handler()
    ccall((:rcutils_logging_get_output_handler, librcutils), rcutils_logging_output_handler_t, ())
end

function rcutils_logging_set_output_handler(_function::rcutils_logging_output_handler_t)
    ccall((:rcutils_logging_set_output_handler, librcutils), Cvoid, (rcutils_logging_output_handler_t,), _function)
end

function rcutils_logging_get_default_logger_level()
    ccall((:rcutils_logging_get_default_logger_level, librcutils), Cint, ())
end

function rcutils_logging_set_default_logger_level(level::Cint)
    ccall((:rcutils_logging_set_default_logger_level, librcutils), Cvoid, (Cint,), level)
end

function rcutils_logging_get_logger_level(name)
    ccall((:rcutils_logging_get_logger_level, librcutils), Cint, (Cstring,), name)
end

function rcutils_logging_get_logger_leveln(name, name_length::Csize_t)
    ccall((:rcutils_logging_get_logger_leveln, librcutils), Cint, (Cstring, Csize_t), name, name_length)
end

function rcutils_logging_set_logger_level(name, level::Cint)
    ccall((:rcutils_logging_set_logger_level, librcutils), rcutils_ret_t, (Cstring, Cint), name, level)
end

function rcutils_logging_logger_is_enabled_for(name, severity::Cint)
    ccall((:rcutils_logging_logger_is_enabled_for, librcutils), Bool, (Cstring, Cint), name, severity)
end

function rcutils_logging_get_logger_effective_level(name)
    ccall((:rcutils_logging_get_logger_effective_level, librcutils), Cint, (Cstring,), name)
end

# FIXME: handle variable args and comment back in
# function rcutils_logging_console_output_handler(location, severity::Cint, name, timestamp::rcutils_time_point_value_t, format, args)
#     ccall((:rcutils_logging_console_output_handler, librcutils), Cvoid, (Ptr{rcutils_log_location_t}, Cint, Cstring, rcutils_time_point_value_t, Cstring, Ptr{va_list}), location, severity, name, timestamp, format, args)
# end

function rcl_get_zero_initialized_arguments()
    ccall((:rcl_get_zero_initialized_arguments, librcl), rcl_arguments_t, ())
end

function rcl_parse_arguments(argc::Cint, argv, allocator::rcl_allocator_t, args_output)
    ccall((:rcl_parse_arguments, librcl), rcl_ret_t, (Cint, Ptr{Cstring}, rcl_allocator_t, Ptr{rcl_arguments_t}), argc, argv, allocator, args_output)
end

function rcl_arguments_get_count_unparsed(args)
    ccall((:rcl_arguments_get_count_unparsed, librcl), Cint, (Ptr{rcl_arguments_t},), args)
end

function rcl_arguments_get_unparsed(args, allocator::rcl_allocator_t, output_unparsed_indices)
    ccall((:rcl_arguments_get_unparsed, librcl), rcl_ret_t, (Ptr{rcl_arguments_t}, rcl_allocator_t, Ptr{Ptr{Cint}}), args, allocator, output_unparsed_indices)
end

function rcl_arguments_get_param_files_count(args)
    ccall((:rcl_arguments_get_param_files_count, librcl), Cint, (Ptr{rcl_arguments_t},), args)
end

function rcl_arguments_get_param_files(arguments, allocator::rcl_allocator_t, parameter_files)
    ccall((:rcl_arguments_get_param_files, librcl), rcl_ret_t, (Ptr{rcl_arguments_t}, rcl_allocator_t, Ptr{Ptr{Cstring}}), arguments, allocator, parameter_files)
end

function rcl_remove_ros_arguments(argv, args, allocator::rcl_allocator_t, nonros_argc, nonros_argv)
    ccall((:rcl_remove_ros_arguments, librcl), rcl_ret_t, (Ptr{Cstring}, Ptr{rcl_arguments_t}, rcl_allocator_t, Ptr{Cint}, Ptr{Ptr{Cstring}}), argv, args, allocator, nonros_argc, nonros_argv)
end

function rcl_arguments_copy(error_alloc::rcl_allocator_t, args, args_out)
    ccall((:rcl_arguments_copy, librcl), rcl_ret_t, (rcl_allocator_t, Ptr{rcl_arguments_t}, Ptr{rcl_arguments_t}), error_alloc, args, args_out)
end

function rcl_arguments_fini(args)
    ccall((:rcl_arguments_fini, librcl), rcl_ret_t, (Ptr{rcl_arguments_t},), args)
end

function rcl_get_global_arguments()
    ccall((:rcl_get_global_arguments, librcl), Ptr{rcl_arguments_t}, ())
end

function rcl_get_zero_initialized_node()
    ccall((:rcl_get_zero_initialized_node, librcl), rcl_node_t, ())
end

function rcl_node_init(node, name, namespace_, options)
    ccall((:rcl_node_init, librcl), rcl_ret_t, (Ptr{rcl_node_t}, Cstring, Cstring, Ptr{rcl_node_options_t}), node, name, namespace_, options)
end

function rcl_node_fini(node)
    ccall((:rcl_node_fini, librcl), rcl_ret_t, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_default_options()
    ccall((:rcl_node_get_default_options, librcl), rcl_node_options_t, ())
end

function rcl_node_options_copy(error_alloc::rcl_allocator_t, options, options_out)
    ccall((:rcl_node_options_copy, librcl), rcl_ret_t, (rcl_allocator_t, Ptr{rcl_node_options_t}, Ptr{rcl_node_options_t}), error_alloc, options, options_out)
end

function rcl_node_is_valid(node, error_msg_allocator)
    ccall((:rcl_node_is_valid, librcl), Bool, (Ptr{rcl_node_t}, Ptr{rcl_allocator_t}), node, error_msg_allocator)
end

function rcl_node_get_name(node)
    ccall((:rcl_node_get_name, librcl), Cstring, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_namespace(node)
    ccall((:rcl_node_get_namespace, librcl), Cstring, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_options(node)
    ccall((:rcl_node_get_options, librcl), Ptr{rcl_node_options_t}, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_domain_id(node, domain_id)
    ccall((:rcl_node_get_domain_id, librcl), rcl_ret_t, (Ptr{rcl_node_t}, Ptr{Csize_t}), node, domain_id)
end

function rcl_node_get_rmw_handle(node)
    ccall((:rcl_node_get_rmw_handle, librcl), Ptr{rmw_node_t}, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_rcl_instance_id(node)
    ccall((:rcl_node_get_rcl_instance_id, librcl), UInt64, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_graph_guard_condition(node)
    ccall((:rcl_node_get_graph_guard_condition, librcl), Ptr{Cvoid}, (Ptr{rcl_node_t},), node)
end

function rcl_node_get_logger_name(node)
    ccall((:rcl_node_get_logger_name, librcl), Cstring, (Ptr{rcl_node_t},), node)
end

function get_message_typesupport_handle(handle, identifier)
    ccall((:get_message_typesupport_handle, librosidl_generator_c), Ptr{rosidl_message_type_support_t}, (Ptr{rosidl_message_type_support_t}, Cstring), handle, identifier)
end

function get_message_typesupport_handle_function(handle, identifier)
    ccall((:get_message_typesupport_handle_function, librosidl_generator_c), Ptr{rosidl_message_type_support_t}, (Ptr{rosidl_message_type_support_t}, Cstring), handle, identifier)
end

function rcl_get_zero_initialized_publisher()
    ccall((:rcl_get_zero_initialized_publisher, librcl), rcl_publisher_t, ())
end

function rcl_publisher_init(publisher, node, type_support, topic_name, options)
    ccall((:rcl_publisher_init, librcl), rcl_ret_t, (Ptr{rcl_publisher_t}, Ptr{rcl_node_t}, Ptr{rosidl_message_type_support_t}, Cstring, Ptr{rcl_publisher_options_t}), publisher, node, type_support, topic_name, options)
end

function rcl_publisher_fini(publisher, node)
    ccall((:rcl_publisher_fini, librcl), rcl_ret_t, (Ptr{rcl_publisher_t}, Ptr{rcl_node_t}), publisher, node)
end

function rcl_publisher_get_default_options()
    ccall((:rcl_publisher_get_default_options, librcl), rcl_publisher_options_t, ())
end

function rcl_publish(publisher, ros_message)
    ccall((:rcl_publish, librcl), rcl_ret_t, (Ptr{rcl_publisher_t}, Ptr{Cvoid}), publisher, ros_message)
end

function rcl_publish_serialized_message(publisher, serialized_message)
    ccall((:rcl_publish_serialized_message, librcl), rcl_ret_t, (Ptr{rcl_publisher_t}, Ptr{rcl_serialized_message_t}), publisher, serialized_message)
end

function rcl_publisher_get_topic_name(publisher)
    ccall((:rcl_publisher_get_topic_name, librcl), Cstring, (Ptr{rcl_publisher_t},), publisher)
end

function rcl_publisher_get_options(publisher)
    ccall((:rcl_publisher_get_options, librcl), Ptr{rcl_publisher_options_t}, (Ptr{rcl_publisher_t},), publisher)
end

function rcl_publisher_get_rmw_handle(publisher)
    ccall((:rcl_publisher_get_rmw_handle, librcl), Ptr{rmw_publisher_t}, (Ptr{rcl_publisher_t},), publisher)
end

function rcl_publisher_is_valid(publisher, error_msg_allocator)
    ccall((:rcl_publisher_is_valid, librcl), Bool, (Ptr{rcl_publisher_t}, Ptr{rcl_allocator_t}), publisher, error_msg_allocator)
end

function rcl_get_zero_initialized_subscription()
    ccall((:rcl_get_zero_initialized_subscription, librcl), rcl_subscription_t, ())
end

function rcl_subscription_init(subscription, node, type_support, topic_name, options)
    ccall((:rcl_subscription_init, librcl), rcl_ret_t, (Ptr{rcl_subscription_t}, Ptr{rcl_node_t}, Ptr{rosidl_message_type_support_t}, Cstring, Ptr{rcl_subscription_options_t}), subscription, node, type_support, topic_name, options)
end

function rcl_subscription_fini(subscription, node)
    ccall((:rcl_subscription_fini, librcl), rcl_ret_t, (Ptr{rcl_subscription_t}, Ptr{rcl_node_t}), subscription, node)
end

function rcl_subscription_get_default_options()
    ccall((:rcl_subscription_get_default_options, librcl), rcl_subscription_options_t, ())
end

function rcl_take(subscription, ros_message, message_info)
    ccall((:rcl_take, librcl), rcl_ret_t, (Ptr{rcl_subscription_t}, Ptr{Cvoid}, Ptr{rmw_message_info_t}), subscription, ros_message, message_info)
end

function rcl_take_serialized_message(subscription, serialized_message, message_info)
    ccall((:rcl_take_serialized_message, librcl), rcl_ret_t, (Ptr{rcl_subscription_t}, Ptr{rcl_serialized_message_t}, Ptr{rmw_message_info_t}), subscription, serialized_message, message_info)
end

function rcl_subscription_get_topic_name(subscription)
    ccall((:rcl_subscription_get_topic_name, librcl), Cstring, (Ptr{rcl_subscription_t},), subscription)
end

function rcl_subscription_get_options(subscription)
    ccall((:rcl_subscription_get_options, librcl), Ptr{rcl_subscription_options_t}, (Ptr{rcl_subscription_t},), subscription)
end

function rcl_subscription_get_rmw_handle(subscription)
    ccall((:rcl_subscription_get_rmw_handle, librcl), Ptr{rmw_subscription_t}, (Ptr{rcl_subscription_t},), subscription)
end

function rcl_subscription_is_valid(subscription, error_msg_allocator)
    ccall((:rcl_subscription_is_valid, librcl), Bool, (Ptr{rcl_subscription_t}, Ptr{rcl_allocator_t}), subscription, error_msg_allocator)
end

function get_service_typesupport_handle(handle, identifier)
    ccall((:get_service_typesupport_handle, librosidl_generator_c), Ptr{rosidl_service_type_support_t}, (Ptr{rosidl_service_type_support_t}, Cstring), handle, identifier)
end

function get_service_typesupport_handle_function(handle, identifier)
    ccall((:get_service_typesupport_handle_function, librosidl_generator_c), Ptr{rosidl_service_type_support_t}, (Ptr{rosidl_service_type_support_t}, Cstring), handle, identifier)
end

function rcl_get_zero_initialized_client()
    ccall((:rcl_get_zero_initialized_client, librcl), rcl_client_t, ())
end

function rcl_client_init(client, node, type_support, service_name, options)
    ccall((:rcl_client_init, librcl), rcl_ret_t, (Ptr{rcl_client_t}, Ptr{rcl_node_t}, Ptr{rosidl_service_type_support_t}, Cstring, Ptr{rcl_client_options_t}), client, node, type_support, service_name, options)
end

function rcl_client_fini(client, node)
    ccall((:rcl_client_fini, librcl), rcl_ret_t, (Ptr{rcl_client_t}, Ptr{rcl_node_t}), client, node)
end

function rcl_client_get_default_options()
    ccall((:rcl_client_get_default_options, librcl), rcl_client_options_t, ())
end

function rcl_send_request(client, ros_request, sequence_number)
    ccall((:rcl_send_request, librcl), rcl_ret_t, (Ptr{rcl_client_t}, Ptr{Cvoid}, Ptr{Int64}), client, ros_request, sequence_number)
end

function rcl_take_response(client, request_header, ros_response)
    ccall((:rcl_take_response, librcl), rcl_ret_t, (Ptr{rcl_client_t}, Ptr{rmw_request_id_t}, Ptr{Cvoid}), client, request_header, ros_response)
end

function rcl_client_get_service_name(client)
    ccall((:rcl_client_get_service_name, librcl), Cstring, (Ptr{rcl_client_t},), client)
end

function rcl_client_get_options(client)
    ccall((:rcl_client_get_options, librcl), Ptr{rcl_client_options_t}, (Ptr{rcl_client_t},), client)
end

function rcl_client_get_rmw_handle(client)
    ccall((:rcl_client_get_rmw_handle, librcl), Ptr{rmw_client_t}, (Ptr{rcl_client_t},), client)
end

function rcl_client_is_valid(client, error_msg_allocator)
    ccall((:rcl_client_is_valid, librcl), Bool, (Ptr{rcl_client_t}, Ptr{rcl_allocator_t}), client, error_msg_allocator)
end

function rcl_get_zero_initialized_guard_condition()
    ccall((:rcl_get_zero_initialized_guard_condition, librcl), rcl_guard_condition_t, ())
end

function rcl_guard_condition_init(guard_condition, options::rcl_guard_condition_options_t)
    ccall((:rcl_guard_condition_init, librcl), rcl_ret_t, (Ptr{rcl_guard_condition_t}, rcl_guard_condition_options_t), guard_condition, options)
end

function rcl_guard_condition_init_from_rmw(guard_condition, rmw_guard_condition, options::rcl_guard_condition_options_t)
    ccall((:rcl_guard_condition_init_from_rmw, librcl), rcl_ret_t, (Ptr{rcl_guard_condition_t}, Ptr{rmw_guard_condition_t}, rcl_guard_condition_options_t), guard_condition, rmw_guard_condition, options)
end

function rcl_guard_condition_fini(guard_condition)
    ccall((:rcl_guard_condition_fini, librcl), rcl_ret_t, (Ptr{rcl_guard_condition_t},), guard_condition)
end

function rcl_guard_condition_get_default_options()
    ccall((:rcl_guard_condition_get_default_options, librcl), rcl_guard_condition_options_t, ())
end

function rcl_trigger_guard_condition(guard_condition)
    ccall((:rcl_trigger_guard_condition, librcl), rcl_ret_t, (Ptr{rcl_guard_condition_t},), guard_condition)
end

function rcl_guard_condition_get_options(guard_condition)
    ccall((:rcl_guard_condition_get_options, librcl), Ptr{rcl_guard_condition_options_t}, (Ptr{rcl_guard_condition_t},), guard_condition)
end

function rcl_guard_condition_get_rmw_handle(guard_condition)
    ccall((:rcl_guard_condition_get_rmw_handle, librcl), Ptr{rmw_guard_condition_t}, (Ptr{rcl_guard_condition_t},), guard_condition)
end

function rcl_get_zero_initialized_service()
    ccall((:rcl_get_zero_initialized_service, librcl), rcl_service_t, ())
end

function rcl_service_init(service, node, type_support, service_name, options)
    ccall((:rcl_service_init, librcl), rcl_ret_t, (Ptr{rcl_service_t}, Ptr{rcl_node_t}, Ptr{rosidl_service_type_support_t}, Cstring, Ptr{rcl_service_options_t}), service, node, type_support, service_name, options)
end

function rcl_service_fini(service, node)
    ccall((:rcl_service_fini, librcl), rcl_ret_t, (Ptr{rcl_service_t}, Ptr{rcl_node_t}), service, node)
end

function rcl_service_get_default_options()
    ccall((:rcl_service_get_default_options, librcl), rcl_service_options_t, ())
end

function rcl_take_request(service, request_header, ros_request)
    ccall((:rcl_take_request, librcl), rcl_ret_t, (Ptr{rcl_service_t}, Ptr{rmw_request_id_t}, Ptr{Cvoid}), service, request_header, ros_request)
end

function rcl_send_response(service, response_header, ros_response)
    ccall((:rcl_send_response, librcl), rcl_ret_t, (Ptr{rcl_service_t}, Ptr{rmw_request_id_t}, Ptr{Cvoid}), service, response_header, ros_response)
end

function rcl_service_get_service_name(service)
    ccall((:rcl_service_get_service_name, librcl), Cstring, (Ptr{rcl_service_t},), service)
end

function rcl_service_get_options(service)
    ccall((:rcl_service_get_options, librcl), Ptr{rcl_service_options_t}, (Ptr{rcl_service_t},), service)
end

function rcl_service_get_rmw_handle(service)
    ccall((:rcl_service_get_rmw_handle, librcl), Ptr{rmw_service_t}, (Ptr{rcl_service_t},), service)
end

function rcl_service_is_valid(service, error_msg_allocator)
    ccall((:rcl_service_is_valid, librcl), Bool, (Ptr{rcl_service_t}, Ptr{rcl_allocator_t}), service, error_msg_allocator)
end

function rcl_clock_valid(clock)
    ccall((:rcl_clock_valid, librcl), Bool, (Ptr{rcl_clock_t},), clock)
end

function rcl_clock_init(clock_type::Cvoid, clock, allocator)
    ccall((:rcl_clock_init, librcl), rcl_ret_t, (Cvoid, Ptr{rcl_clock_t}, Ptr{rcl_allocator_t}), clock_type, clock, allocator)
end

function rcl_clock_fini(clock)
    ccall((:rcl_clock_fini, librcl), rcl_ret_t, (Ptr{rcl_clock_t},), clock)
end

function rcl_ros_clock_init(clock, allocator)
    ccall((:rcl_ros_clock_init, librcl), rcl_ret_t, (Ptr{rcl_clock_t}, Ptr{rcl_allocator_t}), clock, allocator)
end

function rcl_ros_clock_fini(clock)
    ccall((:rcl_ros_clock_fini, librcl), rcl_ret_t, (Ptr{rcl_clock_t},), clock)
end

function rcl_steady_clock_init(clock, allocator)
    ccall((:rcl_steady_clock_init, librcl), rcl_ret_t, (Ptr{rcl_clock_t}, Ptr{rcl_allocator_t}), clock, allocator)
end

function rcl_steady_clock_fini(clock)
    ccall((:rcl_steady_clock_fini, librcl), rcl_ret_t, (Ptr{rcl_clock_t},), clock)
end

function rcl_system_clock_init(clock, allocator)
    ccall((:rcl_system_clock_init, librcl), rcl_ret_t, (Ptr{rcl_clock_t}, Ptr{rcl_allocator_t}), clock, allocator)
end

function rcl_system_clock_fini(clock)
    ccall((:rcl_system_clock_fini, librcl), rcl_ret_t, (Ptr{rcl_clock_t},), clock)
end

function rcl_difference_times(start, finish, delta)
    ccall((:rcl_difference_times, librcl), rcl_ret_t, (Ptr{rcl_time_point_t}, Ptr{rcl_time_point_t}, Ptr{rcl_duration_t}), start, finish, delta)
end

function rcl_clock_get_now(clock, time_point)
    ccall((:rcl_clock_get_now, librcl), rcl_ret_t, (Ptr{rcl_clock_t}, Ptr{rcl_time_point_t}), clock, time_point)
end

function rcl_enable_ros_time_override(clock)
    ccall((:rcl_enable_ros_time_override, librcl), rcl_ret_t, (Ptr{rcl_clock_t},), clock)
end

function rcl_disable_ros_time_override(clock)
    ccall((:rcl_disable_ros_time_override, librcl), rcl_ret_t, (Ptr{rcl_clock_t},), clock)
end

function rcl_is_enabled_ros_time_override(clock, is_enabled)
    ccall((:rcl_is_enabled_ros_time_override, librcl), rcl_ret_t, (Ptr{rcl_clock_t}, Ptr{Bool}), clock, is_enabled)
end

function rcl_set_ros_time_override(clock, time_value::rcl_time_point_value_t)
    ccall((:rcl_set_ros_time_override, librcl), rcl_ret_t, (Ptr{rcl_clock_t}, rcl_time_point_value_t), clock, time_value)
end

function rmw_get_implementation_identifier()
    ccall((:rmw_get_implementation_identifier, librmw), Cstring, ())
end

function rmw_init()
    ccall((:rmw_init, librmw), rmw_ret_t, ())
end

function rmw_create_node(name, namespace_, domain_id::Csize_t, security_options)
    ccall((:rmw_create_node, librmw), Ptr{rmw_node_t}, (Cstring, Cstring, Csize_t, Ptr{rmw_node_security_options_t}), name, namespace_, domain_id, security_options)
end

function rmw_destroy_node(node)
    ccall((:rmw_destroy_node, librmw), rmw_ret_t, (Ptr{rmw_node_t},), node)
end

function rmw_node_get_graph_guard_condition(node)
    ccall((:rmw_node_get_graph_guard_condition, librmw), Ptr{rmw_guard_condition_t}, (Ptr{rmw_node_t},), node)
end

function rmw_create_publisher(node, type_support, topic_name, qos_policies)
    ccall((:rmw_create_publisher, librmw), Ptr{rmw_publisher_t}, (Ptr{rmw_node_t}, Ptr{rosidl_message_type_support_t}, Cstring, Ptr{rmw_qos_profile_t}), node, type_support, topic_name, qos_policies)
end

function rmw_destroy_publisher(node, publisher)
    ccall((:rmw_destroy_publisher, librmw), rmw_ret_t, (Ptr{rmw_node_t}, Ptr{rmw_publisher_t}), node, publisher)
end

function rmw_publish(publisher, ros_message)
    ccall((:rmw_publish, librmw), rmw_ret_t, (Ptr{rmw_publisher_t}, Ptr{Cvoid}), publisher, ros_message)
end

function rmw_publish_serialized_message(publisher, serialized_message)
    ccall((:rmw_publish_serialized_message, librmw), rmw_ret_t, (Ptr{rmw_publisher_t}, Ptr{rmw_serialized_message_t}), publisher, serialized_message)
end

function rmw_serialize(ros_message, type_support, serialized_message)
    ccall((:rmw_serialize, librmw), rmw_ret_t, (Ptr{Cvoid}, Ptr{rosidl_message_type_support_t}, Ptr{rmw_serialized_message_t}), ros_message, type_support, serialized_message)
end

function rmw_deserialize(serialized_message, type_support, ros_message)
    ccall((:rmw_deserialize, librmw), rmw_ret_t, (Ptr{rmw_serialized_message_t}, Ptr{rosidl_message_type_support_t}, Ptr{Cvoid}), serialized_message, type_support, ros_message)
end

function rmw_create_subscription(node, type_support, topic_name, qos_policies, ignore_local_publications::Bool)
    ccall((:rmw_create_subscription, librmw), Ptr{rmw_subscription_t}, (Ptr{rmw_node_t}, Ptr{rosidl_message_type_support_t}, Cstring, Ptr{rmw_qos_profile_t}, Bool), node, type_support, topic_name, qos_policies, ignore_local_publications)
end

function rmw_destroy_subscription(node, subscription)
    ccall((:rmw_destroy_subscription, librmw), rmw_ret_t, (Ptr{rmw_node_t}, Ptr{rmw_subscription_t}), node, subscription)
end

function rmw_take(subscription, ros_message, taken)
    ccall((:rmw_take, librmw), rmw_ret_t, (Ptr{rmw_subscription_t}, Ptr{Cvoid}, Ptr{Bool}), subscription, ros_message, taken)
end

function rmw_take_with_info(subscription, ros_message, taken, message_info)
    ccall((:rmw_take_with_info, librmw), rmw_ret_t, (Ptr{rmw_subscription_t}, Ptr{Cvoid}, Ptr{Bool}, Ptr{rmw_message_info_t}), subscription, ros_message, taken, message_info)
end

function rmw_take_serialized_message(subscription, serialized_message, taken)
    ccall((:rmw_take_serialized_message, librmw), rmw_ret_t, (Ptr{rmw_subscription_t}, Ptr{rmw_serialized_message_t}, Ptr{Bool}), subscription, serialized_message, taken)
end

function rmw_take_serialized_message_with_info(subscription, serialized_message, taken, message_info)
    ccall((:rmw_take_serialized_message_with_info, librmw), rmw_ret_t, (Ptr{rmw_subscription_t}, Ptr{rmw_serialized_message_t}, Ptr{Bool}, Ptr{rmw_message_info_t}), subscription, serialized_message, taken, message_info)
end

function rmw_create_client(node, type_support, service_name, qos_policies)
    ccall((:rmw_create_client, librmw), Ptr{rmw_client_t}, (Ptr{rmw_node_t}, Ptr{rosidl_service_type_support_t}, Cstring, Ptr{rmw_qos_profile_t}), node, type_support, service_name, qos_policies)
end

function rmw_destroy_client(node, client)
    ccall((:rmw_destroy_client, librmw), rmw_ret_t, (Ptr{rmw_node_t}, Ptr{rmw_client_t}), node, client)
end

function rmw_send_request(client, ros_request, sequence_id)
    ccall((:rmw_send_request, librmw), rmw_ret_t, (Ptr{rmw_client_t}, Ptr{Cvoid}, Ptr{Int64}), client, ros_request, sequence_id)
end

function rmw_take_response(client, request_header, ros_response, taken)
    ccall((:rmw_take_response, librmw), rmw_ret_t, (Ptr{rmw_client_t}, Ptr{rmw_request_id_t}, Ptr{Cvoid}, Ptr{Bool}), client, request_header, ros_response, taken)
end

function rmw_create_service(node, type_support, service_name, qos_policies)
    ccall((:rmw_create_service, librmw), Ptr{rmw_service_t}, (Ptr{rmw_node_t}, Ptr{rosidl_service_type_support_t}, Cstring, Ptr{rmw_qos_profile_t}), node, type_support, service_name, qos_policies)
end

function rmw_destroy_service(node, service)
    ccall((:rmw_destroy_service, librmw), rmw_ret_t, (Ptr{rmw_node_t}, Ptr{rmw_service_t}), node, service)
end

function rmw_take_request(service, request_header, ros_request, taken)
    ccall((:rmw_take_request, librmw), rmw_ret_t, (Ptr{rmw_service_t}, Ptr{rmw_request_id_t}, Ptr{Cvoid}, Ptr{Bool}), service, request_header, ros_request, taken)
end

function rmw_send_response(service, request_header, ros_response)
    ccall((:rmw_send_response, librmw), rmw_ret_t, (Ptr{rmw_service_t}, Ptr{rmw_request_id_t}, Ptr{Cvoid}), service, request_header, ros_response)
end

function rmw_create_guard_condition()
    ccall((:rmw_create_guard_condition, librmw), Ptr{rmw_guard_condition_t}, ())
end

function rmw_destroy_guard_condition(guard_condition)
    ccall((:rmw_destroy_guard_condition, librmw), rmw_ret_t, (Ptr{rmw_guard_condition_t},), guard_condition)
end

function rmw_trigger_guard_condition(guard_condition)
    ccall((:rmw_trigger_guard_condition, librmw), rmw_ret_t, (Ptr{rmw_guard_condition_t},), guard_condition)
end

function rmw_create_wait_set(max_conditions::Csize_t)
    ccall((:rmw_create_wait_set, librmw), Ptr{rmw_wait_set_t}, (Csize_t,), max_conditions)
end

function rmw_destroy_wait_set(wait_set)
    ccall((:rmw_destroy_wait_set, librmw), rmw_ret_t, (Ptr{rmw_wait_set_t},), wait_set)
end

function rmw_wait(subscriptions, guard_conditions, services, clients, wait_set, wait_timeout)
    ccall((:rmw_wait, librmw), rmw_ret_t, (Ptr{rmw_subscriptions_t}, Ptr{rmw_guard_conditions_t}, Ptr{rmw_services_t}, Ptr{rmw_clients_t}, Ptr{rmw_wait_set_t}, Ptr{rmw_time_t}), subscriptions, guard_conditions, services, clients, wait_set, wait_timeout)
end

function rmw_get_node_names(node, node_names)
    ccall((:rmw_get_node_names, librmw), rmw_ret_t, (Ptr{rmw_node_t}, Ptr{rcutils_string_array_t}), node, node_names)
end

function rmw_count_publishers(node, topic_name, count)
    ccall((:rmw_count_publishers, librmw), rmw_ret_t, (Ptr{rmw_node_t}, Cstring, Ptr{Csize_t}), node, topic_name, count)
end

function rmw_count_subscribers(node, topic_name, count)
    ccall((:rmw_count_subscribers, librmw), rmw_ret_t, (Ptr{rmw_node_t}, Cstring, Ptr{Csize_t}), node, topic_name, count)
end

function rmw_get_gid_for_publisher(publisher, gid)
    ccall((:rmw_get_gid_for_publisher, librmw), rmw_ret_t, (Ptr{rmw_publisher_t}, Ptr{rmw_gid_t}), publisher, gid)
end

function rmw_compare_gids_equal(gid1, gid2, result)
    ccall((:rmw_compare_gids_equal, librmw), rmw_ret_t, (Ptr{rmw_gid_t}, Ptr{rmw_gid_t}, Ptr{Bool}), gid1, gid2, result)
end

function rmw_service_server_is_available(node, client, is_available)
    ccall((:rmw_service_server_is_available, librmw), rmw_ret_t, (Ptr{rmw_node_t}, Ptr{rmw_client_t}, Ptr{Bool}), node, client, is_available)
end

function rmw_set_log_severity(severity::rmw_log_severity_t)
    ccall((:rmw_set_log_severity, librmw), rmw_ret_t, (rmw_log_severity_t,), severity)
end

function rcl_get_zero_initialized_timer()
    ccall((:rcl_get_zero_initialized_timer, librcl), rcl_timer_t, ())
end

function rcl_timer_init(timer, period::Int64, callback::rcl_timer_callback_t, allocator::rcl_allocator_t)
    ccall((:rcl_timer_init, librcl), rcl_ret_t, (Ptr{rcl_timer_t}, Int64, rcl_timer_callback_t, rcl_allocator_t), timer, period, callback, allocator)
end

function rcl_timer_fini(timer)
    ccall((:rcl_timer_fini, librcl), rcl_ret_t, (Ptr{rcl_timer_t},), timer)
end

function rcl_timer_call(timer)
    ccall((:rcl_timer_call, librcl), rcl_ret_t, (Ptr{rcl_timer_t},), timer)
end

function rcl_timer_is_ready(timer, is_ready)
    ccall((:rcl_timer_is_ready, librcl), rcl_ret_t, (Ptr{rcl_timer_t}, Ptr{Bool}), timer, is_ready)
end

function rcl_timer_get_time_until_next_call(timer, time_until_next_call)
    ccall((:rcl_timer_get_time_until_next_call, librcl), rcl_ret_t, (Ptr{rcl_timer_t}, Ptr{Int64}), timer, time_until_next_call)
end

function rcl_timer_get_time_since_last_call(timer, time_since_last_call)
    ccall((:rcl_timer_get_time_since_last_call, librcl), rcl_ret_t, (Ptr{rcl_timer_t}, Ptr{Int64}), timer, time_since_last_call)
end

function rcl_timer_get_period(timer, period)
    ccall((:rcl_timer_get_period, librcl), rcl_ret_t, (Ptr{rcl_timer_t}, Ptr{Int64}), timer, period)
end

function rcl_timer_exchange_period(timer, new_period::Int64, old_period)
    ccall((:rcl_timer_exchange_period, librcl), rcl_ret_t, (Ptr{rcl_timer_t}, Int64, Ptr{Int64}), timer, new_period, old_period)
end

function rcl_timer_get_callback(timer)
    ccall((:rcl_timer_get_callback, librcl), rcl_timer_callback_t, (Ptr{rcl_timer_t},), timer)
end

function rcl_timer_exchange_callback(timer, new_callback::rcl_timer_callback_t)
    ccall((:rcl_timer_exchange_callback, librcl), rcl_timer_callback_t, (Ptr{rcl_timer_t}, rcl_timer_callback_t), timer, new_callback)
end

function rcl_timer_cancel(timer)
    ccall((:rcl_timer_cancel, librcl), rcl_ret_t, (Ptr{rcl_timer_t},), timer)
end

function rcl_timer_is_canceled(timer, is_canceled)
    ccall((:rcl_timer_is_canceled, librcl), rcl_ret_t, (Ptr{rcl_timer_t}, Ptr{Bool}), timer, is_canceled)
end

function rcl_timer_reset(timer)
    ccall((:rcl_timer_reset, librcl), rcl_ret_t, (Ptr{rcl_timer_t},), timer)
end

function rcl_timer_get_allocator(timer)
    ccall((:rcl_timer_get_allocator, librcl), Ptr{rcl_allocator_t}, (Ptr{rcl_timer_t},), timer)
end

function rcl_get_zero_initialized_wait_set()
    ccall((:rcl_get_zero_initialized_wait_set, librcl), rcl_wait_set_t, ())
end

function rcl_wait_set_init(wait_set, number_of_subscriptions::Csize_t, number_of_guard_conditions::Csize_t, number_of_timers::Csize_t, number_of_clients::Csize_t, number_of_services::Csize_t, allocator::rcl_allocator_t)
    ccall((:rcl_wait_set_init, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Csize_t, Csize_t, Csize_t, Csize_t, Csize_t, rcl_allocator_t), wait_set, number_of_subscriptions, number_of_guard_conditions, number_of_timers, number_of_clients, number_of_services, allocator)
end

function rcl_wait_set_fini(wait_set)
    ccall((:rcl_wait_set_fini, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t},), wait_set)
end

function rcl_wait_set_get_allocator(wait_set, allocator)
    ccall((:rcl_wait_set_get_allocator, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Ptr{rcl_allocator_t}), wait_set, allocator)
end

function rcl_wait_set_add_subscription(wait_set, subscription)
    ccall((:rcl_wait_set_add_subscription, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Ptr{rcl_subscription_t}), wait_set, subscription)
end

function rcl_wait_set_clear_subscriptions(wait_set)
    ccall((:rcl_wait_set_clear_subscriptions, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t},), wait_set)
end

function rcl_wait_set_resize_subscriptions(wait_set, size::Csize_t)
    ccall((:rcl_wait_set_resize_subscriptions, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Csize_t), wait_set, size)
end

function rcl_wait_set_add_guard_condition(wait_set, guard_condition)
    ccall((:rcl_wait_set_add_guard_condition, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Ptr{rcl_guard_condition_t}), wait_set, guard_condition)
end

function rcl_wait_set_clear_guard_conditions(wait_set)
    ccall((:rcl_wait_set_clear_guard_conditions, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t},), wait_set)
end

function rcl_wait_set_resize_guard_conditions(wait_set, size::Csize_t)
    ccall((:rcl_wait_set_resize_guard_conditions, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Csize_t), wait_set, size)
end

function rcl_wait_set_add_timer(wait_set, timer)
    ccall((:rcl_wait_set_add_timer, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Ptr{rcl_timer_t}), wait_set, timer)
end

function rcl_wait_set_clear_timers(wait_set)
    ccall((:rcl_wait_set_clear_timers, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t},), wait_set)
end

function rcl_wait_set_resize_timers(wait_set, size::Csize_t)
    ccall((:rcl_wait_set_resize_timers, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Csize_t), wait_set, size)
end

function rcl_wait_set_add_client(wait_set, client)
    ccall((:rcl_wait_set_add_client, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Ptr{rcl_client_t}), wait_set, client)
end

function rcl_wait_set_clear_clients(wait_set)
    ccall((:rcl_wait_set_clear_clients, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t},), wait_set)
end

function rcl_wait_set_resize_clients(wait_set, size::Csize_t)
    ccall((:rcl_wait_set_resize_clients, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Csize_t), wait_set, size)
end

function rcl_wait_set_add_service(wait_set, service)
    ccall((:rcl_wait_set_add_service, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Ptr{rcl_service_t}), wait_set, service)
end

function rcl_wait_set_clear_services(wait_set)
    ccall((:rcl_wait_set_clear_services, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t},), wait_set)
end

function rcl_wait_set_resize_services(wait_set, size::Csize_t)
    ccall((:rcl_wait_set_resize_services, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Csize_t), wait_set, size)
end

function rcl_wait(wait_set, timeout::Int64)
    ccall((:rcl_wait, librcl), rcl_ret_t, (Ptr{rcl_wait_set_t}, Int64), wait_set, timeout)
end

function rcl_init(argc::Cint, argv, allocator::rcl_allocator_t)
    ccall((:rcl_init, librcl), rcl_ret_t, (Cint, Ptr{Cstring}, rcl_allocator_t), argc, argv, allocator)
end

function rcl_shutdown()
    ccall((:rcl_shutdown, librcl), rcl_ret_t, ())
end

function rcl_get_instance_id()
    ccall((:rcl_get_instance_id, librcl), UInt64, ())
end

function rcl_ok()
    ccall((:rcl_ok, librcl), Bool, ())
end


text:
__precompile__()

module Projections

export project, project!

abstract type ConvexSet end
abstract type NonconvexSet end

"""
    project!(s, v, y)

Overwrite `v` by projection of point `y` to the box set `b`.
"""
function project!(); end

"""
    project(s, y)

Project point `y` to the box set `b`.
"""
function project(); end

include("box.jl")
include("ball.jl")
include("simplex.jl")
include("affine.jl")
include("consensus.jl")
include("finite.jl")
include("halfspace.jl")
include("l1ball.jl")
include("l_infinity.jl")
include("low-rank-matrix.jl")
include("positive-semidefinite.jl")
include("second-order-cone.jl")
include("stiefel-manifold.jl")
end

ext: jl


text:
# This file is a part of Julia. License is MIT: http://julialang.org/license

module PermutedDimsArrays

export permutedims, PermutedDimsArray

# Some day we will want storage-order-aware iteration, so put perm in the parameters
struct PermutedDimsArray{T,N,perm,iperm,AA<:AbstractArray} <: AbstractArray{T,N}
    parent::AA

    function PermutedDimsArray{T,N,perm,iperm,AA}(data::AA) where {T,N,perm,iperm,AA<:AbstractArray}
        (isa(perm, NTuple{N,Int}) && isa(iperm, NTuple{N,Int})) || error("perm and iperm must both be NTuple{$N,Int}")
        isperm(perm) || throw(ArgumentError(string(perm, " is not a valid permutation of dimensions 1:", N)))
        all(map(d->iperm[perm[d]]==d, 1:N)) || throw(ArgumentError(string(perm, " and ", iperm, " must be inverses")))
        new(data)
    end
end

"""
    PermutedDimsArray(A, perm) -> B

Given an AbstractArray `A`, create a view `B` such that the
dimensions appear to be permuted. Similar to `permutedims`, except
that no copying occurs (`B` shares storage with `A`).

See also: [`permutedims`](@ref).

# Example

```jldoctest
julia> A = rand(3,5,4);

julia> B = PermutedDimsArray(A, (3,1,2));

julia> size(B)
(4, 3, 5)

julia> B[3,1,2] == A[1,2,3]
true
```
"""
function PermutedDimsArray(data::AbstractArray{T,N}, perm) where {T,N}
    length(perm) == N || throw(ArgumentError(string(perm, " is not a valid permutation of dimensions 1:", N)))
    iperm = invperm(perm)
    PermutedDimsArray{T,N,(perm...,),(iperm...,),typeof(data)}(data)
end

Base.parent(A::PermutedDimsArray) = A.parent
Base.size{T,N,perm}(A::PermutedDimsArray{T,N,perm})    = genperm(size(parent(A)),    perm)
Base.indices{T,N,perm}(A::PermutedDimsArray{T,N,perm}) = genperm(indices(parent(A)), perm)

Base.unsafe_convert{T}(::Type{Ptr{T}}, A::PermutedDimsArray{T}) = Base.unsafe_convert(Ptr{T}, parent(A))

# It's OK to return a pointer to the first element, and indeed quite
# useful for wrapping C routines that require a different storage
# order than used by Julia. But for an array with unconventional
# storage order, a linear offset is ambiguous---is it a memory offset
# or a linear index?
Base.pointer(A::PermutedDimsArray, i::Integer) = throw(ArgumentError("pointer(A, i) is deliberately unsupported for PermutedDimsArray"))

function Base.strides{T,N,perm}(A::PermutedDimsArray{T,N,perm})
    s = strides(parent(A))
    ntuple(d->s[perm[d]], Val{N})
end

@inline function Base.getindex{T,N,perm,iperm}(A::PermutedDimsArray{T,N,perm,iperm}, I::Vararg{Int,N})
    @boundscheck checkbounds(A, I...)
    @inbounds val = getindex(A.parent, genperm(I, iperm)...)
    val
end
@inline function Base.setindex!{T,N,perm,iperm}(A::PermutedDimsArray{T,N,perm,iperm}, val, I::Vararg{Int,N})
    @boundscheck checkbounds(A, I...)
    @inbounds setindex!(A.parent, val, genperm(I, iperm)...)
    val
end

# For some reason this is faster than ntuple(d->I[perm[d]], Val{N}) (#15276?)
@inline genperm{N}(I::NTuple{N,Any}, perm::Dims{N}) = _genperm((), I, perm...)
_genperm(out, I) = out
@inline _genperm(out, I, p, perm...) = _genperm((out..., I[p]), I, perm...)
@inline genperm(I, perm::AbstractVector{Int}) = genperm(I, (perm...,))

"""
    permutedims(A, perm)

Permute the dimensions of array `A`. `perm` is a vector specifying a permutation of length
`ndims(A)`. This is a generalization of transpose for multi-dimensional arrays. Transpose is
equivalent to `permutedims(A, [2,1])`.

See also: [`PermutedDimsArray`](@ref).

```jldoctest
julia> A = reshape(collect(1:8), (2,2,2))
2×2×2 Array{Int64,3}:
[:, :, 1] =
 1  3
 2  4

[:, :, 2] =
 5  7
 6  8

julia> permutedims(A, [3, 2, 1])
2×2×2 Array{Int64,3}:
[:, :, 1] =
 1  3
 5  7

[:, :, 2] =
 2  4
 6  8
```
"""
function Base.permutedims(A::AbstractArray, perm)
    dest = similar(A, genperm(indices(A), perm))
    permutedims!(dest, A, perm)
end

"""
    permutedims!(dest, src, perm)

Permute the dimensions of array `src` and store the result in the array `dest`. `perm` is a
vector specifying a permutation of length `ndims(src)`. The preallocated array `dest` should
have `size(dest) == size(src)[perm]` and is completely overwritten. No in-place permutation
is supported and unexpected results will happen if `src` and `dest` have overlapping memory
regions.
"""
function Base.permutedims!(dest, src::AbstractArray, perm)
    Base.checkdims_perm(dest, src, perm)
    P = PermutedDimsArray(dest, invperm(perm))
    _copy!(P, src)
    return dest
end

function Base.copy!{T,N}(dest::PermutedDimsArray{T,N}, src::AbstractArray{T,N})
    checkbounds(dest, indices(src)...)
    _copy!(dest, src)
end
Base.copy!(dest::PermutedDimsArray, src::AbstractArray) = _copy!(dest, src)

function _copy!{T,N,perm}(P::PermutedDimsArray{T,N,perm}, src)
    # If dest/src are "close to dense," then it pays to be cache-friendly.
    # Determine the first permuted dimension
    d = 0  # d+1 will hold the first permuted dimension of src
    while d < ndims(src) && perm[d+1] == d+1
        d += 1
    end
    if d == ndims(src)
        copy!(parent(P), src) # it's not permuted
    else
        R1 = CartesianRange(indices(src)[1:d])
        d1 = findfirst(perm, d+1)  # first permuted dim of dest
        R2 = CartesianRange(indices(src)[d+2:d1-1])
        R3 = CartesianRange(indices(src)[d1+1:end])
        _permutedims!(P, src, R1, R2, R3, d+1, d1)
    end
    return P
end

@noinline function _permutedims!(P::PermutedDimsArray, src, R1::CartesianRange{CartesianIndex{0}}, R2, R3, ds, dp)
    ip, is = indices(src, dp), indices(src, ds)
    for jo in first(ip):8:last(ip), io in first(is):8:last(is)
        for I3 in R3, I2 in R2
            for j in jo:min(jo+7, last(ip))
                for i in io:min(io+7, last(is))
                    @inbounds P[i, I2, j, I3] = src[i, I2, j, I3]
                end
            end
        end
    end
    P
end

@noinline function _permutedims!(P::PermutedDimsArray, src, R1, R2, R3, ds, dp)
    ip, is = indices(src, dp), indices(src, ds)
    for jo in first(ip):8:last(ip), io in first(is):8:last(is)
        for I3 in R3, I2 in R2
            for j in jo:min(jo+7, last(ip))
                for i in io:min(io+7, last(is))
                    for I1 in R1
                        @inbounds P[I1, i, I2, j, I3] = src[I1, i, I2, j, I3]
                    end
                end
            end
        end
    end
    P
end

end


text:
using Base: RefValue, UInt64

struct NodeExternal <: NodeValue
    ptr::Ptr{Cvoid}
    NodeExternal(ptr::Ptr{Cvoid}) = new(ptr)
end

NodeExternal(v) = NodeExternal(pointer(reference(v)))
NodeExternal(nv::NapiValue) = NodeExternal(@napi_call napi_get_value_external(nv::NapiValue)::Ptr{Cvoid})

Base.pointer(v::NodeExternal) = getfield(v, :ptr)
value(v::NodeExternal) = let t = get_reference(pointer(v))
    isnothing(t) ? nothing : t[]
end

Base.show(io::IO, v::NodeExternal) = print(io, string(
    typeof(v), ": ", value(v)
))

node_value(v::NodeExternal) = v

external_finalizer(ptr::Ptr{Cvoid}) = dereference(ptr)

napi_value(v::NodeExternal) = @napi_call create_external(pointer(v)::UInt64)::NapiValue

function value(::Type{NodeExternal}, nv::NapiValue)
    e = NodeExternal(nv)
    v = value(e)
    isnothing(v) ? e : v
end


text:
module KineticEnergy

using TypesBasis
using UtilityFunctions

export buildkineticenergy

@doc raw"""
    Use: buildkineticenergy(basisfunc::Basis)

Description: Generate the Ne*N-basis x Ne*N-basis kinetic energy matrix for our contracted basis set. The following expression captures this:

```
$ T_{n,m}$
```

Input:
Results:

"""
function buildkineticenergy(natoms::Int,basisfunc::Array{GaussOrbitals},basis::Basis)

    numbasisfunc = basis.nbasisfunc; #number of basis functions
    basissize = natoms*basis.nbasisfunc; #overlap size
    ke = zeros(Float64,basissize,basissize); #overlap matrix Ne*Gaussians x Ne*Gaussians

    flatbasisfunc = flattenbasisfunc(natoms,numbasisfunc,basisfunc);

    for n=1:basissize
        for m=1:basissize
            basisn = flatbasisfunc[n];
            basism = flatbasisfunc[m];

            #Gaussian factors
            an = basisn.alphas;
            am = basism.alphas;

            #Contraction coeffs.
            cn = basisn.coefs;
            cm = basism.coefs;

            xn,yn,zn = basisn.ax, basisn.ay, basisn.az;
            xm,ym,zm = basism.ax, basism.ay, basism.az;

            #Number of primitive Gaussians
            primsn = length(an);
            primsm = length(am);

            for np=1:primsn
                for mp=1:primsm
                    #Get overlap integral
                    overlap = getgaussoverlap(np,mp,basisn,basism);

                    #Contraction coeff prod.
                    cnm = cn[np]*cm[mp];

                    #Gaussian product theorem
                    p = an[np]+am[mp];
                    px = (an[np]*xn + am[mp]*xm) / p;
                    py = (an[np]*yn + am[mp]*ym) / p;
                    pz = (an[np]*zn + am[mp]*zm) / p;

                    #Build K.E. based on notes
                    ke[n,m] += 3 * cnm * am[mp] * overlap;
                    ke[n,m] -= 2 * cnm * am[mp]^2 * ((px-xm)^2 + 1/(2*p)) * overlap;
                    ke[n,m] -= 2 * cnm * am[mp]^2 * ((py-ym)^2 + 1/(2*p)) * overlap;
                    ke[n,m] -= 2 * cnm * am[mp]^2 * ((pz-zm)^2 + 1/(2*p)) * overlap;
                end
            end # nprims
        end
    end #basissize
    return ke
end #buildkineticenergy

end #KineticEnergy


text:
using DataFrames
using Random: randstring
using JDF
using Test

df = DataFrame([collect(1:10) for i = 1:3000], :auto);
df[!, :strs] = [randstring(8) for i = 1:DataFrames.nrow(df)]
df[!, :substrs] = [SubString(x, 1, 3) for x in df[!, :strs]]

JDF.save("tmp-substring.jdf", df)

df2 = DataFrame(JDF.load("tmp-substring.jdf"))

@test df.substrs == df2.substrs

rm("tmp-substring.jdf", force=true, recursive=true)

max_stars_repo_name: xiaodaigh/JDF

max_issues_repo_name: xiaodaigh/JDF

max_forks_repo_name: xiaodaigh/JDF


text:
function largest_component_test()
    A = load_matrix_network("dfs_example")
    (Acc,p) = largest_component(A)

    if size(Acc,1) != 5
        error("largest_component failed")
    end

    (Acc,p) = largest_component(A,true)
    if size(Acc,1) != 6
        error("largest_component failed")
    end

    A = load_matrix_network("cores_example")
    (Acc1,p1) = largest_component(A)
    (Acc2,p2) = largest_component(A,true)
    if !isequal(Acc1,Acc2)
        error("largest_component failed")
    end

    return true
end


text:
module DiffEqGPU

using GPUifyLoops, CuArrays, CUDAnative, DiffEqBase, LinearAlgebra, Distributed
using CUDAdrv: CuPtr, CU_NULL, Mem, CuDefaultStream
using CuArrays: CUBLAS

function gpu_kernel(f,du,u,p,t)
    @loop for i in (1:size(u,2); (blockIdx().x-1) * blockDim().x + threadIdx().x)
        @views @inbounds f(du[:,i],u[:,i],p[:,i],t)
        nothing
    end
    nothing
end

function jac_kernel(f,J,u,p,t)
    @loop for i in (0:(size(u,2)-1); (blockIdx().x-1) * blockDim().x + threadIdx().x - 1)
        section = 1 + (i*size(u,1)) : ((i+1)*size(u,1))
        @views @inbounds f(J[section,section],u[:,i+1],p[:,i+1],t)
        nothing
    end
    nothing
end

function discrete_condition_kernel(condition,cur,u,t,p)
    @loop for i in (1:size(u,2); (blockIdx().x-1) * blockDim().x + threadIdx().x)
        @views @inbounds cur[i] = condition(u[:,i],t,FakeIntegrator(u[:,i],t,p[:,i]))
        nothing
    end
    nothing
end

function discrete_affect!_kernel(affect!,cur,u,t,p)
    @loop for i in (1:size(u,2); (blockIdx().x-1) * blockDim().x + threadIdx().x)
        @views @inbounds cur[i] && affect!(FakeIntegrator(u[:,i],t,p[:,i]))
        nothing
    end
    nothing
end

function continuous_condition_kernel(condition,out,u,t,p)
    @loop for i in (1:size(u,2); (blockIdx().x-1) * blockDim().x + threadIdx().x)
        @views @inbounds out[i] = condition(u[:,i],t,FakeIntegrator(u[:,i],t,p[:,i]))
        nothing
    end
    nothing
end

function continuous_affect!_kernel(affect!,event_idx,u,t,p)
    @loop for i in ((event_idx,); (blockIdx().x-1) * blockDim().x + threadIdx().x)
        @views @inbounds affect!(FakeIntegrator(u[:,i],t,p[:,i]))
        nothing
    end
    nothing
end

function GPUifyLoops.launch_config(::Union{typeof(gpu_kernel),
                                           typeof(jac_kernel),
                                           typeof(discrete_condition_kernel),
                                           typeof(discrete_affect!_kernel),
                                           typeof(continuous_condition_kernel),
                                           typeof(continuous_affect!_kernel)},
                                           maxthreads,context,g,f,du,u,args...;
                                           kwargs...)
    t = min(maxthreads,size(u,2))
    blocks = ceil(Int,size(u,2)/t)
    (threads=t,blocks=blocks)
end

function W_kernel(jac, W, u, p, gamma, t)
    len = size(u,1)
    @loop for i in (1:size(u,2); (blockIdx().x-1) * blockDim().x + threadIdx().x)
        _W = @inbounds @view(W[:, :, i])
        @views @inbounds jac(_W,u[:,i],p[:,i],t)
        @inbounds for i in eachindex(_W)
            _W[i] = gamma*_W[i]
        end
        _one = one(eltype(_W))
        @inbounds for i in 1:len
            _W[i, i] = _W[i, i] - _one
        end
        nothing
    end
    return nothing
end

function Wt_kernel(jac, W, u, p, gamma, t)
    len = size(u,1)
    @loop for i in (1:size(u,2); (blockIdx().x-1) * blockDim().x + threadIdx().x)
        _W = @inbounds @view(W[:, :, i])
        @views @inbounds jac(_W,u[:,i],p[:,i],t)
        @inbounds for i in 1:len
            _W[i, i] = -inv(gamma) + _W[i, i]
        end
        nothing
    end
    return nothing
end

function GPUifyLoops.launch_config(::Union{typeof(W_kernel),typeof(Wt_kernel)},
                                           maxthreads,context,g,jac,W,u,args...;
                                           kwargs...)
    t = min(maxthreads,size(u,2))
    blocks = ceil(Int,size(u,2)/t)
    (threads=t,blocks=blocks)
end

function cuda_lufact!(W)
    CuArrays.CUBLAS.getrf_strided_batched!(W, false)
    return nothing
end

function cpu_lufact!(W)
    len = size(W, 1)
    for i in 1:size(W,3)
        _W = @inbounds @view(W[:, :, i])
        generic_lufact!(_W, len)
    end
    return nothing
end

struct FakeIntegrator{uType,tType,P}
    u::uType
    t::tType
    p::P
end

abstract type EnsembleArrayAlgorithm <: DiffEqBase.EnsembleAlgorithm end
struct EnsembleCPUArray <: EnsembleArrayAlgorithm end
struct EnsembleGPUArray <: EnsembleArrayAlgorithm end

function DiffEqBase.__solve(ensembleprob::DiffEqBase.AbstractEnsembleProblem,
                 alg::Union{DiffEqBase.DEAlgorithm,Nothing},
                 ensemblealg::EnsembleArrayAlgorithm;
                 trajectories, batch_size = trajectories, kwargs...)

    num_batches = trajectories ÷ batch_size
    num_batches * batch_size != trajectories && (num_batches += 1)

    if num_batches == 1 && ensembleprob.reduction === DiffEqBase.DEFAULT_REDUCTION
       time = @elapsed sol = batch_solve(ensembleprob,alg,ensemblealg,1:trajectories;kwargs...)
       return DiffEqBase.EnsembleSolution(sol,time,true)
    end

    converged::Bool = false
    u = ensembleprob.u_init === nothing ? similar(batch_solve(ensembleprob,alg,ensemblealg,1:batch_size;kwargs...), 0) : ensembleprob.u_init

    if nprocs() == 1
        # While pmap works, this makes much better error messages.
        time = @elapsed begin
            sols = map(1:num_batches) do i
                if i == num_batches
                  I = (batch_size*(i-1)+1):trajectories
                else
                  I = (batch_size*(i-1)+1):batch_size*i
                end
                batch_data = batch_solve(ensembleprob,alg,ensemblealg,I;kwargs...)
                if ensembleprob.reduction !== DiffEqBase.DEFAULT_REDUCTION
                  u, _ = ensembleprob.reduction(u,batch_data,I)
                  return u
                else
                  batch_data
                end
            end
        end
    else
        time = @elapsed begin
            sols = pmap(1:num_batches) do i
                if i == num_batches
                  I = (batch_size*(i-1)+1):trajectories
                else
                  I = (batch_size*(i-1)+1):batch_size*i
                end
                x = batch_solve(ensembleprob,alg,ensemblealg,I;kwargs...)
                yield()
                if ensembleprob.reduction !== DiffEqBase.DEFAULT_REDUCTION
                  u, _ = ensembleprob.reduction(u,x,I)
                else
                  x
                end

            end
        end
    end

    if ensembleprob.reduction === DiffEqBase.DEFAULT_REDUCTION
        DiffEqBase.EnsembleSolution(hcat(sols...),time,true)
    else
        DiffEqBase.EnsembleSolution(sols[end], time, true)
    end
end

function batch_solve(ensembleprob,alg,ensemblealg,I;kwargs...)
    probs = [ensembleprob.prob_func(deepcopy(ensembleprob.prob),i,1) for i in I]
    @assert all(p->p.tspan == probs[1].tspan,probs)
    @assert !isempty(I)
    #@assert all(p->p.f === probs[1].f,probs)

    len = length(probs[1].u0)
    if ensemblealg isa EnsembleGPUArray
        # it's 1:length(I) since probs is generated above with for i in I
        u0 = CuArray(hcat([probs[i].u0 for i in 1:length(I)]...))
        p  = CuArray(hcat([probs[i].p  for i in 1:length(I)]...))
    elseif ensemblealg isa EnsembleCPUArray
        u0 = hcat([probs[i].u0 for i in 1:length(I)]...)
        p  = hcat([probs[i].p  for i in 1:length(I)]...)
    end

    if DiffEqBase.has_jac(probs[1].f)
        jac_prototype = ensemblealg isa EnsembleGPUArray ?
                        cu(zeros(Float32,len,len,length(I))) :
                        zeros(Float32,len,len,length(I))
        if probs[1].f.colorvec !== nothing
            colorvec = repeat(probs[1].f.colorvec,length(I))
        else
            colorvec = repeat(1:length(probs[1].u0),length(I))
        end
    else
        jac_prototype = nothing
        colorvec = nothing
    end

    _callback = generate_callback(probs[1],length(I),ensemblealg)
    prob = generate_problem(probs[1],u0,p,jac_prototype,colorvec)

    internalnorm(u::CuArray,t) = sqrt(maximum(sum(abs2, u, dims=1)/size(u, 1)))
    internalnorm(u::Union{AbstractFloat,Complex},t) = abs(u)

    sol  = solve(prob,alg; callback = _callback,merge_callbacks = false,
                 #internalnorm=internalnorm,
                 kwargs...)

    us = Array.(sol.u)
    solus = [[@view(us[i][:,j]) for i in 1:length(us)] for j in 1:length(probs)]
    [ensembleprob.output_func(DiffEqBase.build_solution(probs[i],alg,sol.t,solus[i],destats=sol.destats,retcode=sol.retcode),i)[1] for i in 1:length(probs)]
end

function generate_problem(prob::ODEProblem,u0,p,jac_prototype,colorvec)
    _f = let f=prob.f.f
        function (du,u,p,t)
            version = u isa CuArray ? CUDA() : CPU()
            @launch version gpu_kernel(f,du,u,p,t)
        end
    end

    if DiffEqBase.has_jac(prob.f)
        _Wfact! = let jac=prob.f.jac
            function (W,u,p,gamma,t)
                iscuda = u isa CuArray
                version = iscuda ? CUDA() : CPU()
                @launch version W_kernel(jac, W, u, p, gamma, t)
                iscuda ? cuda_lufact!(W) : cpu_lufact!(W)
            end
        end
        _Wfact!_t = let jac=prob.f.jac
            function (W,u,p,gamma,t)
                iscuda = u isa CuArray
                version = iscuda ? CUDA() : CPU()
                @launch version Wt_kernel(jac, W, u, p, gamma, t)
                iscuda ? cuda_lufact!(W) : cpu_lufact!(W)
            end
        end
    else
        _Wfact! = nothing
        _Wfact!_t = nothing
    end

    if DiffEqBase.has_tgrad(prob.f)
        _tgrad = let tgrad=prob.f.tgrad
            function (J,u,p,t)
                version = u isa CuArray ? CUDA() : CPU()
                @launch version gpu_kernel(tgrad,J,u,p,t)
            end
        end
    else
        _tgrad = nothing
    end

    f_func = ODEFunction(_f,Wfact = _Wfact!,
                        Wfact_t = _Wfact!_t,
                        #colorvec=colorvec,
                        jac_prototype = jac_prototype,
                        tgrad=_tgrad)
    prob = ODEProblem(f_func,u0,prob.tspan,p;
                      prob.kwargs...)
end

function generate_problem(prob::SDEProblem,u0,p,jac_prototype,colorvec)
    _f = let f=prob.f.f
        function (du,u,p,t)
            version = u isa CuArray ? CUDA() : CPU()
            @launch version gpu_kernel(f,du,u,p,t)
        end
    end

    _g = let f=prob.f.g
        function (du,u,p,t)
            version = u isa CuArray ? CUDA() : CPU()
            @launch version gpu_kernel(f,du,u,p,t)
        end
    end

    if DiffEqBase.has_jac(prob.f)
        _Wfact! = let jac=prob.f.jac
            function (W,u,p,gamma,t)
                iscuda = u isa CuArray
                version = iscuda ? CUDA() : CPU()
                @launch version W_kernel(jac, W, u, p, gamma, t)
                iscuda ? cuda_lufact!(W) : cpu_lufact!(W)
            end
        end
        _Wfact!_t = let jac=prob.f.jac
            function (W,u,p,gamma,t)
                iscuda = u isa CuArray
                version = iscuda ? CUDA() : CPU()
                @launch version Wt_kernel(jac, W, u, p, gamma, t)
                iscuda ? cuda_lufact!(W) : cpu_lufact!(W)
            end
        end
    else
        _Wfact! = nothing
        _Wfact!_t = nothing
    end

    if DiffEqBase.has_tgrad(prob.f)
        _tgrad = let tgrad=prob.f.tgrad
            function (J,u,p,t)
                version = u isa CuArray ? CUDA() : CPU()
                @launch version gpu_kernel(tgrad,J,u,p,t)
            end
        end
    else
        _tgrad = nothing
    end

    f_func = SDEFunction(_f,_g,Wfact = _Wfact!,
                        Wfact_t = _Wfact!_t,
                        #colorvec=colorvec,
                        jac_prototype = jac_prototype,
                        tgrad=_tgrad)
    prob = SDEProblem(f_func,_g,u0,prob.tspan,p;
                      prob.kwargs...)
end

function generate_callback(prob,I,ensemblealg)
    if :callback ∉ keys(prob.kwargs)
        _callback = nothing
    elseif prob.kwargs[:callback] isa DiscreteCallback
        if ensemblealg isa EnsembleGPUArray
            cur = CuArray([false for i in 1:I])
        else
            cur = [false for i in 1:I]
        end
        _condition = prob.kwargs[:callback].condition
        _affect!   = prob.kwargs[:callback].affect!

        condition = function (u,t,integrator)
            version = u isa CuArray ? CUDA() : CPU()
            @launch version discrete_condition_kernel(_condition,cur,u,t,integrator.p)
            any(cur)
        end

        affect! = function (integrator)
            version = integrator.u isa CuArray ? CUDA() : CPU()
            @launch version discrete_affect!_kernel(_affect!,cur,integrator.u,integrator.t,integrator.p)
        end

        _callback = DiscreteCallback(condition,affect!,save_positions=prob.kwargs[:callback].save_positions)
    elseif prob.kwargs[:callback] isa ContinuousCallback
        _condition   = prob.kwargs[:callback].condition
        _affect!     = prob.kwargs[:callback].affect!
        _affect_neg! = prob.kwargs[:callback].affect_neg!

        condition = function (out,u,t,integrator)
            version = u isa CuArray ? CUDA() : CPU()
            @launch version continuous_condition_kernel(_condition,out,u,t,integrator.p)
            nothing
        end

        affect! = function (integrator,event_idx)
            version = integrator.u isa CuArray ? CUDA() : CPU()
            @launch version continuous_affect!_kernel(_affect!,event_idx,integrator.u,integrator.t,integrator.p)
        end

        affect_neg! = function (integrator,event_idx)
            version = integrator.u isa CuArray ? CUDA() : CPU()
            @launch version continuous_affect!_kernel(_affect_neg!,event_idx,integrator.u,integrator.t,integrator.p)
        end

        _callback = VectorContinuousCallback(condition,affect!,affect_neg!,I,save_positions=prob.kwargs[:callback].save_positions)
    end
    _callback
end

### GPU Factorization

struct LinSolveGPUSplitFactorize
    len::Int
    nfacts::Int
end
LinSolveGPUSplitFactorize() = LinSolveGPUSplitFactorize(0, 0)

function (p::LinSolveGPUSplitFactorize)(x,A,b,update_matrix=false;kwargs...)
    version = b isa CuArray ? CUDA() : CPU()
    copyto!(x, b)
    @launch version ldiv!_kernel(A,x,p.len,p.nfacts)
    return nothing
end

function (p::LinSolveGPUSplitFactorize)(::Type{Val{:init}},f,u0_prototype)
    LinSolveGPUSplitFactorize(size(u0_prototype)...)
end

function ldiv!_kernel(W,u,len,nfacts)
    @loop for i in (1:nfacts; (blockIdx().x-1) * blockDim().x + threadIdx().x)
        section = 1 + ((i-1)*len) : (i*len)
        _W = @inbounds @view(W[:, :, i])
        _u = @inbounds @view u[section]
        naivesolve!(_W, _u, len)
        nothing
    end
    return nothing
end

function GPUifyLoops.launch_config(::typeof(ldiv!_kernel),
                                           maxthreads,context,g,W,x,len,nfacts,
                                           args...;
                                           kwargs...)
    t = min(maxthreads,nfacts)
    blocks = ceil(Int,nfacts/t)
    (threads=t,blocks=blocks)
end

function __printjac(A, ii)
    @cuprintf "[%d, %d]\n" ii.offset1 ii.stride2
    @cuprintf "%d %d %d\n%d %d %d\n%d %d %d\n" ii[1, 1] ii[1, 2] ii[1, 3] ii[2, 1] ii[2, 2] ii[2, 3] ii[3, 1] ii[3, 2] ii[3, 3]
    @cuprintf "%2.2f %2.2f %2.2f\n%2.2f %2.2f %2.2f\n%2.2f %2.2f %2.2f" A[ii[1, 1]] A[ii[1, 2]] A[ii[1, 3]] A[ii[2, 1]] A[ii[2, 2]] A[ii[2, 3]] A[ii[3, 1]] A[ii[3, 2]] A[ii[3, 3]]
end

function generic_lufact!(A::AbstractMatrix{T}, minmn) where {T}
    m = n = minmn
    #@cuprintf "\n\nbefore lufact!\n"
    #__printjac(A, ii)
    #@cuprintf "\n"
    @inbounds for k = 1:minmn
        #@cuprintf "inner factorization loop\n"
        # Scale first column
        Akkinv = inv(A[k,k])
        for i = k+1:m
            #@cuprintf "L\n"
            A[i,k] *= Akkinv
        end
        # Update the rest
        for j = k+1:n, i = k+1:m
            #@cuprintf "U\n"
            A[i,j] -= A[i,k]*A[k,j]
        end
    end
    #@cuprintf "after lufact!"
    #__printjac(A, ii)
    #@cuprintf "\n\n\n"
    return nothing
end

struct MyL{T} # UnitLowerTriangular
    data::T
end
struct MyU{T} # UpperTriangular
    data::T
end

function naivesub!(A::MyU, b::AbstractVector, n)
    x = b
    @inbounds for j in n:-1:1
        xj = x[j] = A.data[j,j] \ b[j]
        for i in j-1:-1:1 # counterintuitively 1:j-1 performs slightly better
            b[i] -= A.data[i,j] * xj
        end
    end
    return nothing
end
function naivesub!(A::MyL, b::AbstractVector, n)
    x = b
    @inbounds for j in 1:n
        xj = x[j]
        for i in j+1:n
            b[i] -= A.data[i,j] * xj
        end
    end
    return nothing
end

function naivesolve!(A::AbstractMatrix, x::AbstractVector, n)
    naivesub!(MyL(A), x, n)
    naivesub!(MyU(A), x, n)
    return nothing
end

export EnsembleCPUArray, EnsembleGPUArray, LinSolveGPUSplitFactorize

end # module


text:
module TravelingSalesmanExact

using JuMP, UnicodePlots, Logging, LinearAlgebra, Printf
import MathOptInterface
const MOI = MathOptInterface
export get_optimal_tour,
       plot_cities,
       simple_parse_tsp,
       set_default_optimizer!

# added in Julia 1.2
if VERSION < v"1.2.0-"
    import Base.>
    >(x) = Base.Fix2(>, x)
end

# added in Julia 1.1
if VERSION < v"1.1.0-"
    isnothing(::Any) = false
    isnothing(::Nothing) = true
end

const default_optimizer = Ref{Any}(nothing)

const SLOW_SLEEP = Ref(1.5)

"""
    set_default_optimizer(O)

Sets the default optimizer. For example,

    using GLPK
    set_default_optimizer(GLPK.Optimizer)
"""
set_default_optimizer!(O) = default_optimizer[] = O

"""
    get_default_optimizer()

Gets the default optimizer, which is set by `set_default_optimizer`.
"""
get_default_optimizer() = default_optimizer[]

reset_default_optimizer!() = default_optimizer[] = nothing

"""
    plot_cities(cities)

Uses `UnicodePlots`'s `lineplot` to make a plot of the tour of the cities in
`cities`, in order (including going from the last city back to the first).
"""
function plot_cities(cities)
    loop = [cities[mod1(j+1, end)] for j = 0:length(cities)]
    return lineplot(first.(loop), last.(loop); height=18)
end

"""
    find_cycle(perm_matrix, starting_ind)

Returns the cycle in the permutation described by `perm_matrix` which includes
`starting_ind`.
"""
function find_cycle(perm_matrix, starting_ind = 1)
    cycle = [starting_ind]
    prev_ind = ind = starting_ind
    while true
        # the comparisons `x > (0.5)` should mean `x == 1`. Due to floating point results returned
        # by the solvers, instead we sometimes have `x ≈ 1.0` instead. Since these are binary
        # values, we might as well just compare to 1/2.
        next_ind = findfirst(>(0.5), @views(perm_matrix[ind, 1:prev_ind-1]))
        if isnothing(next_ind)
            next_ind = findfirst(>(0.5), @views(perm_matrix[ind, prev_ind+1:end])) +
                       prev_ind
        end
        next_ind == starting_ind && break
        push!(cycle, next_ind)
        prev_ind, ind = ind, next_ind
    end
    return cycle
end

"""
    get_cycles(perm_matrix)

Returns a list of cycles from the permutation described by `perm_matrix`.
"""
function get_cycles(perm_matrix)
    N = size(perm_matrix, 1)
    remaining_inds = Set(1:N)
    cycles = Vector{Int}[]
    while length(remaining_inds) > 0
        cycle = find_cycle(perm_matrix, first(remaining_inds))
        push!(cycles, cycle)
        setdiff!(remaining_inds, cycle)
    end
    return cycles
end

"""
    show_tour(cities, perm_matrix)

Show a plot of the tour described by `perm_matrix` of the cities in the vector `cities`.
"""
function plot_tour(cities, perm_matrix)
    cycles = get_cycles(perm_matrix)
    tour = reduce(vcat, cycles)
    return plot_cities(cities[tour])
end

"""
    remove_cycles!(model, tour_matrix)

Find the (non-maximal-length) cycles in the current solution `tour_matrix`
and add constraints to the JuMP model to disallow them. Returns the
number of cycles found.
"""
function remove_cycles!(model, tour_matrix; symmetric)
    tour_matrix_val = value.(tour_matrix)
    cycles = get_cycles(tour_matrix_val)
    length(cycles) == 1 && return 1
    for cycle in cycles
        constr = symmetric ? 2 * length(cycle) - 2 : length(cycle) - 1
        @constraint(model, sum(tour_matrix[cycle, cycle]) <= constr)
    end
    return length(cycles)
end

"""
    euclidean_distance(city1, city2)

The usual Euclidean distance measure.
"""
euclidean_distance(city1, city2) = sqrt((city1[1] - city2[1])^2 + (city1[2] - city2[2])^2)

"""
    ATT(city1, city2)

The `ATT` distance measure as specified in TSPLIB:
<http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/tsp95.pdf>.
"""
function ATT(city1, city2)
    xd = city1[1] - city2[1]
    yd = city1[2] - city2[2]
    r = sqrt((xd^2 + yd^2) / 10.0)
    t = round(Int, r)
    if t < r
        d = t + 1
    else
        d = t
    end
    return d
end

"""
    get_optimal_tour(
        cities::AbstractVector,
        optimizer = get_default_optimizer();
        distance = euclidean_distance,
        kwargs...
    )

    get_optimal_tour(
        cost::AbstractMatrix
        optimizer = get_default_optimizer();
        kwargs...
    )

Solves the travelling salesman problem for a list of cities using JuMP by
formulating a MILP using the Dantzig-Fulkerson-Johnson formulation and
adaptively adding constraints to disallow non-maximal cycles. Returns an optimal
tour and the cost of the optimal path. Optionally specify a distance metric.

The second argument is mandatory if a default optimizer has not been set (via
`set_default_optimizer`). This argument should be a function which creates an optimizer, e.g.

    get_optimal_tour(cities, GLPK.Optimizer)

There are five boolean optional keyword arguments:

* `verbose` (default: false) indicates whether or not to print lots of information as the algorithm proceeds.
* `symmetric` indicates whether or not the cost matrix is symmetric. By default, `issymmetric` is used to check.
* `lazy_constraints` indicates whether lazy constraints should be used (which requires a [compatible solver](https://www.juliaopt.org/JuMP.jl/v0.21/callbacks/#Available-solvers-1)).
* `slow` artifically sleeps after each solve to slow down the output for visualization purposes. Only takes affect if `verbose==true`.
* `silent_optimizer` calls `JuMP.set_silent` on the resulting model to prevent the optimizer from emitting logging information.

## Example

```jldoctest
julia> using TravelingSalesmanExact, GLPK, LinearAlgebra

julia> set_default_optimizer!(GLPK.Optimizer)
GLPK.Optimizer

julia> cities = [[0, 0], [0, 1], [1, 1], [1, 0]]
4-element Vector{Vector{Int64}}:
 [0, 0]
 [0, 1]
 [1, 1]
 [1, 0]

julia> tour, cost = get_optimal_tour(cities)
([4, 1, 2, 3], 4.0)

julia> cost_matrix = [norm(cities[i] - cities[j]) for i = 1:4, j = 1:4]
4×4 Matrix{Float64}:
 0.0      1.0      1.41421  1.0
 1.0      0.0      1.0      1.41421
 1.41421  1.0      0.0      1.0
 1.0      1.41421  1.0      0.0

julia> tour, cost = get_optimal_tour(cost_matrix)
([4, 1, 2, 3], 4.0)

```
"""
get_optimal_tour

function get_optimal_tour(
    cities::AbstractVector,
    optimizer = get_default_optimizer();
    verbose = false,
    distance = euclidean_distance,
    symmetric = nothing,
    lazy_constraints = false,
    slow=false,
    silent_optimizer=true,
)
    isnothing(optimizer) && throw(ArgumentError("An optimizer is required if a default optimizer has not been set."))
    N = length(cities)
    cost = [distance(cities[i], cities[j]) for i = 1:N, j = 1:N]
    if symmetric === nothing
        symmetric = issymmetric(cost)
    end
    return _get_optimal_tour(cost, optimizer, symmetric, verbose, lazy_constraints, cities, slow, silent_optimizer)
end

function get_optimal_tour(
    cost::AbstractMatrix,
    optimizer = get_default_optimizer();
    verbose = false,
    symmetric = issymmetric(cost),
    lazy_constraints = false,
    slow = false,
    silent_optimizer=true
)
    size(cost, 1) == size(cost, 2) || throw(ArgumentError("First argument must be a square matrix"))
    isnothing(optimizer) && throw(ArgumentError("An optimizer is required if a default optimizer has not been set."))
    return _get_optimal_tour(cost, optimizer, symmetric, verbose, lazy_constraints, nothing, slow, silent_optimizer)
end

function build_tour_matrix(model, cost::AbstractMatrix, symmetric::Bool)
    N = size(cost, 1)
    if symmetric
        # `tour_matrix` has tour_matrix[i,j] = 1 iff cities i and j should be connected
       @variable(model, tour_matrix[1:N, 1:N], Symmetric, binary = true)

       # cost of the tour
       @objective(model, Min, sum(tour_matrix[i, j] * cost[i, j] for i = 1:N, j = 1:i))
       for i = 1:N
           @constraint(model, sum(tour_matrix[i, :]) == 2) # degree of each city is 2
           @constraint(model, tour_matrix[i, i] == 0) # rule out cycles of length 1
       end
   else
       # `tour_matrix` will be a permutation matrix
       @variable(model, tour_matrix[1:N, 1:N], binary = true)
       @objective(model, Min, sum(tour_matrix[i, j] * cost[i, j] for i = 1:N, j = 1:N))
       for i = 1:N
           @constraint(model, sum(tour_matrix[i, :]) == 1) # row-sum is 1
           @constraint(model, sum(tour_matrix[:, i]) == 1) # col-sum is 1
           @constraint(model, tour_matrix[i, i] == 0) # rule out cycles of length 1
           for j = 1:N
               @constraint(model, tour_matrix[i, j] + tour_matrix[j, i] <= 1) # rule out cycles of length 2
           end
       end
   end
   return tour_matrix
end

function format_time(t)
    # I want more decimal digits to print the smaller the number is,
    # but never more than 4 decimal digits.
    # I think `round(t; sigdigits = ...)` might be a way to do
    # something like this, but I couldn't get it to work.
    str = if t > 100
        @sprintf("%.0f", t)
    elseif t > 1
        @sprintf("%.2f", t)
    elseif t > 0.1
        @sprintf("%.3f", t)
    else
        @sprintf("%.4f", t)
    end
    return str * " seconds"
end

function _get_optimal_tour(
    cost::AbstractMatrix,
    optimizer,
    symmetric,
    verbose,
    lazy_constraints,
    cities,
    slow,
    silent_optimizer,
)
    has_cities = !isnothing(cities)

    model = Model(optimizer)
    silent_optimizer && set_silent(model)
    tour_matrix = build_tour_matrix(model, cost, symmetric)

    if has_cities && verbose
        @info "Starting optimization." plot_cities(cities)
    elseif verbose
        @info "Starting optimization."
    end

    # counts for logging
    iter = Ref(0)
    tot_cycles = Ref(0)
    all_time = Ref(0.0)

    if lazy_constraints
        remove_cycles_callback = make_remove_cycles_callback(model, tour_matrix, has_cities, cities, verbose, symmetric, tot_cycles)
        MOI.set(model, MOI.LazyConstraintCallback(), remove_cycles_callback)
    end

    num_cycles = 2 # just something > 1

    while num_cycles > 1
        t = @elapsed optimize!(model)
        all_time[] += t
        status = termination_status(model)
        status == MOI.OPTIMAL || @warn("Problem status not optimal; got status $status")
        num_cycles = remove_cycles!(model, tour_matrix; symmetric = symmetric)
        tot_cycles[] += num_cycles
        iter[] += 1
        if verbose
            if num_cycles == 1
                description = "found a full cycle!"
            else
                description = "disallowed $num_cycles cycles."
            end

            if has_cities
                slow && sleep(max(0, SLOW_SLEEP[] - t))
                @info "Iteration $(iter[]) took $(format_time(t)), $description" plot_tour(
                    cities,
                    value.(tour_matrix),
                )
            else
                @info "Iteration $(iter[]) took $(format_time(t)), $description"
            end
        end
    end
    tot_cycles[] -= 1 # remove the true cycle

    status = termination_status(model)
    status == MOI.OPTIMAL || @warn(status)

    cycles = get_cycles(value.(tour_matrix))
    length(cycles) == 1 || error("Something went wrong; did not elimate all subtours. Please file an issue.")

    if verbose
        slow && sleep(SLOW_SLEEP[])
        obj = objective_value(model)
        obj_string = isinteger(obj) ? @sprintf("%i", obj) : @sprintf("%.2f", obj)
        @info "Optimization finished; adaptively disallowed $(tot_cycles[]) cycles."
        @info "The optimization runs took $(format_time(all_time[])) in total."
        @info "Final path has length $(obj_string)."
        @info "Final problem has $(num_constraints(model, VariableRef, MOI.ZeroOne)) binary variables,
            $(num_constraints(model,
            GenericAffExpr{Float64,VariableRef}, MOI.LessThan{Float64})) inequality constraints, and
            $(num_constraints(model, GenericAffExpr{Float64,VariableRef}, MOI.EqualTo{Float64})) equality constraints."
    end
    return first(cycles), objective_value(model)
end

function make_remove_cycles_callback(model, tour_matrix, has_cities, cities, verbose, symmetric, tot_cycles)
    num_triggers = Ref(0)
    return function remove_cycles_callback(cb_data)
        tour_matrix_val = callback_value.(Ref(cb_data), tour_matrix)

        # We only handle integral solutions
        # Could possibly also find cycles in the integer part of a mixed solution.
        any(x -> !(x ≈ round(Int, x)), tour_matrix_val) && return

        num_triggers[] += 1
        cycles = get_cycles(tour_matrix_val)

        if length(cycles) == 1
            if has_cities && verbose
                @info "Lazy constaint triggered ($(num_triggers[])); found a full cycle!" plot_tour(
                    cities,
                    tour_matrix_val,
                )
            elseif verbose
                @info "Lazy constaint triggered ($(num_triggers[])); found a full cycle!"
            end
            return nothing
        end

        for cycle in cycles
            constr = symmetric ? 2 * length(cycle) - 2 : length(cycle) - 1
            cycle_constraint = @build_constraint( sum(tour_matrix[cycle, cycle]) <= constr)
            MOI.submit(model, MOI.LazyConstraint(cb_data), cycle_constraint)
        end

        num_cycles = length(cycles)
        tot_cycles[] += num_cycles
        if has_cities && verbose
            @info "Lazy constaint triggered ($(num_triggers[])); disallowed $num_cycles cycles." plot_tour(
                cities,
                tour_matrix_val,
            )
        elseif verbose
            @info "Lazy constaint triggered ($(num_triggers[])); disallowed $num_cycles cycles."
        end
    end
    return nothing
end

"""
    simple_parse_tsp(filename; verbose = true)

Try to parse the ".tsp" file given by `filename`. Very simple implementation
just to be able to test the optimization; may break on other files. Returns a
list of cities for use in `get_optimal_tour`.
"""
function simple_parse_tsp(filename; verbose = true)
    cities = Vector{Float64}[]
    section = :Meta
    for line in readlines(filename)
        line = strip(line)
        line == "EOF" && break

        if section == :Meta && verbose
            println(line)
        end
        if section == :NODE_COORD_SECTION
            nums = split(line)
            @assert length(nums) == 3
            x = parse(Float64, nums[2])
            y = parse(Float64, nums[3])
            push!(cities, [x, y])
        end
        # change section type
        if line == "NODE_COORD_SECTION"
            section = :NODE_COORD_SECTION
        end
    end
    return cities
end

"""
    get_ATT48_cities() -> Vector{Vector{Int}}

A simple helper function to get the problem data for the ATT48 TSPLIB problem.

# Example

```jldoctest
julia> using TravelingSalesmanExact, GLPK

julia> cities = TravelingSalesmanExact.get_ATT48_cities()
48-element Vector{Vector{Float64}}:
 [6734.0, 1453.0]
 [2233.0, 10.0]
 [5530.0, 1424.0]
 [401.0, 841.0]
 [3082.0, 1644.0]
 [7608.0, 4458.0]
 [7573.0, 3716.0]
 [7265.0, 1268.0]
 [6898.0, 1885.0]
 [1112.0, 2049.0]
 ⋮
 [6271.0, 2135.0]
 [4985.0, 140.0]
 [1916.0, 1569.0]
 [7280.0, 4899.0]
 [7509.0, 3239.0]
 [10.0, 2676.0]
 [6807.0, 2993.0]
 [5185.0, 3258.0]
 [3023.0, 1942.0]

julia> get_optimal_tour(cities, GLPK.Optimizer, distance = TravelingSalesmanExact.ATT)
([5, 42, 24, 10, 45, 35, 4, 26, 2, 29  …  30, 36, 46, 33, 20, 47, 21, 32, 39, 48], 10628.0)

```
"""
function get_ATT48_cities()
    path = joinpath(@__DIR__, "..", "data", "att48.tsp")
    cities = simple_parse_tsp(path; verbose = false)
    return cities
end

end # module