<commit_before>this.page = 0;
this.nb_items = 10;
this.search = getUrlParameter('search');
this.popular = getUrlParameter('popular');
this.tags = new Array();
this.users = new Array();
this.period = '';
$(document).ready(function() {
	this.page = getUrlParameter('num_page');
	this.nb_items = 10;
	this.search = getUrlParameter('search');
	this.popular = getUrlParameter('popular');
	if (this.popular == 'true') {
		$('#filter-popular').attr('style', '');
	}
	this.tags = new Array();
	this.users = new Array();
	this.period = '';

	$('#search_form').submit(function() {
		var data = $('#search_form').serializeArray();
		jQuery.each(data, function(i, field){
			if (field.name == 'search') {
				add_search(field.value);
			}
		});
		return false;
	});

	$.ajax({
		type: "POST",
		url: "api/",
		data: {
			'ajax' : 'main',
			'action' : 'fetch'
		},
		success: function(msg){
		}
	});

	$('div#loginBox span#dropdown').click(function() {
		var form_status = $('div#loginBox').attr('status');
		if (form_status == 'open') {
			$('div#loginBox').attr('status', 'close');
			$('div#loginBox').attr('class', 'close');
			toggle_login_dropdown('close');
		} else {
			$('div#loginBox').attr('class', 'open');
			$('div#loginBox').attr('status', 'open');
			toggle_login_dropdown('open');
		}
	});
	$("form.comment-form").submit(function() {
		var id = $(this).attr('postid');
		data = {
				'ajax' : 'comment',
				'action' : 'post_comment',
				'post_id' : id
			};
		$.each($(this).serializeArray(), function(i, field) {
			data[field['name']]=field['value'];
		});
		data['content'] = $('textarea#comment_text_'+id).attr('value');
		$.ajax({
			type: "POST",
			url: "api/",
			data: data,
			success: function(msg){
				updatePostList();
			}
		});
		return false;
	})
});

function getUrlParameter(name) {
	var searchString = location.search.substring(1).split('&');
	for (var i = 0; i < searchString.length; i++) {
		var parameter = searchString[i].split('=');
		if(name == parameter[0])
			return parameter[1];
	}
	return '';
}

function arrayToString(array) {
	var string = '';
	for (var i = 0; i < array.length; i++) {
		string += array[i];
		if (i < array.length -1) {
			string += ',';
		}
	}
	return string;
}

function updatePostList() {
	$('#filter-status').attr('style', '');
	var main_div = "body";
	$('div#'+main_div).fadeTo('slow', 0.5, function(){});
	$.ajax({
		type: "POST",
		url: "api/",
		data: {
			'ajax' : 'main',
			'action' : 'list',
			'page' : this.page,
			'nb_items' : this.nb_items,
			'search' : this.search,
			'popular' : this.popular,
			'tags' : arrayToString(this.tags),
			'users' : arrayToString(this.users),
			'period' : this.period
		},
		success: function(msg){
			$('div#'+main_div).html(msg);
			$('div#'+main_div).fadeTo('slow', 1, function(){});
			updateFeedList();
		}
	});
}

function next_page() {
	this.page += 1;
	updatePostList();
	$('#filter-page-content').html(this.page);
	$('#filter-page').attr('style', '');
}
function prev_page() {
	if (this.page > 0) {
		this.page -= 1;
	}
	updatePostList();
	if (this.page == 0) {
		$('#filter-page').attr('style', 'display:none;');
	} else {
		$('#filter-page-content').html(this.page);
		$('#filter-page').attr('style', '');
	}
}
function add_tag(tag) {
	this.page = 0;
	var already_exists = false;
	jQuery.each(this.tags, function(i, val) {
		if (val == tag) {
			already_exists = true;
		}
	});
	if (!already_exists) {
		this.tags.push(tag);
		updatePostList();
		var taglist = '';
		jQuery.each(this.tags, function(i, val) {
			taglist += ''+val+'';
		});
		$('#filter-page').attr('style', 'display:none;');
		$('#filter-tags-content').html(taglist);
		$('#filter-tags').attr('style', '');
	}
}
function rm_tag(tag) {
	this.page = 0;
	this.tags.pop(tag);
	updatePostList();
	$('#filter-page').attr('style', 'display:none;');
	if (this.tags.length == 0) {
		$('#filter-tags').attr('style', 'display:none;');
	} else {
		var taglist = '';
		jQuery.each(this.tags, function(i, tag) {
			taglist += ''+tag+'';
		});
		$('#filter-tags-content').html(taglist);
		$('#filter-tags').attr('style', '');
	}
}
function add_user(user) {
	this.page = 0;
	var already_exists = false;
	jQuery.each(this.users, function(i, val) {
		if (val == user) {
			already_exists = true;
		}
	});
	if (!already_exists) {
		this.users.push(user);
		updatePostList();
		var userlist = '';
		jQuery.each(this.users, function(i, val) {
			userlist += ''+val+'';
		});
		$('#filter-page').attr('style', 'display:none;');
		$('#filter-users-content').html(userlist);
		$('#filter-users').attr('style', '');
	}
}
function rm_user(user) {
	this.page = 0;
	this.users.pop(user);
	updatePostList();
	$('#filter-page').attr('style', 'display:none;');
	if (this.users.length == 0) {
		$('#filter-users').attr('style', 'display:none;');
	} else {
		var userlist = '';
		jQuery.each(this.users, function(i, user) {
			userlist += ''+user+'';
		});
		$('#filter-users-content').html(userlist);
		$('#filter-users').attr('style', '');
	}
}
function add_search(search) {
	this.page = 0;
	this.search = search;
	updatePostList();
	$('#filter-page').attr('style', 'display:none;');
	$('#filter-search-content').html(search+' (x)');
	$('#filter-search').attr('style', '');
}
function clear_search() {
	this.search = '';
	this.page = 0;
	updatePostList();
	$('#filter-page').attr('style', 'display:none;');
	$('#filter-search').attr('style', 'display:none');
}
function set_period(period) {
	this.page = 0;
	this.period = period;
	updatePostList();
	$('#filter-page').attr('style', 'display:none;');
	$('#filter-period-content').html(period+' (x)');
	$('#filter-period').attr('style', '');
}
function rm_period() {
	this.page = 0;
	this.period = '';
	updatePostList();
	$('#filter-page').attr('style', 'display:none;');
	$('#filter-period').attr('style', 'display:none');
}
function set_nb_items(nb) {
	this.page = 0;
	this.nb_items = nb;
	updatePostList();
	var html = '';
	$('#filter-page').attr('style', 'display:none;');
	if (nb != 10) {
		html += '10, '
	} else {
		html += '10, ';
	}
	if (nb != 15) {
		html += '15, '
	} else {
		html += '15, ';
	}
	if (nb != 20) {
		html += '20'
	} else {
		html += '20';
	}
	$('#filter-nb-items-content').html(html);
}

function updateFeedList() {
	var feedlink = 'http://localhost/~greg/bilboplanet/';
	feedlink += getFeedURL();
	$('a#filter-feed').attr('href',feedlink);
	if (this.tags.length > 0 || this.users.length > 0) {
		$('div#filter-feed').attr('style', '');
	} else {
		$('div#filter-feed').attr('style', 'display:none;');
	}
}
function getFeedURL() {
	var feed_params = 'feed.php?type=atom';
	if (this.tags.length > 0) {
		var tag_list = 'tags='+arrayToString(this.tags);
		feed_params += '&'+tag_list;
	}
	if (this.users.length > 0) {
		var user_list = 'users='+arrayToString(this.users);
		feed_params += '&'+user_list;
	}
	if (this.popular) {
		feed_params += '&popular=true';
	}
	return feed_params;
}

function popup(url) {
	var width = $(window).width() * 0.9;
	var height = $(window).height() * 0.9;
	$('div#popup').attr('style', 'z-index:1000;width:'+width+'px;height:'+height+'px;');
	var iframe_w = width;
	var iframe_h = height - 20;
	$('div#popup .popup-content').html(''
	);
}
function close_popup() {
	$('div#popup .popup-content').html('');
	$('div#popup').attr('style', 'display:none;');
}
function toggle_login_dropdown(position, url) {
	if (position == 'open') {
		$("div#loginForm").attr('style', 'z-index: 100;');
	} else {
		$("div#loginForm").attr('style', 'z-index: -100;display:none');
	}
}
function tag_post(post_id, post_title) {
    var content = $('#tag-post-form form').clone();
    Boxy.askform(content, function(val) {
		var data = content.serialize().split('=');
        $.ajax({
            type: "POST",
            url: "user/api/",
			data : {'ajax' : 'tagging', 'action' : 'add_tags', 'post_id' : post_id, 'tags' : data[1]},
            success: function(msg){
                updatePostList();
            }
        });
    }, {
        title: "Tagging : " + post_title,
    });
}

function toggle_post_comments(post_id, comment_status) {
    $.ajax({
        type: "POST",
        url: "user/api/",
        data : {'ajax' : 'post',
			'action' : 'comment',
			'post_id' : post_id,
			'status': comment_status},
        success: function(msg){
            updatePostList();
        }
    });
}
<commit_msg>Ajout d'une croix<commit_after>this.page = 0;
this.nb_items = 10;
this.search = getUrlParameter('search');
this.popular = getUrlParameter('popular');
this.tags = new Array();
this.users = new Array();
this.period = '';
$(document).ready(function() {
	this.page = getUrlParameter('num_page');
	this.nb_items = 10;
	this.search = getUrlParameter('search');
	this.popular = getUrlParameter('popular');
	if (this.popular == 'true') {
		$('#filter-popular').attr('style', '');
	}
	this.tags = new Array();
	this.users = new Array();
	this.period = '';

	$('#search_form').submit(function() {
		var data = $('#search_form').serializeArray();
		jQuery.each(data, function(i, field){
			if (field.name == 'search') {
				add_search(field.value);
			}
		});
		return false;
	});

	$.ajax({
		type: "POST",
		url: "api/",
		data: {
			'ajax' : 'main',
			'action' : 'fetch'
		},
		success: function(msg){
		}
	});

	$('div#loginBox span#dropdown').click(function() {
		var form_status = $('div#loginBox').attr('status');
		if (form_status == 'open') {
			$('div#loginBox').attr('status', 'close');
			$('div#loginBox').attr('class', 'close');
			toggle_login_dropdown('close');
		} else {
			$('div#loginBox').attr('class', 'open');
			$('div#loginBox').attr('status', 'open');
			toggle_login_dropdown('open');
		}
	});
	$("form.comment-form").submit(function() {
		var id = $(this).attr('postid');
		data = {
				'ajax' : 'comment',
				'action' : 'post_comment',
				'post_id' : id
			};
		$.each($(this).serializeArray(), function(i, field) {
			data[field['name']]=field['value'];
		});
		data['content'] = $('textarea#comment_text_'+id).attr('value');
		$.ajax({
			type: "POST",
			url: "api/",
			data: data,
			success: function(msg){
				updatePostList();
			}
		});
		return false;
	})
});

