PK %Hm$! fmrbenchmark-stable/.buildinfo# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config:
tags:
PK %H fmrbenchmark-stable/objects.inv# Sphinx inventory version 2
# Project: fmrbenchmark
# Version: 0.0.4
# The remainder of this file is compressed using zlib.
xmA
1E=EaFp;7p!x MhmZUA܅>߲x!~hxGbs+/m
^*g
~lJf,
A/3ORULgK~s.cUe,FZV/UU/PK %H$Y fmrbenchmark-stable/index.html
This is the User’s Guide to the fmrbenchmark repository, which is part of a project to
develop benchmark problems for research in so-called “formal methods for
robotics.” This effort is stimulated by competitions, and the main website is
http://fmrchallenge.org. The two other major forms of documentation are the API
manual and the benchmark specifications. Among the latter documents are competition
rules. Besides these sources of documentation, there are comments in the code as
well as README and similar files throughout the repository.
For newcomers, a good place to begin is the Introduction.
This page provides orientation and an overall introduction to the repository. It
is a good place to begin before studying a particular benchmark. There are two
founding ambitions of the project: to develop benchmark problems for research in
so-called “formal methods for robotics,” and to create standard interfaces,
formats, etc. for expressing problems and using tools that implement methods
described in the research literature. Our effort is analogous to that of
SMT-LIB, which is for research in satisfiability
modulo theories.
There are four major kinds of entities in the repository:
benchmarks;
analysis tools for reviewing results from using benchmarks;
examples demonstrating components of benchmarks and solution controllers;
documentation.
Spanning all four of the above kinds is the supporting infrastructure. This
refers to header files, message formats, etc. that may be used by more than one
benchmark and that may be of independent interest, besides benchmarking.
The repository as a whole has a single version number. Depending on the eventual
pace of growth and styles of usage, we may begin to version significant
components separately. In any case, version numbers are of the form M.m.u,
and changes only to u are not expected to break any current usage.
Warning
The interfaces to command-line tools, the names of important ROS topics, and
other user-level aspects of the repository may change with little warning
until version 0.1.0. Beginning at that time, care will be taken to ensure
backwards-compatibility and to have more gradual deprecation.
A normative description of benchmarks as well as a development of notation and
problem formulation is given in the Challenge Document.
Below is a summary.
Benchmarks are organized into problem domains (sometimes also called “problem
settings”), which are defined in terms of several parameters. A problem
variant refines the domain by constraining possible values that may be assigned
to a parameter, e.g., deciding that time can only be a multiple of a constant
(the period). Finally, a problem instance is defined as a particular selection
of values consistent with a problem variant. The instance is the thing that is
actually to be solved. A special case of this taxonomy is a concrete benchmark
from industry that is to be solved as given, i.e., there is no need to provide
more details like how time progresses or what the initial state can be. In such
a case, the problem domain, variant, and instance are all the same.
There are no generic installation instructions. Instead, instructions and
requirements are described separately for each benchmark. Though there are
shared dependencies and some similar preparations, separately treating each
facilitates users who are only interested in some parts of the repository. E.g.,
try the Problem domain: Scaling chains of integrators.
While it may be possible to build the benchmarks and infrastructure on other
platforms, the current target is Ubuntu 14.04
running Linux x86_64 and the following:
The benchmarks are primarily implemented in C++ and C. As of version 0.0.0, most
of the examples and tools for reviewing results are in C++ and Python.
Often referred to as “the first domain,” the basic problem is to find a
controller for a given chain of integrators system so that all trajectories
repeatedly reach several regions while avoiding others.
While below we include pointers to the main websites for dependencies, many are
available via packages for your OS and may already be installed, especially if
you have ROS on Ubuntu 14.04. Supported platforms are described in the Introduction.
While not necessary to use the benchmark per se, supplemental objects including
tools for visualizing and reviewing results and example solutions are provided.
These have additional dependencies besides those that are required for the
benchmark. In particular, plotp.py and tdstat.py provide a means to
examine problem instances and results of trials, as demonstrated in the tutorial
below. Together with the fmrb Python package, which is under
tools/fmrb-pkg/ in the repository, the following additional dependencies are
present:
To build the “standalone” (i.e., independent of ROS) examples demonstrating
various parts of this benchmark, go to the dynamaestro directory
($FMRBENCHMARK/domains/integrator_chains/dynamaestro) and then follow the
usual CMake build instructions. On Unix without an
IDE, usually these are
mkdir build
cd build
cmake ..
make
One of the resulting programs is genproblem, the source of which is
$FMRBENCHMARK/domains/integrator_chains/dynamaestro/examples/standalone/genproblem.cpp.
The output is a problem instance in JSON. To visualize it, try
Note that the example controller lqr.py requires the Python Control System Library
(control) and a standard scientific Python stack including NumPy. Obtaining
these is described above in the Section Preparations.
Create a catkin workspace.
mkdir -p integrators_workspace/src
cd integrators_workspace/src
catkin_init_workspace
Create symbolic links to the ROS packages in the fmrbenchmark repository
required for this example.
Because the installation is local to the catkin workspace, before beginning and
whenever a new shell session is created, you must first
source install/setup.zsh
where the source command assumes that you are using the Z shell; try
setup.bash if you use Bash.
To initiate the performance of a collection of trials defined by the
configuration file mc-small-out3-order3.json in the ROS package
sci_concrete_examples of example controllers,
This will cause trial data to be saved to the file mydata.json in the local
directory from where the above command is executed. A description of options can
be obtained from trial-runner.py-h.
In a separate terminal, run the example controller using:
roslaunch sci_concrete_examples lqr.launch
You can observe the sequence of states and control inputs using rostopicechostate and rostopicechoinput, respectively. At each time increment, the
state labeling is published to the topic /dynamaestro/loutput as an array of
strings (labels) corresponding to the polytopes containing the output at that
time.
Because we used the -l flag when invoking trial-runner.py above, two
additional topics are available. The labeling without repetition is published to
“/logger/loutput_norep”, and several elements (up to 3) of the state vector are
published to “/logger/state_PointStamped” as a PointStamped message, which can
be viewed in rviz.
Once all trials have completed, the trial data can be examined using
tdstat.py. E.g., to get a summary about the data for each trial,
Often referred to as “the second domain,” the basic setting is navigation in a
small network of roads with vehicles that follow unicycle-like dynamics.
Every road network is a 4-connected grid, subject to a rigid-body transformation: as such, the segments may not be axis-aligned.
While below we include pointers to the main websites for dependencies, many are
available via packages for your OS and may already be installed, especially if
you have ROS on Ubuntu 14.04. Supported platforms are described in the Introduction.
There are two major variants of this benchmark: one based in simulation and
another on a physical testbed. We begin with preparations appropriate for both.
Teleoperation of the vehicle to be controlled can be achieved using
kobuki_keyop ROS package. An example
demonstrating a configuration known to work in the simulation variant:
To build the “standalone” (i.e., independent of ROS) examples demonstrating
various parts of this benchmark, go to the dubins_traffic_utils directory
($FMRBENCHMARK/domains/dubins_traffic/dubins_traffic_utils) and then follow the usual CMake build instructions. On Unix without an
IDE, usually these are
mkdir build
cd build
cmake ..
make
One of the resulting programs is genproblem, the source of which is
$FMRBENCHMARK/domains/dubins_traffic/dubins_traffic_utils/examples/standalone/genproblem.cpp.
The output is a problem instance in JSON. To visualize it, try
Because the installation is local to the catkin workspace, before beginning and
whenever a new shell session is created, you must first
source install/setup.zsh
where the source command assumes that you are using the Z shell; try
setup.bash if you use Bash.
Finally, launch a small 4-grid road network with two adversarially controlled
vehicles, also known as e-agents (where ``e’’ abbreviates ``environment’‘).
This will cause trial data to be saved to the file mydata.json in the local directory from where the above command is executed.
The Gazebo server is launched without a GUI frontend, which is also known as
running headless.
A local viewer can be launched using
gzclient
The vehicle to be controlled has the ROS namespace /ego. The e-agents have
namespaces defined in the trials configuration file. In the example
mc-small-4grid-agents2.json used in this tutorial, these are /agent0 and
/agent1.
In a separate terminal, run your controller. For example, assuming your controller
is contained in the package your_controller with launch file foo.launch,
in a separate terminal, run
roslaunch your_controller foo.launch
You can run an example controller using:
roslaunch dubins_traffic_examples simple.launch
This is a simple controller that sets the ego vehicle’s forward and angular velocity based on the next goal to be visited, and cycles through goals in this manner.
Support code for working with road network descriptions is available in
roadnet.hpp and dubins_traffic.py.
You must hold the copyright or have explicit permission from the copyright
holder for anything that you contribute. Furthermore, to be included in this
project, your contributed works must be under the standard “BSD 3-clause
license” or a comparable open-source license (including public domain
dedication). You can find a copy at LICENSE in the root of the
repository. A license is “comparable” if it is no more restrictive than the
Apache License, Version 2.0.
Please report potential bugs or request features using the issue tracker. Guidelines for
participating in development are given in Developer’s Guide.
Proposals about benchmark problems or supporting infrastructure are always
welcome and need not have a demonstrating implementation. Furthermore, in your
proposal you can use an implementation that is not ready for immediate inclusion
in the repository, e.g., if it is created entirely in MATLAB. Such
implementations are still useful because they provide a reference about your
original intent and can be a basis for porting, e.g., to C++ or Python. In most
cases, there are three parts involved in the inclusion of a benchmark:
a normative description about the problem and methods of evaluation in the
Challenge Document;
introductory and tutorial treatment in the User’s Guide,
and relevant additions to the API manual;
details and practical considerations for using it as part of a competition.
Please report potential bugs or request features using the issue tracker.
Working on physical variants of the problem domains¶
One of our ambitions is to create benchmarks that involve physical systems. In
other words, we want to create well-documented testbeds that facilitate
repeatability of published experiments involving real robot hardware and are
challenging with respect to the state of the art.
There are a lot of incidental costs and resource requirements to develop
physical benchmarks, such as raw materials, lab space, etc. Usually these are
provided by each lab group for their own internal purposes (often with little or
no public disclosure of details). However, this project is a joint effort that
is not under the purview of a single grant nor institution. Thus an important
manner of contribution is to realize physical variants of the benchmarks in your
own lab and then give feedback about missing details, subtle considerations,
etc. Any of the venues listed above (at the beginning of Contributing)
can be used to provide comments. Also, the authors can be emailed directly.
Two important aspects of benchmarking are scale and comparability of performance
results. Several of the domains are designed to have problem instances that can
be arbitrarily large, e.g., Problem domain: Scaling chains of integrators. To support these
ambitions, we accept donations of hardware as well as of remote access to
computing resources, e.g., university-managed clusters or cloud computing
services.
Bugfixes and other corrections, implementations of new features, improvements to
documentation, etc. should be offered as pull requests. Patches can be submitted
through other media if you prefer, but please try to make it easy to use and
understand your proposed changes.
The benchmarks are primarily implemented in C++ and C. Unless there are strong
motivations to use a different programming language, we prefer these for
well-known reasons: they are fast, mature, standard, etc. Besides C and C++,
several core tools for analysis of results are in Python and rely on widely-used numerical and scientific
Python packages, among others. Observe that “tools for analysis” are not part of
the benchmarks per se.
Examples can be expressed in any programming language or depend on any tool,
including dependencies that have restrictive licenses. However, as with
everything else in the repository, the example itself must be under the standard
“BSD 3-clause license” or a comparable open-source license (including public
domain dedication). If you are going to contribute examples having dependencies
that are not free as in freedom, please carefully document the special
requirements for running the example controller.
')
.appendTo($('#searchbox'));
}
},
/**
* init the domain index toggle buttons
*/
initIndexTable : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle();
if (src.substr(-9) == 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click();
}
},
/**
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('#searchbox .highlight-link').fadeOut(300);
$('span.highlighted').removeClass('highlighted');
},
/**
* make the url absolute
*/
makeURL : function(relativeURL) {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
},
/**
* get the current relative url
*/
getCurrentURL : function() {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this == '..')
parts.pop();
});
var url = parts.join('/');
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
}
};
// quick alias for translations
_ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});
PK H8c c ) fmrbenchmark-stable/_static/websupport.js/*
* websupport.js
* ~~~~~~~~~~~~~
*
* sphinx.websupport utilties for all documentation.
*
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
(function($) {
$.fn.autogrow = function() {
return this.each(function() {
var textarea = this;
$.fn.autogrow.resize(textarea);
$(textarea)
.focus(function() {
textarea.interval = setInterval(function() {
$.fn.autogrow.resize(textarea);
}, 500);
})
.blur(function() {
clearInterval(textarea.interval);
});
});
};
$.fn.autogrow.resize = function(textarea) {
var lineHeight = parseInt($(textarea).css('line-height'), 10);
var lines = textarea.value.split('\n');
var columns = textarea.cols;
var lineCount = 0;
$.each(lines, function() {
lineCount += Math.ceil(this.length / columns) || 1;
});
var height = lineHeight * (lineCount + 1);
$(textarea).css('height', height);
};
})(jQuery);
(function($) {
var comp, by;
function init() {
initEvents();
initComparator();
}
function initEvents() {
$(document).on("click", 'a.comment-close', function(event) {
event.preventDefault();
hide($(this).attr('id').substring(2));
});
$(document).on("click", 'a.vote', function(event) {
event.preventDefault();
handleVote($(this));
});
$(document).on("click", 'a.reply', function(event) {
event.preventDefault();
openReply($(this).attr('id').substring(2));
});
$(document).on("click", 'a.close-reply', function(event) {
event.preventDefault();
closeReply($(this).attr('id').substring(2));
});
$(document).on("click", 'a.sort-option', function(event) {
event.preventDefault();
handleReSort($(this));
});
$(document).on("click", 'a.show-proposal', function(event) {
event.preventDefault();
showProposal($(this).attr('id').substring(2));
});
$(document).on("click", 'a.hide-proposal', function(event) {
event.preventDefault();
hideProposal($(this).attr('id').substring(2));
});
$(document).on("click", 'a.show-propose-change', function(event) {
event.preventDefault();
showProposeChange($(this).attr('id').substring(2));
});
$(document).on("click", 'a.hide-propose-change', function(event) {
event.preventDefault();
hideProposeChange($(this).attr('id').substring(2));
});
$(document).on("click", 'a.accept-comment', function(event) {
event.preventDefault();
acceptComment($(this).attr('id').substring(2));
});
$(document).on("click", 'a.delete-comment', function(event) {
event.preventDefault();
deleteComment($(this).attr('id').substring(2));
});
$(document).on("click", 'a.comment-markup', function(event) {
event.preventDefault();
toggleCommentMarkupBox($(this).attr('id').substring(2));
});
}
/**
* Set comp, which is a comparator function used for sorting and
* inserting comments into the list.
*/
function setComparator() {
// If the first three letters are "asc", sort in ascending order
// and remove the prefix.
if (by.substring(0,3) == 'asc') {
var i = by.substring(3);
comp = function(a, b) { return a[i] - b[i]; };
} else {
// Otherwise sort in descending order.
comp = function(a, b) { return b[by] - a[by]; };
}
// Reset link styles and format the selected sort option.
$('a.sel').attr('href', '#').removeClass('sel');
$('a.by' + by).removeAttr('href').addClass('sel');
}
/**
* Create a comp function. If the user has preferences stored in
* the sortBy cookie, use those, otherwise use the default.
*/
function initComparator() {
by = 'rating'; // Default to sort by rating.
// If the sortBy cookie is set, use that instead.
if (document.cookie.length > 0) {
var start = document.cookie.indexOf('sortBy=');
if (start != -1) {
start = start + 7;
var end = document.cookie.indexOf(";", start);
if (end == -1) {
end = document.cookie.length;
by = unescape(document.cookie.substring(start, end));
}
}
}
setComparator();
}
/**
* Show a comment div.
*/
function show(id) {
$('#ao' + id).hide();
$('#ah' + id).show();
var context = $.extend({id: id}, opts);
var popup = $(renderTemplate(popupTemplate, context)).hide();
popup.find('textarea[name="proposal"]').hide();
popup.find('a.by' + by).addClass('sel');
var form = popup.find('#cf' + id);
form.submit(function(event) {
event.preventDefault();
addComment(form);
});
$('#s' + id).after(popup);
popup.slideDown('fast', function() {
getComments(id);
});
}
/**
* Hide a comment div.
*/
function hide(id) {
$('#ah' + id).hide();
$('#ao' + id).show();
var div = $('#sc' + id);
div.slideUp('fast', function() {
div.remove();
});
}
/**
* Perform an ajax request to get comments for a node
* and insert the comments into the comments tree.
*/
function getComments(id) {
$.ajax({
type: 'GET',
url: opts.getCommentsURL,
data: {node: id},
success: function(data, textStatus, request) {
var ul = $('#cl' + id);
var speed = 100;
$('#cf' + id)
.find('textarea[name="proposal"]')
.data('source', data.source);
if (data.comments.length === 0) {
ul.html('
No comments yet.
');
ul.data('empty', true);
} else {
// If there are comments, sort them and put them in the list.
var comments = sortComments(data.comments);
speed = data.comments.length * 100;
appendComments(comments, ul);
ul.data('empty', false);
}
$('#cn' + id).slideUp(speed + 200);
ul.slideDown(speed);
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem retrieving the comments.');
},
dataType: 'json'
});
}
/**
* Add a comment via ajax and insert the comment into the comment tree.
*/
function addComment(form) {
var node_id = form.find('input[name="node"]').val();
var parent_id = form.find('input[name="parent"]').val();
var text = form.find('textarea[name="comment"]').val();
var proposal = form.find('textarea[name="proposal"]').val();
if (text == '') {
showError('Please enter a comment.');
return;
}
// Disable the form that is being submitted.
form.find('textarea,input').attr('disabled', 'disabled');
// Send the comment to the server.
$.ajax({
type: "POST",
url: opts.addCommentURL,
dataType: 'json',
data: {
node: node_id,
parent: parent_id,
text: text,
proposal: proposal
},
success: function(data, textStatus, error) {
// Reset the form.
if (node_id) {
hideProposeChange(node_id);
}
form.find('textarea')
.val('')
.add(form.find('input'))
.removeAttr('disabled');
var ul = $('#cl' + (node_id || parent_id));
if (ul.data('empty')) {
$(ul).empty();
ul.data('empty', false);
}
insertComment(data.comment);
var ao = $('#ao' + node_id);
ao.find('img').attr({'src': opts.commentBrightImage});
if (node_id) {
// if this was a "root" comment, remove the commenting box
// (the user can get it back by reopening the comment popup)
$('#ca' + node_id).slideUp();
}
},
error: function(request, textStatus, error) {
form.find('textarea,input').removeAttr('disabled');
showError('Oops, there was a problem adding the comment.');
}
});
}
/**
* Recursively append comments to the main comment list and children
* lists, creating the comment tree.
*/
function appendComments(comments, ul) {
$.each(comments, function() {
var div = createCommentDiv(this);
ul.append($(document.createElement('li')).html(div));
appendComments(this.children, div.find('ul.comment-children'));
// To avoid stagnating data, don't store the comments children in data.
this.children = null;
div.data('comment', this);
});
}
/**
* After adding a new comment, it must be inserted in the correct
* location in the comment tree.
*/
function insertComment(comment) {
var div = createCommentDiv(comment);
// To avoid stagnating data, don't store the comments children in data.
comment.children = null;
div.data('comment', comment);
var ul = $('#cl' + (comment.node || comment.parent));
var siblings = getChildren(ul);
var li = $(document.createElement('li'));
li.hide();
// Determine where in the parents children list to insert this comment.
for(i=0; i < siblings.length; i++) {
if (comp(comment, siblings[i]) <= 0) {
$('#cd' + siblings[i].id)
.parent()
.before(li.html(div));
li.slideDown('fast');
return;
}
}
// If we get here, this comment rates lower than all the others,
// or it is the only comment in the list.
ul.append(li.html(div));
li.slideDown('fast');
}
function acceptComment(id) {
$.ajax({
type: 'POST',
url: opts.acceptCommentURL,
data: {id: id},
success: function(data, textStatus, request) {
$('#cm' + id).fadeOut('fast');
$('#cd' + id).removeClass('moderate');
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem accepting the comment.');
}
});
}
function deleteComment(id) {
$.ajax({
type: 'POST',
url: opts.deleteCommentURL,
data: {id: id},
success: function(data, textStatus, request) {
var div = $('#cd' + id);
if (data == 'delete') {
// Moderator mode: remove the comment and all children immediately
div.slideUp('fast', function() {
div.remove();
});
return;
}
// User mode: only mark the comment as deleted
div
.find('span.user-id:first')
.text('[deleted]').end()
.find('div.comment-text:first')
.text('[deleted]').end()
.find('#cm' + id + ', #dc' + id + ', #ac' + id + ', #rc' + id +
', #sp' + id + ', #hp' + id + ', #cr' + id + ', #rl' + id)
.remove();
var comment = div.data('comment');
comment.username = '[deleted]';
comment.text = '[deleted]';
div.data('comment', comment);
},
error: function(request, textStatus, error) {
showError('Oops, there was a problem deleting the comment.');
}
});
}
function showProposal(id) {
$('#sp' + id).hide();
$('#hp' + id).show();
$('#pr' + id).slideDown('fast');
}
function hideProposal(id) {
$('#hp' + id).hide();
$('#sp' + id).show();
$('#pr' + id).slideUp('fast');
}
function showProposeChange(id) {
$('#pc' + id).hide();
$('#hc' + id).show();
var textarea = $('#pt' + id);
textarea.val(textarea.data('source'));
$.fn.autogrow.resize(textarea[0]);
textarea.slideDown('fast');
}
function hideProposeChange(id) {
$('#hc' + id).hide();
$('#pc' + id).show();
var textarea = $('#pt' + id);
textarea.val('').removeAttr('disabled');
textarea.slideUp('fast');
}
function toggleCommentMarkupBox(id) {
$('#mb' + id).toggle();
}
/** Handle when the user clicks on a sort by link. */
function handleReSort(link) {
var classes = link.attr('class').split(/\s+/);
for (var i=0; iThank you! Your comment will show up '
+ 'once it is has been approved by a moderator.');
}
// Prettify the comment rating.
comment.pretty_rating = comment.rating + ' point' +
(comment.rating == 1 ? '' : 's');
// Make a class (for displaying not yet moderated comments differently)
comment.css_class = comment.displayed ? '' : ' moderate';
// Create a div for this comment.
var context = $.extend({}, opts, comment);
var div = $(renderTemplate(commentTemplate, context));
// If the user has voted on this comment, highlight the correct arrow.
if (comment.vote) {
var direction = (comment.vote == 1) ? 'u' : 'd';
div.find('#' + direction + 'v' + comment.id).hide();
div.find('#' + direction + 'u' + comment.id).show();
}
if (opts.moderator || comment.text != '[deleted]') {
div.find('a.reply').show();
if (comment.proposal_diff)
div.find('#sp' + comment.id).show();
if (opts.moderator && !comment.displayed)
div.find('#cm' + comment.id).show();
if (opts.moderator || (opts.username == comment.username))
div.find('#dc' + comment.id).show();
}
return div;
}
/**
* A simple template renderer. Placeholders such as <%id%> are replaced
* by context['id'] with items being escaped. Placeholders such as <#id#>
* are not escaped.
*/
function renderTemplate(template, context) {
var esc = $(document.createElement('div'));
function handle(ph, escape) {
var cur = context;
$.each(ph.split('.'), function() {
cur = cur[this];
});
return escape ? esc.text(cur || "").html() : cur;
}
return template.replace(/<([%#])([\w\.]*)\1>/g, function() {
return handle(arguments[2], arguments[1] == '%' ? true : false);
});
}
/** Flash an error message briefly. */
function showError(message) {
$(document.createElement('div')).attr({'class': 'popup-error'})
.append($(document.createElement('div'))
.attr({'class': 'error-message'}).text(message))
.appendTo('body')
.fadeIn("slow")
.delay(2000)
.fadeOut("slow");
}
/** Add a link the user uses to open the comments popup. */
$.fn.comment = function() {
return this.each(function() {
var id = $(this).attr('id').substring(1);
var count = COMMENT_METADATA[id];
var title = count + ' comment' + (count == 1 ? '' : 's');
var image = count > 0 ? opts.commentBrightImage : opts.commentImage;
var addcls = count == 0 ? ' nocomment' : '';
$(this)
.append(
$(document.createElement('a')).attr({
href: '#',
'class': 'sphinx-comment-open' + addcls,
id: 'ao' + id
})
.append($(document.createElement('img')).attr({
src: image,
alt: 'comment',
title: title
}))
.click(function(event) {
event.preventDefault();
show($(this).attr('id').substring(2));
})
)
.append(
$(document.createElement('a')).attr({
href: '#',
'class': 'sphinx-comment-close hidden',
id: 'ah' + id
})
.append($(document.createElement('img')).attr({
src: opts.closeCommentImage,
alt: 'close',
title: 'close'
}))
.click(function(event) {
event.preventDefault();
hide($(this).attr('id').substring(2));
})
);
});
};
var opts = {
processVoteURL: '/_process_vote',
addCommentURL: '/_add_comment',
getCommentsURL: '/_get_comments',
acceptCommentURL: '/_accept_comment',
deleteCommentURL: '/_delete_comment',
commentImage: '/static/_static/comment.png',
closeCommentImage: '/static/_static/comment-close.png',
loadingImage: '/static/_static/ajax-loader.gif',
commentBrightImage: '/static/_static/comment-bright.png',
upArrow: '/static/_static/up.png',
downArrow: '/static/_static/down.png',
upArrowPressed: '/static/_static/up-pressed.png',
downArrowPressed: '/static/_static/down-pressed.png',
voting: false,
moderator: false
};
if (typeof COMMENT_OPTIONS != "undefined") {
opts = jQuery.extend(opts, COMMENT_OPTIONS);
}
var popupTemplate = '\
\ Sort by:\ best rated\ newest\ oldest\
\\
Add a comment\ (markup):
\``code``
, \ code blocks:::
and an indented block after blank line