PK UHm$! opauth-1.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 UH5^ opauth-1.0/objects.inv# Sphinx inventory version 2
# Project: Opauth
# Version: 1.0
# The remainder of this file is compressed using zlib.
xK.JM,IU(.IILJQ5TKI(QNO.M+-.)KL-VVQphJTVru bs`QZPO)Ij*NM,J@(HLO yJPK UH]0L L opauth-1.0/index.html
Opauth is a multi-provider authentication framework for PHP, inspired by
OmniAuth for Ruby
Opauth enables PHP applications to do user authentication with ease, by providing a standardized method for PHP
applications to interface with authentication providers.
For many authentication providers we have strategies. A strategy is the adapter specific to a certain
authentication provider. If Opauth does not have a strategy for your favorite provider, it’s easy to
create one.
The easiest way to start with Opauth is using composer. Choosing to do a manual installation of Opauth will require
additional code for autoloading in your application.
We will use the Facebook strategy in the following example, but you
can use another strategy as well to get started. Just make sure you check the strategy README for the correct strategy
configuration keys. Also the strategy README files will include more info about setting up
everything specific to the provider.
You can add Opauth and strategies to your applications composer.json:
Next you to define your configuration. How/where you define and load the configuration array is entirely up to you.
The easiest way to configure Opauth is to use a single array that contains the both the configs for Opauth itself and the
strategies. Opauth config values are at the root level of the array, while the strategy configurations are stored in the
Strategy key. The array would look something like:
Next we will create opauth.php with the following contents:
<?phprequire'vendor/autoload.php';$config=array('Strategy'=>array('Facebook'=>array('app_id'=>'your_key','app_secret'=>'your_secret'),),'path'=>'/opauth.php/');$Opauth=newOpauth\Opauth\Opauth($config);try{$response=$Opauth->run();echo"Authed as ".$response->name." with uid".$response->uid;}catch(OpauthException$e){echo"Authentication error: ".$e->getMessage();}
Set DocumentRoot of your web server to this directory, or create a vhost as this example does not work when opauth
is in a subdirectory.
Now point the browser to http://localhost/opauth.php/facebook to see it in action.
Opauth v1 is more flexible then the 0.4 series, meaning you can use your own request parser class and inject strategies
manually. If you want to handle the request parsing yourself, you can create a class for this, which must implement
Opauth\Opauth\ParserInterface
You can now inject your own parser into Opauth`s constructor:
<?phpuseOpauth\Opauth\ParserInterface;classMyParserimplementsParserInterface{publicfunction__construct($path='/'){//your implementation}publicfunctionaction(){//your implementation}publicfunctionurlname(){//your implementation}publicfunctionproviderUrl(){//your implementation}}//Inject your parser object into Opauth constructor$Opauth=newOpauth\Opauth\Opauth($config,newMyParser('opauth-path'));$Opauth->run();
You can also set a strategy manually, instead of letting Opauth decide which strategy to run based off the parsed request:
Instantiation of Opauth class accepts a configuration array as input.
require'vendor/autoload.php';$config=array('path'=>'/auth/','http_client'=>"Opauth\\Opauth\\HttpClient\\Curl",'callback'=>'callback','Strategy'=>array(//strategy configurations should go here//See Strategy configuration section))$Opauth=newOpauth\Opauth\Opauth($config);$response=$Opauth->run();
path
Default: /
Path where Opauth is accessed.
Begins and ends with /
For example, if Opauth is reached at http://example.org/auth/, path
should be set to /auth/; if Opauth is reached at http://auth.example.org/,
path should be set to /
http_client
Default: Opauth\\Opauth\\HttpClient\\Curl for cURL (requires php_curl)
Client to be used by Opauth for making HTTP calls to authentication providers.
Each strategy has its own configuration keys. Check the strategy README file for more information.
The strategies should be configured in the 'Strategy' key in the config array, each under its own key that matches
the classname of the strategy.
Opauth now returns a Response object, which stores the result of a successful authentication.
A Response object must have five properties accesible publicly: provider, raw, uid, name, and credentials.
provider - The provider with which the user authenticated (e.g. ‘Twitter’ or ‘Facebook’)
raw - An array of all information gather about a user returned by the provider.
uid - A user identifier unique to the given provider, such as a Twitter user ID.
name - A user name unique to the given provider, such as a Facebook username.
credentials - If the authenticating service provides some kind of access token or other credentials upon authentication, these are passed through here.
info - An array containing information about the user, such as name, image, location, etc.
The following components of Opauth v1 is fully extensible:
Request parser
Opauth makes decision on which strategy, method, action to call based on URL.
You can override this if you wish to make a different decision.
Refer to Request/Parser.php and ParserInterface.php for more details.
HTTP Client
Opauth uses by default cURL for making http requests and has some other built-in clients.
Your own http client can be created if none of the built-in ones fits your needs.
Refer to HttpClientInterface.php for more details if you wish to create your own HTTP clients.
Strategy
Strategies are specific instructions for Opauth on how to handle 3rd-party provider’s authentication steps, which
can be hugely different from one to other.
See Available strategies for known list of Opauth-managed and community-contributed strategies.
Or see the Strategy contribution guide below if you would like to author your own.
Omit Opauth class
You can even choose not to use the Opauth class and just use the Strategies directly if needed, although this
will require additional code in your application. This possibility has been made possible based on users requesting
for this in the 0.4 cycle. In most cases you can probably still use Opauth class now and use a custom request
parser class to bend it to your needs.
Opauth is now more extensible than ever. Do not like how our parser works? You can easily extend or override it. The same can be said for many other components on Opauth. See Extend Opauth.
More streamlined callbacks
Opauth no longer does another internal callback to pass data back to your app. Now it simply returns the response. With this change, security components and v0.x transport mechanisms have been dropped, as they are no longer needed.
PHP >= 5.3
With the use of namespace, Opauth 1.0 is dropping support for PHP 5.2 and supports PHP >= 5.3.
Tighter integration with Composer
Opauth now makes full use of Composer for loading of strategies and any related dependencies.
Response object
Opauth now returns a more flexible and consistent Response object.
To upgrade your application (or framework specific plugin) from v0.4 to v1.0 you need to use Composer and go through the following changes:
Update the composer.json file of your application, if you had any, else you need to create the file in the root
of your application. The composer.json should look something like:
You need to point the versions for Opauth and the strategies you use to the 1.0 series.
Note
While Opauth and the strategies have not reached stable your root composer.json also needs to have:
"minimum-stability":"dev"
Run the following command: composerupdate, to get the correct versions installed into the vendor directory.
Add require'vendor/autoload.php'; in your application to get composers autoloading, if you don’t already have this.
Make sure you have a recent composer version, which includes PSR4 support. If you run into errors, run:
composerself-update.
You can keep the existing Opauth configuration array that you were using in v0.4, although many configuration options
have been removed. Please check the configurations section to see the current options.
In the file where you create an Opauth instance, add the following line at the top:
Next you need to make sure your strategy has both request() and callback() methods.
The request() method handles
the initial authentication request and MUST redirect or throw an OpauthException. To redirect you can use
AbstractStrategy::redirect($url,$data=array(),$exit=true).
The callback() method handles the callback from the provider and MUST return a Response object or throw
OpauthException.
For error handling AbstractStrategy has a convenience method error($message,$code,$raw=null) which will
throw the exception.
The AbstractStrategy also has a convenience method response($raw) for returning response objects.
If your strategy needs to read/write session data, please use the AbstractStrategy::sessionData($data=null)
getter/setter method.
To obtain the callback url you can use AbstractStrategy::callbackUrl()
Response attributes $uid, $name and $credentials MUST be set.
You can do this either using the response map:
//in your ``callback()`` method$response=$this->response($credentials);$responseMap=array('uid'=>'id','name'=>'name','info.name'=>'name','info.nickname'=>'screen_name');$response->setMap($responseMap);return$response;
or directly assiging values to the attributes themselves:
//in your ``callback()`` method$response->credentials=array('token'=>$results['oauth_token'],'secret'=>$results['oauth_token_secret']);return$response;
Opauth will use the response map to set values from the raw response to the Response class attributes.
This replaces the multiple calls to OpauthStrategy::mapProfile($person,'username._content','info.nickname'); in
version 0.4.
The argument for AbstractStrategy::setMap($map) should be an array, with keys pointing to dotnotated paths to the
Response attribute names and values containing the path to the raw data value.
If your strategy uses tmhOauth library, please add it as composer required library, instead of adding it as gitmodule
or including the code itself.
For more information about creating 1.0 strategies please check the Create a strategy section
Now that you are done migrating your strategy we would like to ask you to take the following into account:
Opauth itself now uses PSR2 coding standards. It is recommended to choose a coding standard for your strategy.
Ofcourse you are free not to use this or any other standard. Please at least mention which standard to be used, if any.
You can easily check if your strategy matches your standard with php-codesniffer.
Just run from commandline: phpcs--standard=PSR2--extensions=phpsrc/ and fix any errors/warnings if there are any.
Using a standard helps readabilty for other developers to contribute.
Please submit your strategy to packagist if you haven’t already. The package name would be the Opauth vendorname and
your strategyname, divided by a forward slash. The above example would result in opauth/example. Once its added
to packagist we can add your strategy to the list of supported strategies for version 1.0. Ofcourse you are free to
use your own vendorname instead of Opauth’s, but using opauth will make it more easy to be found.
If you need help with upgrading or you have other questions, please contact us for support
As with any open source project all help is very welcome. You can help by submitting pull requests or issues at github.
Also documentation changes can be done by github pull requests.
Furthermore you can create your own strategy if your favorite provider isn’t listed
yet and tell us about it, so we can add it to the list.
If you want to have your offline documentation, cd to the docs directory and run:
makehtml
Next you can open up docs/_build/html/index.html in your browser to view this documentation locally.
Also blogging, tweeting or promoting Opauth in any other way will help the project.
')
.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 yUH*&c c opauth-1.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