function getUrlParameter(name) {
	var searchString = location.search.substring(1).split('&');
	for (var i = 0; i < searchString.length; i++) {
		var parameter = searchString[i].split('=');
		if(name == parameter[0])
			return parameter[1];
	}
	return '';
}

function arrayToString(array) {
	var string = '';
	for (var i = 0; i < array.length; i++) {
		string += array[i];
		if (i < array.length -1) {
			string += ',';
		}
	}
	return string;
}

function updatePostList() {
	$('#filter-status').attr('style', '');
	var main_div = "body";
	$('div#'+main_div).fadeTo('slow', 0.5, function(){});
	$.ajax({
		type: "POST",
		url: "api/",
		data: {
			'ajax' : 'main',
			'action' : 'list',
			'page' : this.page,
			'nb_items' : this.nb_items,
			'search' : this.search,
			'popular' : this.popular,
			'tags' : arrayToString(this.tags),
			'users' : arrayToString(this.users),
			'period' : this.period
		},
		success: function(msg){
			$('div#'+main_div).html(msg);
			$('div#'+main_div).fadeTo('slow', 1, function(){});
			updateFeedList();
		}
	});
}

function next_page() {
	this.page += 1;
	updatePostList();
	$('#filter-page-content').html(this.page);
	$('#filter-page').attr('style', '');
}
function prev_page() {
	if (this.page > 0) {
		this.page -= 1;
	}
	updatePostList();
	if (this.page == 0) {
		$('#filter-page').attr('style', 'display:none;');
	} else {
		$('#filter-page-content').html(this.page);
		$('#filter-page').attr('style', '');
	}
}
function add_tag(tag) {
	this.page = 0;
	var already_exists = false;
	jQuery.each(this.tags, function(i, val) {
		if (val == tag) {
			already_exists = true;
		}
	});
	if (!already_exists) {
		this.tags.push(tag);
		updatePostList();
		var taglist = '';
		jQuery.each(this.tags, function(i, val) {
			taglist += ''+val+' x';
		});
		$('#filter-page').attr('style', 'display:none;');
		$('#filter-tags-content').html(taglist);
		$('#filter-tags').attr('style', '');
	}
}
function rm_tag(tag) {
	this.page = 0;
	this.tags.pop(tag);
	updatePostList();
	$('#filter-page').attr('style', 'display:none;');
	if (this.tags.length == 0) {
		$('#filter-tags').attr('style', 'display:none;');
	} else {
		var taglist = '';
		jQuery.each(this.tags, function(i, tag) {
			taglist += ''+tag+'';
		});
		$('#filter-tags-content').html(taglist);
		$('#filter-tags').attr('style', '');
	}
}
function add_user(user) {
	this.page = 0;
	var already_exists = false;
	jQuery.each(this.users, function(i, val) {
		if (val == user) {
			already_exists = true;
		}
	});
	if (!already_exists) {
		this.users.push(user);
		updatePostList();
		var userlist = '';
		jQuery.each(this.users, function(i, val) {
			userlist += ''+val+'';
		});
		$('#filter-page').attr('style', 'display:none;');
		$('#filter-users-content').html(userlist);
		$('#filter-users').attr('style', '');
	}
}
function rm_user(user) {
	this.page = 0;
	this.users.pop(user);
	updatePostList();
	$('#filter-page').attr('style', 'display:none;');
	if (this.users.length == 0) {
		$('#filter-users').attr('style', 'display:none;');
	} else {
		var userlist = '';
		jQuery.each(this.users, function(i, user) {
			userlist += ''+user+'';
		});
		$('#filter-users-content').html(userlist);
		$('#filter-users').attr('style', '');
	}
}
function add_search(search) {
	this.page = 0;
	this.search = search;
	updatePostList();
	$('#filter-page').attr('style', 'display:none;');
	$('#filter-search-content').html(search+' (x)');
	$('#filter-search').attr('style', '');
}
function clear_search() {
	this.search = '';
	this.page = 0;
	updatePostList();
	$('#filter-page').attr('style', 'display:none;');
	$('#filter-search').attr('style', 'display:none');
}
function set_period(period) {
	this.page = 0;
	this.period = period;
	updatePostList();
	$('#filter-page').attr('style', 'display:none;');
	$('#filter-period-content').html(period+' (x)');
	$('#filter-period').attr('style', '');
}
function rm_period() {
	this.page = 0;
	this.period = '';
	updatePostList();
	$('#filter-page').attr('style', 'display:none;');
	$('#filter-period').attr('style', 'display:none');
}
function set_nb_items(nb) {
	this.page = 0;
	this.nb_items = nb;
	updatePostList();
	var html = '';
	$('#filter-page').attr('style', 'display:none;');
	if (nb != 10) {
		html += '10, '
	} else {
		html += '10, ';
	}
	if (nb != 15) {
		html += '15, '
	} else {
		html += '15, ';
	}
	if (nb != 20) {
		html += '20'
	} else {
		html += '20';
	}
	$('#filter-nb-items-content').html(html);
}

function updateFeedList() {
	var feedlink = 'http://localhost/~greg/bilboplanet/';
	feedlink += getFeedURL();
	$('a#filter-feed').attr('href',feedlink);
	if (this.tags.length > 0 || this.users.length > 0) {
		$('div#filter-feed').attr('style', '');
	} else {
		$('div#filter-feed').attr('style', 'display:none;');
	}
}
function getFeedURL() {
	var feed_params = 'feed.php?type=atom';
	if (this.tags.length > 0) {
		var tag_list = 'tags='+arrayToString(this.tags);
		feed_params += '&'+tag_list;
	}
	if (this.users.length > 0) {
		var user_list = 'users='+arrayToString(this.users);
		feed_params += '&'+user_list;
	}
	if (this.popular) {
		feed_params += '&popular=true';
	}
	return feed_params;
}

function popup(url) {
	var width = $(window).width() * 0.9;
	var height = $(window).height() * 0.9;
	$('div#popup').attr('style', 'z-index:1000;width:'+width+'px;height:'+height+'px;');
	var iframe_w = width;
	var iframe_h = height - 20;
	$('div#popup .popup-content').html(''
	);
}
function close_popup() {
	$('div#popup .popup-content').html('');
	$('div#popup').attr('style', 'display:none;');
}
function toggle_login_dropdown(position, url) {
	if (position == 'open') {
		$("div#loginForm").attr('style', 'z-index: 100;');
	} else {
		$("div#loginForm").attr('style', 'z-index: -100;display:none');
	}
}
function tag_post(post_id, post_title) {
    var content = $('#tag-post-form form').clone();
    Boxy.askform(content, function(val) {
		var data = content.serialize().split('=');
        $.ajax({
            type: "POST",
            url: "user/api/",
			data : {'ajax' : 'tagging', 'action' : 'add_tags', 'post_id' : post_id, 'tags' : data[1]},
            success: function(msg){
                updatePostList();
            }
        });
    }, {
        title: "Tagging : " + post_title,
    });
}

