PK #qVHm$! convexjl-v0.2.0/.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 #qVHa convexjl-v0.2.0/objects.inv# Sphinx inventory version 2
# Project: Convex.jl
# Version: 0.1
# The remainder of this file is compressed using zlib.
xKOKIP(.IILJQ5THe(+x\)XT$}SJsRS3P@Ġ!
S D1PK #qVHݵּa a convexjl-v0.2.0/index.html
Convex.jl is a Julia package for Disciplined Convex Programming (DCP).
Convex.jl makes it easy to describe optimization problems in a natural, mathematical syntax,
and to solve those problems using a variety of different (commercial and open-source) solvers.
Convex.jl can solve
linear programs
mixed-integer linear programs and mixed-integer second-order cone programs
Note that Convex.jl was previously called CVX.jl. This package is under active development; we welcome bug reports and feature requests. For usage questions, please contact us via the JuliaOpt mailing list.
Installing Convex.jl is a one step process. Open up Julia and type
Pkg.update()Pkg.add("Convex")
This does not install any solvers. If you don’t have a solver installed already, you will want to install a solver such as SCS by running
Pkg.add("SCS")
To solve certain problems such as mixed integer programming problems you will need to install another solver as well, such as GLPK. If you wish to use other solvers, please read the section on solvers.
with variable \(x\in \mathbf{R}^{n}\),
and problem data \(A \in \mathbf{R}^{m \times n}\), \(b \in \mathbf{R}^{m}\).
This problem can be solved in Convex.jl as follows:
# Make the Convex.jl module available
using Convex
# Generate random problem data
m = 4; n = 5
A = randn(m, n); b = randn(m, 1)
# Create a (column vector) variable of size n x 1.
x = Variable(n)
# The problem is to minimize ||Ax - b||^2 subject to x >= 0
# This can be done by: minimize(objective, constraints)
problem = minimize(sumsquares(A * x - b), [x >= 0])
# Solve the problem by calling solve!
solve!(problem)
# Check the status of the problem
problem.status # :Optimal, :Infeasible, :Unbounded etc.
# Get the optimum value
problem.optval
The basic building block of Convex.jl is called an expression, which can represent a variable, a constant, or a function of another expression. We discuss each kind of expression in turn.
The simplest kind of expression in Convex.jl is a variable. Variables in Convex.jl are declared using the Variable keyword, along with the dimensions of the variable.
Numbers, vectors, and matrices present in the Julia environment are wrapped automatically into a Constant expression when used in a Convex.jl expression.
Expressions in Convex.jl are formed by applying any atom (mathematical function defined in Convex.jl) to variables, constants, and other expressions. For a list of these functions, see operations.
Atoms are applied to expressions using operator overloading. For example, 2+2 calls Julia’s built-in addition operator, while 2+x calls the Convex.jl addition method and returns a Convex.jl expression. Many of the useful language features in Julia, such as arithmetic, array indexing, and matrix transpose are overloaded in Convex.jl so they may be used with variables and expressions just as they are used with native Julia types.
Expressions that are created must be DCP-compliant.
More information on DCP can be found here.
x=Variable(5)# The following are all expressionsy=sum(x)z=4*x+yz_1=z[1]
Convex.jl allows the values of the expressions to be evaluated directly.
x = Variable()
y = Variable()
z = Variable()
expr = x + y + z
problem = minimize(expr, x >= 1, y >= x, 4 * z >= y)
solve!(problem)
# Once the problem is solved, we can call evaluate() on expr:
evaluate(expr)
Constraints in Convex.jl are declared using the standard comparison operators <=, >=, and ==. They specify relations that must hold between two expressions. Convex.jl does not distinguish between strict and non-strict inequality constraints.
The objective of the problem is a scalar expression to be maximized or minimized by using maximize or minimize respectively. Feasibility problems can be expressed by either giving a constant as the objective, or using problem=satisfy(constraints).
A problem in Convex.jl consists of a sense (minimize, maximize, or satisfy), an objective (an expression to which the sense verb is to be
applied), and zero or more constraints that must be satisfied at the solution.
Problems may be constructed as
Constraints can be added at any time before the problem is solved.
# No constraints givenproblem=minimize(objective)# Add some constraintproblem.constraints+=constraint# Add many more constraintsproblem.constraints+=[constraint1,constraint2,...]
A problem can be solved by calling solve!:
solve!(problem)
After the problem is solved, problem.status records the status returned by the optimization solver, and can be :Optimal, :Infeasible, :Unbounded, :Indeterminate or :Error.
If the status is :Optimal, problem.optval will record the optimum value of the problem.
The optimal value for each variable x participating in the problem can be found in x.value.
The optimal value of an expression can be found by calling the evaluate() function on the expression as follows: evaluate(expr).
Convex.jl currently supports the following functions.
These functions may be composed according to the DCP composition rules to form new convex, concave, or affine expressions.
Convex.jl transforms each problem into an equivalent cone program in order to pass the problem to a specialized solver.
Depending on the types of functions used in the problem, the conic constraints may include linear, second-order, exponential, or semidefinite constraints, as well as any binary or integer constraints placed on the variables.
Below, we list each function available in Convex.jl organized by the (most complex) type of cone used to represent that function,
and indicate which solvers may be used to solve problems with those cones.
Problems mixing many different conic constraints can be solved by any solver that supports every kind of cone present in the problem.
In the notes column in the tables below, we denote implicit constraints imposed on the arguments to the function by IC,
and parameter restrictions that the arguments must obey by PR.
(Convex.jl will automatically impose ICs; the user must make sure to satisfy PRs.)
An optimization problem using these functions can be solved by any SOCP solver (including ECOS, SCS, Mosek, Gurobi, and CPLEX).
Of course, if an optimization problem has both LP and SOCP representable functions, then any solver that can solve both LPs and SOCPs can solve the problem.
operation
description
vexity
slope
notes
norm(x,p)
\((\sum x_i^p)^{1/p}\)
convex
increasing on
\(x \ge 0\)
decreasing on
\(x \le 0\)
PR: p>=1
vecnorm(x,p)
\((\sum x_{ij}^p)^{1/p}\)
convex
increasing on
\(x \ge 0\)
decreasing on
\(x \le 0\)
PR: p>=1
quadform(x,P)
\(x^T P x\)
convex in
\(x\)
affine in
\(P\)
increasing on
\(x \ge 0\)
decreasing on
\(x \le 0\)
increasing in
\(P\)
PR: either \(x\) or
\(P\)
must be constant;
if \(x\) is not
constant, then \(P\)
must be symmetric and
positive semidefinite
quadoverlin(x,y)
\(x^T x/y\)
convex
increasing on
\(x \ge 0\)
decreasing on
\(x \le 0\)
decreasing in
\(y\)
IC: \(y > 0\)
sumsquares(x)
\(\sum x_i^2\)
convex
increasing on
\(x \ge 0\)
decreasing on
\(x \le 0\)
none
sqrt(x)
\(\sqrt{x}\)
convex
decreasing
IC: \(x>0\)
square(x),x^2
\(x^2\)
convex
increasing on
\(x \ge 0\)
decreasing on
\(x \le 0\)
none
geomean(x,y)
\(\sqrt{xy}\)
concave
increasing
IC: \(x\ge0\),
\(y\ge0\)
huber(x)
huber(x,M)
\(\begin{cases}
x^2 &|x| \leq
M \\
2M|x| - M^2
&|x| > M
\end{cases}\)
An optimization problem using these functions can be solved by any solver that supports exponential constraints and semidefinite constraints simultaneously (SCS).
When an atom or constraint is applied to a scalar and a higher dimensional variable, the scalars are promoted. For example, we can do max(x,0) gives an expression with the shape of x whose elements are the maximum of the corresponding element of x and 0.
Convex.jl transforms each problem into an equivalent cone program in order to pass the problem to a specialized solver.
Depending on the types of functions used in the problem, the conic constraints may include linear, second-order, exponential, or semidefinite constraints, as well as any binary or integer constraints placed on the variables.
By default, Convex.jl does not install any solvers. Many users use the solver SCS, which is able to solve problems with linear, second-order cone constraints (SOCPs), exponential constraints and semidefinite constraints (SDPs).
Any other solver in JuliaOpt may also be used, so long as it supports the conic constraints used to represent the problem.
Most other solvers in the JuliaOpt ecosystem can be used to solve (mixed integer) linear programs (LPs and MILPs).
Mosek and Gurobi can be used to solve SOCPs (even with binary or integer constraints), and Mosek can also solve SDPs.
For up-to-date information about solver capabilities, please see the table here
describing which solvers can solve which kind of problems.
Installing these solvers is very simple. Just follow the instructions in the documentation for that solver.
To use a specific solver, you can use the following syntax
(Of course, the solver must be installed first.) For example, we can use GLPK to solve a MILP
using GLPKMathProgInterface
solve!(p, GLPKSolverMIP())
You can set or see the current default solver by
get_default_solver()
using Gurobi
set_default_solver(GurobiSolver()) # or set_default_solver(SCSSolver(verbose=0))
# Now Gurobi will be used by default as a solver
Many of the solvers also allow options to be passed in. More details can be found in each solver’s documentation.
For example, if we wish to turn off printing for the SCS solver (ie, run in quiet mode), we can do so by
using SCS
solve!(p, SCSSolver(verbose=false))
If we wish to increase the maximum number of iterations for ECOS or SCS, we can do so by
using ECOS
solve!(p, ECOSSolver(maxit=10000))
using SCS
solve!(p, SCSSolver(max_iters=10000))
Convex.jl and JuMP are both modelling languages for mathematical programming embedded in Julia, and both
interface with solvers via the MathProgBase interface, so many of the same solvers are available in both.
Convex.jl converts problems to a standard conic form. This approach requires (and certifies) that the problem
is convex and DCP compliant, and guarantees global optimality of the resulting solution.
JuMP allows nonlinear programming through an interface that learns about functions via their derivatives.
This approach is more flexible (for example, you can optimize non-convex functions), but can’t
guarantee global optimality if your function is not convex, or warn you if you’ve entered a non-convex formulation.
For linear programming, the difference is more stylistic. JuMP’s syntax is scalar-based and similar to AMPL and GAMS
making it easy and fast to create constraints by indexing and summation (like sum{x[i],i=1:numLocation}).
Convex.jl allows (and prioritizes) linear algebraic and functional constructions (like max(x,y)<A*z);
indexing and summation are also supported in Convex.jl, but are somewhat slower than in JuMP.
JuMP also lets you efficiently solve a sequence of problems when new constraints are added
or when coefficients are modified,
whereas Convex.jl parses the problem again whenever the solve! method is called.
Where can I learn more about Convex Optimization?¶
See the freely available book Convex Optimization by Boyd and Vandenberghe for general background on convex optimization.
For help understanding the rules of Disciplined Convex Programming, we recommend this DCP tutorial website.
Are there similar packages available in other languages?¶
Indeed! You might use CVXPY in Python, or CVX in Matlab.
If you use Convex.jl for published work, we encourage you to cite the software using the following BibTeX citation:
@article{convexjl,
title = {Convex Optimization in {J}ulia},
author ={Udell, Madeleine and Mohan, Karanveer and Zeng, David and Hong, Jenny and Diamond, Steven and Boyd, Stephen},
year = {2014},
journal = {SC14 Workshop on High Performance Technical Computing in Dynamic Languages},
archivePrefix = "arXiv",
eprint = {1410.4821},
primaryClass = "math-oc",
}
Convex.jl also returns the optimal dual variables for a problem. These are stored in the dual field associated with each constraint.
using Convex
x = Variable()
constraint = x >= 0
p = minimize(x, constraint)
solve!(p)
# Get the dual value for the constraint
p.constraints[1].dual
# or
constraint.dual
If you’re solving the same problem many times with different values
of a parameter, Convex.jl can initialize many solvers with the solution
to the previous problem, which sometimes speeds up the solution time.
This is called a warm start.
To use this feature,
pass the optional argument warmstart=true to the solve! method.
# initialize data
n = 1000
y = rand(n)
x = Variable(n)
# first solve
lambda = 100
problem = minimize(sumsquares(y - x) + lambda * sumsquares(x - 10))
@time solve!(problem)
# now warmstart
# if the solver takes advantage of warmstarts,
# this run will be faster
lambda = 105
@time solve!(problem, warmstart=true)
Convex.jl allows you to fix a variable x to a value by calling the fix! method.
Fixing the variable essentially turns it into a constant.
Fixed variables are sometimes also called parameters.
fix(x, v) fixes the variable x to the value v.
fix(x) fixes x to the value x.value, which might be the value
obtained by solving another problem involving the variable x.
To allow the variable x to vary again, call free!(x).
Fixing and freeing variables can be particularly useful as a tool
for performing alternating minimization on nonconvex problems.
For example, we can find an approximate solution to a nonnegative matrix factorization problem
with alternating minimization as follows.
We use warmstarts to speed up the solution.
# initialize nonconvex problem
n, k = 10, 1
A = rand(n, k) * rand(k, n)
x = Variable(n, k)
y = Variable(k, n)
problem = minimize(sum_squares(A - x*y), x>=0, y>=0)
# initialize value of y
y.value = rand(k, n)
# we'll do 10 iterations of alternating minimization
for i=1:10
# first solve for x
# with y fixed, the problem is convex
fix!(y)
solve!(problem, warmstart = i > 1 ? true : false)
free!(y)
# now solve for y with x fixed at the previous solution
fix!(x)
solve!(problem, warmstart = true)
free!(x)
end
')
.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 qVH*&c c % convexjl-v0.2.0/_static/websupport.js/*
* websupport.js
* ~~~~~~~~~~~~~
*
* sphinx.websupport utilties for all documentation.
*
* :copyright: Copyright 2007-2015 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