<commit_before>const async = require("async");

module.exports = Chron;

function Chron(opts = {}) {
	let tasks      = [];
	let timer      = null;
	let reschedule = () => {
		if (timer) clearTimeout(timer);
		if (tasks.length === 0) return;

		let next = null;

		tasks.map((task) => {
			if (task.paused === true) return;

			if (!next || task.next < next) {
				next = task.next;
			}
		});

		if (!next) return;

		if (next < Date.now()) {
			return trigger();
		}

		timer = setTimeout(trigger, next - Date.now());
	};

	let task_next = (task) => {
		task.next = Date.now() + task.period;

		if (opts.align) {
			task.next -= (task.next % task.period);
		}
	};
	let trigger = () => {
		if (timer) clearTimeout(timer);
		if (tasks.length === 0) return;

		var now = Date.now();

		async.eachSeries(tasks, (task, next) => {
			if (task.paused === true) return next();

			// Date.now() is called every time to compensate
			// function call.
			// This ensures that 2 timers that should trigger in a couple
			// of milliseconds will actually be called because the first
			// will delay a bit and then the second will trigger (avoiding)
			// creating a timer to trigger a few milliseconds later.
			if (task.next >= Date.now() + opts.advanceMargin) return next();

			if (opts.async === true) {
				call(task, () => {
					task_next(task);

					return next();
				});
			} else {
				call(task);
				task_next(task);

				return next();
			}
		}, reschedule);
	};

	let call = (task, next) => {
		task.task({
			pause : function () {
				task.paused = true;

				if (next) next();

				return this;
			},
			resume : function () {

				delete task.paused;

				return this;
			},
			remove : function () {
				chron.remove(task.task);

				if (next) next();
			},
			next : function () {
				if (next) next();
			}
		});
	};

	// 100 milli is the margin to call a task in advance
	opts.advanceMargin = opts.advanceMargin || 0.1;
	opts.advanceMargin *= 1000;

	let chron = {
		add : function (period, task) {
			period *= 1000;

			tasks.push({
				period : period,
				task   : task
			});

			task_next(tasks[tasks.length - 1]);

			return this.resume();
		},
		remove : function (task) {
			tasks = tasks.filter((t) => (t.task !== task));

			return this.resume();
		},
		clear : function () {
			tasks = [];

			return this.pause();
		},
		pause : function () {
			if (timer) clearTimeout(timer);

			return this;
		},
		resume : function () {
			reschedule();

			return this;
		}
	};

	return chron;
}
<commit_msg>stop tasks execution if chron is cleared in the middle of a round<commit_after>const async = require("async");

module.exports = Chron;