function toggle_post_comments(post_id, comment_status) {
    $.ajax({
        type: "POST",
        url: "user/api/",
        data : {'ajax' : 'post',
			'action' : 'comment',
			'post_id' : post_id,
			'status': comment_status},
        success: function(msg){
            updatePostList();
        }
    });
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
/* mrkdwn v0.1.0 : github.com/benvacha/mrkdwn */

/*
Test suite for javascript mrkdwn implementation.
Exercises the mrkdwn implementation through node interface.

Requires:
    colors : https://github.com/Marak/colors.js
    diff : https://github.com/kpdecker/jsdiff

All Commands From Root (not javascript) Directory

Initial Setup
    npm install colors
    npm install diff

Run All Tests, prints pass or fail
    node javascript/test.js

Run All Tests, prints pass or fail and diff
    node javascript/test.js -v

Run A Test, prints pass or fail
    node javascript/test.js testName

Run A Test, prints pass or fail and diff
    node javascript/test.js -v testName

Run Multiple Tests, prints pass or fail
    node javascript/test.js testName testName testName

Run Multiple Tests, prints pass or fail and diff
    node javascript/test.js -v testName testName testName

*/

/*
 *
*/

// import node modules
var fs = require('fs'),
    colors = require('colors'),
    jsdiff = require('diff'),
    mrkdwn = require('./mrkdwn.js');

// parse command line arguements
var testDirectory = 'test/',
    verbose = false,
    testRuns = [];
if(process.argv[2] && process.argv[2] === '-v') {
    verbose = true;
    for(var i=3; i<process.argv.length; i++) {
        testRuns.push(process.argv[i]);
    }
} else {
    for(var i=2; i<process.argv.length; i++) {
        testRuns.push(process.argv[i]);
    }
}

/*
 *
*/

var utils = {

    // return blank string if invalid file, else return file contents as string
    readFile: function(fileName) {
        fileName = testDirectory + fileName;
        if(!fs.existsSync(fileName)) {
            console.log('## Invalid File: ' + fileName);
            return '';
        }
        return fs.readFileSync(fileName, {encoding:'utf8'})
    },

    // load markdownFile and markupFile, run testMethod on the markdown, return diff
    runTest: function(test) {
        if(!test) return null;
        var markdown = utils.readFile(test.markdown),
            markup = utils.readFile(test.markup);
        return jsdiff.diffChars(markup, test.method(markdown));
    },

    // print if the test passed or failed
    printPassFail: function(testName, diff) {
        if(diff && diff.length === 1) {
            console.log('# Passed Test: ' + testName);
        } else if(diff) {
            console.log('# Failed Test: ' + testName);
        } else {
            console.log('# Invalid Test: ' + testName);
        }
    },

    // print if the test passed or failed, print color coded diff
    printPassFailDiff: function(testName, diff) {
        utils.printPassFail(testName, diff);
        if(diff) {
            diff.forEach(function(part){
                if(part.added || part.removed) {
                    part.value = part.value.replace(/ /g, '_');
                }
                process.stdout.write(part.value.replace(/\n/g, '\\n\n')[part.added ? 'green' : part.removed ? 'red' : 'grey']);
            });
        }
        console.log('# End Test: ' + testName + '\n');
    }

};

/*
 *
*/

var tests = {

    escapedChars: {
        markdown: 'old/escaped-chars.markdown',
        markup: 'old/escaped-chars.markup',
        method: mrkdwn.markup.escapedChars
    }

};

/*
 *
*/

// if tests specified, run just those
// if no tests specified, run all tests
// if verbose print pass or fail and diff
// if not verbose print pass or fail
var diff;
if(testRuns.length) {
    for(var i=0; i<testRuns.length; i++) {
        diff = utils.runTest(tests[testRuns[i]]);
        if(verbose) {
            utils.printPassFailDiff(testRuns[i], diff);
        } else {
            utils.printPassFail(testRuns[i], diff);
        }
    }
} else {
    for(test in tests) {
        diff = utils.runTest(tests[test]);
        if(verbose) {
            utils.printPassFailDiff(test, diff);
        } else {
            utils.printPassFail(test, diff);
        }
    }
}<commit_msg>clean up verbose argument detection<commit_after>#!/usr/bin/env node
/* mrkdwn v0.1.0 : github.com/benvacha/mrkdwn */

/*
Test suite for javascript mrkdwn implementation.
Exercises the mrkdwn implementation through node interface.

Requires:
    colors : https://github.com/Marak/colors.js
    diff : https://github.com/kpdecker/jsdiff

All Commands From Root (not javascript) Directory

Initial Setup
    npm install colors
    npm install diff

Run All Tests, prints pass or fail
    node javascript/test.js

Run All Tests, prints pass or fail and diff
    node javascript/test.js -v

Run A Test, prints pass or fail
    node javascript/test.js testName

Run A Test, prints pass or fail and diff
    node javascript/test.js -v testName

Run Multiple Tests, prints pass or fail
    node javascript/test.js testName testName testName

Run Multiple Tests, prints pass or fail and diff
    node javascript/test.js -v testName testName testName

*/

/*
 *
*/

// import node modules
var fs = require('fs'),
    colors = require('colors'),
    jsdiff = require('diff'),
    mrkdwn = require('./mrkdwn.js');

// parse command line arguements
var testDirectory = 'test/',
    verbose = false,
    testRuns = [];
for(var i=2; i<process.argv.length; i++) {
    if(process.argv[i] === '-v') {
        verbose = true;
    } else {
        testRuns.push(process.argv[i]);
    }
}

/*
 *
*/

var utils = {

    // return blank string if invalid file, else return file contents as string
    readFile: function(fileName) {
        fileName = testDirectory + fileName;
        if(!fs.existsSync(fileName)) {
            console.log('## Invalid File: ' + fileName);
            return '';
        }
        return fs.readFileSync(fileName, {encoding:'utf8'})
    },

    // load markdownFile and markupFile, run testMethod on the markdown, return diff
    runTest: function(test) {
        if(!test) return null;
        var markdown = utils.readFile(test.markdown),
            markup = utils.readFile(test.markup);
        return jsdiff.diffChars(markup, test.method(markdown));
    },

    // print if the test passed or failed
    printPassFail: function(testName, diff) {
        if(diff && diff.length === 1) {
            console.log('# Passed Test: ' + testName);
        } else if(diff) {
            console.log('# Failed Test: ' + testName);
        } else {
            console.log('# Invalid Test: ' + testName);
        }
    },

    // print if the test passed or failed, print color coded diff
    printPassFailDiff: function(testName, diff) {
        utils.printPassFail(testName, diff);
        if(diff) {
            diff.forEach(function(part){
                if(part.added || part.removed) {
                    part.value = part.value.replace(/ /g, '_');
                }
                process.stdout.write(part.value.replace(/\n/g, '\\n\n')[part.added ? 'green' : part.removed ? 'red' : 'grey']);
            });
        }
        console.log('# End Test: ' + testName + '\n');
    }

};

/*
 *
*/

var tests = {

    escapedChars: {
        markdown: 'old/escaped-chars.markdown',
        markup: 'old/escaped-chars.markup',
        method: mrkdwn.markup.escapedChars
    }

};

/*
 *
*/

// if tests specified, run just those
// if no tests specified, run all tests
// if verbose print pass or fail and diff
// if not verbose print pass or fail
var diff;
if(testRuns.length) {
    for(var i=0; i<testRuns.length; i++) {
        diff = utils.runTest(tests[testRuns[i]]);
        if(verbose) {
            utils.printPassFailDiff(testRuns[i], diff);
        } else {
            utils.printPassFail(testRuns[i], diff);
        }
    }
} else {
    for(test in tests) {
        diff = utils.runTest(tests[test]);
        if(verbose) {
            utils.printPassFailDiff(test, diff);
        } else {
            utils.printPassFail(test, diff);
        }
    }
}<|endoftext|>


<commit_before>$(document).ready(function() {

	/* Use this js doc for all application specific JS */

	/* TABS --------------------------------- */
	/* Remove if you don't need :) */

	var tabs = $('dl.tabs');
		tabsContent = $('ul.tabs-content')

	function activateTab($tab) {
	  var $activeTab = $tab.closest('dl').find('a.active'),
	      contentLocation = $tab.attr("href") + 'Tab';

	  //Make Tab Active
	  $activeTab.removeClass('active');
	  $tab.addClass('active');

    //Show Tab Content
		$(contentLocation).closest('.tabs-content').find('li').hide();
		$(contentLocation).show();
	}

	tabs.each(function(i) {
		//Get all tabs
		var tab = $(this).children('dd').children('a');
		tab.click(function(e) {
		  activateTab($(this));
		});
	});

	if(window.location.hash) {
    activateTab($('a[href="' + window.location.hash + '"]'));
  }

	/* PLACEHOLDER FOR FORMS ------------- */
	/* Remove this and jquery.placeholder.min.js if you don't need :) */

	$('input, textarea').placeholder();

	/* DISABLED BUTTONS ------------- */
	/* Gives elements with a class of 'disabled' a return: false; */

});<commit_msg>Formatting and naming<commit_after>$(document).ready(function () {

	/* Use this js doc for all application specific JS */

	/* TABS --------------------------------- */
	/* Remove if you don't need :) */

	function activateTab($tab) {
	  var $activeTab = $tab.closest('dl').find('a.active'),
	      contentLocation = $tab.attr("href") + 'Tab';

	  //Make Tab Active
	  $activeTab.removeClass('active');
	  $tab.addClass('active');

    //Show Tab Content
		$(contentLocation).closest('.tabs-content').find('li').hide();
		$(contentLocation).show();
	}

	$('dl.tabs').each(function () {
		//Get all tabs
		var tabs = $(this).children('dd').children('a');
		tabs.click(function (e) {
		  activateTab($(this));
		});
	});

	if (window.location.hash) {
    activateTab($('a[href="' + window.location.hash + '"]'));
  }

	/* PLACEHOLDER FOR FORMS ------------- */
	/* Remove this and jquery.placeholder.min.js if you don't need :) */

	$('input, textarea').placeholder();

	/* DISABLED BUTTONS ------------- */
	/* Gives elements with a class of 'disabled' a return: false; */

});<|endoftext|>


<commit_before>import React, { Component } from 'react'

import 'normalize.css/normalize.css'
import './defaults.scss'
import './App.scss'
import './Range.scss'

import { version } from '../../package.json'
import ReactPlayer from '../ReactPlayer'
import Duration from './Duration'

export default class App extends Component {
  state = {
    url: null,
    playing: true,
    volume: 0.8,
    played: 0,
    loaded: 0,
    duration: 0
  }
  load = url => {
    this.setState({
      url,
      played: 0,
      loaded: 0
    })
  }
  playPause = () => {
    this.setState({ playing: !this.state.playing })
  }
  stop = () => {
    this.setState({ url: null, playing: false })
  }
  setVolume = e => {
    this.setState({ volume: parseFloat(e.target.value) })
  }
  onSeekMouseDown = e => {
    this.setState({ seeking: true })
  }
  onSeekChange = e => {
    this.setState({ played: parseFloat(e.target.value) })
  }
  onSeekMouseUp = e => {
    this.setState({ seeking: false })
    this.refs.player.seekTo(parseFloat(e.target.value))
  }
  onProgress = state => {
    // We only want to update time slider if we are not currently seeking
    if (!this.state.seeking) {
      this.setState(state)
    }
  }
  onConfigSubmit = () => {
    let config
    try {
      config = JSON.parse(this.refs.config.value)
    } catch (error) {
      config = {}
      console.error('Error setting config:', error)
    }
    this.setState(config)
  }
  renderLoadButton = (url, label) => {
    return (
      <button onClick={() => this.load(url)}>
        {label}
      </button>
    )
  }
  render () {
    const {
      url, playing, volume,
      played, loaded, duration,
      soundcloudConfig,
      vimeoConfig,
      youtubeConfig,
      fileConfig
    } = this.state
    const SEPARATOR = ' · '

    return (

ReactPlayer Demo

          <ReactPlayer
            ref='player'
            className='react-player'
            width={480}
            height={270}
            url={url}
            playing={playing}
            volume={volume}
            soundcloudConfig={soundcloudConfig}
            vimeoConfig={vimeoConfig}
            youtubeConfig={youtubeConfig}
            fileConfig={fileConfig}
            onStart={() => console.log('onStart')}
            onPlay={() => this.setState({ playing: true })}
            onPause={() => this.setState({ playing: false })}
            onBuffer={() => console.log('onBuffer')}
            onEnded={() => this.setState({ playing: false })}
            onError={e => console.log('onError', e)}
            onProgress={this.onProgress}
            onDuration={duration => this.setState({ duration })}
          />

              Controls

                <button onClick={this.stop}>Stop</button>
                <button onClick={this.playPause}>{playing ? 'Pause' : 'Play'}</button>

              Seek

                <input
                  type='range' min={0} max={1} step='any'
                  value={played}
                  onMouseDown={this.onSeekMouseDown}
                  onChange={this.onSeekChange}
                  onMouseUp={this.onSeekMouseUp}
                />

              Volume

                <input type='range' min={0} max={1} step='any' value={volume} onChange={this.setVolume} />

              Played
              <progress max={1} value={played} />

              Loaded
              <progress max={1} value={loaded} />

              YouTube

                {this.renderLoadButton('https://www.youtube.com/watch?v=oUFJJNQGwhk', 'Test A')}
                {this.renderLoadButton('https://www.youtube.com/watch?v=jNgP6d9HraI', 'Test B')}

              SoundCloud

                {this.renderLoadButton('https://soundcloud.com/miami-nights-1984/accelerated', 'Test A')}
                {this.renderLoadButton('https://soundcloud.com/tycho/tycho-awake', 'Test B')}

              Vimeo

                {this.renderLoadButton('https://vimeo.com/90509568', 'Test A')}
                {this.renderLoadButton('https://vimeo.com/94502406', 'Test B')}

              Streamable

                {this.renderLoadButton('https://streamable.com/moo', 'Test A')}
                {this.renderLoadButton('https://streamable.com/ifjh', 'Test B')}

              Files

                {this.renderLoadButton('http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4', 'MP4')}
                {this.renderLoadButton('http://clips.vorwaerts-gmbh.de/big_buck_bunny.ogv', 'OGV')}
                {this.renderLoadButton('http://clips.vorwaerts-gmbh.de/big_buck_bunny.webm', 'WEBM')}

              Custom URL

                <input ref='url' type='text' placeholder='Enter URL' />
                <button onClick={() => this.setState({ url: this.refs.url.value })}>Load</button>

              Custom config

                <textarea ref='config' placeholder='Enter JSON'></textarea>
                <button onClick={this.onConfigSubmit}>Update Config</button>

State

              url
              {url || 'null'}

              playing
              {playing ? 'true' : 'false'}

              volume
              {volume.toFixed(3)}

              played
              {played.toFixed(3)}

              loaded
              {loaded.toFixed(3)}

              duration
              <Duration seconds={duration} />

              elapsed
              <Duration seconds={duration * played} />

              remaining
              <Duration seconds={duration * (1 - played)} />

          Version {version}
          {SEPARATOR}
          GitHub
          {SEPARATOR}
          npm

    )
  }
}
<commit_msg>Textarea is self-closing<commit_after>import React, { Component } from 'react'

import 'normalize.css/normalize.css'
import './defaults.scss'
import './App.scss'
import './Range.scss'

import { version } from '../../package.json'
import ReactPlayer from '../ReactPlayer'
import Duration from './Duration'

export default class App extends Component {
  state = {
    url: null,
    playing: true,
    volume: 0.8,
    played: 0,
    loaded: 0,
    duration: 0
  }
  load = url => {
    this.setState({
      url,
      played: 0,
      loaded: 0
    })
  }
  playPause = () => {
    this.setState({ playing: !this.state.playing })
  }
  stop = () => {
    this.setState({ url: null, playing: false })
  }
  setVolume = e => {
    this.setState({ volume: parseFloat(e.target.value) })
  }
  onSeekMouseDown = e => {
    this.setState({ seeking: true })
  }
  onSeekChange = e => {
    this.setState({ played: parseFloat(e.target.value) })
  }
  onSeekMouseUp = e => {
    this.setState({ seeking: false })
    this.refs.player.seekTo(parseFloat(e.target.value))
  }
  onProgress = state => {
    // We only want to update time slider if we are not currently seeking
    if (!this.state.seeking) {
      this.setState(state)
    }
  }
  onConfigSubmit = () => {
    let config
    try {
      config = JSON.parse(this.refs.config.value)
    } catch (error) {
      config = {}
      console.error('Error setting config:', error)
    }
    this.setState(config)
  }
  renderLoadButton = (url, label) => {
    return (
      <button onClick={() => this.load(url)}>
        {label}
      </button>
    )
  }
  render () {
    const {
      url, playing, volume,
      played, loaded, duration,
      soundcloudConfig,
      vimeoConfig,
      youtubeConfig,
      fileConfig
    } = this.state
    const SEPARATOR = ' · '

    return (

ReactPlayer Demo

          <ReactPlayer
            ref='player'
            className='react-player'
            width={480}
            height={270}
            url={url}
            playing={playing}
            volume={volume}
            soundcloudConfig={soundcloudConfig}
            vimeoConfig={vimeoConfig}
            youtubeConfig={youtubeConfig}
            fileConfig={fileConfig}
            onStart={() => console.log('onStart')}
            onPlay={() => this.setState({ playing: true })}
            onPause={() => this.setState({ playing: false })}
            onBuffer={() => console.log('onBuffer')}
            onEnded={() => this.setState({ playing: false })}
            onError={e => console.log('onError', e)}
            onProgress={this.onProgress}
            onDuration={duration => this.setState({ duration })}
          />

              Controls

                <button onClick={this.stop}>Stop</button>
                <button onClick={this.playPause}>{playing ? 'Pause' : 'Play'}</button>

              Seek

                <input
                  type='range' min={0} max={1} step='any'
                  value={played}
                  onMouseDown={this.onSeekMouseDown}
                  onChange={this.onSeekChange}
                  onMouseUp={this.onSeekMouseUp}
                />

              Volume

                <input type='range' min={0} max={1} step='any' value={volume} onChange={this.setVolume} />

              Played
              <progress max={1} value={played} />

              Loaded
              <progress max={1} value={loaded} />

              YouTube

                {this.renderLoadButton('https://www.youtube.com/watch?v=oUFJJNQGwhk', 'Test A')}
                {this.renderLoadButton('https://www.youtube.com/watch?v=jNgP6d9HraI', 'Test B')}

              SoundCloud

                {this.renderLoadButton('https://soundcloud.com/miami-nights-1984/accelerated', 'Test A')}
                {this.renderLoadButton('https://soundcloud.com/tycho/tycho-awake', 'Test B')}

              Vimeo

                {this.renderLoadButton('https://vimeo.com/90509568', 'Test A')}
                {this.renderLoadButton('https://vimeo.com/94502406', 'Test B')}

              Streamable

                {this.renderLoadButton('https://streamable.com/moo', 'Test A')}
                {this.renderLoadButton('https://streamable.com/ifjh', 'Test B')}

              Files

                {this.renderLoadButton('http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4', 'MP4')}
                {this.renderLoadButton('http://clips.vorwaerts-gmbh.de/big_buck_bunny.ogv', 'OGV')}
                {this.renderLoadButton('http://clips.vorwaerts-gmbh.de/big_buck_bunny.webm', 'WEBM')}

              Custom URL

                <input ref='url' type='text' placeholder='Enter URL' />
                <button onClick={() => this.setState({ url: this.refs.url.value })}>Load</button>

              Custom config

                <textarea ref='config' placeholder='Enter JSON' />
                <button onClick={this.onConfigSubmit}>Update Config</button>

State

              url
              {url || 'null'}

              playing
              {playing ? 'true' : 'false'}

              volume
              {volume.toFixed(3)}

              played
              {played.toFixed(3)}

              loaded
              {loaded.toFixed(3)}

              duration
              <Duration seconds={duration} />

              elapsed
              <Duration seconds={duration * played} />

              remaining
              <Duration seconds={duration * (1 - played)} />

          Version {version}
          {SEPARATOR}
          GitHub
          {SEPARATOR}
          npm

    )
  }
}
<|endoftext|>


<commit_before>var Dominion = (function () {
  "use strict";

  var Cards = (function () {
    /**
     * IMPORTANT
     *
     * `play will be called with
     * `apply` against the Player object
     */
    var Cards =  {
      "Copper": {
        name: "Copper",
        type: "Treasure",
        cost: 0,
        play: function () {
          this.addCoins(1);
        }
      },
      "Silver": {
        name: "Silver",
        type: "Treasure",
        cost: 3,
        play: function () {
          this.addCoins(2);
        }
      },
      "Gold": {
        name: "Gold",
        type: "Treasure",
        cost: 6,
        play: function () {
          this.addCoins(3);
        }
      },
      "Estate": {
        name: "Estate",
        type: "Victory",
        cost: 2
      },
      "Duchy": {
        name: "Duchy",
        type: "Victory",
        cost: 5
      },
      "Province": {
        name: "Province",
        type: "Victory",
        cost: 8
      },
      "Curse": {
        name: "Curse",
        type: "Curse",
        cost: 0
      },
      "Cellar": {
        name: "Cellar",
        type: "Action",
        cost: 2,
        play: function () {
          Player.addActions(1);

          return function (cards) {
            if (!Game.getPendingAction()) {
              throw "Invalid pending action";
            }

            if (!(cards instanceof Array)) {
              throw "Invalid list of cards";
            }

            for (var i = 0; i < cards.length; i++) {
              Player.discardCard(cards[i]);
              Player.drawCard();
            }

            Game.removePendingAction();
          };
        }
      },
      "Chapel":  {
        name: "Chapel",
        type: "Action",
        cost: 2,
        play: function () {
          return function (cards) {
            if (!Game.getPendingAction()) {
              throw "Invalid pending action";
            }

            if (!(cards instanceof Array)) {
              throw "Invalid list of cards";
            }

            if (cards.length > 4) {
              throw "Invalid number of cards to trash";
            }

            for (var i = 0; i < cards.length; i++) {
              Player.trashCard(cards[i]);
            }

            Game.removePendingAction();
          };
        }
      },
      "Moat": {
        name:   "Moat",
        type:   "Action - Reaction",
        cost:   2,
        immune: true,
        play:   function () {
          this.drawCard();
          this.drawCard();
        }
      },
      "Chancellor": {
        name: "Chancellor",
        type: "Action",
        cost: 3,
        play: function () {
          this.addCoins(2);
          this.discard_deck();
        }
      },
      "Village": {
        name: "Village",
        type: "Action",
        cost: 3,
        play: function () {
          this.drawcard();
          this.addActions(2);
        }
      },
      "Woodcutter": {
        name: "Woodcutter",
        type: "Action",
        cost: 3,
        play: function () {
          this.addBuys(1);
          this.addCoins(2);
        }
      },
      "Workshop": {
        name: "Workshop",
        type: "Action",
        cost: 3,
        play: function () {
          this.gain_card_costing_up_to(4);
        }
      },
      "Bureaucrat": {
        name: "Bureaucrat",
        type: "Action - Attack",
        cost: 4,
        play: function () {
          this.bureaucrat();
        }
      },
      "Feast": {
        name: "Feast",
        type: "Action",
        cost: 4,
        play: function () {
          this.trash_this_card();
          this.gain_card_costing_up_to(5);
        }
      },
      "Gardens": {
        name: "Gardens",
        type: "Victory",
        cost: 4
      },
      "Militia": {
        name: "Militia",
        type: "Action - Attack",
        cost: 4,
        play: function () {
          this.addCoins(2);
          this.other_players_discard_down_to(3);
        }
      },
      "Moneylender": {
        name: "Moneylender",
        type: "Action",
        cost: 4,
        play: function () {
          this.trash_copper_for_coins(3);
        }
      },
      "Remodel": {
        name: "Remodel",
        type: "Action",
        cost: 4,
        play: function () {
          this.trash_card_for_card_costing_more(3);
        }
      },
      "Smithy": {
        name: "Smithy",
        type: "Action",
        cost: 4,
        play: function () {
          this.drawCard();
          this.drawCard();
          this.drawCard();
        }
      },
      "Spy": {
        name: "Spy",
        type: "Action - Attack",
        cost: 4,
        play: function () {
          this.spy();
        }
      },
      "Thief": {
        name: "Thief",
        type: "Action - Attack",
        cost: 4,
        play: function () {
          this.thief();
        }
      },
      "ThroneRoom": {
        name: "ThroneRoom",
        type: "Action",
        cost: 4,
        play: function () {
          this.chose_card_play_it_twice();
        }
      },
      "CouncilRoom": {
        name: "CouncilRoom",
        type: "Action",
        cost: 5,
        play: function () {
          this.drawCards();
          this.drawCards();
          this.drawCards();
          this.drawCards();
          this.addBuys(1);
          // this.other_players_draw_cards(1);
        }
      },
      "Festival": {
        name: "Festival",
        type: "Action",
        cost: 5,
        play: function () {
          this.addActions(2);
          this.addBuys(1);
          this.addCoins(2);
        }
      },
      "Laboratory": {
        name: "Laboratory",
        type: "Action",
        cost: 5,
        play: function () {
          this.drawCard();
          this.drawCard();
          this.addActions(1);
        }
      },
      "Library": {
        name: "Library",
        type: "Action",
        cost: 5,
        play: function () {
          //this.library();
        }
      },
      "Market": {
        name: "Market",
        type: "Action",
        cost: 5,
        play: function () {
          this.drawCard();
          this.addActions(1);
          this.addBuys(1);
          this.addCoins(1);
        }
      },
      "Mine": {
        name: "Mine",
        type: "Action",
        cost: 5,
        play: function () {
          //this.mine();
        }
      },
      "Witch": {
        name: "Witch",
        type: "Action - Attack",
        cost: 5,
        play: function () {
          this.drawCard();
          this.drawCard();
          //this.other_players_get_curse_card();
        }
      },
      "Adventurer": {
        name: "Adventurer",
        type: "Action",
        cost: 6,
        play: function () {
          //this.adventurer();
        }
      }
    };

    return Cards;
  }());

  var Board = (function () {
    var Board =  {
      kingdom: {}, // kingdom cards aka available cards
      trashed: [], // cards that are trashed
      onBoard: [], // visible cards that are placed on the board

      init: function (gamePreset) {
        this.reset();

        if (gamePreset === undefined || gamePreset === "firstGame") {
          this.pickFirstGameKingdomCards();
        }

        this.pickVictoryAndTreasureCards();

        return this;
      },
      reset: function () {
        this.onBoard = [];
        this.trashed = [];
        this.kingdom = {};
      },
      clear: function () {
        this.onBoard = [];
      },
      takeKingdomCard: function (card) {
        if (!this.kingdom[card]) {
          throw card + " is not part of the kingdom cards";
        }

        if (this.kingdom[card] <= 0) {
          throw "Card out of supply";
        }

        this.kingdom[card] -= 1;
      },
      pickVictoryAndTreasureCards: function () {
        var infinity = 1.0/0;

        this.kingdom["Estate"]   = 8;
        this.kingdom["Duchy"]    = 8;
        this.kingdom["Province"] = 8;
        this.kingdom["Curse"]    = 10;

        this.kingdom["Copper"] = infinity;
        this.kingdom["Silver"] = infinity;
        this.kingdom["Gold"]   = infinity;
      },
      pickFirstGameKingdomCards: function () {
        var firstGameCards = [
          "Cellar", "Market", "Militia", "Mine", "Moat", "Remodel",
          "Smithy", "Village", "Woodcutter", "Workshop"
        ];

        for (var i = 0; i < firstGameCards.length; i++) {
          this.kingdom[firstGameCards[i]] = 10;
        }
      }
    };

    return Board;
  }());

  var Player = (function () {
    var Player = {
      phase:       null, // can be action phase, buy phase
      drawPile:    [],
      discardPile: [],
      hand:        [],
      actions:     1,
      buys:        1,
      coins:       0,

      /**
       *  Initializers and resetters
       */
      init: function () {
        this.dealInitialHand();

        return this;
      },
      clearHand: function () {
        this.actions = 1;
        this.buys    = 1;
        this.coins   = 0;
        this.hand    = [];
      },
      clearBoard: function () {
        Board.clear();
      },
      dealInitialHand: function () {
        this.drawPile = [
          "Estate", "Estate", "Estate", "Copper", "Copper",
          "Copper", "Copper", "Copper", "Copper", "Copper"
        ];

        this.shuffleDrawPile();
        this.clearHand();
        this.drawNextHand();
      },

      /**
       *  Turn interactions
       */
      drawNextHand: function () {
        for (var i = 0; i < 5; i++) {
          this.drawCard();
        }
      },
      endOfTurn: function () {
        this.moveCardsToDiscardPile();
        this.drawNextHand();
      },
      shuffleDrawPile: function () {
        var counter = this.drawPile.length,
            temp,
            index;

        while (counter > 0) {
          index    = Math.floor(Math.random() * counter);
          counter -= 1;

          temp = this.drawPile[counter];

          this.drawPile[counter] = this.drawPile[index];
          this.drawPile[index]   = temp;
        }
      },
      moveDiscardPileToDrawPile: function () {
        this.drawPile    = this.discardPile;
        this.discardPile = [];

        this.shuffleDrawPile();
      },
      moveCardsToDiscardPile: function () {
        for (var i = 0; i < this.hand.length; i++) {
          this.discardPile.push(this.hand[i]);
        }

        this.clearHand();

        for (var i = 0; i < Board.onBoard.length; i++) {
          this.discardPile.push(Board.onBoard[i]);
        }

        this.clearBoard();
      },
      isDrawPileEmpty: function () {
        return this.drawPile.length === 0;
      },
      moveCardFromHandToBoard: function (cardIndex) {
        Board.onBoard.push(this.hand.splice(cardIndex, 1).pop());
      },
      moveCardFromHandToDiscardPile: function (cardIndex) {
        this.discardPile.push(this.hand.splice(cardIndex, 1).pop());
      },
      drawCard: function () {
        if (this.isDrawPileEmpty()) {
          this.moveDiscardPileToDrawPile();
        }

        var card = this.drawPile.shift();
        if (card) {
          this.hand.push(card);
        }
      },
      discardCard: function (card) {
        var cardIndex = this.hand.indexOf(card);

        if (cardIndex !== -1) {
          this.moveCardFromHandToDiscardPile(cardIndex);
        } else {
          throw card + " card cannot be discarded as it's not part of your hand";
        }
      },
      trashCard: function (card) {
        var cardIndex = this.hand.indexOf(card);

        if (cardIndex !== -1) {
          Board.trashed.push(this.hand.splice(cardIndex, 1).pop());
        } else {
          throw card + " card cannot be trashed as it's not part of your hand";
        }
      },
      playCard: function (card) {
        // could be extracted to Player.holdsCard(card)
        var cardIndex = this.hand.indexOf(card);

        if (cardIndex !== -1) {
          this.moveCardFromHandToBoard(cardIndex);
          if (Cards[card].play) {
            this.takeActions(1);
            return Cards[card].play.apply(this);
          }
        } else {
          throw card + " card cannot be played as it's not part of your hand";
        }
      },
      buyCard: function (card) {
        if (this.buys < 1) {
          throw "Not enough buy points";
        }

        if (this.coins < Cards[card].cost) {
          throw "Not enough treasure points";
        }

        Board.takeKingdomCard(card);

        this.takeBuys(1);
        this.takeCoins(Cards[card].cost);

        this.discardPile.push(card);
      },

      /**
       * Card interactions
       */
      addCoins: function (n) {
        this.coins += n;
      },
      addActions: function (n) {
        this.actions += n;
      },
      addBuys: function (n) {
        this.buys += n;
      },
      takeCoins: function (n) {
        this.coins -= n;
      },
      takeActions: function (n) {
        this.actions -= n;
      },
      takeBuys: function (n) {
        this.buys -= n;
      },

      /**
       * End game interactions
       */
      countVictoryPoints: function () {}
    };

    return Player;
  }());

  var Game = (function () {
    /**
     * Context for the views
     * @returns {{kingdom: *, onBoard: *, trashPile: *, drawPile: *, discardPile: *, hand: *, game: {context: context, start: start, play: play, pending: pending, buy: buy, endOfTurn: endOfTurn, clearPendingAction: clearPendingAction, quit: quit, debug: debug}}}
     */
    var context = function () {
      return {
        kingdom:     Board.kingdom,
        onBoard:     Board.onBoard,
        trashPile:   Board.trashed,
        drawPile:    Player.drawPile,
        discardPile: Player.discardPile,
        hand:        Player.hand,
        game:        Game
      };
    };

    /**
     * Pending action callback
     * @type {null}
     */
    var pendingAction = null;

    var Game = {
      context: function () {
        return context();
      },
      start: function (cardListOrPresetName) {
        Board.init(cardListOrPresetName);
        Player.init();
      },
      play: function (card) {
        if (pendingAction instanceof Function) {
          throw "Call getPendingAction() to get the callback to continue"
        }

        return pendingAction = Player.playCard(card) || null;
      },
      buy: function (card) {
        Player.buyCard(card);
      },
      endOfTurn: function () {
        Player.endOfTurn();
      },
      getPendingAction: function () {
        return pendingAction;
      },
      removePendingAction: function () {
        pendingAction = null;
      },
      quit: function () {
      },

      debug: Player.debug
    };

    return Game;
  }());

  return Game;
}());

Dominion.start();
Dominion.play('Copper');
Dominion.play('Copper');
Dominion.buy('Cellar');
Dominion.endOfTurn();
Dominion.endOfTurn();
Dominion.context();
Dominion.play('Cellar');<commit_msg>Mine rules<commit_after>var Dominion = (function () {
  "use strict";

  var Cards = (function () {
    /**
     * IMPORTANT
     *
     * `play will be called with
     * `apply` against the Player object
     */
    var Cards =  {
      "Copper": {
        name: "Copper",
        type: "Treasure",
        cost: 0,
        play: function () {
          this.addCoins(1);
        }
      },
      "Silver": {
        name: "Silver",
        type: "Treasure",
        cost: 3,
        play: function () {
          this.addCoins(2);
        }
      },
      "Gold": {
        name: "Gold",
        type: "Treasure",
        cost: 6,
        play: function () {
          this.addCoins(3);
        }
      },
      "Estate": {
        name: "Estate",
        type: "Victory",
        cost: 2
      },
      "Duchy": {
        name: "Duchy",
        type: "Victory",
        cost: 5
      },
      "Province": {
        name: "Province",
        type: "Victory",
        cost: 8
      },
      "Curse": {
        name: "Curse",
        type: "Curse",
        cost: 0
      },
      "Cellar": {
        name: "Cellar",
        type: "Action",
        cost: 2,
        play: function () {
          Player.addActions(1);

          return function (cards) {
            if (!Game.getPendingAction()) {
              throw "Invalid pending action";
            }

            if (!(cards instanceof Array)) {
              throw "Invalid list of cards";
            }

            for (var i = 0; i < cards.length; i++) {
              Player.discardCard(cards[i]);
              Player.drawCard();
            }

            Game.removePendingAction();
          };
        }
      },
      "Chapel":  {
        name: "Chapel",
        type: "Action",
        cost: 2,
        play: function () {
          return function (cards) {
            if (!Game.getPendingAction()) {
              throw "Invalid pending action";
            }

            if (!(cards instanceof Array)) {
              throw "Invalid list of cards";
            }

            if (cards.length > 4) {
              throw "Invalid number of cards to trash";
            }

            for (var i = 0; i < cards.length; i++) {
              Player.trashCard(cards[i]);
            }

            Game.removePendingAction();
          };
        }
      },
      "Moat": {
        name:   "Moat",
        type:   "Action - Reaction",
        cost:   2,
        immune: true,
        play:   function () {
          this.drawCard();
          this.drawCard();
        }
      },
      "Chancellor": {
        name: "Chancellor",
        type: "Action",
        cost: 3,
        play: function () {
          this.addCoins(2);

          return function (answer) {
            if (!Game.getPendingAction()) {
              throw "Invalid pending action";
            }

            if (answer === 1) {
              Player.moveDiscardPileToDrawPile();
              Player.shuffleDrawPile();
            }

            Game.removePendingAction();
          };
        }
      },
      "Village": {
        name: "Village",
        type: "Action",
        cost: 3,
        play: function () {
          this.drawcard();
          this.addActions(2);
        }
      },
      "Woodcutter": {
        name: "Woodcutter",
        type: "Action",
        cost: 3,
        play: function () {
          this.addBuys(1);
          this.addCoins(2);
        }
      },
      "Workshop": {
        name: "Workshop",
        type: "Action",
        cost: 3,
        play: function () {
          this.gain_card_costing_up_to(4);
        }
      },
      "Bureaucrat": {
        name: "Bureaucrat",
        type: "Action - Attack",
        cost: 4,
        play: function () {
          this.bureaucrat();
        }
      },
      "Feast": {
        name: "Feast",
        type: "Action",
        cost: 4,
        play: function () {
          this.trash_this_card();
          this.gain_card_costing_up_to(5);
        }
      },
      "Gardens": {
        name: "Gardens",
        type: "Victory",
        cost: 4
      },
      "Militia": {
        name: "Militia",
        type: "Action - Attack",
        cost: 4,
        play: function () {
          this.addCoins(2);
          // todo
          // this.otherPlayersDiscardDownTo(3);
        }
      },
      "Moneylender": {
        name: "Moneylender",
        type: "Action",
        cost: 4,
        play: function () {
          this.trash_copper_for_coins(3);
        }
      },
      "Remodel": {
        name: "Remodel",
        type: "Action",
        cost: 4,
        play: function () {
          this.trash_card_for_card_costing_more(3);
        }
      },
      "Smithy": {
        name: "Smithy",
        type: "Action",
        cost: 4,
        play: function () {
          this.drawCard();
          this.drawCard();
          this.drawCard();
        }
      },
      "Spy": {
        name: "Spy",
        type: "Action - Attack",
        cost: 4,
        play: function () {
          this.spy();
        }
      },
      "Thief": {
        name: "Thief",
        type: "Action - Attack",
        cost: 4,
        play: function () {
          this.thief();
        }
      },
      "ThroneRoom": {
        name: "ThroneRoom",
        type: "Action",
        cost: 4,
        play: function () {
          this.chose_card_play_it_twice();
        }
      },
      "CouncilRoom": {
        name: "CouncilRoom",
        type: "Action",
        cost: 5,
        play: function () {
          this.drawCards();
          this.drawCards();
          this.drawCards();
          this.drawCards();
          this.addBuys(1);
          // this.other_players_draw_cards(1);
        }
      },
      "Festival": {
        name: "Festival",
        type: "Action",
        cost: 5,
        play: function () {
          this.addActions(2);
          this.addBuys(1);
          this.addCoins(2);
        }
      },
      "Laboratory": {
        name: "Laboratory",
        type: "Action",
        cost: 5,
        play: function () {
          this.drawCard();
          this.drawCard();
          this.addActions(1);
        }
      },
      "Library": {
        name: "Library",
        type: "Action",
        cost: 5,
        play: function () {
          //this.library();
        }
      },
      "Market": {
        name: "Market",
        type: "Action",
        cost: 5,
        play: function () {
          this.drawCard();
          this.addActions(1);
          this.addBuys(1);
          this.addCoins(1);
        }
      },
      "Mine": {
        name: "Mine",
        type: "Action",
        cost: 5,
        play: function () {
          return function (oldCard, newCard) {
            if (!Game.getPendingAction()) {
              throw "Invalid pending action";
            }

            if (Cards[oldCard].type !== "Treasure") {
              throw oldCard + " is not a treasure card";
            }

            if (Cards[newCard].type !== "Treasure") {
              throw newCard + " is not a treasure card";
            }

            if (Cards[newCard].cost > Cards[oldCard].cost + 3) {
              throw newCard + ", cannot gain the card";
            }

            Player.trashCard(oldCard);
            Player.gainCard(newCard);
          };
        }
      },
      "Witch": {
        name: "Witch",
        type: "Action - Attack",
        cost: 5,
        play: function () {
          this.drawCard();
          this.drawCard();
          //this.other_players_get_curse_card();
        }
      },
      "Adventurer": {
        name: "Adventurer",
        type: "Action",
        cost: 6,
        play: function () {
          //this.adventurer();
        }
      }
    };

    return Cards;
  }());

  var Board = (function () {
    var Board =  {
      kingdom: {}, // kingdom cards aka available cards
      trashed: [], // cards that are trashed
      onBoard: [], // visible cards that are placed on the board

      init: function (gamePreset) {
        this.reset();

        if (gamePreset === undefined || gamePreset === "firstGame") {
          this.pickFirstGameKingdomCards();
        }

        this.pickVictoryAndTreasureCards();

        return this;
      },
      reset: function () {
        this.onBoard = [];
        this.trashed = [];
        this.kingdom = {};
      },
      clear: function () {
        this.onBoard = [];
      },
      takeKingdomCard: function (card) {
        if (!this.kingdom[card]) {
          throw card + " is not part of the kingdom cards";
        }

        if (this.kingdom[card] <= 0) {
          throw "Card out of supply";
        }

        this.kingdom[card] -= 1;
      },
      pickVictoryAndTreasureCards: function () {
        var infinity = 1.0/0;

        this.kingdom["Estate"]   = 8;
        this.kingdom["Duchy"]    = 8;
        this.kingdom["Province"] = 8;
        this.kingdom["Curse"]    = 10;

        this.kingdom["Copper"] = infinity;
        this.kingdom["Silver"] = infinity;
        this.kingdom["Gold"]   = infinity;
      },
      pickFirstGameKingdomCards: function () {
        var firstGameCards = [
          "Cellar", "Market", "Militia", "Mine", "Moat", "Remodel",
          "Smithy", "Village", "Woodcutter", "Workshop"
        ];

        for (var i = 0; i < firstGameCards.length; i++) {
          this.kingdom[firstGameCards[i]] = 10;
        }
      }
    };

    return Board;
  }());

  var Player = (function () {
    var Player = {
      phase:       null, // can be action phase, buy phase
      drawPile:    [],
      discardPile: [],
      hand:        [],
      actions:     1,
      buys:        1,
      coins:       0,

      /**
       *  Initializers and resetters
       */
      init: function () {
        this.dealInitialHand();

        return this;
      },
      clearHand: function () {
        this.actions = 1;
        this.buys    = 1;
        this.coins   = 0;
        this.hand    = [];
      },
      clearBoard: function () {
        Board.clear();
      },
      dealInitialHand: function () {
        this.drawPile = [
          "Estate", "Estate", "Estate", "Copper", "Copper",
          "Copper", "Copper", "Copper", "Copper", "Copper"
        ];

        this.shuffleDrawPile();
        this.clearHand();
        this.drawNextHand();
      },

      /**
       *  Turn interactions
       */
      drawNextHand: function () {
        for (var i = 0; i < 5; i++) {
          this.drawCard();
        }
      },
      endOfTurn: function () {
        this.moveCardsToDiscardPile();
        this.drawNextHand();
      },
      shuffleDrawPile: function () {
        var counter = this.drawPile.length,
            temp,
            index;

        while (counter > 0) {
          index    = Math.floor(Math.random() * counter);
          counter -= 1;

          temp = this.drawPile[counter];

          this.drawPile[counter] = this.drawPile[index];
          this.drawPile[index]   = temp;
        }
      },
      moveDiscardPileToDrawPile: function () {
        this.drawPile    = this.discardPile;
        this.discardPile = [];

        this.shuffleDrawPile();
      },
      moveCardsToDiscardPile: function () {
        for (var i = 0; i < this.hand.length; i++) {
          this.discardPile.push(this.hand[i]);
        }

        this.clearHand();

        for (var i = 0; i < Board.onBoard.length; i++) {
          this.discardPile.push(Board.onBoard[i]);
        }

        this.clearBoard();
      },
      isDrawPileEmpty: function () {
        return this.drawPile.length === 0;
      },
      moveCardFromHandToBoard: function (cardIndex) {
        Board.onBoard.push(this.hand.splice(cardIndex, 1).pop());
      },
      moveCardFromHandToDiscardPile: function (cardIndex) {
        this.discardPile.push(this.hand.splice(cardIndex, 1).pop());
      },
      drawCard: function () {
        if (this.isDrawPileEmpty()) {
          this.moveDiscardPileToDrawPile();
        }

        var card = this.drawPile.shift();
        if (card) {
          this.hand.push(card);
        }

        return Cards[card];
      },
      discardCard: function (card) {
        var cardIndex = this.hand.indexOf(card);

        if (cardIndex !== -1) {
          this.moveCardFromHandToDiscardPile(cardIndex);
        } else {
          throw card + " card cannot be discarded as it's not part of your hand";
        }

        return Cards[card];
      },
      trashCard: function (card) {
        var cardIndex = this.hand.indexOf(card);

        if (cardIndex !== -1) {
          Board.trashed.push(this.hand.splice(cardIndex, 1).pop());
        } else {
          throw card + " card cannot be trashed as it's not part of your hand";
        }

        return Cards[card];
      },
      playCard: function (card) {
        // could be extracted to Player.holdsCard(card)
        var cardIndex = this.hand.indexOf(card);

        if (cardIndex !== -1) {
          this.moveCardFromHandToBoard(cardIndex);
          if (Cards[card].play) {
            this.takeActions(1);
            return Cards[card].play.apply(this);
          }
        } else {
          throw card + " card cannot be played as it's not part of your hand";
        }

        return Cards[card];
      },
      buyCard: function (card) {
        if (this.buys < 1) {
          throw "Not enough buy points";
        }

        if (this.coins < Cards[card].cost) {
          throw "Not enough treasure points";
        }

        Board.takeKingdomCard(card);

        this.takeBuys(1);
        this.takeCoins(Cards[card].cost);

        this.discardPile.push(card);

        return Cards[card];
      },
      gainCard: function (card) {
        Board.takeKingdomCard(card);
        this.hand.push(card);

        return Cards[card];
      },

      /**
       * Card interactions
       */
      addCoins: function (n) {
        this.coins += n;
      },
      addActions: function (n) {
        this.actions += n;
      },
      addBuys: function (n) {
        this.buys += n;
      },
      takeCoins: function (n) {
        this.coins -= n;
      },
      takeActions: function (n) {
        this.actions -= n;
      },
      takeBuys: function (n) {
        this.buys -= n;
      },

      /**
       * End game interactions
       */
      countVictoryPoints: function () {}
    };

    return Player;
  }());

  var Game = (function () {
    /**
     * Context for the views
     */
    var context = function () {
      return {
        kingdom:     Board.kingdom,
        onBoard:     Board.onBoard,
        trashPile:   Board.trashed,
        drawPile:    Player.drawPile,
        discardPile: Player.discardPile,
        hand:        Player.hand,
        game:        Game
      };
    };

    /**
     * Pending action callback
     * @type {null}
     */
    var pendingAction = null;

    var Game = {
      context: function () {
        return context();
      },
      start: function (cardListOrPresetName) {
        Board.init(cardListOrPresetName);
        Player.init();
      },
      play: function (card) {
        if (pendingAction instanceof Function) {
          throw "Call getPendingAction() to get the callback to continue"
        }

        return pendingAction = Player.playCard(card) || null;
      },
      buy: function (card) {
        Player.buyCard(card);
      },
      endOfTurn: function () {
        Player.endOfTurn();
      },
      getPendingAction: function () {
        return pendingAction;
      },
      removePendingAction: function () {
        pendingAction = null;
      },
      quit: function () {
      },

      debug: Player.debug
    };

    return Game;
  }());

  return Game;
}());

Dominion.start();
Dominion.play('Copper');
Dominion.play('Copper');
Dominion.buy('Cellar');
Dominion.endOfTurn();
Dominion.endOfTurn();
Dominion.context();
Dominion.play('Cellar');<|endoftext|>


<commit_before>var render = (function () {

var exports = {};

var fs = require('fs');
var path = require("path");
var _ = require('third/underscore/underscore.js');
var Handlebars = require('handlebars');

function template_dir() {
    return __dirname + '/../../static/templates/';
}

var list_of_exceptions = [""].concat((function () {
    return fs.readdirSync(template_dir()).filter(function (file) {
        return fs.statSync(path.join(template_dir(), file)).isDirectory();
    });
}()));

exports.init = function () {
    Handlebars.templates = {};
};

exports.make_sure_all_templates_have_been_compiled = function () {
    var dir = template_dir();
    var fns = fs.readdirSync(dir).filter(function (fn) {
        return (/\.handlebars/).test(fn);
    });

    _.each(fns, function (fn) {
        var name = fn.split('.')[0];
        if (!Handlebars.templates[name]) {
            throw "The file " + fn + " has no test coverage.";
        }
    });
};

exports.use_template = function (name) {
    if (Handlebars.templates === undefined) {
        Handlebars.templates = {};
    }

    var flag = false,
        counter = 0,
        data;

    while (flag === false && counter < list_of_exceptions.length) {
        try {
            data = fs.readFileSync(path.join(template_dir(), list_of_exceptions[counter], name + '.handlebars')).toString();
            if (data) {
                flag = true;
            }
        } catch (err) {
            flag = false;
        } finally {
            counter++;
        }
    }

    Handlebars.templates[name] = Handlebars.compile(data);
};

// list all files in a directory and it's subdirectories in a recursive sync way.
exports.walk = function (dir, filelist) {
    filelist = filelist || [];

    // grab files one level deep.
    var files = fs.readdirSync(dir);

    // for each file, check if it's a directory. If so, continue recursion.
    // if not add to the file list.
    files.forEach(function (file) {
        if (fs.statSync(dir + "/" + file).isDirectory()) {
            filelist = exports.walk(dir + "/" + file, filelist);
        } else {
            filelist.push({
                url: dir + "/" + file,
                name: file
            });
        }
    });

    // return all recursively found files.
    return filelist;
};

exports.template_finder = (function () {
    // This class lets you find template files in our file system.
    // It may be slightly overkill for our flat directory system;
    // it might make more sense to just do something more like
    // this: get_template_dir() + name + '.handlebars'

    var self = {};

    // get all files and then map them into friendlier names.
    var files = exports.walk(template_dir()).map(function (file) {
        return {
            url: file.url,
            name: file.name.replace(/\.handlebars$/, "")
        };
    });

    self.get = function (name) {
        var file = files.find(function (file) {
            return file.name === name;
        });
        assert(file);

        return file;
    };

    return self;
}());

exports.find_included_partials = function (name) {

    var file = exports.template_finder.get(name);

    assert(file);

    var template = fs.readFileSync(file.url, "utf8");

    var lst = [];

    // match partial tags.
    // this uses String.prototype.replace which is kind of hacky but
    // it is the only JS function IIRC that allows you to match all
    // instances of a pattern AND return capture groups.
    template.replace(/\{\{\s*partial\s*"(.+?)"/ig, function (match, $1) {
        lst.push($1);
    });

    return lst;
};

exports.partial_finder = (function () {
    var meta = {
        read: []
    };

    // this is the external function that is called that will recursively search
    // for partials in a file and partials inside partials until it finds them all.
    // it then adds them to a maintenance list of already read partials so that
    // they don't have to be read/searched again.
    var __prototype__ = function (name, callback) {
        if (meta.read.indexOf(name) === -1) {
            if (callback) {
                callback(name);
            }

            meta.read.push(name);
            var included_fns = exports.find_included_partials(name);

            _.each(included_fns, function (fn) {
                __prototype__(fn, callback);
            });

        }
    };

    return __prototype__;
}());

fs.readdirSync(path.join(__dirname, "../../static/templates/", "settings")).forEach(function (o) {
    exports.use_template(o.replace(/\.handlebars/, ""));
});

return exports;
}());
module.exports = render;
<commit_msg>node tests: Avoid re-compiling templates.<commit_after>var render = (function () {

var exports = {};

var fs = require('fs');
var path = require("path");
var _ = require('third/underscore/underscore.js');
var Handlebars = require('handlebars');

function template_dir() {
    return __dirname + '/../../static/templates/';
}

var list_of_exceptions = [""].concat((function () {
    return fs.readdirSync(template_dir()).filter(function (file) {
        return fs.statSync(path.join(template_dir(), file)).isDirectory();
    });
}()));

exports.init = function () {
    Handlebars.templates = {};
};

exports.make_sure_all_templates_have_been_compiled = function () {
    var dir = template_dir();
    var fns = fs.readdirSync(dir).filter(function (fn) {
        return (/\.handlebars/).test(fn);
    });

    _.each(fns, function (fn) {
        var name = fn.split('.')[0];
        if (!Handlebars.templates[name]) {
            throw "The file " + fn + " has no test coverage.";
        }
    });
};

exports.use_template = function (name) {
    if (Handlebars.templates === undefined) {
        Handlebars.templates = {};
    }

    if (_.has(Handlebars.template, name)) {
        // we already compile the template
        return;
    }

    var flag = false,
        counter = 0,
        data;

    while (flag === false && counter < list_of_exceptions.length) {
        try {
            data = fs.readFileSync(path.join(template_dir(), list_of_exceptions[counter], name + '.handlebars')).toString();
            if (data) {
                flag = true;
            }
        } catch (err) {
            flag = false;
        } finally {
            counter++;
        }
    }

    Handlebars.templates[name] = Handlebars.compile(data);
};

// list all files in a directory and it's subdirectories in a recursive sync way.
exports.walk = function (dir, filelist) {
    filelist = filelist || [];

    // grab files one level deep.
    var files = fs.readdirSync(dir);

    // for each file, check if it's a directory. If so, continue recursion.
    // if not add to the file list.
    files.forEach(function (file) {
        if (fs.statSync(dir + "/" + file).isDirectory()) {
            filelist = exports.walk(dir + "/" + file, filelist);
        } else {
            filelist.push({
                url: dir + "/" + file,
                name: file
            });
        }
    });

    // return all recursively found files.
    return filelist;
};

exports.template_finder = (function () {
    // This class lets you find template files in our file system.
    // It may be slightly overkill for our flat directory system;
    // it might make more sense to just do something more like
    // this: get_template_dir() + name + '.handlebars'

    var self = {};

    // get all files and then map them into friendlier names.
    var files = exports.walk(template_dir()).map(function (file) {
        return {
            url: file.url,
            name: file.name.replace(/\.handlebars$/, "")
        };
    });

    self.get = function (name) {
        var file = files.find(function (file) {
            return file.name === name;
        });
        assert(file);

        return file;
    };

    return self;
}());

exports.find_included_partials = function (name) {

    var file = exports.template_finder.get(name);

    assert(file);

    var template = fs.readFileSync(file.url, "utf8");

    var lst = [];

    // match partial tags.
    // this uses String.prototype.replace which is kind of hacky but
    // it is the only JS function IIRC that allows you to match all
    // instances of a pattern AND return capture groups.
    template.replace(/\{\{\s*partial\s*"(.+?)"/ig, function (match, $1) {
        lst.push($1);
    });

    return lst;
};

exports.partial_finder = (function () {
    var meta = {
        read: []
    };

    // this is the external function that is called that will recursively search
    // for partials in a file and partials inside partials until it finds them all.
    // it then adds them to a maintenance list of already read partials so that
    // they don't have to be read/searched again.
    var __prototype__ = function (name, callback) {
        if (meta.read.indexOf(name) === -1) {
            if (callback) {
                callback(name);
            }

            meta.read.push(name);
            var included_fns = exports.find_included_partials(name);

            _.each(included_fns, function (fn) {
                __prototype__(fn, callback);
            });

        }
    };

    return __prototype__;
}());

fs.readdirSync(path.join(__dirname, "../../static/templates/", "settings")).forEach(function (o) {
    exports.use_template(o.replace(/\.handlebars/, ""));
});

return exports;
}());
module.exports = render;
<|endoftext|>


<commit_before>import React, { PureComponent, PropTypes } from 'react';
import { BinaryChart } from 'binary-charts';
import { actions } from '../../_store';
import {
    internalTradeModelToChartTradeModel,
    serverContractModelToChartContractModel,
} from '../adapters/TradeObjectAdapter';

const zoomToLatest = (ev, chart) => {
    const { dataMax, dataMin } = chart.xAxis[0].getExtremes();
    const half = (dataMax - dataMin) * 0.5 + dataMin;
    chart.xAxis[0].setExtremes(half, dataMax);
};

const chartToDataType = {
    area: 'ticks',
    candlestick: 'candles',
};

export default class TradeViewChart extends PureComponent {

    static contextTypes = {
        theme: PropTypes.string,
    };

    static propTypes = {
        contractForChart: PropTypes.object,
        ticks: PropTypes.array.isRequired,
        ohlc: PropTypes.array.isRequired,
        index: PropTypes.number.isRequired,
        events: PropTypes.array.isRequired,
        feedLicense: PropTypes.string.isRequired,
        pipSize: PropTypes.number,
        tradeForChart: PropTypes.object,
        tradingTime: PropTypes.object.isRequired,
    };

    static defaultProps = {
        type: 'full',
        feedLicense: '',
        events: [{
            type: 'zoom-to-latest',
            handler: zoomToLatest,
        }],
        ticks: [],
        ohlc: [],
        tradingTime: {},
    };

    constructor(props) {
        super(props);
        this.state = {
            dataType: 'ticks',
            chartType: 'area',
        };
    }

    componentWillReceiveProps(nextProps) {
        if (
            (this.props.tradeForChart && nextProps.tradeForChart) &&
            (this.props.tradeForChart.symbol !== nextProps.tradeForChart.symbol)
        ) {
            this.setState({
                dataType: 'ticks',
                chartType: 'area',
            });
        }
    }

    rangeChange = () => {
        const { tradeForChart } = this.props;
        const { dataType } = this.state;
        return (count, type) => actions.getDataForSymbol(tradeForChart.symbol, count, type, dataType);
    };

    changeChartType = type => {
        const { tradeForChart, contractForChart, feedLicense } = this.props;
        const { chartType } = this.state;

        // do nothing if there' no license for chart data or it's showing a contract
        if (feedLicense === 'chartonly' || contractForChart) {
            return {};
        }

        if (chartType === type) {
            return {};
        }

        const newDataType = chartToDataType[type];
        this.setState({ chartType: type, dataType: newDataType });
        const dataResult = actions
            .getDataForSymbol(tradeForChart.symbol, 1, 'hour', newDataType, true)
            .catch(err => {
                const serverError = err.error.error;
                if (serverError.code === 'NoRealtimeQuotes' || serverError.code === 'MarketIsClosed') {
                    return actions.getDataForSymbol(tradeForChart.symbol, 1, 'hour', newDataType, false);
                }
                throw new Error(`Fetch data failed: ${serverError.message}`);
            });
        return dataResult;
    }

    render() {
        const { contractForChart, index, ticks, ohlc, events,
            feedLicense, pipSize, tradeForChart, tradingTime } = this.props;
        const { theme } = this.context;
        const { chartType, dataType } = this.state;

        return (
            <BinaryChart
                id={`trade-chart${index}`}
                className="trade-chart"
                contract={contractForChart && serverContractModelToChartContractModel(contractForChart)}
                defaultRange={1}                      // TODO: figure out how to set this dynamically so it looks good despite of data size
                events={events}
                noData={feedLicense === 'chartonly'}
                pipSize={pipSize}
                rangeChange={contractForChart ? undefined : this.rangeChange()}
                shiftMode={contractForChart ? 'dynamic' : 'fixed'}
                symbol={tradeForChart && tradeForChart.symbolName}
                ticks={(dataType === 'ticks' || contractForChart) ? ticks : ohlc}
                theme={theme}
                type={contractForChart ? 'area' : chartType}
                trade={tradeForChart && internalTradeModelToChartTradeModel(tradeForChart)}
                typeChange={contractForChart ? undefined : this.changeChartType}   // do not allow change type when there's contract
                tradingTime={tradingTime}
            />
        );
    }
}
<commit_msg>Fix dumb type mistake<commit_after>import React, { PureComponent, PropTypes } from 'react';
import { BinaryChart } from 'binary-charts';
import { actions } from '../../_store';
import {
    internalTradeModelToChartTradeModel,
    serverContractModelToChartContractModel,
} from '../adapters/TradeObjectAdapter';

const zoomToLatest = (ev, chart) => {
    const { dataMax, dataMin } = chart.xAxis[0].getExtremes();
    const half = (dataMax - dataMin) * 0.5 + dataMin;
    chart.xAxis[0].setExtremes(half, dataMax);
};

const chartToDataType = {
    area: 'ticks',
    candlestick: 'candles',
};

export default class TradeViewChart extends PureComponent {

    static contextTypes = {
        theme: PropTypes.string,
    };

    static propTypes = {
        contractForChart: PropTypes.object,
        ticks: PropTypes.array.isRequired,
        ohlc: PropTypes.array.isRequired,
        index: PropTypes.number.isRequired,
        events: PropTypes.array.isRequired,
        feedLicense: PropTypes.string.isRequired,
        pipSize: PropTypes.number,
        tradeForChart: PropTypes.object,
        tradingTime: PropTypes.object.isRequired,
    };

    static defaultProps = {
        type: 'full',
        feedLicense: '',
        events: [{
            type: 'zoom-to-latest',
            handler: zoomToLatest,
        }],
        ticks: [],
        ohlc: [],
        tradingTime: {},
    };

    constructor(props) {
        super(props);
        this.state = {
            dataType: 'ticks',
            chartType: 'area',
        };
    }

    componentWillReceiveProps(nextProps) {
        if (
            (this.props.tradeForChart && nextProps.tradeForChart) &&
            (this.props.tradeForChart.symbol !== nextProps.tradeForChart.symbol)
        ) {
            this.setState({
                dataType: 'ticks',
                chartType: 'area',
            });
        }
    }

    rangeChange = () => {
        const { tradeForChart } = this.props;
        const { dataType } = this.state;
        return (count, type) => actions.getDataForSymbol(tradeForChart.symbol, count, type, dataType);
    };

    changeChartType = type => {
        const { tradeForChart, contractForChart, feedLicense } = this.props;
        const { chartType } = this.state;

        // do nothing if there' no license for chart data or it's showing a contract
        if (feedLicense === 'chartonly' || contractForChart) {
            return {};
        }

        if (chartType === type) {
            return {};
        }

        const newDataType = chartToDataType[type];
        this.setState({ chartType: type, dataType: newDataType });
        const dataResult = actions
            .getDataForSymbol(tradeForChart.symbol, 1, 'hour', newDataType, true)
            .catch(err => {
                const serverError = err.error.error;
                if (serverError.code === 'NoRealtimeQuotes' || serverError.code === 'MarketIsClosed') {
                    return actions.getDataForSymbol(tradeForChart.symbol, 1, 'hour', newDataType, false);
                }
                throw new Error(`Fetch data failed: ${serverError.message}`);
            });
        return dataResult;
    }

    render() {
        const { contractForChart, index, ticks, ohlc, events,
            feedLicense, pipSize, tradeForChart, tradingTime } = this.props;
        const { theme } = this.context;
        const { chartType, dataType } = this.state;

        return (
            <BinaryChart
                id={`trade-chart${index}`}
                className="trade-chart"
                contract={contractForChart && serverContractModelToChartContractModel(contractForChart)}
                defaultRange={1}                      // TODO: figure out how to set this dynamically so it looks good despite of data size
                events={events}
                noData={feedLicense === 'chartonly'}
                pipSize={pipSize}
                rangeChange={contractForChart ? undefined : this.rangeChange()}
                shiftMode={contractForChart ? 'dynamic' : 'fixed'}
                symbol={tradeForChart && tradeForChart.symbolName}
                ticks={(dataType === 'ticks' || contractForChart) ? ticks : ohlc}
                theme={theme}
                type={contractForChart ? 'area' : chartType}
                trade={tradeForChart && internalTradeModelToChartTradeModel(tradeForChart)}
                typeChange={contractForChart ? undefined : this.changeChartType}   // do not allow change type when there's contract
                tradingTimes={tradingTime.times}
            />
        );
    }
}
<|endoftext|>