function Chron(opts = {}) {
	let tasks      = [];
	let timer      = null;
	let reschedule = () => {
		if (timer) clearTimeout(timer);
		if (tasks.length === 0) return;

		let next = null;

		tasks.map((task) => {
			if (task.paused === true) return;

			if (!next || task.next < next) {
				next = task.next;
			}
		});

		if (!next) return;

		if (next < Date.now()) {
			return trigger();
		}

		timer = setTimeout(trigger, next - Date.now());
	};

	let task_next = (task) => {
		task.next = Date.now() + task.period;

		if (opts.align) {
			task.next -= (task.next % task.period);
		}
	};
	let trigger = () => {
		if (timer) clearTimeout(timer);
		if (tasks.length === 0) return;

		var now = Date.now();

		async.eachSeries(tasks, (task, next) => {
			// task paused
			if (task.paused === true) return next();
			// tasks were cleared in the meantime
			if (!tasks.length) return next();

			// Date.now() is called every time to compensate
			// function call.
			// This ensures that 2 timers that should trigger in a couple
			// of milliseconds will actually be called because the first
			// will delay a bit and then the second will trigger (avoiding)
			// creating a timer to trigger a few milliseconds later.
			if (task.next >= Date.now() + opts.advanceMargin) return next();

			if (opts.async === true) {
				call(task, () => {
					task_next(task);

					return next();
				});
			} else {
				call(task);
				task_next(task);

				return next();
			}
		}, reschedule);
	};

	let call = (task, next) => {
		task.task({
			pause : function () {
				task.paused = true;

				if (next) next();

				return this;
			},
			resume : function () {

				delete task.paused;

				return this;
			},
			remove : function () {
				chron.remove(task.task);

				if (next) next();
			},
			next : function () {
				if (next) next();
			}
		});
	};

	// 100 milli is the margin to call a task in advance
	opts.advanceMargin = opts.advanceMargin || 0.1;
	opts.advanceMargin *= 1000;

	let chron = {
		add : function (period, task) {
			period *= 1000;

			tasks.push({
				period : period,
				task   : task
			});

			task_next(tasks[tasks.length - 1]);

			return this.resume();
		},
		remove : function (task) {
			tasks = tasks.filter((t) => (t.task !== task));

			return this.resume();
		},
		clear : function () {
			tasks = [];

			return this.pause();
		},
		pause : function () {
			if (timer) clearTimeout(timer);

			return this;
		},
		resume : function () {
			reschedule();

			return this;
		}
	};

	return chron;
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * @license
 * Copyright (c) 2011 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License v1.0
 * (http://www.eclipse.org/legal/epl-v10.html), and the Eclipse Distribution
 * License v1.0 (http://www.eclipse.org/org/documents/edl-v10.html).
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
/*global define console */

define(function(){

	var OPERATOR = {
		NUL: {first:"", sep:",", named: false, ifemp: "", allow: "U"},
		"+": {first:"", sep:",", named: false, ifemp: "", allow: "U+R"},
		".": {first:".", sep:",", named: false, ifemp: "", allow: "U"},
		"/": {first:"/", sep:"/", named: false, ifemp: "", allow: "U"},
		";": {first:";", sep:";", named: true, ifemp: "", allow: "U"},
		"?": {first:"?", sep:"&", named: true, ifemp: "=", allow: "U"},
		"&": {first:"&", sep:"&", named: true, ifemp: "=", allow: "U"},
		"#": {first:"#", sep:",", named: false, ifemp: "", allow: "U+R"},
		",": {first:"", sep:",", named: false, ifemp: "", allow: "U+R-,"}
	};

	var VARSPEC_REGEXP = /^((?:(?:[a-zA-Z0-9_])|(?:%[0-9A-F][0-9A-F]))(?:(?:[a-zA-Z0-9_.])|(?:%[0-9A-F][0-9A-F]))*)(?:(\*)|:([0-9]+))?$/;

	function Literal(text) {
		this._text = text;
	}

	Literal.prototype = {
		expand: function(vars) {
			return encodeURI(this._text);
		}
	};

	function encodeString(value, encoding) {
		if (encoding === "U") {
			return encodeURIComponent(value).replace(/[!'()*]/g, function(str) {
				return '%' + str.charCodeAt(0).toString(16).toUpperCase();
			});
		}
		if (encoding === "U+R") {
			return encodeURI(value).replace(/%5B/g, '[').replace(/%5D/g, ']');
		}
		if (encoding === "U+R-,") {
			return encodeURI(value).replace(/%5B/g, '[').replace(/%5D/g, ']').replace(/,/g, '%2C');
		}
		throw new Error("Unknown allowed character set: " + encoding);
	}

	function encodeArray(value, encoding, separator) {
		var result = [];
		for (var i=0; i < value.length; i++) {
			if (typeof(value[i]) !== "undefined") {
				result.push(encodeString(value[i], encoding));
			}
		}
		return result.join(separator);
	}

	function encodeObject(value, encoding, nameValueSeparator, pairSeparator ) {
		var keys = Object.keys(value);
		var result = [];
		for (var i=0; i < keys.length; i++) {
			if (typeof(value[keys[i]]) !== "undefined") {
				result.push(encodeString(keys[i], encoding) + nameValueSeparator + encodeString(value[keys[i]], encoding));
			}
		}
		return result.join(pairSeparator);
	}

	function parseVarSpecs(text) {
		var result = [];
		var rawSpecs = text.split(",");
		for (var i=0; i < rawSpecs.length; i++) {
			var match = rawSpecs[i].match(VARSPEC_REGEXP);
			if (match === null) {
				throw new Error("Bad VarSpec: " + text);
			}
			result.push({
				name: match[1],
				explode: !!match[2],
				prefix: match[3] ? parseInt(match[3], 10) : -1
			});
		}
		return result;
	}

	function Expression(text) {
		if (text.length === 0) {
			throw new Error("Invalid Expression: 0 length expression");
		}

		this._operator = OPERATOR[text[0]];
		if (this._operator) {
			text = text.substring(1);
		} else {
			this._operator = OPERATOR.NUL;
		}

		this._varSpecList = parseVarSpecs(text);
	}

	Expression.prototype = {
		expand: function(params) {
			var result = [];
			for (var i=0; i < this._varSpecList.length; i++) {
				var varSpec = this._varSpecList[i];
				var name = varSpec.name;
				var value = params[name];
				var valueType = typeof(value);
				if (valueType !== "undefined" && value !== null) {
					var resultText = result.length === 0 ? this._operator.first: this._operator.sep;
					if (valueType === "string") {
						if (this._operator.named) {
							resultText += encodeString(name, "U+R");
							resultText += (value.length === 0) ? this._operator.ifemp : "=";
						}
						if (varSpec.prefix !== -1 && varSpec.prefix < value.length) {
							value = value.substring(0, varSpec.prefix);
						}

						resultText += encodeString(value, this._operator.allow);
					} else if (Array.isArray(value)) {
						if (!varSpec.explode) {
							if (this._operator.named) {
								resultText += encodeString(name, "U+R");
								resultText += (value.length === 0) ? this._operator.ifemp : "=";
							}
							resultText += encodeArray(value, this._operator.allow, ",");
						} else {
							resultText += encodeArray(value, this._operator.allow, this._operator.sep);
						}
					} else if (valueType === "object") {
						if (!varSpec.explode) {
							if (this._operator.named) {
								resultText += encodeString(name, "U+R");
								resultText += (Object.keys(value).length === 0) ? this._operator.ifemp : "=";
							}
							resultText += encodeObject(value, this._operator.allow, ",", ",");
						} else {
							resultText += encodeObject(value, this._operator.allow, "=", this._operator.sep);
						}
					} else {
						throw new Error("bad param type: " + name + " : " + valueType);
					}
					result.push(resultText);
				}
			}
			return result.join("");
		}
	};

	function parseTemplate(text) {
		var result = [];
		var current = 0;
		var curlyStartIndex = text.indexOf("{", current);
		while (curlyStartIndex !== -1) {
			result.push(new Literal(text.substring(current, curlyStartIndex)));
			var curlyEndIndex = text.indexOf("}", curlyStartIndex + 1);
			if (curlyEndIndex === -1) {
				throw new Error("Invalid template: " + text);
			}
			result.push(new Expression(text.substring(curlyStartIndex + 1, curlyEndIndex)));
			current = curlyEndIndex + 1;
			curlyStartIndex = text.indexOf("{", current);
		}
		result.push(new Literal(text.substring(current)));
		return result;
	}

	function URITemplate(template) {
		this._templateComponents = parseTemplate(template);
	}

	URITemplate.prototype = {
		expand: function(params) {
			var result = [];
			for (var i = 0; i < this._templateComponents.length; i++) {
				result.push(this._templateComponents[i].expand(params));
			}
			return result.join("");
		}
	};

	return URITemplate;
});<commit_msg>Minify URITemplate<commit_after>define(function(){function c(a){this._text=a}function d(a,b){if(b==="U")return encodeURIComponent(a).replace(/[!'()*]/g,function(a){return"%"+a.charCodeAt(0).toString(16).toUpperCase()});if(b==="U+R")return encodeURI(a).replace(/%5B/g,"[").replace(/%5D/g,"]");if(b==="U+R-,")return encodeURI(a).replace(/%5B/g,"[").replace(/%5D/g,"]").replace(/,/g,"%2C");throw new Error("Unknown allowed character set: "+b)}function e(a,b,c){var e=[];for(var f=0;f<a.length;f++)typeof a[f]!="undefined"&&e.push(d(a[f],b));return e.join(c)}function f(a,b,c,e){var f=Object.keys(a),g=[];for(var h=0;h<f.length;h++)typeof a[f[h]]!="undefined"&&g.push(d(f[h],b)+c+d(a[f[h]],b));return g.join(e)}function g(a){var c=[],d=a.split(",");for(var e=0;e<d.length;e++){var f=d[e].match(b);if(f===null)throw new Error("Bad VarSpec: "+a);c.push({name:f[1],explode:!!f[2],prefix:f[3]?parseInt(f[3],10):-1})}return c}function h(b){if(b.length===0)throw new Error("Invalid Expression: 0 length expression");this._operator=a[b[0]],this._operator?b=b.substring(1):this._operator=a.NUL,this._varSpecList=g(b)}function i(a){var b=[],d=0,e=a.indexOf("{",d);while(e!==-1){b.push(new c(a.substring(d,e)));var f=a.indexOf("}",e+1);if(f===-1)throw new Error("Invalid template: "+a);b.push(new h(a.substring(e+1,f))),d=f+1,e=a.indexOf("{",d)}return b.push(new c(a.substring(d))),b}function j(a){this._templateComponents=i(a)}var a={NUL:{first:"",sep:",",named:!1,ifemp:"",allow:"U"},"+":{first:"",sep:",",named:!1,ifemp:"",allow:"U+R"},".":{first:".",sep:",",named:!1,ifemp:"",allow:"U"},"/":{first:"/",sep:"/",named:!1,ifemp:"",allow:"U"},";":{first:";",sep:";",named:!0,ifemp:"",allow:"U"},"?":{first:"?",sep:"&",named:!0,ifemp:"=",allow:"U"},"&":{first:"&",sep:"&",named:!0,ifemp:"=",allow:"U"},"#":{first:"#",sep:",",named:!1,ifemp:"",allow:"U+R"},",":{first:"",sep:",",named:!1,ifemp:"",allow:"U+R-,"}},b=/^((?:(?:[a-zA-Z0-9_])|(?:%[0-9A-F][0-9A-F]))(?:(?:[a-zA-Z0-9_.])|(?:%[0-9A-F][0-9A-F]))*)(?:(\*)|:([0-9]+))?$/;return c.prototype={expand:function(a){return encodeURI(this._text)}},h.prototype={expand:function(a){var b=[];for(var c=0;c<this._varSpecList.length;c++){var g=this._varSpecList[c],h=g.name,i=a[h],j=typeof i;if(j!=="undefined"&&i!==null){var k=b.length===0?this._operator.first:this._operator.sep;if(j==="string")this._operator.named&&(k+=d(h,"U+R"),k+=i.length===0?this._operator.ifemp:"="),g.prefix!==-1&&g.prefix<i.length&&(i=i.substring(0,g.prefix)),k+=d(i,this._operator.allow);else if(Array.isArray(i))g.explode?k+=e(i,this._operator.allow,this._operator.sep):(this._operator.named&&(k+=d(h,"U+R"),k+=i.length===0?this._operator.ifemp:"="),k+=e(i,this._operator.allow,","));else{if(j!=="object")throw new Error("bad param type: "+h+" : "+j);g.explode?k+=f(i,this._operator.allow,"=",this._operator.sep):(this._operator.named&&(k+=d(h,"U+R"),k+=Object.keys(i).length===0?this._operator.ifemp:"="),k+=f(i,this._operator.allow,",",","))}b.push(k)}}return b.join("")}},j.prototype={expand:function(a){var b=[];for(var c=0;c<this._templateComponents.length;c++)b.push(this._templateComponents[c].expand(a));return b.join("")}},j})<|endoftext|>


<commit_before>try{ m = angular.module('proso_apps.services'); } catch (err) { m = angular.module('proso_apps.services', []); }
m.service("practiceService", ["$http", "$q", "configService", function($http, $q, configService){
    var self = this;

    var queue = [];
    var deferred_fc = null;
    var promise_resolved_tmp = false;
    var current_fc = null;
    var answer_queue = [];

    var config = {};
    var current = 0;
    var set_id = 0;
    var summary = {
        flashcards: [],
        answers: [],
        correct: 0,
        count: 0
    };

    var contexts = {};

    // called on create and set reset
    self.init_set = function(config_name){
        var key = "practice." + config_name + ".";
        config.set_length = configService.get_config("proso_flashcards", key + "set_length", 10);
        config.fc_queue_size_max = configService.get_config("proso_flashcards", key + "fc_queue_size_max", 1);
        config.fc_queue_size_min = configService.get_config("proso_flashcards", key + "fc_queue_size_min", 1);
        config.save_answer_immediately = configService.get_config("proso_flashcards", key + "save_answer_immediately", false);
        config.cache_context = configService.get_config("proso_flashcards", key + "cache_context", false);

        self.set_filter({});
        current = 0;
        self.flush_answer_queue();
        self.clear_queue();
        deferred_fc = null;
        set_id++;
    };

    self.set_filter = function(filter){
        config.filter = {
            contexts: [],
            categories: [],
            types: [],
            language: "en"
        };
        angular.extend(config.filter, filter);
    };

    self.get_current = function(){
        return current;
    };

    self.get_config = function(){
        return angular.copy(config);
    };

    // add answer to queue and upload queued answers if necessary
    self.save_answer = function(answer, farce_save){
        if (answer) {
            answer_queue.push(answer);
            summary.answers.push(answer);
            summary.count++;
            if (answer.flashcard_id == answer.flashcard_answered_id)
                summary.correct++;
        }

        if (config.save_answer_immediately || farce_save || current >= config.set_length) {
            if (answer_queue.length > 0) {
                $http.post("/flashcards/answer/", {answers: answer_queue})
                    .error(function (response) {
                        console.error("Problem while uploading answer", response)
                    });
                answer_queue = [];
            }
        }
    };

    self.flush_answer_queue = function(){
        self.save_answer(null, true)
    };

    // build answer from current FC and save
    self.save_answer_to_current_fc = function(answered_fc_id, response_time, meta){
        if (!current_fc) {
            console.error("There is no current flashcard");
            return;
        }
        var answer = {
            flashcard_id: current_fc.id,
            flashcard_answered_id: answered_fc_id,
            response_time: response_time,
            direction: current_fc.direction
        };
        if (meta)
            answer.meta = meta;
        if (current_fc.options){
            answer.option_ids = [];
            current_fc.options.forEach(function(o){
                if (o.id != current_fc.id)
                    answer.option_ids.push(o.id);
            });
        }
        self.save_answer(answer);
    };

    // return promise of flashcard
    self.get_flashcard = function(){
        if(deferred_fc){
            return $q(function(resolve, reject){
                reject("Already one flashcard promised")
            });
        }
        deferred_fc  = $q.defer();
        promise_resolved_tmp = false;
        _resolve_promise();
        deferred_fc.promise.then(function(){ deferred_fc = null;}, function(){ deferred_fc = null;});
        return deferred_fc.promise;
    };

    self.clear_queue = function(){
        queue = [];
    };

    // preload flashcards
    self.preload_flashcards = function(){
        _load_flashcards();
    };

    self.get_fc_queue = function(){
        return queue;
    };

    self.get_answer_queue = function(){
        return answer_queue;
    };

    self.get_summary = function(){
        return summary;
    };

    var _load_flashcards = function(){
        if (queue.length >= config.fc_queue_size_min)                                           // if there are some FC queued
            return;
        config.filter.limit  = config.fc_queue_size_max - queue.length;
        if (deferred_fc && !promise_resolved_tmp) config.filter.limit ++;                  // if we promised one flashcard
        config.filter.limit = Math.min(config.filter.limit, config.set_length - current - queue.length);  // check size of set
        if (config.filter.limit == 0) return;                         // nothing to do
        config.filter.avoid = current_fc ? [current_fc.id] : [];      // avoid current FC
        queue.forEach(function(fc){
            config.filter.avoid.push(fc.id);
        });

        var filter = {};
        for (var key in config.filter){
            if (config.filter[key] instanceof Array) {
                filter[key] = JSON.stringify(config.filter[key]);
            }else{
                filter[key] = config.filter[key];
            }
        }
        if (config.cache_context){
            filter["without_contexts"] = 1;
        }

        var request;
        if (answer_queue.length == 0) {
            request = $http.get("/flashcards/practice/", {params: filter});
        }else{
            request = $http.post("/flashcards/practice/", {answers: answer_queue}, {params: filter});
            answer_queue = [];
        }
        var request_in_set = set_id;
        request
            .success(function(response){
                if (request_in_set != set_id)
                    return;
                queue = queue.concat(response.data.flashcards);
                _load_contexts();
                if (queue.length > 0)
                    _resolve_promise();
                else{
                    console.error("No Flashcards to practice")
                }
            })
            .error(function (response) {
                console.error("Something went wrong while loading flashcards from backend.")
            });

    };

    var _load_contexts = function(){
        if (config.cache_context){
            queue.forEach(function(fc){
                if (fc.context_id in contexts){
                    if (contexts[fc.context_id] != "loading"){
                        fc.context = contexts[fc.context_id];
                    }
                }else{
                    contexts[fc.context_id] = "loading";
                    $http.get("/flashcards/context/" + fc.context_id)
                        .success(function(response){
                            contexts[fc.context_id] = response.data;
                            _resolve_promise();
                        }).error(function(){
                            delete contexts[fc.context_id];
                            console.error("Error while loading context from backend")
                        })
                }
            });
        }
    };

    var _resolve_promise = function(){
        if (deferred_fc == null){
            return;
        }
        if (config.set_length == current){
            deferred_fc.reject("Set was completed");
            return;
        }
        if (queue.length > 0) {
            if (config.cache_context){
                if (typeof contexts[queue[0].context_id]  === 'object'){
                    queue[0].context = contexts[queue[0].context_id];
                }else{
                    return;
                }
            }
            current_fc = queue.shift();
            current++;
            promise_resolved_tmp = true;
            summary.flashcards.push(current_fc);
            deferred_fc.resolve(current_fc);
        }
        _load_flashcards();
    };
}]);<commit_msg>practice_service: add csrf token to http post<commit_after>try{ m = angular.module('proso_apps.services'); } catch (err) { m = angular.module('proso_apps.services', []); }
m.service("practiceService", ["$http", "$q", "configService", "$cookies", function($http, $q, configService, $cookies){
    var self = this;

    var queue = [];
    var deferred_fc = null;
    var promise_resolved_tmp = false;
    var current_fc = null;
    var answer_queue = [];

    var config = {};
    var current = 0;
    var set_id = 0;
    var summary = {
        flashcards: [],
        answers: [],
        correct: 0,
        count: 0
    };

    var contexts = {};

    // called on create and set reset
    self.init_set = function(config_name){
        var key = "practice." + config_name + ".";
        config.set_length = configService.get_config("proso_flashcards", key + "set_length", 10);
        config.fc_queue_size_max = configService.get_config("proso_flashcards", key + "fc_queue_size_max", 1);
        config.fc_queue_size_min = configService.get_config("proso_flashcards", key + "fc_queue_size_min", 1);
        config.save_answer_immediately = configService.get_config("proso_flashcards", key + "save_answer_immediately", false);
        config.cache_context = configService.get_config("proso_flashcards", key + "cache_context", false);

        self.set_filter({});
        current = 0;
        self.flush_answer_queue();
        self.clear_queue();
        deferred_fc = null;
        set_id++;
    };

    self.set_filter = function(filter){
        config.filter = {
            contexts: [],
            categories: [],
            types: [],
            language: "en"
        };
        angular.extend(config.filter, filter);
    };

    self.get_current = function(){
        return current;
    };

    self.get_config = function(){
        return angular.copy(config);
    };

    // add answer to queue and upload queued answers if necessary
    self.save_answer = function(answer, farce_save){
        if (answer) {
            answer_queue.push(answer);
            summary.answers.push(answer);
            summary.count++;
            if (answer.flashcard_id == answer.flashcard_answered_id)
                summary.correct++;
        }

        if (config.save_answer_immediately || farce_save || current >= config.set_length) {
            if (answer_queue.length > 0) {
                $http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
                $http.post("/flashcards/answer/", {answers: answer_queue})
                    .error(function (response) {
                        console.error("Problem while uploading answer", response)
                    });
                answer_queue = [];
            }
        }
    };

    self.flush_answer_queue = function(){
        self.save_answer(null, true)
    };

    // build answer from current FC and save
    self.save_answer_to_current_fc = function(answered_fc_id, response_time, meta){
        if (!current_fc) {
            console.error("There is no current flashcard");
            return;
        }
        var answer = {
            flashcard_id: current_fc.id,
            flashcard_answered_id: answered_fc_id,
            response_time: response_time,
            direction: current_fc.direction
        };
        if (meta)
            answer.meta = meta;
        if (current_fc.options){
            answer.option_ids = [];
            current_fc.options.forEach(function(o){
                if (o.id != current_fc.id)
                    answer.option_ids.push(o.id);
            });
        }
        self.save_answer(answer);
    };

    // return promise of flashcard
    self.get_flashcard = function(){
        if(deferred_fc){
            return $q(function(resolve, reject){
                reject("Already one flashcard promised")
            });
        }
        deferred_fc  = $q.defer();
        promise_resolved_tmp = false;
        _resolve_promise();
        deferred_fc.promise.then(function(){ deferred_fc = null;}, function(){ deferred_fc = null;});
        return deferred_fc.promise;
    };

    self.clear_queue = function(){
        queue = [];
    };

    // preload flashcards
    self.preload_flashcards = function(){
        _load_flashcards();
    };

    self.get_fc_queue = function(){
        return queue;
    };

    self.get_answer_queue = function(){
        return answer_queue;
    };

    self.get_summary = function(){
        return summary;
    };

    var _load_flashcards = function(){
        if (queue.length >= config.fc_queue_size_min)                                           // if there are some FC queued
            return;
        config.filter.limit  = config.fc_queue_size_max - queue.length;
        if (deferred_fc && !promise_resolved_tmp) config.filter.limit ++;                  // if we promised one flashcard
        config.filter.limit = Math.min(config.filter.limit, config.set_length - current - queue.length);  // check size of set
        if (config.filter.limit == 0) return;                         // nothing to do
        config.filter.avoid = current_fc ? [current_fc.id] : [];      // avoid current FC
        queue.forEach(function(fc){
            config.filter.avoid.push(fc.id);
        });

        var filter = {};
        for (var key in config.filter){
            if (config.filter[key] instanceof Array) {
                filter[key] = JSON.stringify(config.filter[key]);
            }else{
                filter[key] = config.filter[key];
            }
        }
        if (config.cache_context){
            filter["without_contexts"] = 1;
        }

        var request;
        if (answer_queue.length == 0) {
            request = $http.get("/flashcards/practice/", {params: filter});
        }else{
            $http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
            request = $http.post("/flashcards/practice/", {answers: answer_queue}, {params: filter});
            answer_queue = [];
        }
        var request_in_set = set_id;
        request
            .success(function(response){
                if (request_in_set != set_id)
                    return;
                queue = queue.concat(response.data.flashcards);
                _load_contexts();
                if (queue.length > 0)
                    _resolve_promise();
                else{
                    console.error("No Flashcards to practice")
                }
            })
            .error(function (response) {
                console.error("Something went wrong while loading flashcards from backend.")
            });

    };

    var _load_contexts = function(){
        if (config.cache_context){
            queue.forEach(function(fc){
                if (fc.context_id in contexts){
                    if (contexts[fc.context_id] != "loading"){
                        fc.context = contexts[fc.context_id];
                    }
                }else{
                    contexts[fc.context_id] = "loading";
                    $http.get("/flashcards/context/" + fc.context_id)
                        .success(function(response){
                            contexts[fc.context_id] = response.data;
                            _resolve_promise();
                        }).error(function(){
                            delete contexts[fc.context_id];
                            console.error("Error while loading context from backend")
                        })
                }
            });
        }
    };

    var _resolve_promise = function(){
        if (deferred_fc == null){
            return;
        }
        if (config.set_length == current){
            deferred_fc.reject("Set was completed");
            return;
        }
        if (queue.length > 0) {
            if (config.cache_context){
                if (typeof contexts[queue[0].context_id]  === 'object'){
                    queue[0].context = contexts[queue[0].context_id];
                }else{
                    return;
                }
            }
            current_fc = queue.shift();
            current++;
            promise_resolved_tmp = true;
            summary.flashcards.push(current_fc);
            deferred_fc.resolve(current_fc);
        }
        _load_flashcards();
    };
}]);<|endoftext|>


<commit_before>/**
 * Knorm
 */
class Knorm {
  /**
   * Create a new ORM instance.
   *
   * @param {object} [config={}] ORM configuration.
   * @param {function} config.fieldToColumn A function to convert all field-names
   * to column names, for example [snakeCase](https://lodash.com/docs/4.17.10#snakeCase).
   * @param {boolean} config.debug Whether or not to enable debug mode.
   *
   */
  constructor(config = {}) {
    this.plugins = {};
    this.models = {};
    this.config = config;

    class Model extends this.constructor.Model {}
    class Query extends this.constructor.Query {}
    class Transaction extends this.constructor.Transaction {}

    let Field;
    const { fieldToColumn } = config;

    if (typeof fieldToColumn === 'function') {
      Field = class Field extends this.constructor.Field {
        getColumnName(fieldName) {
          return fieldToColumn.call(this, fieldName);
        }
      };
      Model.Field = Field;
    } else {
      Field = this.constructor.Field;
    }

    Model.Query = Query;

    Model.prototype.knorm = Model.knorm = this;
    Field.prototype.knorm = Field.knorm = this;
    Query.prototype.knorm = Query.knorm = this;
    Transaction.prototype.knorm = Transaction.knorm = this;

    Field.prototype.models = Field.models = this.models;
    Model.prototype.models = Model.models = this.models;
    Query.prototype.models = Query.models = this.models;
    Transaction.prototype.models = Transaction.models = this.models;

    this.Field = Field;
    this.Model = Model;
    this.Query = Query;
    this.Transaction = Transaction;
  }

  /**
   * Load a plugin into the ORM.
   *
   * @param {object|function} plugin The plugin to load. If passed as a function,
   * the function is called with the ORM instance for initialisation. If passed
   * as an object, it should have `name` and `init` properties.
   * @param {string} plugin.name The name of the plugin. This allows later
   * accessing the plugin via `orm.plugins['plugin name']`.
   * @param {function} plugin.init The function called to initialise the plugin.
   *
   * @returns {Knorm} The ORM instance.
   */
  use(plugin) {
    if (!plugin) {
      throw new this.constructor.KnormError('no plugin provided');
    }

    if (typeof plugin !== 'function' && typeof plugin.init !== 'function') {
      throw new this.constructor.KnormError('invalid plugin provided');
    }

    const { name } = plugin;

    if (!name) {
      throw new this.constructor.KnormError('plugins should have a `name`');
    }

    if (this.plugins[name] !== undefined) {
      throw new this.constructor.KnormError(
        `plugin \`${name}\` has already been added`
      );
    }

    this.plugins[name] = plugin;

    if (plugin.init) {
      plugin.init(this);
    } else {
      plugin(this);
    }

    return this;
  }

  addModel(model) {
    if (!model) {
      throw new this.constructor.KnormError(`no model provided`);
    }

    if (!(model.prototype instanceof this.Model) && model !== this.Model) {
      throw new this.constructor.KnormError(
        `model should be a subclass of \`knorm.Model\``
      );
    }

    const { name } = model;

    if (this.models[name]) {
      throw new this.constructor.KnormError(
        `model \`${name}\` has already been added`
      );
    }

    this.models[name] = model;
  }

  clone() {
    const clone = new Knorm(this.config);

    Object.values(this.plugins).forEach(plugin => {
      clone.use(plugin);
    });

    Object.entries(this.models).forEach(([name, model]) => {
      clone.models[name] = model;
    });

    return clone;
  }
}

/**
 * Reference to the Model class
 * @type {Model}
 */
Knorm.Model = require('./Model');

/**
 * Reference to the Query class
 * @type {Query}
 */
Knorm.Query = require('./Query');

/**
 * Reference to the Field class
 * @type {Field}
 */
Knorm.Field = require('./Field');

/**
 * Reference to the Transaction class
 * @type {Transaction}
 */
Knorm.Transaction = require('./Transaction');

/**
 * Reference to the KnormError class
 * @type {KnormError}
 */
Knorm.KnormError = require('./KnormError');

module.exports = Knorm;
<commit_msg>docs(Knorm): document methods<commit_after>/**
 * Creates and configures ORMs.
 */
class Knorm {
  /**
   * Creates a new ORM instance.
   *
   * @param {object} [config={}] The ORM's configuration.
   * @param {function} config.fieldToColumn A function to convert all
   * field-names  to column names, for example
   * [snakeCase](https://lodash.com/docs/4.17.10#snakeCase).
   * @param {boolean} config.debug Whether or not to enable debug mode.
   *
   */
  constructor(config = {}) {
    this.plugins = {};
    this.models = {};
    this.config = config;

    class Model extends this.constructor.Model {}
    class Query extends this.constructor.Query {}
    class Transaction extends this.constructor.Transaction {}

    let Field;
    const { fieldToColumn } = config;

    if (typeof fieldToColumn === 'function') {
      Field = class Field extends this.constructor.Field {
        getColumnName(fieldName) {
          return fieldToColumn.call(this, fieldName);
        }
      };
      Model.Field = Field;
    } else {
      Field = this.constructor.Field;
    }

    Model.Query = Query;

    Model.prototype.knorm = Model.knorm = this;
    Field.prototype.knorm = Field.knorm = this;
    Query.prototype.knorm = Query.knorm = this;
    Transaction.prototype.knorm = Transaction.knorm = this;

    Field.prototype.models = Field.models = this.models;
    Model.prototype.models = Model.models = this.models;
    Query.prototype.models = Query.models = this.models;
    Transaction.prototype.models = Transaction.models = this.models;

    this.Field = Field;
    this.Model = Model;
    this.Query = Query;
    this.Transaction = Transaction;
  }

  /**
   * Loads a plugin into the ORM.
   *
   * @param {object|function} plugin The plugin to load. If passed as a
   * function,  the function is called with the ORM instance for initialisation.
   * Note that if an object is passed, it should have `name` and `init`
   * properties.
   * @param {string} plugin.name The name of the plugin. This allows later
   * accessing the plugin via the ORM's `plugins` object. Note that for
   * functions, the plugin's `name` is the function's name.
   * @param {function} plugin.init The function called to initialise the plugin.
   *
   * @throws {KnormError} if the plugin provided is not a function or is an
   * object without an `init` method.
   * @throws {KnormError} if the plugin has no `name` property.
   * @throws {KnormError} if the plugin has already been added.
   *
   * @returns {Knorm} the ORM instance.
   */
  use(plugin) {
    if (!plugin) {
      throw new this.constructor.KnormError('no plugin provided');
    }

    if (typeof plugin !== 'function' && typeof plugin.init !== 'function') {
      throw new this.constructor.KnormError('invalid plugin provided');
    }

    const { name } = plugin;

    if (!name) {
      throw new this.constructor.KnormError('plugins should have a `name`');
    }

    if (this.plugins[name] !== undefined) {
      throw new this.constructor.KnormError(
        `plugin \`${name}\` has already been added`
      );
    }

    this.plugins[name] = plugin;

    if (plugin.init) {
      plugin.init(this);
    } else {
      plugin(this);
    }

    return this;
  }

  /**
   * Adds a model to a {@link Knorm} instance.
   *
   * @param {Model} model The model to add to the ORM. Note that models are
   * automatically added to a {@link Knorm} instance when they are configured,
   * therefore you will only need to call this method to add models that are not
   * configured. See {@link /guides/models.html#model-registry} for more info.
   *
   * @throws {KnormError} if the model passed does not inherit the ORM's
   * {@link Model} instance. This prevents one from (perhaps accidentally)
   * adding a model from ORM instance X to ORM instance Y.
   * @throws {KnormError} if the model has already been added.
   *
   * @todo return the {@link Knorm} instance.
   */
  addModel(model) {
    if (!model) {
      throw new this.constructor.KnormError(`no model provided`);
    }

    if (!(model.prototype instanceof this.Model) && model !== this.Model) {
      throw new this.constructor.KnormError(
        `model should be a subclass of \`knorm.Model\``
      );
    }

    const { name } = model;

    if (this.models[name]) {
      throw new this.constructor.KnormError(
        `model \`${name}\` has already been added`
      );
    }

    this.models[name] = model;
  }

  /**
   * Creates a clone of an existing {@link Knorm} instance, copying all the
   * models and plugins loaded into the original orm.
   *
   * @returns {Knorm} the newly cloned ORM instance.
   */
  clone() {
    const clone = new Knorm(this.config);

    Object.values(this.plugins).forEach(plugin => {
      clone.use(plugin);
    });

    Object.entries(this.models).forEach(([name, model]) => {
      clone.models[name] = model;
    });

    return clone;
  }
}

/**
 * Reference to the {@link Model} class.
 *
 * @type {Model}
 */
Knorm.Model = require('./Model');

/**
 * Reference to the {@link Query} class.
 *
 * @type {Query}
 */
Knorm.Query = require('./Query');

/**
 * Reference to the {@link Field} class.
 *
 * @type {Field}
 */
Knorm.Field = require('./Field');

/**
 * Reference to the {@link Transaction} class.
 *
 * @type {Transaction}
 */
Knorm.Transaction = require('./Transaction');

/**
 * Reference to the {@link KnormError} class.
 *
 * @type {KnormError}
 */
Knorm.KnormError = require('./KnormError');

module.exports = Knorm;
<|endoftext|>


<commit_before>/**
 * Created by andreafspeziale on 13/04/16.
 */
dashboard.controller('DashboardController', ['$scope', 'LiskServices','$http', 'ExchangeServices', '$aside','usSpinnerService', 'EnvServices', 'BackendServices',
    function($scope, LiskServices, $http, ExchangeServices, $aside, usSpinnerService, EnvServices, BackendServices) {

        console.log('Hey, what are you looking for here? ;)');
        usSpinnerService.spin('spinner-voters');

        /**
         * Vars
         */

        var body = angular.element( document.querySelector( 'body' ) );
        var aside = angular.element( document.querySelector( 'aside' ) );

        var liskit_address = EnvServices.poolAddress;
        // $scope.swap_holding = EnvServices.swapHolding;
        $scope.forging_shares = {};

        $scope.address_forging = '';
        $scope.voters_account = [];
        $scope.guest_address = '';
        $scope.delegates = [];
        $scope.delegates_total_balance = 0;
        $scope.pagination = {
            currentPage : 1,
            itemsPerPage :10,
            maxSize : 3
        };

        /**
        * Asides
        */

        $scope.detail_aside = $aside({
            scope: $scope,
            animation: 'am-slide-right',
            templateUrl: './public/src/detail/views/detail.html',
            show: false,
            keyboard: false,
            backdrop: true,
            tag: 'detailAside'
        });

        $scope.$on('aside.hide', function(e, target) {
          if (target.$options.tag == 'detailAside') {
            body.removeClass('overflow-hidden');
            aside.removeClass('overflow-scroll');
          }
        });

        /**
        * Close / open asides
        */

        $scope.openDetail = function(address,balance){
            console.log('Open detail');
            console.log('Address setted: ', address);
            $scope.address_forging = address;
            $scope.balance_forging = balance;
            $scope.closeDetail();
            body.addClass('overflow-hidden');
            aside.addClass('overflow-scroll');
            $scope.detail_aside.show();
        };

        $scope.closeDetail = function(){
            var myEl = angular.element( document.querySelector( 'body' ) );
            body.removeClass('overflow-hidden');
            aside.removeClass('overflow-scroll');
            $scope.detail_aside.hide();
        };

        /**
         * Graph config
         */

        var uptime_graph_config = liquidFillGaugeDefaultSettings();
            uptime_graph_config.circleColor = "#94A9BE";
            uptime_graph_config.textColor = "#94A9BE";
            uptime_graph_config.textSize = 0.55;
            uptime_graph_config.waveTextColor = "#fff";
            uptime_graph_config.waveColor = "rgba(148, 169, 190, 0.72)";
            uptime_graph_config.circleThickness = 0.1;
            uptime_graph_config.circleFillGap = 0.2;
            uptime_graph_config.textVertPosition = 0.5;
            uptime_graph_config.waveAnimateTime = 2000;
            uptime_graph_config.waveHeight = 0.3;
            uptime_graph_config.waveCount = 1;

        /**
         * Pagination handler
         */

        $scope.pageChanged = function() {
            $log.log('Page changed to: ' + $scope.pagination.currentPage);
        };

        /**
         * Dashboard functions
         */

        $scope.calculateForgingShares = function() {
            if(EnvServices.dynamicPool) {
                $scope.$watchGroup(['rank'],function(newValues, oldValues, scope){
                    if($scope.rank >= 50) {
                        $scope.forging_shares['maintenance_perc'] = EnvServices.maintenancePerc
                        $scope.forging_shares['stack_perc'] = 100-EnvServices.maintenancePerc-EnvServices.top101perc
                        $scope.forging_shares['share_perc'] = EnvServices.top101perc
                    }
                    if($scope.rank < 50 && $scope.rank >= 20) {
                        console.log("rank less than 50");
                        $scope.forging_shares['maintenance_perc'] = EnvServices.maintenancePerc
                        $scope.forging_shares['stack_perc'] = 100-EnvServices.maintenancePerc-EnvServices.top101perc
                        $scope.forging_shares['share_perc'] = EnvServices.top50perc
                    }
                    if($scope.rank < 20) {
                        $scope.forging_shares['maintenance_perc'] = EnvServices.maintenancePerc
                        $scope.forging_shares['stack_perc'] = 100-EnvServices.maintenancePerc-EnvServices.top101perc
                        $scope.forging_shares['share_perc'] = EnvServices.top20perc
                    }
                })
            } else {
                $scope.forging_shares['maintenance_perc'] = EnvServices.maintenancePerc
                $scope.forging_shares['stack_perc'] = 100-EnvServices.maintenancePerc-EnvServices.staticPerc
                $scope.forging_shares['share_perc'] = EnvServices.staticPerc
            }
        }

        $scope.getBalance = function(address) {
            LiskServices.getBalance(address).then(function (balance) {
                BackendServices.getLastPayoutInfo().then(function (forged) {

                    usSpinnerService.stop('spinner-forging-pool');
                    $scope.balance = (0 + forged.result.forged)/10000/10000;
                    $scope.payday = forged.result.date;

                }, function (error) {
                    console.log('getLastPayoutInfo function error');
                    console.log(error);
                })
            }, function (error) {
                console.log('getBalance function error');
                console.log(error);
            });
        };

        $scope.getDelegateList = function() {
          LiskServices.getDelegates().then(function(list) {
                $scope.delegates = list.delegates;
                console.log($scope.delegates);
            }, function (error) {
                console.log('getDelegates function error');
                console.log(error);
            });
        };

        // Turn Around
        $scope.getVotesOfAccount = function(address) {
            LiskServices.getVotesOfAccount(address).then(function (delegates) {
                angular.forEach(delegates.delegates, function(delegate){
                    if(delegate.address == liskit_address){
                        $scope.rank = delegate.rate;
                        $scope.productivity =  delegate.productivity;
                        if($scope.productivity != 0 )
                            var uptime_graph = loadLiquidFillGauge("uptime", $scope.productivity, uptime_graph_config);
                    }
                });
            }, function (data) {
                console.log('getDelegateStats function error');
                console.log(data);
            });
        };

        $scope.totalDelegatesForged = function() {
            LiskServices.getDelegateStats().then(function (delegates) {
                $scope.total_delegate = delegates.totalCount;
                angular.forEach(delegates, function(delegate){
                    angular.forEach(delegate, function(value){
                        LiskServices.getBalance(value.address).then(function (balance) {
                            $scope.delegates_total_balance = $scope.delegates_total_balance + balance.balance/10000/10000;
                        }, function (error) {
                            console.log('totalDelegatesForged function error');
                            console.log(data);
                        });
                    });
                });
            }, function (data) {
                console.log('totalDelegatesForged function error');
                console.log(data);
            });
        };

        $scope.getNumberOfVoters = function(address) {
            //console.log('Loading getNumberOfVoters function');
            LiskServices.getPublicKey(address).then(function (public_key) {
                var public_key = public_key.publicKey;
                LiskServices.getVoters(public_key).then(function(voters) {
                    $scope.voters = voters.accounts;
                    $scope.number_of_voters = $scope.voters.length;
                })
            }, function(data) {
                console.log('getPublicKey function error');
                console.log(data);
            })
        };

        $scope.getVoters = function(address) {
            $scope.guest_voters_account = [];
            $scope.error_message = '';
                $scope.delegates = $scope.totalDelegatesRegistered;
                LiskServices.getPublicKey(address).then(function (public_key) {
                    if (public_key.success == true) {
                        var public_key = public_key.publicKey;
                        LiskServices.getVoters(public_key).then(function (voters) {
                            if (voters.accounts.length) {
                                $scope.voters = voters.accounts;
                                for(j = 0; j<$scope.voters.length; j++) {
                                    var flag = 0;
                                    for(var i = 0; i<$scope.delegates.length; i++) {
                                        if($scope.delegates[i].address == $scope.voters[j].address) {
                                            var tmp = $scope.voters[j];
                                            tmp.rate = $scope.delegates[i].rate;
                                            if (address == liskit_address) {
                                                $scope.voters_account.push(tmp);
                                            }
                                            if (address != liskit_address) {
                                                $scope.guest_voters_account.push(tmp);
                                            }
                                            flag = 1;
                                            break;
                                        }
                                    }
                                    if(flag==0){
                                        if (address == liskit_address) {
                                            $scope.voters_account.push($scope.voters[j]);
                                        }
                                        if (address != liskit_address) {
                                            $scope.guest_voters_account.push($scope.voters[j]);
                                        }
                                    }
                                }
                            } else {
                                toastr.warning("This address doesn't have any supporter");
                                $scope.guest_voters_account = [];
                                $scope.guestFilterSearch = '';
                            }
                        }, function (data) {
                            console.log('getVoters function error');
                            console.log(data);

                        })
                    } else {
                        $scope.guest_voters_account = [];
                        $scope.guestFilterSearch = '';
                        $scope.guest_address = '';
                        $scope.error_message = public_key.error;
                        toastr.warning(public_key.error);
                    }
                }, function (data) {
                    console.log('getPublicKey function error');
                    console.log(data);
                })

        };

        $scope.getBlockChainHeight = function() {
            LiskServices.getBlockChainHeight().then(function(blockchain_height) {
                $scope.blockchain_height = blockchain_height.height;
            }, function(data) {
                console.log('getBlockChainHeight function error');
                console.log(data);
            });
        };

        $scope.getSynchronisationStatus = function(client_ip) {
            LiskServices.getSynchronisationStatus(client_ip).then(function(status) {
                $scope.status = status.success.toString();
            }, function(data) {
                console.log('getSynchronisationStatus function error');
                console.log(data);
            });
        };

        $scope.getTotalRegisteredDelegates = function() {
            var counter = 1;
            $scope.totalDelegatesRegistered = [];
            LiskServices.getDelegateStats().then(function (delegates) {
                var delegates = delegates.totalCount;
                while (counter < delegates) {
                    LiskServices.getDelegates(counter).then(function (list) {
                        angular.forEach(list.delegates, function(value){
                            $scope.totalDelegatesRegistered.push(value);
                        })
                        if($scope.totalDelegatesRegistered.length == delegates-1){
                            $scope.getVoters(liskit_address);
                        }
                    }, function (error) {
                        console.log('getDelegates function error');
                        console.log(error);
                    });
                    counter += 101;
                }
            }, function (error) {
                console.log('getDelegateStats function error');
                console.log(error);
            });
        };

        /**
         * Exchange test - getting BTC:ALTCOIN status - example below
         * Arguments:
         *      polo for Poloniex
         * Arguments
         *      LSK for lisk
         */

        $scope.getTicker = function() {
            ExchangeServices.getTicker('polo', 'LSK').then(function (response) {
                $scope.liskLastPrice = response.last;
            }, function (error) {
                console.log('getTicker lisk service promise rejected');
                console.log(error);
            });
        };

        /**
         * Run
         */
        $scope.getTotalRegisteredDelegates();
        $scope.getBlockChainHeight();
        $scope.getBalance(liskit_address);
        $scope.getNumberOfVoters(liskit_address);
        //$scope.getDelegateStats(liskit_address);
        $scope.getVotesOfAccount(liskit_address);
        $scope.totalDelegatesForged();
        $scope.getSynchronisationStatus();
        $scope.getTicker();
        $scope.calculateForgingShares();
    }])
    /**
     * Pagination custom filter
     */
    .filter('startFrom', function() {
        return function(input, start) {
            if (!input || !input.length) { return; }
            start = +start;
            return input.slice(start);
        }
    });
<commit_msg>Add total share calculation to gdt<commit_after>/**
 * Created by andreafspeziale on 13/04/16.
 */
dashboard.controller('DashboardController', ['$scope', 'LiskServices','$http', 'ExchangeServices', '$aside','usSpinnerService', 'EnvServices', 'BackendServices',
    function($scope, LiskServices, $http, ExchangeServices, $aside, usSpinnerService, EnvServices, BackendServices) {

        console.log('Hey, what are you looking for here? ;)');
        usSpinnerService.spin('spinner-voters');

        /**
         * Vars
         */

        var body = angular.element( document.querySelector( 'body' ) );
        var aside = angular.element( document.querySelector( 'aside' ) );

        var liskit_address = EnvServices.poolAddress;
        var gdt_address = EnvServices.gdtPoolAddress;
        // $scope.swap_holding = EnvServices.swapHolding;
        $scope.forging_shares = {};

        $scope.address_forging = '';
        $scope.voters_account = [];
        $scope.guest_address = '';
        $scope.delegates = [];
        $scope.delegates_total_balance = 0;
        $scope.gdt_total_shared = 0;
        $scope.pagination = {
            currentPage : 1,
            itemsPerPage :10,
            maxSize : 3
        };

        /**
        * Asides
        */

        $scope.detail_aside = $aside({
            scope: $scope,
            animation: 'am-slide-right',
            templateUrl: './public/src/detail/views/detail.html',
            show: false,
            keyboard: false,
            backdrop: true,
            tag: 'detailAside'
        });

        $scope.$on('aside.hide', function(e, target) {
          if (target.$options.tag == 'detailAside') {
            body.removeClass('overflow-hidden');
            aside.removeClass('overflow-scroll');
          }
        });

        /**
        * Close / open asides
        */

        $scope.openDetail = function(address,balance){
            console.log('Open detail');
            console.log('Address setted: ', address);
            $scope.address_forging = address;
            $scope.balance_forging = balance;
            $scope.closeDetail();
            body.addClass('overflow-hidden');
            aside.addClass('overflow-scroll');
            $scope.detail_aside.show();
        };

        $scope.closeDetail = function(){
            var myEl = angular.element( document.querySelector( 'body' ) );
            body.removeClass('overflow-hidden');
            aside.removeClass('overflow-scroll');
            $scope.detail_aside.hide();
        };

        /**
         * Graph config
         */

        var uptime_graph_config = liquidFillGaugeDefaultSettings();
            uptime_graph_config.circleColor = "#94A9BE";
            uptime_graph_config.textColor = "#94A9BE";
            uptime_graph_config.textSize = 0.55;
            uptime_graph_config.waveTextColor = "#fff";
            uptime_graph_config.waveColor = "rgba(148, 169, 190, 0.72)";
            uptime_graph_config.circleThickness = 0.1;
            uptime_graph_config.circleFillGap = 0.2;
            uptime_graph_config.textVertPosition = 0.5;
            uptime_graph_config.waveAnimateTime = 2000;
            uptime_graph_config.waveHeight = 0.3;
            uptime_graph_config.waveCount = 1;

        /**
         * Pagination handler
         */

        $scope.pageChanged = function() {
            $log.log('Page changed to: ' + $scope.pagination.currentPage);
        };

        /**
         * Dashboard functions
         */

        $scope.calculateForgingShares = function() {
            if(EnvServices.dynamicPool) {
                $scope.$watchGroup(['rank'],function(newValues, oldValues, scope){
                    if($scope.rank >= 50) {
                        $scope.forging_shares['maintenance_perc'] = EnvServices.maintenancePerc
                        $scope.forging_shares['stack_perc'] = 100-EnvServices.maintenancePerc-EnvServices.top101perc
                        $scope.forging_shares['share_perc'] = EnvServices.top101perc
                    }
                    if($scope.rank < 50 && $scope.rank >= 20) {
                        console.log("rank less than 50");
                        $scope.forging_shares['maintenance_perc'] = EnvServices.maintenancePerc
                        $scope.forging_shares['stack_perc'] = 100-EnvServices.maintenancePerc-EnvServices.top101perc
                        $scope.forging_shares['share_perc'] = EnvServices.top50perc
                    }
                    if($scope.rank < 20) {
                        $scope.forging_shares['maintenance_perc'] = EnvServices.maintenancePerc
                        $scope.forging_shares['stack_perc'] = 100-EnvServices.maintenancePerc-EnvServices.top101perc
                        $scope.forging_shares['share_perc'] = EnvServices.top20perc
                    }
                })
            } else {
                $scope.forging_shares['maintenance_perc'] = EnvServices.maintenancePerc
                $scope.forging_shares['stack_perc'] = 100-EnvServices.maintenancePerc-EnvServices.staticPerc
                $scope.forging_shares['share_perc'] = EnvServices.staticPerc
            }
        }

        LiskServices.getTransactions(liskit_address, gdt_address).then(function(list) {
            usSpinnerService.stop('spinner-payments');
            console.log(list.transactions)
            $scope.delegates_total_balance = list.transactions.reduce(function(sum, item) {
                return sum + item.amount
            }, 0);
        }, function (error) {
            console.log('getTransactions function error');
            console.log(error);
        });

        $scope.getBalance = function(address) {
            LiskServices.getBalance(address).then(function (balance) {
                BackendServices.getLastPayoutInfo().then(function (forged) {

                    usSpinnerService.stop('spinner-forging-pool');
                    $scope.balance = (0 + forged.result.forged)/10000/10000;
                    $scope.payday = forged.result.date;

                }, function (error) {
                    console.log('getLastPayoutInfo function error');
                    console.log(error);
                })
            }, function (error) {
                console.log('getBalance function error');
                console.log(error);
            });
        };

        $scope.getDelegateList = function() {
          LiskServices.getDelegates().then(function(list) {
                $scope.delegates = list.delegates;
                console.log($scope.delegates);
            }, function (error) {
                console.log('getDelegates function error');
                console.log(error);
            });
        };

        // Turn Around
        $scope.getVotesOfAccount = function(address) {
            LiskServices.getVotesOfAccount(address).then(function (delegates) {
                angular.forEach(delegates.delegates, function(delegate){
                    if(delegate.address == liskit_address){
                        $scope.rank = delegate.rate;
                        $scope.productivity =  delegate.productivity;
                        if($scope.productivity != 0 )
                            var uptime_graph = loadLiquidFillGauge("uptime", $scope.productivity, uptime_graph_config);
                    }
                });
            }, function (data) {
                console.log('getDelegateStats function error');
                console.log(data);
            });
        };

        $scope.totalDelegatesForged = function() {
            LiskServices.getDelegateStats().then(function (delegates) {
                $scope.total_delegate = delegates.totalCount;
                angular.forEach(delegates, function(delegate){
                    angular.forEach(delegate, function(value){
                        LiskServices.getBalance(value.address).then(function (balance) {
                            $scope.delegates_total_balance = $scope.delegates_total_balance + balance.balance/10000/10000;
                        }, function (error) {
                            console.log('totalDelegatesForged function error');
                            console.log(data);
                        });
                    });
                });
            }, function (data) {
                console.log('totalDelegatesForged function error');
                console.log(data);
            });
        };

        $scope.getNumberOfVoters = function(address) {
            //console.log('Loading getNumberOfVoters function');
            LiskServices.getPublicKey(address).then(function (public_key) {
                var public_key = public_key.publicKey;
                LiskServices.getVoters(public_key).then(function(voters) {
                    $scope.voters = voters.accounts;
                    $scope.number_of_voters = $scope.voters.length;
                })
            }, function(data) {
                console.log('getPublicKey function error');
                console.log(data);
            })
        };

        $scope.getVoters = function(address) {
            $scope.guest_voters_account = [];
            $scope.error_message = '';
                $scope.delegates = $scope.totalDelegatesRegistered;
                LiskServices.getPublicKey(address).then(function (public_key) {
                    if (public_key.success == true) {
                        var public_key = public_key.publicKey;
                        LiskServices.getVoters(public_key).then(function (voters) {
                            if (voters.accounts.length) {
                                $scope.voters = voters.accounts;
                                for(j = 0; j<$scope.voters.length; j++) {
                                    var flag = 0;
                                    for(var i = 0; i<$scope.delegates.length; i++) {
                                        if($scope.delegates[i].address == $scope.voters[j].address) {
                                            var tmp = $scope.voters[j];
                                            tmp.rate = $scope.delegates[i].rate;
                                            if (address == liskit_address) {
                                                $scope.voters_account.push(tmp);
                                            }
                                            if (address != liskit_address) {
                                                $scope.guest_voters_account.push(tmp);
                                            }
                                            flag = 1;
                                            break;
                                        }
                                    }
                                    if(flag==0){
                                        if (address == liskit_address) {
                                            $scope.voters_account.push($scope.voters[j]);
                                        }
                                        if (address != liskit_address) {
                                            $scope.guest_voters_account.push($scope.voters[j]);
                                        }
                                    }
                                }
                            } else {
                                toastr.warning("This address doesn't have any supporter");
                                $scope.guest_voters_account = [];
                                $scope.guestFilterSearch = '';
                            }
                        }, function (data) {
                            console.log('getVoters function error');
                            console.log(data);

                        })
                    } else {
                        $scope.guest_voters_account = [];
                        $scope.guestFilterSearch = '';
                        $scope.guest_address = '';
                        $scope.error_message = public_key.error;
                        toastr.warning(public_key.error);
                    }
                }, function (data) {
                    console.log('getPublicKey function error');
                    console.log(data);
                })

        };

        $scope.getBlockChainHeight = function() {
            LiskServices.getBlockChainHeight().then(function(blockchain_height) {
                $scope.blockchain_height = blockchain_height.height;
            }, function(data) {
                console.log('getBlockChainHeight function error');
                console.log(data);
            });
        };

        $scope.getSynchronisationStatus = function(client_ip) {
            LiskServices.getSynchronisationStatus(client_ip).then(function(status) {
                $scope.status = status.success.toString();
            }, function(data) {
                console.log('getSynchronisationStatus function error');
                console.log(data);
            });
        };

        $scope.getTotalRegisteredDelegates = function() {
            var counter = 1;
            $scope.totalDelegatesRegistered = [];
            LiskServices.getDelegateStats().then(function (delegates) {
                var delegates = delegates.totalCount;
                while (counter < delegates) {
                    LiskServices.getDelegates(counter).then(function (list) {
                        angular.forEach(list.delegates, function(value){
                            $scope.totalDelegatesRegistered.push(value);
                        })
                        if($scope.totalDelegatesRegistered.length == delegates-1){
                            $scope.getVoters(liskit_address);
                        }
                    }, function (error) {
                        console.log('getDelegates function error');
                        console.log(error);
                    });
                    counter += 101;
                }
            }, function (error) {
                console.log('getDelegateStats function error');
                console.log(error);
            });
        };

        /**
         * Exchange test - getting BTC:ALTCOIN status - example below
         * Arguments:
         *      polo for Poloniex
         * Arguments
         *      LSK for lisk
         */

        $scope.getTicker = function() {
            ExchangeServices.getTicker('polo', 'LSK').then(function (response) {
                $scope.liskLastPrice = response.last;
            }, function (error) {
                console.log('getTicker lisk service promise rejected');
                console.log(error);
            });
        };

        /**
         * Run
         */
        $scope.getTotalRegisteredDelegates();
        $scope.getBlockChainHeight();
        $scope.getBalance(liskit_address);
        $scope.getNumberOfVoters(liskit_address);
        //$scope.getDelegateStats(liskit_address);
        $scope.getVotesOfAccount(liskit_address);
        $scope.totalDelegatesForged();
        $scope.getSynchronisationStatus();
        $scope.getTicker();
        $scope.calculateForgingShares();
    }])
    /**
     * Pagination custom filter
     */
    .filter('startFrom', function() {
        return function(input, start) {
            if (!input || !input.length) { return; }
            start = +start;
            return input.slice(start);
        }
    });
<|endoftext|>


<commit_before>import {ITERATOR_SYMBOL, ITERATOR_FUNCTION} from './Iterator';

export default function Maybe(v) {
	return isDefined(v) ? Just(v) : Nothing();
}

export function from(generator, ...args) {
	const iterator = generator(...args);
	let step;

	do {
		step = iterator.next();
	} while (!step.done && step.value !== null && step.value !== undefined);

	return step.value === null || step.value === undefined ? null : step.value;
}

export function Just(v) {
	return isMonad(v) ? v : {
		type: Just,
		map: fn => Just(fn(v)),
		valueOf: () => v,
		[ITERATOR_SYMBOL]: () => ITERATOR_FUNCTION(v)
	};
}

export function Nothing() {
	return {
		type: Nothing,
		map: fn => Nothing(),
		valueOf: () => null,
		[ITERATOR_SYMBOL]: () => ITERATOR_FUNCTION(null)
	};
}

function isMonad(v) {
	return isDefined(v) && (v.type === Just || v.type === Nothing);
}

function isDefined(v) {
	return v !== void 0 && v !== null;
}
<commit_msg>dogfooding<commit_after>import {ITERATOR_SYMBOL, ITERATOR_FUNCTION} from './Iterator';

export default function Maybe(v) {
	return isDefined(v) ? Just(v) : Nothing();
}

export function from(generator, ...args) {
	const iterator = generator(...args);
	let step;

	do {
		step = iterator.next();
	} while (!step.done && isDefined(step.value));

	return Maybe(step.value);
}

export function Just(v) {
	return isMonad(v) ? v : {
		type: Just,
		map: fn => Just(fn(v)),
		valueOf: () => v,
		[ITERATOR_SYMBOL]: () => ITERATOR_FUNCTION(v)
	};
}

export function Nothing() {
	return {
		type: Nothing,
		map: fn => Nothing(),
		valueOf: () => null,
		[ITERATOR_SYMBOL]: () => ITERATOR_FUNCTION(null)
	};
}

function isMonad(v) {
	return isDefined(v) && (v.type === Just || v.type === Nothing);
}

function isDefined(v) {
	return v !== void 0 && v !== null;
}
<|endoftext|>


<commit_before>//Chris Samuel
//ksamuel.chris@gme.com
//Filename : Inverted Peninsula

(function(){
  inhabitants = [
    {
      name: "Choshizen",
      race:  "Elvaan"
    },
    {
      name: "Tessius",
      race:  "Hume"
    }
  ];
//   // Add an extra humans method property to the inhabitants array to return all Humans
// //  this.inhabitants.humans = function(){
//     /* returns all Human inhabitatans*/
//   };
//   // create a new invertedPeninsula instance
//   //var invertedPeninsula = new InvertedPeninsula();
//
//   // Log the name of each invertedPeninsula inhabitants
//         for(var i = 0, o = invertedPeninsula.inhabitants; i < o.length; i++){
//     console.log(invertedPeninsula.inhabitants[i].name);
  // }
})();

var ppl = inhabitants;
console.log(ppl);
// var g = new InvertedPeninsula();
<commit_msg>added a name to the function and called the function back<commit_after>//Chris Samuel
//ksamuel.chris@gme.com
//Filename : Inverted Peninsula

var InvertedPeninsula = function(){
  inhabitants = [
    {
      name: "Choshizen",
      race:  "Elvaan"
    },
    {
      name: "Tessius",
      race:  "Hume"
    }
  ];
  console.log(inhabitants)
//   // Add an extra humans method property to the inhabitants array to return all Humans
// //  this.inhabitants.humans = function(){
//     /* returns all Human inhabitatans*/
//   };
//   // create a new invertedPeninsula instance
//   //var invertedPeninsula = new InvertedPeninsula();
//
//   // Log the name of each invertedPeninsula inhabitants
//         for(var i = 0, o = invertedPeninsula.inhabitants; i < o.length; i++){
//     console.log(invertedPeninsula.inhabitants[i].name);
  // }
};

InvertedPeninsula();

// var ppl = inhabitants;
// console.log(ppl);
// var g = new InvertedPeninsula();
<|endoftext|>


<commit_before>module.exports = function (yargs) {
  var copy = require('copy')
  // var vueBuildRoot = '../'
  var projectRoot = process.cwd()

  var inquirer = require('inquirer')
  inquirer.prompt([
    {type: 'confirm', name: 'envFile', message: 'Create env file?', default: true},
    {type: 'confirm', name: 'eslintFile', message: 'Create eslint file?', default: true},
    {type: 'confirm', name: 'sourceFolder', message: 'Create /src folder?', default: true},
    {type: 'confirm', name: 'testFolder', message: 'Create /test folder?', default: true}
  ])
  .then(function (answers) {
    console.log(answers)
    if (answers.envFile) {
      copy('../.env', projectRoot, function (err, files) {
        if (err) { throw err }
      })
    }
  })
}
<commit_msg>init - added better pathing<commit_after>module.exports = function (yargs) {
  var path = require('path')
  var copy = require('copy')
  let vueBuildRoot = path.join(__dirname, '../')
  var projectRoot = process.cwd()

  var inquirer = require('inquirer')
  inquirer.prompt([
    {type: 'confirm', name: 'envFile', message: 'Create env file?', default: true},
    {type: 'confirm', name: 'eslintFile', message: 'Create eslint file?', default: true},
    {type: 'confirm', name: 'sourceFolder', message: 'Create /src folder?', default: true},
    {type: 'confirm', name: 'testFolder', message: 'Create /test folder?', default: true}
  ])
  .then(function (answers) {
    console.log(answers)
    if (answers.envFile) {
      copy(vueBuildRoot + '.env', projectRoot, function (err, files) {
        if (err) { throw err }
      })
    }
  })
}
<|endoftext|>


<commit_before>import styles from './Header.less';

import React, { Component } from 'react';
import fetch from 'isomorphic-fetch';
import Link from 'Link/Link';
import GitHub from 'GitHub/GitHub';

export default class Header extends Component {
  constructor() {
    super();

    this.state = {
      stargazers: '2363'
    };
  }

  componentDidMount() {
    fetch('https://api.github.com/repos/moroshko/react-autosuggest')
      .then(response => response.json())
      .then(response => {
        if (response.stargazers_count) {
          this.setState({
            stargazers: String(response.stargazers_count)
          });
        }
      });
  }

  render() {
    const { stargazers } = this.state;

    return (

React Autosuggest

          WAI-ARIA compliant autosuggest component built in React

          Get started

          <Link
            className={styles.stargazersLink}
            href="https://github.com/moroshko/react-autosuggest/stargazers"
            underline={false}
          >
            {stargazers} stargazers
          </Link>
          <Link
            className={styles.twitterLink}
            href="https://twitter.com/moroshko"
            underline={false}
          >
            @moroshko
          </Link>

        <GitHub user="moroshko" repo="react-autosuggest" />

    );
  }
}
<commit_msg>Rebuild demo<commit_after>import styles from './Header.less';

import React, { Component } from 'react';
import fetch from 'isomorphic-fetch';
import Link from 'Link/Link';
import GitHub from 'GitHub/GitHub';

export default class Header extends Component {
  constructor() {
    super();

    this.state = {
      stargazers: '3754'
    };
  }

  componentDidMount() {
    fetch('https://api.github.com/repos/moroshko/react-autosuggest')
      .then(response => response.json())
      .then(response => {
        if (response.stargazers_count) {
          this.setState({
            stargazers: String(response.stargazers_count)
          });
        }
      });
  }

  render() {
    const { stargazers } = this.state;

    return (

React Autosuggest

          WAI-ARIA compliant autosuggest component built in React

          Get started

          <Link
            className={styles.stargazersLink}
            href="https://github.com/moroshko/react-autosuggest/stargazers"
            underline={false}
          >
            {stargazers} stargazers
          </Link>
          <Link
            className={styles.twitterLink}
            href="https://twitter.com/moroshko"
            underline={false}
          >
            @moroshko
          </Link>

        <GitHub user="moroshko" repo="react-autosuggest" />

    );
  }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

/**
 * Module dependencies.
 */

var fs = require('fs')
  , program = require('commander')
  , path = require('path')
  , basename = path.basename
  , dirname = path.dirname
  , resolve = path.resolve
  , join = path.join
  , mkdirp = require('mkdirp')
  , jade = require('../');

// jade options

var options = {};

// options

program
  .version(require('../package.json').version)
  .usage('[options] [dir|file ...]')
  .option('-O, --obj <str>', 'javascript options object')
  .option('-o, --out <dir>', 'output the compiled html to <dir>')
  .option('-p, --path <path>', 'filename used to resolve includes')
  .option('-P, --pretty', 'compile pretty html output')
  .option('-c, --client', 'compile function for client-side runtime.js')
  .option('-n, --name <str>', 'The name of the compiled template (requires --client)')
  .option('-D, --no-debug', 'compile without debugging (smaller functions)')
  .option('-w, --watch', 'watch files for changes and automatically re-render')
  .option('-E, --extension <extension>', 'specify the output file extension')
  .option('--name-after-file', 'Name the template after the last section of the file path (requires --client and overriden by --name)')
  .option('--doctype <str>', 'Specify the doctype on the command line (useful if it is not specified by the template)')

program.on('--help', function(){
  console.log('  Examples:');
  console.log('');
  console.log('    # translate jade the templates dir');
  console.log('    $ jade templates');
  console.log('');
  console.log('    # create {foo,bar}.html');
  console.log('    $ jade {foo,bar}.jade');
  console.log('');
  console.log('    # jade over stdio');
  console.log('    $ jade < my.jade > my.html');
  console.log('');
  console.log('    # jade over stdio');
  console.log('    $ echo \'h1 Jade!\' | jade');
  console.log('');
  console.log('    # foo, bar dirs rendering to /tmp');
  console.log('    $ jade foo bar --out /tmp ');
  console.log('');
});

program.parse(process.argv);

// options given, parse them

if (program.obj) {
  if (fs.existsSync(program.obj)) {
    options = JSON.parse(fs.readFileSync(program.obj));
  } else {
    options = eval('(' + program.obj + ')');
  }
}

// --filename

if (program.path) options.filename = program.path;

// --no-debug

options.compileDebug = program.debug;

// --client

options.client = program.client;

// --pretty

options.pretty = program.pretty;

// --watch

options.watch = program.watch;

// --name

if (typeof program.name === 'string') {
  options.name = program.name;
}

// --doctype

options.doctype = program.doctype;

// left-over args are file paths

var files = program.args;

// compile files

if (files.length) {
  console.log();
  if (options.watch) {
    files.forEach(function(filename) {
      function errorToString(e) {
        return e.stack || /* istanbul ignore next */ (e.message || e);
      }
      try {
        renderFile(filename);
      } catch (e) {
        // keep watching when error occured.
        console.error(errorToString(e));
      }
      fs.watchFile(filename, {persistent: true, interval: 200},
                   function (curr, prev) {
        // istanbul ignore if
        if (curr.mtime.getTime() === prev.mtime.getTime()) return;
        try {
          renderFile(filename);
        } catch (e) {
          // keep watching when error occured.
          console.error(errorToString(e));
        }
      });
    });
    process.on('SIGINT', function() {
      process.exit(1);
    });
  } else {
    files.forEach(renderFile);
  }
  process.on('exit', function () {
    console.log();
  });
// stdio
} else {
  stdin();
}

/**
 * Compile from stdin.
 */

function stdin() {
  var buf = '';
  process.stdin.setEncoding('utf8');
  process.stdin.on('data', function(chunk){ buf += chunk; });
  process.stdin.on('end', function(){
    var output;
    if (options.client) {
      output = jade.compileClient(buf, options);
    } else {
      var fn = jade.compile(buf, options);
      var output = fn(options);
    }
    process.stdout.write(output);
  }).resume();

  process.on('SIGINT', function() {
    process.stdout.write('\n');
    process.stdin.emit('end');
    process.stdout.write('\n');
    process.exit();
  })
}

/**
 * Process the given path, compiling the jade files found.
 * Always walk the subdirectories.
 */

function renderFile(path) {
  var re = /\.jade$/;
  var stat = fs.lstatSync(path);
  // Found jade file/\.jade$/
  if (stat.isFile() && re.test(path)) {
    var str = fs.readFileSync(path, 'utf8');
    options.filename = path;
    if (program.nameAfterFile) {
      options.name = getNameFromFileName(path);
    }
    var fn = options.client ? jade.compileClient(str, options) : jade.compile(str, options);

    // --extension
    if (program.extension)   var extname = '.' + program.extension;
    else if (options.client) var extname = '.js';
    else                     var extname = '.html';

    path = path.replace(re, extname);
    if (program.out) path = join(program.out, basename(path));
    var dir = resolve(dirname(path));
    mkdirp.sync(dir, 0755);
    var output = options.client ? fn : fn(options);
    fs.writeFileSync(path, output);
    console.log('  \033[90mrendered \033[36m%s\033[0m', path);
  // Found directory
  } else if (stat.isDirectory()) {
    var files = fs.readdirSync(path);
    files.map(function(filename) {
      return path + '/' + filename;
    }).forEach(renderFile);
  }
}

/**
 * Get a sensible name for a template function from a file path
 *
 * @param {String} filename
 * @returns {String}
 */
function getNameFromFileName(filename) {
  var file = basename(filename, '.jade');
  return file.toLowerCase().replace(/[^a-z0-9]+([a-z])/g, function (_, character) {
    return character.toUpperCase();
  }) + 'Template';
}
<commit_msg>Fixes #1086. Now jade watches all rendered files.<commit_after>#!/usr/bin/env node

/**
 * Module dependencies.
 */

var fs = require('fs')
  , program = require('commander')
  , path = require('path')
  , basename = path.basename
  , dirname = path.dirname
  , resolve = path.resolve
  , join = path.join
  , mkdirp = require('mkdirp')
  , jade = require('../');

// jade options

var options = {};

// options

program
  .version(require('../package.json').version)
  .usage('[options] [dir|file ...]')
  .option('-O, --obj <str>', 'javascript options object')
  .option('-o, --out <dir>', 'output the compiled html to <dir>')
  .option('-p, --path <path>', 'filename used to resolve includes')
  .option('-P, --pretty', 'compile pretty html output')
  .option('-c, --client', 'compile function for client-side runtime.js')
  .option('-n, --name <str>', 'The name of the compiled template (requires --client)')
  .option('-D, --no-debug', 'compile without debugging (smaller functions)')
  .option('-w, --watch', 'watch files for changes and automatically re-render')
  .option('-E, --extension <extension>', 'specify the output file extension')
  .option('--name-after-file', 'Name the template after the last section of the file path (requires --client and overriden by --name)')
  .option('--doctype <str>', 'Specify the doctype on the command line (useful if it is not specified by the template)')

program.on('--help', function(){
  console.log('  Examples:');
  console.log('');
  console.log('    # translate jade the templates dir');
  console.log('    $ jade templates');
  console.log('');
  console.log('    # create {foo,bar}.html');
  console.log('    $ jade {foo,bar}.jade');
  console.log('');
  console.log('    # jade over stdio');
  console.log('    $ jade < my.jade > my.html');
  console.log('');
  console.log('    # jade over stdio');
  console.log('    $ echo \'h1 Jade!\' | jade');
  console.log('');
  console.log('    # foo, bar dirs rendering to /tmp');
  console.log('    $ jade foo bar --out /tmp ');
  console.log('');
});

program.parse(process.argv);

// options given, parse them

if (program.obj) {
  if (fs.existsSync(program.obj)) {
    options = JSON.parse(fs.readFileSync(program.obj));
  } else {
    options = eval('(' + program.obj + ')');
  }
}

// --filename

if (program.path) options.filename = program.path;

// --no-debug

options.compileDebug = program.debug;

// --client

options.client = program.client;

// --pretty

options.pretty = program.pretty;

// --watch

options.watch = program.watch;

// --name

if (typeof program.name === 'string') {
  options.name = program.name;
}

// --doctype

options.doctype = program.doctype;

// left-over args are file paths

var files = program.args;

var watchList = [];

// compile files

if (files.length) {
  console.log();
  if (options.watch) {
    process.on('SIGINT', function() {
      process.exit(1);
    });
    process.on("exit", function () {
      watchList.forEach(fs.unwatchFile);
    });
  }
  files.forEach(renderFile);
  process.on('exit', function () {
    console.log();
  });
// stdio
} else {
  stdin();
}

function watchFile(path, base) {
  if (watchList.indexOf(path) !== -1) return;
  console.log("  \033[90mwatching \033[36m%s\033[0m", path);
  fs.watchFile(path, {persistent: true, interval: 200},
               function (curr, prev) {
    // istanbul ignore if
    if (curr.mtime.getTime() === prev.mtime.getTime()) return;
    if (!fs.existsSync(path)) {
      // file was removed or moved
      console.log("  \033[90munwatching \033[36m%s\033[0m", path);
      watchList.splice(watchList.indexOf(path), 1);
      fs.unwatchFile(path);
      return;
    }
    tryRender(base || path);
  });
  watchList.push(path);
}

function errorToString(e) {
  return e.stack || /* istanbul ignore next */ (e.message || e);
}

function tryRender(path) {
  try {
    renderFile(path);
  } catch (e) {
    // keep watching when error occured.
    console.error(errorToString(e));
  }
}

/**
 * Compile from stdin.
 */

function stdin() {
  var buf = '';
  process.stdin.setEncoding('utf8');
  process.stdin.on('data', function(chunk){ buf += chunk; });
  process.stdin.on('end', function(){
    var output;
    if (options.client) {
      output = jade.compileClient(buf, options);
    } else {
      var fn = jade.compile(buf, options);
      var output = fn(options);
    }
    process.stdout.write(output);
  }).resume();

  process.on('SIGINT', function() {
    process.stdout.write('\n');
    process.stdin.emit('end');
    process.stdout.write('\n');
    process.exit();
  })
}

/**
 * Process the given path, compiling the jade files found.
 * Always walk the subdirectories.
 */

function renderFile(path) {
  var re = /\.jade$/;
  var stat = fs.lstatSync(path);
  // Found jade file/\.jade$/
  if (stat.isFile() && re.test(path)) {
    if (options.watch) watchFile(path);
    var str = fs.readFileSync(path, 'utf8');
    options.filename = path;
    if (program.nameAfterFile) {
      options.name = getNameFromFileName(path);
    }
    var fn = options.client ? jade.compileClient(str, options) : jade.compile(str, options);
    if (fn.dependencies) {
      fn.dependencies.forEach(function (dep) {
        watchFile(dep, path);
      });
    }

    // --extension
    if (program.extension)   var extname = '.' + program.extension;
    else if (options.client) var extname = '.js';
    else                     var extname = '.html';

    path = path.replace(re, extname);
    if (program.out) path = join(program.out, basename(path));
    var dir = resolve(dirname(path));
    mkdirp.sync(dir, 0755);
    var output = options.client ? fn : fn(options);
    fs.writeFileSync(path, output);
    console.log('  \033[90mrendered \033[36m%s\033[0m', path);
  // Found directory
  } else if (stat.isDirectory()) {
    var files = fs.readdirSync(path);
    files.map(function(filename) {
      return path + '/' + filename;
    }).forEach(renderFile);
  }
}

/**
 * Get a sensible name for a template function from a file path
 *
 * @param {String} filename
 * @returns {String}
 */
function getNameFromFileName(filename) {
  var file = basename(filename, '.jade');
  return file.toLowerCase().replace(/[^a-z0-9]+([a-z])/g, function (_, character) {
    return character.toUpperCase();
  }) + 'Template';
}
<|endoftext|>