<commit_before>'use strict';

/* Controllers */

angular.module('qcmffvl.controllers', [])

.controller('MainCtrl', function($scope, API, $location, $timeout, $http, $filter, dialogs, deviceDetector) {

    $scope.main = {
        category: {
            options: [ "Parapente" ],
            checked: "Parapente"
        },
        level: {
            options: [ "Brevet Initial", "Brevet de Pilote", "Brevet de Pilote Confirmé"],
            checked: "Brevet de Pilote"
        },
        nbquestions: {
        	options: [ "10", "30", "60", "90", "Toutes" ],
        	checked: "30"
        },
        typeExam: {
            options: [ "Révision", "Examen papier (candidat)", "Examen papier (examinateur)" ],
            checked: "Révision"
        },
        displayLimit: 10000,
        checkAnswers: false,
        score: {
            total: 0,
            nb: 0,
            percentage: 0,
            user: 0
        },
        exam: [],
        QCMID: "",
        QCMIDUser: ""
    }
    $scope.main.search  = {
    	num_niveau: $scope.main.level.options.indexOf($scope.main.level.checked)
    }
    $scope.main.limit = $scope.main.nbquestions.checked;
    $scope.main.reloadQCM = false;
    // automatically removed by a directive when the QCM is loaded
    $scope.loading = false;
    $scope.hideNavbarButtons = false;
    $scope.browserCheckOverride = false;

    $scope.loadJSON = function() {
        $scope.loading = true;
        $timeout(function() {
            $http.get('/json/qcm2014-1.json')
            .success(function(data, status, headers, config){
                $scope.qcmOrig = angular.copy(data);
                $scope.generateQCM($scope.main.QCMID);
            })
            .error(function() {
                var dlg = dialogs.error('Erreur','Impossible de charger le JSON');
                dlg.result();
            });
        }, 100);
    },
    $scope.generateQCM = function(QCMID) {
        $scope.loading = true;
        $scope.main.checkAnswers = false;
        if (QCMID) {
            $scope.arrayToOptions(API.uncomputeID(QCMID).options);
        }
        $timeout(function() {
            $scope.qcm = angular.copy($scope.qcmOrig);
            $scope.main.QCMID = API.generateQCM($scope.qcm, $scope.optionsToArray(), QCMID);
            if ($scope.main.exam.papierExaminateur)
                API.tickAnswers($scope.qcm);
        },300);
    },
    $scope.optionsToArray = function() {
        var opt = [];
        opt[0] = $scope.main.category.options.indexOf($scope.main.category.checked)
        opt[1] = $scope.main.level.options.indexOf($scope.main.level.checked)
        opt[2] = $scope.main.nbquestions.options.indexOf($scope.main.nbquestions.checked)
        return opt;
    },
    $scope.arrayToOptions = function(opt) {
        $scope.main.category.checked = $scope.main.category.options[opt[0]];
        $scope.main.level.checked = $scope.main.level.options[opt[1]];
        $scope.main.nbquestions.checked = $scope.main.nbquestions.options[opt[2]];
    },
    $scope.updateQCMID = function() {
        var num = API.uncomputeID($scope.main.QCMID).num;
        $scope.main.QCMID = API.computeID(num, $scope.optionsToArray());
    },
    $scope.reload = function() {
        var dlg = dialogs.confirm('Confirmation','Composer un nouveau questionnaire (ceci effacera vos réponses) ?');
        dlg.result.then(function(btn){
            $scope.main.QCMID = '';
        	$scope.main.reloadQCM = true;
        },function(btn){
            //cancel
        });
    }
    $scope.scoreClass = function(score) {
        if (score.percentage >= 75) {
            return "good-score";
        } else {
            return "bad-score";
        }
    }
    $scope.resetQCMDisplay = function() {
        // is unset in the directive "removeLoaderWhenReady()"
		$scope.loading = true;
		$scope.main.displayLimit = 0;
		$timeout(function() {
			$scope.main.displayLimit = 10000;
		}, 0);
        if ($scope.qcm && !$scope.main.exam.mode && $scope.main.checkAnswers) {
            API.untickAnswers($scope.qcm);
            $scope.main.checkAnswers = false;
        }
    }

    $scope.collapseNav = function() {
        $('html').trigger('click');
        $scope.navCollapsed = true;
    }

    $scope.browserChrome = function() {
        return (deviceDetector.browser == "chrome");
    }

    // show magic button when in /dev
    $scope.isDevURL = function() {
        return ($location.absUrl().indexOf("/dev") != -1);
    }

    // we are in a stable version only when a push to prod has been done
    $scope.isProdURL = function() {
        return ($location.absUrl().indexOf("sativouf.net") == -1);
    }

    $scope.gotoMainURL = function() {
        if ($location.url().indexOf("/qcm") == -1) {
            $location.url("/qcm/");
        }
    }

    $scope.resetQCMIDUser = function() {
        $scope.main.QCMIDUser = $scope.main.QCMID;
        $scope.main.formattedQCMIDUser = $filter('formatQCMID')($scope.main.QCMIDUser);
    }

    $scope.fillQCMAnswers = function() {
        $scope.main.checkAnswers = true;
        API.tickAnswers($scope.qcm);
    }

    $scope.unfillQCMAnswers = function() {
        $scope.main.checkAnswers = false;
        API.untickAnswers($scope.qcm);
    }

    $scope.toggleCheck = function(answer) {
        if ($scope.navCollapsed && !$scope.main.checkAnswers && !$scope.main.exam.papier) {
            answer.checked = !answer.checked;
        }
    }
    $scope.dialogQCMID = function() {
        var prepend = "";
        if ($scope.isDevURL())
            prepend = "/dev"
        var dlg = dialogs.create(prepend + '/dialogs/qcmid.html','QCMIDDialogCtrl',$scope.main, {size:'lg'});
                    dlg.result.then(function(name){
                    },function(){
                    });
    }

    // "called" by modals
    $scope.$watch("main.reloadQCM", function(newval, oldval) {
        if (newval == true) {
            // wait for modal to close
            $timeout(function() {
                $scope.loading = true;
            }, 500);
            $timeout(function() {
                $scope.main.reloadQCM = false;
                $scope.collapseNav();
                $scope.generateQCM($scope.main.QCMID);
            },700);
        }
    })

    $scope.$watch('main.nbquestions.checked', function(newval, oldval) {
        $scope.loading = true;
        if (newval != oldval) {
            $timeout(function() {
                $scope.resetQCMDisplay();
                $scope.updateQCMID();
                var limit = $scope.main.nbquestions.checked;
                if (limit === "Toutes") {
                    limit = 10000;
                }
                $scope.main.limit = limit;
            },100);
        }
    })

    $scope.$watch('main.level.checked', function(newval, oldval) {
        $scope.loading = true;
        if (newval != oldval) {
            $timeout(function() {
                $scope.resetQCMDisplay();
                $scope.updateQCMID();
                $scope.main.search.num_niveau = $scope.main.level.options.indexOf($scope.main.level.checked);
            },100);
        }
    });

    $scope.$watch('main.typeExam.checked', function(newval, oldval) {
        if (newval != oldval) {
            $scope.main.exam = [];
            $scope.main.checkAnswers = false;
            if (newval.indexOf("Examen papier") != -1) {
                $scope.main.exam.mode = true;
                $scope.main.exam.papier = true;
            }
            if (newval == "Examen papier (candidat)") {
                $scope.main.exam.papierCandidat = true;
            } else if (newval == "Examen papier (examinateur)") {
                $scope.main.exam.papierExaminateur = true;
            }
            // back from examPapierExaminateur, we want to erase the answers ticked
            $scope.unfillQCMAnswers();
            if ($scope.main.exam.papierExaminateur) {
                API.tickAnswers($scope.qcm);
            }
            document.body.scrollTop = document.documentElement.scrollTop = 0;
        }
    });

    $scope.$watch('main.QCMID', function(newval, oldval) {
        if (newval != oldval) {
            if ($scope.main.QCMIDUser != $scope.main.QCMID) {
                $scope.resetQCMIDUser();
            }
            $scope.main.QCMIDCRC = API.crc($scope.main.QCMID);
            $scope.main.QCMIDURL = $location.absUrl() + "/" + $scope.main.QCMID;
        }
    });

    $scope.$watch('main.formattedQCMIDUser', function(newval, oldval) {
        if (newval != oldval) {
            $scope.main.QCMIDUser = $filter('removeSpaces')(newval);
            $scope.main.formattedQCMIDUser = $filter('formatQCMID')($scope.main.QCMIDUser);
        }
    });

 })

.controller('QCMCtrl', function($scope, $filter, $timeout, $routeParams, $location, dialogs, API, filterFilter) {
    $scope.questions = [];
    $scope.$parent.hideNavbarButtons = false;
    $scope.$parent.main.checkAnswers = false;
    $scope.$parent.collapseNav();

    var QCMID = $routeParams.param1;

    if (QCMID) {
        $location.path("/qcm", false);
        if (API.verifyChecksum(QCMID)) {
            // used by loadJSON()
            $scope.$parent.main.QCMID = QCMID;
        } else {
            dialogs.error('Erreur','ID QCM invalide : ' + QCMID);
        }
    }
    if ($scope.$parent.qcm) {
        $scope.$parent.generateQCM($scope.$parent.main.QCMID);
    } else {
        $scope.$parent.loadJSON();
    }

    $scope.getPoints = function(question) {
        var total = 0;
        for (var i = 0; i < question.ans.length; i++) {
            if (question.ans[i].checked) {
                total += parseInt(question.ans[i].pts);
            }
        }
        if (total < 0) {
            total = 0;
        }
        return total;
    }

    $scope.getScore = function() {
        var arr = filterFilter($scope.qcm, $scope.main.search);
        arr = $filter('limitTo')(arr, $scope.main.limit)
        var score = { user: 0, nb: 0, percentage: 0 };
        for(var i = 0; i < arr.length; i++){
            var question = arr[i];
            score.user += $scope.getPoints(question);
        }
        score.nb = i;
        score.total = i*6;
        if (score.total > 0) {
            score.percentage = Math.round(score.user / score.total * 100);
        }
        return score;
    }

    $scope.successQuestion = function(question) {
        if ($scope.main.exam.papier || !$scope.main.checkAnswers)
            return false;
        return ($scope.getPoints(question) === 6);
    }

    $scope.failedQuestion = function(question) {
        if ($scope.main.exam.papier || !$scope.main.checkAnswers)
            return false;
        return ($scope.getPoints(question) === 0);
    }

    $scope.warningQuestion = function(question) {
        if ($scope.main.exam.papier || !$scope.main.checkAnswers)
            return false;
        var points = $scope.getPoints(question);
        return (points >= 1 && points <=5);
    }

    $scope.goodAnswer = function(answer) {
        if ($scope.main.exam.papier || !$scope.main.checkAnswers)
            return false;
        return (answer.pts >= 0 && answer.checked);
    }

    $scope.badAnswer = function(answer) {
        if ($scope.main.exam.papier || !$scope.main.checkAnswers)
            return false;
        return (answer.pts < 0 && answer.checked);
    }

    $scope.goodAnswerNotChecked = function(answer) {
        if ($scope.main.exam.papier || !$scope.main.checkAnswers)
            return false;
        return (answer.pts > 0 && !answer.checked);
    }

    $scope.updateScore = function() {
        if ($scope.main.checkAnswers) {
            $scope.main.score = $scope.getScore();
        }
    }

    $scope.$watch('main.checkAnswers', function() {
        $scope.updateScore();
    })

})

.controller('SelfTestCtrl', function($scope, API) {
    $scope.$parent.loading = false;
	$scope.selftest = [];
	$scope.selftest.numitems   = 600;
	$scope.selftest.numruns    = 10000;
	$scope.selftest.showperrun = 60;

	$scope.selftest.qcm = [];
	for(var i = 1; i <= $scope.selftest.numitems; i++) {
		var obj = { question : i , ans : "x", shown : 0 };
		$scope.selftest.qcm.push(obj);
	}
//	console.log($scope.selftest.qcm);
	for(var i = 1; i <= $scope.selftest.numruns; i++){
//		console.log("run " + i );
		API.generateQCM($scope.selftest.qcm);
//		console.log($scope.selftest.qcm);
		for(var j = 0; j < $scope.main.nbquestions.checked ; j++){
			$scope.selftest.qcm[j].shown++;
		}
	}
	for(var i = 0; i < $scope.selftest.numitems; i++) {
		$scope.selftest.qcm[i].percent = (($scope.selftest.qcm[i].shown / $scope.selftest.numruns) * 100).toFixed(2);;
	}

})

.controller('AboutCtrl', function($scope) {
    $scope.$parent.navCollapsed = true;
    $scope.$parent.loading = false;
    $scope.$parent.hideNavbarButtons = true;

    document.body.scrollTop = document.documentElement.scrollTop = 0;
})

.controller('QCMIDDialogCtrl', function($scope, $modalInstance, data, API) {
    $scope.main = data;

    $scope.savedFormattedQCMIDUser = angular.copy($scope.main.formattedQCMIDUser);
    $scope.verifyQCMIDUser = function() {
        if ($scope.main.formattedQCMIDUser != $scope.savedFormattedQCMIDUser) {
            return API.verifyChecksum($scope.main.QCMIDUser);
        } else {
            return true;
        }
    }
    $scope.cancelIDChanges = function() {
        if (! $scope.verifyQCMIDUser)
            $scope.main.formattedQCMIDUser = angular.copy($scope.savedFormattedQCMIDUser);
    }
    $scope.loadQCMID = function() {
        $modalInstance.dismiss('OK');
        $scope.main.QCMID = $scope.main.QCMIDUser;
        $scope.main.reloadQCM = true;
    }
    $scope.ok = function(){
        $modalInstance.dismiss('OK');
    };
});
<commit_msg>better display reload text / better handling of modal load ID<commit_after>'use strict';

/* Controllers */

angular.module('qcmffvl.controllers', [])

.controller('MainCtrl', function($scope, API, $location, $timeout, $http, $filter, dialogs, deviceDetector) {

    $scope.main = {
        category: {
            options: [ "Parapente" ],
            checked: "Parapente"
        },
        level: {
            options: [ "Brevet Initial", "Brevet de Pilote", "Brevet de Pilote Confirmé"],
            checked: "Brevet de Pilote"
        },
        nbquestions: {
        	options: [ "10", "30", "60", "90", "Toutes les" ],
        	checked: "30"
        },
        typeExam: {
            options: [ "Révision", "Examen papier (candidat)", "Examen papier (examinateur)" ],
            checked: "Révision"
        },
        displayLimit: 10000,
        checkAnswers: false,
        score: {
            total: 0,
            nb: 0,
            percentage: 0,
            user: 0
        },
        exam: [],
        QCMID: "",
        QCMIDUser: ""
    }
    $scope.main.search  = {
    	num_niveau: $scope.main.level.options.indexOf($scope.main.level.checked)
    }
    $scope.main.limit = $scope.main.nbquestions.checked;
    $scope.main.reloadQCM = false;
    // automatically removed by a directive when the QCM is loaded
    $scope.loading = false;
    $scope.hideNavbarButtons = false;
    $scope.browserCheckOverride = false;

    $scope.loadJSON = function() {
        $scope.loading = true;
        $timeout(function() {
            $http.get('/json/qcm2014-1.json')
            .success(function(data, status, headers, config){
                $scope.qcmOrig = angular.copy(data);
                $scope.generateQCM($scope.main.QCMID);
            })
            .error(function() {
                var dlg = dialogs.error('Erreur','Impossible de charger le JSON');
                dlg.result();
            });
        }, 100);
    },
    $scope.generateQCM = function(QCMID) {
        $scope.loading = true;
        $scope.main.checkAnswers = false;
        if (QCMID) {
            $scope.arrayToOptions(API.uncomputeID(QCMID).options);
        }
        $timeout(function() {
            $scope.qcm = angular.copy($scope.qcmOrig);
            $scope.main.QCMID = API.generateQCM($scope.qcm, $scope.optionsToArray(), QCMID);
            if ($scope.main.exam.papierExaminateur)
                API.tickAnswers($scope.qcm);
        },300);
    },
    $scope.optionsToArray = function() {
        var opt = [];
        opt[0] = $scope.main.category.options.indexOf($scope.main.category.checked)
        opt[1] = $scope.main.level.options.indexOf($scope.main.level.checked)
        opt[2] = $scope.main.nbquestions.options.indexOf($scope.main.nbquestions.checked)
        return opt;
    },
    $scope.arrayToOptions = function(opt) {
        $scope.main.category.checked = $scope.main.category.options[opt[0]];
        $scope.main.level.checked = $scope.main.level.options[opt[1]];
        $scope.main.nbquestions.checked = $scope.main.nbquestions.options[opt[2]];
    },
    $scope.updateQCMID = function() {
        var num = API.uncomputeID($scope.main.QCMID).num;
        $scope.main.QCMID = API.computeID(num, $scope.optionsToArray());
    },
    $scope.reload = function() {
        var dlg = dialogs.confirm('Confirmation','Composer un nouveau questionnaire ' + $scope.main.category.checked + ' niveau "' + $scope.main.level.checked + '" avec ' + $scope.main.nbquestions.checked.toLowerCase() + ' questions (et effacer vos réponses) ?', {size:"lg"});
        dlg.result.then(function(btn){
            $scope.main.QCMID = '';
        	$scope.main.reloadQCM = true;
        },function(btn){
            //cancel
        });
    }
    $scope.scoreClass = function(score) {
        if (score.percentage >= 75) {
            return "good-score";
        } else {
            return "bad-score";
        }
    }
    $scope.resetQCMDisplay = function() {
        // is unset in the directive "removeLoaderWhenReady()"
		$scope.loading = true;
		$scope.main.displayLimit = 0;
		$timeout(function() {
			$scope.main.displayLimit = 10000;
		}, 0);
        if ($scope.qcm && !$scope.main.exam.mode && $scope.main.checkAnswers) {
            API.untickAnswers($scope.qcm);
            $scope.main.checkAnswers = false;
        }
    }

    $scope.collapseNav = function() {
        $('html').trigger('click');
        $scope.navCollapsed = true;
    }

    $scope.browserChrome = function() {
        return (deviceDetector.browser == "chrome");
    }

    // show magic button when in /dev
    $scope.isDevURL = function() {
        return ($location.absUrl().indexOf("/dev") != -1);
    }

    // we are in a stable version only when a push to prod has been done
    $scope.isProdURL = function() {
        return ($location.absUrl().indexOf("sativouf.net") == -1);
    }

    $scope.gotoMainURL = function() {
        if ($location.url().indexOf("/qcm") == -1) {
            $location.url("/qcm/");
        }
    }

    $scope.resetQCMIDUser = function() {
        $scope.main.QCMIDUser = $scope.main.QCMID;
        $scope.main.formattedQCMIDUser = $filter('formatQCMID')($scope.main.QCMIDUser);
    }

    $scope.fillQCMAnswers = function() {
        $scope.main.checkAnswers = true;
        API.tickAnswers($scope.qcm);
    }

    $scope.unfillQCMAnswers = function() {
        $scope.main.checkAnswers = false;
        API.untickAnswers($scope.qcm);
    }

    $scope.toggleCheck = function(answer) {
        if ($scope.navCollapsed && !$scope.main.checkAnswers && !$scope.main.exam.papier) {
            answer.checked = !answer.checked;
        }
    }
    $scope.dialogQCMID = function() {
        var prepend = "";
        if ($scope.isDevURL())
            prepend = "/dev"
        var dlg = dialogs.create(prepend + '/dialogs/qcmid.html','QCMIDDialogCtrl',$scope.main, {size:'lg'});
                    dlg.result.then(function(name){
                        if ($scope.main.QCMIDUser != $scope.main.QCMID) {
                            $scope.collapseNav();
                            $location.path("/qcm/" + $scope.main.QCMIDUser);
                        }
                    },function(){
                    });
    }

    // "called" by modals
    $scope.$watch("main.reloadQCM", function(newval, oldval) {
        if (newval == true) {
            // wait for modal to close
            $timeout(function() {
                $scope.loading = true;
            }, 500);
            $timeout(function() {
                $scope.main.reloadQCM = false;
                $scope.collapseNav();
                $scope.generateQCM($scope.main.QCMID);
            },700);
        }
    })

    $scope.$watch('main.nbquestions.checked', function(newval, oldval) {
        $scope.loading = true;
        if (newval != oldval) {
            $timeout(function() {
                $scope.resetQCMDisplay();
                $scope.updateQCMID();
                var limit = $scope.main.nbquestions.checked;
                if (limit === "Toutes les") {
                    limit = 10000;
                }
                $scope.main.limit = limit;
            },100);
        }
    })

    $scope.$watch('main.level.checked', function(newval, oldval) {
        $scope.loading = true;
        if (newval != oldval) {
            $timeout(function() {
                $scope.resetQCMDisplay();
                $scope.updateQCMID();
                $scope.main.search.num_niveau = $scope.main.level.options.indexOf($scope.main.level.checked);
            },100);
        }
    });

    $scope.$watch('main.typeExam.checked', function(newval, oldval) {
        if (newval != oldval) {
            $scope.main.exam = [];
            $scope.main.checkAnswers = false;
            if (newval.indexOf("Examen papier") != -1) {
                $scope.main.exam.mode = true;
                $scope.main.exam.papier = true;
            }
            if (newval == "Examen papier (candidat)") {
                $scope.main.exam.papierCandidat = true;
            } else if (newval == "Examen papier (examinateur)") {
                $scope.main.exam.papierExaminateur = true;
            }
            // back from examPapierExaminateur, we want to erase the answers ticked
            $scope.unfillQCMAnswers();
            if ($scope.main.exam.papierExaminateur) {
                API.tickAnswers($scope.qcm);
            }
            document.body.scrollTop = document.documentElement.scrollTop = 0;
        }
    });

    $scope.$watch('main.QCMID', function(newval, oldval) {
        if (newval != oldval) {
            if ($scope.main.QCMIDUser != $scope.main.QCMID) {
                $scope.resetQCMIDUser();
            }
            $scope.main.QCMIDCRC = API.crc($scope.main.QCMID);
            $scope.main.QCMIDURL = $location.absUrl() + "/" + $scope.main.QCMID;
        }
    });

    $scope.$watch('main.formattedQCMIDUser', function(newval, oldval) {
        if (newval != oldval) {
            $scope.main.QCMIDUser = $filter('removeSpaces')(newval);
            $scope.main.formattedQCMIDUser = $filter('formatQCMID')($scope.main.QCMIDUser);
        }
    });

 })

.controller('QCMCtrl', function($scope, $filter, $timeout, $routeParams, $location, dialogs, API, filterFilter) {
    $scope.questions = [];
    $scope.$parent.hideNavbarButtons = false;
    $scope.$parent.main.checkAnswers = false;

    var QCMID = $routeParams.param1;

    if (QCMID) {
        $location.path("/qcm", false);
        if (API.verifyChecksum(QCMID)) {
            // used by loadJSON()
            $scope.$parent.main.QCMID = QCMID;
        } else {
            dialogs.error('Erreur','ID QCM invalide : ' + QCMID);
        }
    }
    if ($scope.$parent.qcm) {
        $scope.$parent.generateQCM($scope.$parent.main.QCMID);
    } else {
        $scope.$parent.loadJSON();
    }

    $scope.getPoints = function(question) {
        var total = 0;
        for (var i = 0; i < question.ans.length; i++) {
            if (question.ans[i].checked) {
                total += parseInt(question.ans[i].pts);
            }
        }
        if (total < 0) {
            total = 0;
        }
        return total;
    }

    $scope.getScore = function() {
        var arr = filterFilter($scope.qcm, $scope.main.search);
        arr = $filter('limitTo')(arr, $scope.main.limit)
        var score = { user: 0, nb: 0, percentage: 0 };
        for(var i = 0; i < arr.length; i++){
            var question = arr[i];
            score.user += $scope.getPoints(question);
        }
        score.nb = i;
        score.total = i*6;
        if (score.total > 0) {
            score.percentage = Math.round(score.user / score.total * 100);
        }
        return score;
    }

    $scope.successQuestion = function(question) {
        if ($scope.main.exam.papier || !$scope.main.checkAnswers)
            return false;
        return ($scope.getPoints(question) === 6);
    }

    $scope.failedQuestion = function(question) {
        if ($scope.main.exam.papier || !$scope.main.checkAnswers)
            return false;
        return ($scope.getPoints(question) === 0);
    }

    $scope.warningQuestion = function(question) {
        if ($scope.main.exam.papier || !$scope.main.checkAnswers)
            return false;
        var points = $scope.getPoints(question);
        return (points >= 1 && points <=5);
    }

    $scope.goodAnswer = function(answer) {
        if ($scope.main.exam.papier || !$scope.main.checkAnswers)
            return false;
        return (answer.pts >= 0 && answer.checked);
    }

    $scope.badAnswer = function(answer) {
        if ($scope.main.exam.papier || !$scope.main.checkAnswers)
            return false;
        return (answer.pts < 0 && answer.checked);
    }

    $scope.goodAnswerNotChecked = function(answer) {
        if ($scope.main.exam.papier || !$scope.main.checkAnswers)
            return false;
        return (answer.pts > 0 && !answer.checked);
    }

    $scope.updateScore = function() {
        if ($scope.main.checkAnswers) {
            $scope.main.score = $scope.getScore();
        }
    }

    $scope.$watch('main.checkAnswers', function() {
        $scope.updateScore();
    })

})

.controller('SelfTestCtrl', function($scope, API) {
    $scope.$parent.loading = false;
	$scope.selftest = [];
	$scope.selftest.numitems   = 600;
	$scope.selftest.numruns    = 10000;
	$scope.selftest.showperrun = 60;

	$scope.selftest.qcm = [];
	for(var i = 1; i <= $scope.selftest.numitems; i++) {
		var obj = { question : i , ans : "x", shown : 0 };
		$scope.selftest.qcm.push(obj);
	}
//	console.log($scope.selftest.qcm);
	for(var i = 1; i <= $scope.selftest.numruns; i++){
//		console.log("run " + i );
		API.generateQCM($scope.selftest.qcm);
//		console.log($scope.selftest.qcm);
		for(var j = 0; j < $scope.main.nbquestions.checked ; j++){
			$scope.selftest.qcm[j].shown++;
		}
	}
	for(var i = 0; i < $scope.selftest.numitems; i++) {
		$scope.selftest.qcm[i].percent = (($scope.selftest.qcm[i].shown / $scope.selftest.numruns) * 100).toFixed(2);;
	}

})

.controller('AboutCtrl', function($scope) {
    $scope.$parent.navCollapsed = true;
    $scope.$parent.loading = false;
    $scope.$parent.hideNavbarButtons = true;

    document.body.scrollTop = document.documentElement.scrollTop = 0;
})

.controller('QCMIDDialogCtrl', function($scope, $modalInstance, $location, $timeout, data, API) {
    $scope.main = data;

    $scope.savedFormattedQCMIDUser = angular.copy($scope.main.formattedQCMIDUser);
    $scope.verifyQCMIDUser = function() {
        if ($scope.main.formattedQCMIDUser != $scope.savedFormattedQCMIDUser) {
            return API.verifyChecksum($scope.main.QCMIDUser);
        } else {
            return true;
        }
    }
    $scope.cancelIDChanges = function() {
        if (! $scope.verifyQCMIDUser)
            $scope.main.formattedQCMIDUser = angular.copy($scope.savedFormattedQCMIDUser);
    }
    $scope.loadQCMID = function() {
        $modalInstance.close();
    }
    $scope.ok = function(){
        $modalInstance.dismiss();
    };
});
<|endoftext|>


<commit_before>
module.exports = exports = rebuild

exports.usage = 'Attempts to install pre-built binary for module'

var fs = require('fs')
  , tar = require('tar')
  , path = require('path')
  , zlib = require('zlib')
  , log = require('npmlog')
  , semver = require('semver')
  , request = require('request')
  , win = process.platform == 'win32'
  , os = require('os')
  , existsAsync = fs.exists || path.exists
  , cp = require('child_process')
  , versioning = require('./util/versioning.js')
  , compile = require('./util/compile.js')

function test_binary(opts,callback) {
    var args = [];
    var shell_cmd;
    var arch_names = {
        'ia32':'-i386',
        'x64':'-x86_64'
    }
    if (process.platform === 'darwin' && arch_names[opts.target_arch]) {
        shell_cmd = 'arch';
        args.push(arch_names[opts.target_arch]);
        args.push(process.execPath);
    } else if (process.arch == opts.target_arch) {
        shell_cmd = process.execPath;
    }
    if (!shell_cmd) {
        return callback();
    }
    args.push(opts.module_main);
    cp.execFile(shell_cmd, args, function(err, stdout, stderr) {
        if (err || stderr) {
            return callback(new Error(err.message || stderr));
        }
        return callback();
    });
}

function download(url,opts,callback) {
    log.http('GET', url)

    var req = null
    var requestOpts = {
        uri: url
      , headers: {
          'User-Agent': 'node-pre-gyp (node ' + process.version + ')'
        }
    }

    var proxyUrl = opts.proxy
                || process.env.http_proxy
                || process.env.HTTP_PROXY
                || process.env.npm_config_proxy
    if (proxyUrl) {
      if (/^https?:\/\//i.test(proxyUrl)) {
        log.verbose('download', 'using proxy url: "%s"', proxyUrl)
        requestOpts.proxy = proxyUrl
      } else {
        log.warn('download', 'ignoring invalid "proxy" config setting: "%s"', proxyUrl)
      }
    }
    try {
      req = request(requestOpts)
    } catch (e) {
      callback(e)
    }
    if (req) {
      req.on('response', function (res) {
        log.http(res.statusCode, url)
      })
    }
    callback(null,req);
}

function place_binary(from,to,opts,callback) {
    download(from,opts,function(err,req) {
        if (err) return callback(err);
        if (!req) return callback(new Error("empty req"));
        var badDownload = false
            , extractCount = 0
            , gunzip = zlib.createGunzip()
            , extracter = tar.Extract({ path: to, strip: 1, filter: isValid });
        function afterTarball(err) {
            if (err) return callback(err);
            if (badDownload) return callback(new Error("bad download"));
            if (extractCount === 0) {
              return callback(new Error('There was a fatal problem while downloading/extracting the tarball'))
            }
            log.info('tarball', 'done parsing tarball')
            callback();
        }
        function isValid () {
            extractCount++
            return true
        };
        gunzip.on('error', callback)
        extracter.on('error', callback)
        extracter.on('end', afterTarball)

        req.on('error', function (err) {
            badDownload = true
            callback(err)
        })

        req.on('close', function () {
            if (extractCount === 0) {
              callback(new Error('Connection closed while downloading tarball file'))
            }
        })

        req.on('response', function (res) {
            if (res.statusCode !== 200) {
              badDownload = true
              callback(new Error(res.statusCode + ' status code downloading tarball'))
              return
            }
            // start unzipping and untaring
            req.pipe(gunzip).pipe(extracter)
        })
    });
}

function rebuild(gyp, argv, callback) {
    // @TODO - respect -C/--directory
    var package_json = JSON.parse(fs.readFileSync('./package.json'));
    if (gyp.opts['build_from_source'] && (
        (gyp.opts['build_from_source'] === true || gyp.opts['build_from_source'] === 'true') ||
        (gyp.opts['build_from_source'] === package_json.name))) {
        log.info('rebuild','requesting source compile');
        return compile.run_gyp(['rebuild'],gyp.opts,callback);
    }
    versioning.evaluate(package_json, gyp.opts, function(err,opts) {
        if (err) return callback(err);
        var from = package_json.binary.remote_uri + '/' + opts.versioned;
        var to = package_json.binary.module_path;
        var binary_module = path.join(to,opts.module_name+'.node');
        if (existsAsync(binary_module,function(found) {
            if (found) {
                log.info('install','Sweet: "'+binary_module+'" is installed!');
                callback();
            } else {
                place_binary(from,to,opts,function(err) {
                    if (err) {
                        log.info('build','source compile required');
                        compile.run_gyp(['rebuild'],opts,callback);
                    } else {
                        test_binary(opts,function(err) {
                            if (err) {
                                log.info("Testing pre-built binary failed, falling back to source compile: ("+err.message+")");
                                compile.run_gyp(['rebuild'],opts,callback);
                            }
                            log.info('rebuild','Sweet: "'+binary_module+'" was successfully built!');
                            return callback();
                        });
                    };
                });
            }
        }));
    });
}
<commit_msg>fix --build-from-source to work when node-pre-gyp is run directly as well as via npm<commit_after>
module.exports = exports = rebuild

exports.usage = 'Attempts to install pre-built binary for module'

var fs = require('fs')
  , tar = require('tar')
  , path = require('path')
  , zlib = require('zlib')
  , log = require('npmlog')
  , semver = require('semver')
  , request = require('request')
  , win = process.platform == 'win32'
  , os = require('os')
  , existsAsync = fs.exists || path.exists
  , cp = require('child_process')
  , versioning = require('./util/versioning.js')
  , compile = require('./util/compile.js')

function test_binary(opts,callback) {
    var args = [];
    var shell_cmd;
    var arch_names = {
        'ia32':'-i386',
        'x64':'-x86_64'
    }
    if (process.platform === 'darwin' && arch_names[opts.target_arch]) {
        shell_cmd = 'arch';
        args.push(arch_names[opts.target_arch]);
        args.push(process.execPath);
    } else if (process.arch == opts.target_arch) {
        shell_cmd = process.execPath;
    }
    if (!shell_cmd) {
        return callback();
    }
    args.push(opts.module_main);
    cp.execFile(shell_cmd, args, function(err, stdout, stderr) {
        if (err || stderr) {
            return callback(new Error(err.message || stderr));
        }
        return callback();
    });
}

function download(url,opts,callback) {
    log.http('GET', url)

    var req = null
    var requestOpts = {
        uri: url
      , headers: {
          'User-Agent': 'node-pre-gyp (node ' + process.version + ')'
        }
    }

    var proxyUrl = opts.proxy
                || process.env.http_proxy
                || process.env.HTTP_PROXY
                || process.env.npm_config_proxy
    if (proxyUrl) {
      if (/^https?:\/\//i.test(proxyUrl)) {
        log.verbose('download', 'using proxy url: "%s"', proxyUrl)
        requestOpts.proxy = proxyUrl
      } else {
        log.warn('download', 'ignoring invalid "proxy" config setting: "%s"', proxyUrl)
      }
    }
    try {
      req = request(requestOpts)
    } catch (e) {
      callback(e)
    }
    if (req) {
      req.on('response', function (res) {
        log.http(res.statusCode, url)
      })
    }
    callback(null,req);
}

function place_binary(from,to,opts,callback) {
    download(from,opts,function(err,req) {
        if (err) return callback(err);
        if (!req) return callback(new Error("empty req"));
        var badDownload = false
            , extractCount = 0
            , gunzip = zlib.createGunzip()
            , extracter = tar.Extract({ path: to, strip: 1, filter: isValid });
        function afterTarball(err) {
            if (err) return callback(err);
            if (badDownload) return callback(new Error("bad download"));
            if (extractCount === 0) {
              return callback(new Error('There was a fatal problem while downloading/extracting the tarball'))
            }
            log.info('tarball', 'done parsing tarball')
            callback();
        }
        function isValid () {
            extractCount++
            return true
        };
        gunzip.on('error', callback)
        extracter.on('error', callback)
        extracter.on('end', afterTarball)

        req.on('error', function (err) {
            badDownload = true
            callback(err)
        })

        req.on('close', function () {
            if (extractCount === 0) {
              callback(new Error('Connection closed while downloading tarball file'))
            }
        })

        req.on('response', function (res) {
            if (res.statusCode !== 200) {
              badDownload = true
              return callback(new Error(res.statusCode + ' status code downloading tarball'))
            }
            // start unzipping and untaring
            req.pipe(gunzip).pipe(extracter)
        })
    });
}

function rebuild(gyp, argv, callback) {
    // @TODO - respect -C/--directory
    var package_json = JSON.parse(fs.readFileSync('./package.json'));
    // @TODO = if run via npm dashes will become underscore - why?
    var source_build = gyp.opts['build-from-source'] || gyp.opts['build_from_source'];
    if (source_build === package_json.name ||
        source_build === true ||
        source_build === 'true') {
        log.info('rebuild','requesting source compile');
        compile.run_gyp(['rebuild'],gyp.opts,function(err,opts) {
            return callback(err);
        });
    }
    versioning.evaluate(package_json, gyp.opts, function(err,opts) {
        if (err) return callback(err);
        var from = package_json.binary.remote_uri + '/' + opts.versioned;
        var to = package_json.binary.module_path;
        var binary_module = path.join(to,opts.module_name+'.node');
        if (existsAsync(binary_module,function(found) {
            if (found) {
                log.info('install','Sweet: "'+binary_module+'" is installed!');
                callback();
            } else {
                place_binary(from,to,opts,function(err) {
                    if (err) {
                        log.info('build','source compile required');
                        compile.run_gyp(['rebuild'],opts,function(err,opts) {
                            return callback(err);
                        });
                    } else {
                        test_binary(opts,function(err) {
                            if (err) {
                                log.info("Testing pre-built binary failed, falling back to source compile: ("+err.message+")");
                                compile.run_gyp(['rebuild'],opts,function(err,opts) {
                                    return callback(err);
                                });
                            }
                            log.info('rebuild','Sweet: "'+binary_module+'" was successfully built!');
                            return callback();
                        });
                    };
                });
            }
        }));
    });
}
<|endoftext|>


<commit_before>'use strict';

var fs       = require('fs');
var path     = require('path');
var expect   = require('expect.js');
var rimraf   = require('rimraf');
var mkdirp   = require('mkdirp');
var which    = require('which');
var buffered = require('./util/buffered');
var spawn    = require('../');

var isWin    = process.platform === 'win32';

// Fix AppVeyor tests because Git bin folder is in PATH and it has a "echo" program there
if (isWin) {
    process.env.PATH = process.env.PATH
    .split(path.delimiter)
    .filter(function (entry) {
        return !/\\git\\bin$/i.test(path.normalize(entry));
    })
    .join(path.delimiter);
}

describe('cross-spawn', function () {
    var methods = ['spawn', 'sync'];

    methods.forEach(function (method) {
        describe(method, function() {
            var originalPath = process.env.PATH;

            before(function () {
                mkdirp.sync(__dirname + '/tmp');
            });

            after(function (next) {
                rimraf(__dirname + '/tmp', function (err) {
                    // Ignore ENOTEMPTY on windows.. RIMRAF was giving problems
                    next(err && err.code === 'ENOTEMPTY' ? null : err);
                });
            });

            afterEach(function () {
                process.env.PATH = originalPath;
            });

            it('should support shebang in executables with /usr/bin/env', function (next) {
                buffered(method, __dirname + '/fixtures/shebang', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('shebang works!');

                    // Test if the actual shebang file is resolved against the PATH
                    process.env.PATH = path.normalize(__dirname + '/fixtures/') + path.delimiter + process.env.PATH;

                    buffered(method, 'shebang', function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);
                        expect(data).to.equal('shebang works!');

                        next();
                    });
                });
            });

            it('should support shebang in executables without /usr/bin/env', function (next) {
                var nodejs = which.sync('node');
                var file = __dirname + '/fixtures/shebang_noenv';

                fs.writeFileSync(file, '#!' + nodejs + '\n\nprocess.stdout.write(\'shebang works!\');', {
                    mode: parseInt('0777', 8)
                });

                buffered(method, file, function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('shebang works!');

                    // Test if the actual shebang file is resolved against the PATH
                    process.env.PATH = path.normalize(__dirname + '/fixtures/') + path.delimiter + process.env.PATH;

                    buffered(method, 'shebang_noenv', function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);
                        expect(data).to.equal('shebang works!');

                        next();
                    });
                });
            });

            it('should support shebang in executables with relative path', function (next) {
                var executable = './' + path.relative(process.cwd(), __dirname + '/fixtures/shebang');

                fs.writeFileSync(__dirname + '/tmp/shebang', '#!/usr/bin/env node\n\nprocess.stdout.write(\'yeah\');', { mode: parseInt('0777', 8) });
                process.env.PATH = path.normalize(__dirname + '/tmp/') + path.delimiter + process.env.PATH;

                buffered(method, executable, function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('shebang works!');

                    next();
                });
            });

            it('should support shebang in executables with extensions', function (next) {
                fs.writeFileSync(__dirname + '/tmp/shebang.js', '#!/usr/bin/env node\n\nprocess.stdout.write(\'shebang with extension\');', { mode: parseInt('0777', 8) });
                process.env.PATH = path.normalize(__dirname + '/tmp/') + path.delimiter + process.env.PATH;

                buffered(method, __dirname + '/tmp/shebang.js', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('shebang with extension');

                    // Test if the actual shebang file is resolved against the PATH
                    process.env.PATH = path.normalize(__dirname + '/fixtures/') + path.delimiter + process.env.PATH;

                    buffered(method, 'shebang.js', function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);
                        expect(data).to.equal('shebang with extension');

                        next();
                    });
                });
            });

            it('should expand using PATHEXT properly', function (next) {
                buffered(method, __dirname + '/fixtures/foo', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data.trim()).to.equal('foo');

                    next();
                });
            });

            it('should handle commands with spaces', function (next) {
                buffered(method, __dirname + '/fixtures/bar space', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data.trim()).to.equal('bar');

                    next();
                });
            });

            it('should handle commands with special shell chars', function (next) {
                buffered(method, __dirname + '/fixtures/()%!^&;, ', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data.trim()).to.equal('special');

                    next();
                });
            });

            it('should handle empty arguments', function (next) {
                buffered(method, 'node', [
                    __dirname + '/fixtures/echo',
                    'foo',
                    '',
                    'bar'
                ], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('foo\n\nbar');

                    buffered(method, 'echo', [
                        'foo',
                        '',
                        'bar'
                    ], function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);
                        expect(data.trim()).to.equal('foo  bar');

                        next();
                    });
                });
            });

            it('should handle non-string arguments', function (next) {
                buffered(method, 'node', [
                    __dirname + '/fixtures/echo',
                    1234
                ], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('1234');

                    next();
                });
            });

            it('should handle arguments with spaces', function (next) {
                buffered(method, 'node', [
                    __dirname + '/fixtures/echo',
                    'I am',
                    'André Cruz'
                ], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('I am\nAndré Cruz');

                    next();
                });
            });

            it('should handle arguments with \\"', function (next) {
                buffered(method, 'node', [
                    __dirname + '/fixtures/echo',
                    'foo',
                    '\\"',
                    'bar'
                ], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('foo\n\\"\nbar');

                    next();
                });
            });

            it('should handle arguments that end with \\', function (next) {
                buffered(method, 'node', [
                    __dirname + '/fixtures/echo',
                    'foo',
                    'bar\\',
                    'baz'
                ], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('foo\nbar\\\nbaz');

                    next();
                });
            });

            it('should handle arguments that contain shell special chars', function (next) {
                buffered(method, 'node', [
                    __dirname + '/fixtures/echo',
                    'foo',
                    '()',
                    'foo',
                    '%!',
                    'foo',
                    '^<',
                    'foo',
                    '>&',
                    'foo',
                    '|;',
                    'foo',
                    ', ',
                    'foo'
                ], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('foo\n()\nfoo\n%!\nfoo\n^<\nfoo\n>&\nfoo\n|;\nfoo\n, \nfoo');

                    next();
                });
            });

            it('should handle special arguments when using echo', function (next) {
                buffered(method, 'echo', ['foo\\"foo\\foo&bar"foo\'bar'], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data.trim()).to.equal('foo\\"foo\\foo&bar"foo\'bar');

                    buffered(method, 'echo', [
                        'foo',
                        '()',
                        'foo',
                        '%!',
                        'foo',
                        '^<',
                        'foo',
                        '>&',
                        'foo',
                        '|;',
                        'foo',
                        ', ',
                        'foo'
                    ], function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);
                        expect(data.trim()).to.equal('foo () foo %! foo ^< foo >& foo |; foo ,  foo');

                        next();
                    });
                });
            });

            it('should handle optional args correctly', function (next) {
                buffered(method, __dirname + '/fixtures/foo', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);

                    buffered(method, __dirname + '/fixtures/foo', {
                        stdio: ['pipe', 'pipe', 'pipe'],
                    }, function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);

                        buffered(method, __dirname + '/fixtures/foo', null, {
                            stdio: ['pipe', 'pipe', 'pipe'],
                        }, function (err, data, code) {
                            expect(err).to.not.be.ok();
                            expect(code).to.be(0);

                            next();
                        });
                    });
                });
            });

            it('should not mutate args nor options', function (next) {
                var args = [];
                var options = {};

                buffered(method, __dirname + '/fixtures/foo', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);

                    expect(args).to.have.length(0);
                    expect(Object.keys(options)).to.have.length(0);

                    next();
                });
            });

            it('should give correct exit code', function (next) {
                buffered(method, 'node', [__dirname + '/fixtures/exit'], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(25);

                    next();
                });
            });

            it('should work with a relative command', function (next) {
                buffered(method, path.relative(process.cwd(), __dirname + '/fixtures/foo'), function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data.trim()).to.equal('foo');

                    if (!isWin) {
                        return next();
                    }

                    buffered(method, path.relative(process.cwd(), __dirname + '/fixtures/foo.bat'), function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);
                        expect(data.trim()).to.equal('foo');

                        next();
                    });
                });
            });

            it('should emit "error" and "close" if command does not exist', function (next) {
                var errors;
                var spawned = spawn[method]('somecommandthatwillneverexist');

                this.timeout(5000);

                function assertError(err) {
                    var syscall = method === 'sync' ? 'spawnSync' : 'spawn';

                    expect(err).to.be.an(Error);
                    expect(err.message).to.contain(syscall);
                    expect(err.message).to.contain('ENOENT');
                    expect(err.message).to.not.contain('undefined');
                    expect(err.code).to.be('ENOENT');
                    expect(err.errno).to.be('ENOENT');
                    expect(err.syscall).to.contain(syscall);
                    expect(err.syscall).to.not.contain('undefined');
                }

                if (method === 'spawn') {
                    errors = [];

                    spawned
                    .on('error', function (err) {
                        errors.push(err);
                    })
                    .on('exit', function () {
                        spawned.removeAllListeners();
                        next(new Error('Should not emit exit'));
                    })
                    .on('close', function (code, signal) {
                        expect(code).to.not.be(0);
                        expect(signal).to.be(null);

                        setTimeout(function () {
                            expect(errors).to.have.length(1);
                            assertError(errors[0]);

                            next();
                        }, 1000);
                    });
                } else {
                    assertError(spawned.error);
                    next();
                }
            });

            it('should NOT emit "error" if shebang command does not exist', function (next) {
                var spawned = spawn[method](__dirname + '/fixtures/shebang_enoent');
                var exited;
                var timeout;

                this.timeout(5000);

                if (method === 'spawn') {
                    spawned
                    .on('error', function (err) {
                        spawned.removeAllListeners();
                        clearTimeout(timeout);
                        next(new Error('Should not emit error'));
                    })
                    .on('exit', function () {
                        exited = true;
                    })
                    .on('close', function (code, signal) {
                        expect(code).to.not.be(0);
                        expect(signal).to.be(null);
                        expect(exited).to.be(true);

                        timeout = setTimeout(next, 1000);
                    });
                } else {
                    expect(spawned.error).to.not.be.ok();
                    next();
                }
            });

            it('should NOT emit "error" if the command actual exists but exited with 1', function (next) {
                var spawned = spawn[method](__dirname + '/fixtures/exit1');
                var exited;
                var timeout;

                this.timeout(5000);

                if (method === 'spawn') {
                    spawned
                    .on('error', function (err) {
                        spawned.removeAllListeners();
                        clearTimeout(timeout);
                        next(new Error('Should not emit error'));
                    })
                    .on('exit', function () {
                        exited = true;
                    })
                    .on('close', function (code, signal) {
                        expect(code).to.not.be(0);
                        expect(signal).to.be(null);
                        expect(exited).to.be(true);

                        timeout = setTimeout(next, 1000);
                    });
                } else {
                    expect(spawned.error).to.not.be.ok();
                    next();
                }
            });
        });
    });
});
<commit_msg>Argh...<commit_after>'use strict';

var fs       = require('fs');
var path     = require('path');
var expect   = require('expect.js');
var rimraf   = require('rimraf');
var mkdirp   = require('mkdirp');
var which    = require('which');
var buffered = require('./util/buffered');
var spawn    = require('../');

var isWin    = process.platform === 'win32';

// Fix AppVeyor tests because Git bin folder is in PATH and it has a "echo" program there
if (isWin) {
    process.env.PATH = process.env.PATH
    .split(path.delimiter)
    .filter(function (entry) {
        return !/\\git\\bin$/i.test(path.normalize(entry));
    })
    .join(path.delimiter);
}

describe('cross-spawn', function () {
    var methods = ['spawn', 'sync'];

    methods.forEach(function (method) {
        describe(method, function() {
            var originalPath = process.env.PATH;

            before(function () {
                mkdirp.sync(__dirname + '/tmp');
            });

            after(function (next) {
                rimraf(__dirname + '/tmp', function (err) {
                    // Ignore errors, RIMRAF was giving problems on windows
                    next(null);
                });
            });

            afterEach(function () {
                process.env.PATH = originalPath;
            });

            it('should support shebang in executables with /usr/bin/env', function (next) {
                buffered(method, __dirname + '/fixtures/shebang', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('shebang works!');

                    // Test if the actual shebang file is resolved against the PATH
                    process.env.PATH = path.normalize(__dirname + '/fixtures/') + path.delimiter + process.env.PATH;

                    buffered(method, 'shebang', function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);
                        expect(data).to.equal('shebang works!');

                        next();
                    });
                });
            });

            it('should support shebang in executables without /usr/bin/env', function (next) {
                var nodejs = which.sync('node');
                var file = __dirname + '/fixtures/shebang_noenv';

                fs.writeFileSync(file, '#!' + nodejs + '\n\nprocess.stdout.write(\'shebang works!\');', {
                    mode: parseInt('0777', 8)
                });

                buffered(method, file, function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('shebang works!');

                    // Test if the actual shebang file is resolved against the PATH
                    process.env.PATH = path.normalize(__dirname + '/fixtures/') + path.delimiter + process.env.PATH;

                    buffered(method, 'shebang_noenv', function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);
                        expect(data).to.equal('shebang works!');

                        next();
                    });
                });
            });

            it('should support shebang in executables with relative path', function (next) {
                var executable = './' + path.relative(process.cwd(), __dirname + '/fixtures/shebang');

                fs.writeFileSync(__dirname + '/tmp/shebang', '#!/usr/bin/env node\n\nprocess.stdout.write(\'yeah\');', { mode: parseInt('0777', 8) });
                process.env.PATH = path.normalize(__dirname + '/tmp/') + path.delimiter + process.env.PATH;

                buffered(method, executable, function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('shebang works!');

                    next();
                });
            });

            it('should support shebang in executables with extensions', function (next) {
                fs.writeFileSync(__dirname + '/tmp/shebang_' + method + '.js', '#!/usr/bin/env node\n\nprocess.stdout.write(\'shebang with extension\');', { mode: parseInt('0777', 8) });
                process.env.PATH = path.normalize(__dirname + '/tmp/') + path.delimiter + process.env.PATH;

                buffered(method, __dirname + '/tmp/shebang_' + method + '.js', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('shebang with extension');

                    // Test if the actual shebang file is resolved against the PATH
                    process.env.PATH = path.normalize(__dirname + '/fixtures/') + path.delimiter + process.env.PATH;

                    buffered(method, 'shebang_' + method + '.js', function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);
                        expect(data).to.equal('shebang with extension');

                        next();
                    });
                });
            });

            it('should expand using PATHEXT properly', function (next) {
                buffered(method, __dirname + '/fixtures/foo', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data.trim()).to.equal('foo');

                    next();
                });
            });

            it('should handle commands with spaces', function (next) {
                buffered(method, __dirname + '/fixtures/bar space', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data.trim()).to.equal('bar');

                    next();
                });
            });

            it('should handle commands with special shell chars', function (next) {
                buffered(method, __dirname + '/fixtures/()%!^&;, ', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data.trim()).to.equal('special');

                    next();
                });
            });

            it('should handle empty arguments', function (next) {
                buffered(method, 'node', [
                    __dirname + '/fixtures/echo',
                    'foo',
                    '',
                    'bar'
                ], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('foo\n\nbar');

                    buffered(method, 'echo', [
                        'foo',
                        '',
                        'bar'
                    ], function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);
                        expect(data.trim()).to.equal('foo  bar');

                        next();
                    });
                });
            });

            it('should handle non-string arguments', function (next) {
                buffered(method, 'node', [
                    __dirname + '/fixtures/echo',
                    1234
                ], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('1234');

                    next();
                });
            });

            it('should handle arguments with spaces', function (next) {
                buffered(method, 'node', [
                    __dirname + '/fixtures/echo',
                    'I am',
                    'André Cruz'
                ], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('I am\nAndré Cruz');

                    next();
                });
            });

            it('should handle arguments with \\"', function (next) {
                buffered(method, 'node', [
                    __dirname + '/fixtures/echo',
                    'foo',
                    '\\"',
                    'bar'
                ], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('foo\n\\"\nbar');

                    next();
                });
            });

            it('should handle arguments that end with \\', function (next) {
                buffered(method, 'node', [
                    __dirname + '/fixtures/echo',
                    'foo',
                    'bar\\',
                    'baz'
                ], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('foo\nbar\\\nbaz');

                    next();
                });
            });

            it('should handle arguments that contain shell special chars', function (next) {
                buffered(method, 'node', [
                    __dirname + '/fixtures/echo',
                    'foo',
                    '()',
                    'foo',
                    '%!',
                    'foo',
                    '^<',
                    'foo',
                    '>&',
                    'foo',
                    '|;',
                    'foo',
                    ', ',
                    'foo'
                ], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data).to.equal('foo\n()\nfoo\n%!\nfoo\n^<\nfoo\n>&\nfoo\n|;\nfoo\n, \nfoo');

                    next();
                });
            });

            it('should handle special arguments when using echo', function (next) {
                buffered(method, 'echo', ['foo\\"foo\\foo&bar"foo\'bar'], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data.trim()).to.equal('foo\\"foo\\foo&bar"foo\'bar');

                    buffered(method, 'echo', [
                        'foo',
                        '()',
                        'foo',
                        '%!',
                        'foo',
                        '^<',
                        'foo',
                        '>&',
                        'foo',
                        '|;',
                        'foo',
                        ', ',
                        'foo'
                    ], function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);
                        expect(data.trim()).to.equal('foo () foo %! foo ^< foo >& foo |; foo ,  foo');

                        next();
                    });
                });
            });

            it('should handle optional args correctly', function (next) {
                buffered(method, __dirname + '/fixtures/foo', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);

                    buffered(method, __dirname + '/fixtures/foo', {
                        stdio: ['pipe', 'pipe', 'pipe'],
                    }, function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);

                        buffered(method, __dirname + '/fixtures/foo', null, {
                            stdio: ['pipe', 'pipe', 'pipe'],
                        }, function (err, data, code) {
                            expect(err).to.not.be.ok();
                            expect(code).to.be(0);

                            next();
                        });
                    });
                });
            });

            it('should not mutate args nor options', function (next) {
                var args = [];
                var options = {};

                buffered(method, __dirname + '/fixtures/foo', function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);

                    expect(args).to.have.length(0);
                    expect(Object.keys(options)).to.have.length(0);

                    next();
                });
            });

            it('should give correct exit code', function (next) {
                buffered(method, 'node', [__dirname + '/fixtures/exit'], function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(25);

                    next();
                });
            });

            it('should work with a relative command', function (next) {
                buffered(method, path.relative(process.cwd(), __dirname + '/fixtures/foo'), function (err, data, code) {
                    expect(err).to.not.be.ok();
                    expect(code).to.be(0);
                    expect(data.trim()).to.equal('foo');

                    if (!isWin) {
                        return next();
                    }

                    buffered(method, path.relative(process.cwd(), __dirname + '/fixtures/foo.bat'), function (err, data, code) {
                        expect(err).to.not.be.ok();
                        expect(code).to.be(0);
                        expect(data.trim()).to.equal('foo');

                        next();
                    });
                });
            });

            it('should emit "error" and "close" if command does not exist', function (next) {
                var errors;
                var spawned = spawn[method]('somecommandthatwillneverexist');

                this.timeout(5000);

                function assertError(err) {
                    var syscall = method === 'sync' ? 'spawnSync' : 'spawn';

                    expect(err).to.be.an(Error);
                    expect(err.message).to.contain(syscall);
                    expect(err.message).to.contain('ENOENT');
                    expect(err.message).to.not.contain('undefined');
                    expect(err.code).to.be('ENOENT');
                    expect(err.errno).to.be('ENOENT');
                    expect(err.syscall).to.contain(syscall);
                    expect(err.syscall).to.not.contain('undefined');
                }

                if (method === 'spawn') {
                    errors = [];

                    spawned
                    .on('error', function (err) {
                        errors.push(err);
                    })
                    .on('exit', function () {
                        spawned.removeAllListeners();
                        next(new Error('Should not emit exit'));
                    })
                    .on('close', function (code, signal) {
                        expect(code).to.not.be(0);
                        expect(signal).to.be(null);

                        setTimeout(function () {
                            expect(errors).to.have.length(1);
                            assertError(errors[0]);

                            next();
                        }, 1000);
                    });
                } else {
                    assertError(spawned.error);
                    next();
                }
            });

            it('should NOT emit "error" if shebang command does not exist', function (next) {
                var spawned = spawn[method](__dirname + '/fixtures/shebang_enoent');
                var exited;
                var timeout;

                this.timeout(5000);

                if (method === 'spawn') {
                    spawned
                    .on('error', function (err) {
                        spawned.removeAllListeners();
                        clearTimeout(timeout);
                        next(new Error('Should not emit error'));
                    })
                    .on('exit', function () {
                        exited = true;
                    })
                    .on('close', function (code, signal) {
                        expect(code).to.not.be(0);
                        expect(signal).to.be(null);
                        expect(exited).to.be(true);

                        timeout = setTimeout(next, 1000);
                    });
                } else {
                    expect(spawned.error).to.not.be.ok();
                    next();
                }
            });

            it('should NOT emit "error" if the command actual exists but exited with 1', function (next) {
                var spawned = spawn[method](__dirname + '/fixtures/exit1');
                var exited;
                var timeout;

                this.timeout(5000);

                if (method === 'spawn') {
                    spawned
                    .on('error', function (err) {
                        spawned.removeAllListeners();
                        clearTimeout(timeout);
                        next(new Error('Should not emit error'));
                    })
                    .on('exit', function () {
                        exited = true;
                    })
                    .on('close', function (code, signal) {
                        expect(code).to.not.be(0);
                        expect(signal).to.be(null);
                        expect(exited).to.be(true);

                        timeout = setTimeout(next, 1000);
                    });
                } else {
                    expect(spawned.error).to.not.be.ok();
                    next();
                }
            });
        });
    });
});
<|endoftext|>


<commit_before>define(["js/core/UIComponent", "js/core/Router"], function (UIComponent, Router) {
    return UIComponent.inherit("js.core.Module", {

        ctor: function() {
            this.callBase();
            this.$routers = [];
        },

        /**
         * loads the
         * @param callback
         * @param [routeContext]
         */
        start: function (callback, routeContext) {
            if (callback) {
                callback();
            }
        },

        render: function (target) {
            // module won't render anything, but delivers content via js:Content
            // content is rendered inside ContentPlaceHolders
        },

        addComponent: function(component) {
            this.callBase();

            if (component instanceof Router) {
                this.$routers.push(component);
            }
        }
    });
});<commit_msg>refactored addComponent to addChild ...<commit_after>define(["js/core/UIComponent", "js/core/Router"], function (UIComponent, Router) {
    return UIComponent.inherit("js.core.Module", {

        ctor: function() {
            this.callBase();
            this.$routers = [];
        },

        /**
         * loads the
         * @param callback
         * @param [routeContext]
         */
        start: function (callback, routeContext) {
            if (callback) {
                callback();
            }
        },

        render: function (target) {
            // module won't render anything, but delivers content via js:Content
            // content is rendered inside ContentPlaceHolders
        },

        addChild: function(component) {
            this.callBase();

            if (component instanceof Router) {
                this.$routers.push(component);
            }
        }
    });
});<|endoftext|>


<commit_before>const Rx = require('rxjs/Rx');
const fs = require('fs');
const _ = require('lodash');
const utils = require('./utils');

// TODO:
// - on init accept custom file path

exports.set = function(key, value) {
  // save the value in observable format
  var writeFileObservable = Rx.Observable.bindCallback(fs.writeFile);
  // return save chain
  return utils.getFilePath(key)
    .concatMap(function(filePath) {
      // stringify the json object
      value = JSON.stringify(value);
      if (!value) {
        return Rx.Observable.throw(new Error('Invalid JSON data'));
      }
      // save the file to the system
      return writeFileObservable(filePath, value);
    });
}

exports.get = function(key) {
  var readFileObservable = Rx.Observable.bindCallback(fs.readFile);
  return utils.getFilePath(key)
    .concatMap(function(filePath) {
      return readFileObservable(filePath, {
        encoding: 'utf8'
      })
    })
    .flatMap(function(res) {
      // Rx.Observable.bindCallback returns an array of the args returned
      // meaning err is res[0] and any other values follow
      if (res[0]) {
        if (res[0].code === 'ENOENT') {
          return Rx.Observable.of(JSON.stringify({}));
        }
        return Rx.Observable.throw('Error reading file.');
      }
      return Rx.Observable.of(res[1]);
    })
    // process JSON object
    .flatMap(function(obj) {
      var objectJSON = {};
      try {
        objectJSON = JSON.parse(obj);
      } catch (err) {
        return Rx.Observable.throw(new Error('Invalid data'));
      }
      return Rx.Observable.of(objectJSON);
    })
}

exports.has = function(has) {
  return false;
}
exports.remove = function(key) {
  return false;
}
exports.clear = function() {
  return false;

}
exports.concurrentGet = function() {
  // forkjoin an array of observable get requests
  return false;
}<commit_msg>Added .has(key) method<commit_after>const Rx = require('rxjs/Rx');
const fs = require('fs');
const utils = require('./utils');
const _ = require('lodash');

// TODO:
// - on init accept custom file path

exports.set = function(key, value) {
  var writeFileStream = Rx.Observable.bindCallback(fs.writeFile);
  // return save chain
  return utils.getFilePath(key)
    .concatMap(function(filePath) {
      // stringify the json object
      value = JSON.stringify(value);
      if (!value) {
        return Rx.Observable.throw(new Error('Invalid data'));
      }
      // save the file to the system
      return writeFileStream(filePath, value);
    });
}

exports.get = function(key) {
  var readFileStream = Rx.Observable.bindCallback(fs.readFile);
  return utils.getFilePath(key)
    .concatMap(function(filePath) {
      return readFileStream(filePath, {
        encoding: 'utf8'
      })
    })
    .flatMap(function(res) {
      // Rx.Observable.bindCallback returns an array of the args returned
      // meaning err is res[0] and any other values follow
      if (res[0]) {
        if (res[0].code === 'ENOENT') {
          return Rx.Observable.of(JSON.stringify({}));
        }
        return Rx.Observable.throw('Error reading file.');
      }
      return Rx.Observable.of(res[1]);
    })
    // process JSON object
    .flatMap(function(obj) {
      var objectJSON = {};
      try {
        objectJSON = JSON.parse(obj);
      } catch (err) {
        return Rx.Observable.throw(new Error('Invalid data'));
      }
      return Rx.Observable.of(objectJSON);
    })
}

exports.has = function(key) {
  var hasFileStream = Rx.Observable.bindCallback(fs.stat);
  return utils.getFilePath(key)
    .concatMap(function(filePath) {
      return hasFileStream(filePath);
    })
    .flatMap(function(res) {
      // for some reason binding the callback of fs.stat only return an object on error
      // so we have to check to see if it's not an array. If it isn't, there is an error.
      if (!_.isArray(res)) {
        if (res.code === 'ENOENT') {
          // file doen't exist
          return Rx.Observable.of(false);
        }
        // unkown error
        return Rx.Observable.throw(res);
      }
      // file exists
      return Rx.Observable.of(true);
    })
}

exports.remove = function(key) {
  return false;
}

exports.clear = function() {
  return false;
}

exports.concurrentGet = function() {
  // forkjoin an array of observable get requests
  return false;
}<|endoftext|>


<commit_before>/*
	jRespond.js (a simple way to globally manage javascript on responsive websites)
	version 0.7.2
	(c) 2012 Jeremy Fields [jeremy.fields@viget.com]
	released under the MIT license
*/
(function(c,b,a){c.jRespond=function(l){var e=[];var g=[];var o=l;var s="";var n;var d=0;var m=100;var p=500;var j=p;var i=function(){var t=0;if(!window.innerWidth){if(!(document.documentElement.clientWidth===0)){t=document.documentElement.clientWidth}else{t=document.body.clientWidth}}else{t=window.innerWidth}return t};var h=function(v){var u=v.breakpoint;var t=v.enter||undefined;e.push(v);g.push(false);if(k(u)){if(t!==undefined){t.call()}g[(e.length-1)]=true}};var q=function(){var A=[],z=[];for(var y=0;y<e.length;y++){var v=e[y]["breakpoint"];var t=e[y]["enter"]||undefined;var x=e[y]["exit"]||undefined;if(k(v)){if(t!==undefined&&!g[y]){A.push(t)}g[y]=true}else{if(x!==undefined&&g[y]){z.push(x)}g[y]=false}}for(var w=0;w<z.length;w++){z[w].call()}for(var u=0;u<A.length;u++){A[u].call()}};var r=function(u){for(var t=0;t<o.length;t++){if(u>=o[t]["enter"]&&u<=o[t]["exit"]&&s!==o[t]["label"]){s=o[t]["label"];q()}}};var k=function(t){if(typeof t==="object"){if(t.join().indexOf(s)>=0){return true}}else{if(typeof t==="string"){if(s===t){return true}}}};var f=function(){var t=i();if(t!==d){j=m;r(t)}else{j=p}d=t;setTimeout(f,j)};f();return{addFunc:function(t){h(t)}}}}(this,this.document));<commit_msg>Updated min file<commit_after>/*
	jRespond.js (a simple way to globally manage javascript on responsive websites)
	version 0.7.2
	(c) 2012 Jeremy Fields [jeremy.fields@viget.com]
	released under the MIT license
*/
(function(b,a,c){b.jRespond=function(l){var e=[];var g=[];var o=l;var s="";var n;var d=0;var m=100;var p=500;var j=p;var i=function(){var t=0;if(!window.innerWidth){if(!(document.documentElement.clientWidth===0)){t=document.documentElement.clientWidth}else{t=document.body.clientWidth}}else{t=window.innerWidth}return t};var h=function(v){var u=v.breakpoint;var t=v.enter||c;e.push(v);g.push(false);if(k(u)){if(t!==c){t.call()}g[(e.length-1)]=true}};var q=function(){var A=[],z=[];for(var y=0;y<e.length;y++){var v=e[y]["breakpoint"];var t=e[y]["enter"]||c;var x=e[y]["exit"]||c;if(k(v)){if(t!==c&&!g[y]){A.push(t)}g[y]=true}else{if(x!==c&&g[y]){z.push(x)}g[y]=false}}for(var w=0;w<z.length;w++){z[w].call()}for(var u=0;u<A.length;u++){A[u].call()}};var r=function(u){for(var t=0;t<o.length;t++){if(u>=o[t]["enter"]&&u<=o[t]["exit"]&&s!==o[t]["label"]){s=o[t]["label"];q()}}};var k=function(t){if(typeof t==="object"){if(t.join().indexOf(s)>=0){return true}}else{if(typeof t==="string"){if(s===t){return true}}}};var f=function(){var t=i();if(t!==d){j=m;r(t)}else{j=p}d=t;setTimeout(f,j)};f();return{addFunc:function(t){h(t)}}}}(this,this.document));<|endoftext|>


<commit_before>(function($) {
    var passy = {
        character: { DIGIT: 1, LOWERCASE: 2, UPPERCASE: 4, PUNCTUATION: 8 },
        strength: { LOW: 0, MEDIUM: 1, HIGH: 2, EXTREME: 3 },

        dictionary: [],

        patterns: [
            '0123456789',
            'abcdefghijklmnopqrstuvwxyz',
            'qwertyuiopasdfghjklzxcvbnm',
            'azertyuiopqsdfghjklmwxcvbn',
            '!#$*+-.:?@^'
        ],

        threshold: {
            medium: 16,
            high: 22,
            extreme: 36
        }
    };

    passy.requirements = {
        characters: passy.character.DIGIT | passy.character.LOWERCASE | passy.character.UPPERCASE,
        length: {
            min: 6,
            max: Infinity
        }
    };

    if(Object.seal) {
        Object.seal(passy.character);
        Object.seal(passy.strength);
    }

    if(Object.freeze) {
        Object.freeze(passy.character);
        Object.freeze(passy.strength);
    }

    passy.analize = function(password) {
        var score = Math.floor(password.length * 2);
        var i = password.length;

        score += $.passy.analizePatterns(password);
        score += $.passy.analizeDictionary(password);

        while(i--) score += $.passy.analizeCharacter(password.charAt(i));

        return $.passy.analizeScore(score);
    };

    passy.analizeCharacter = function(character) {
        var code = character.charCodeAt(0);

        if(code >= 97 && code <= 122) return 1; // lower case
        if(code >= 48 && code <= 57) return 2;  // numeric
        if(code >= 65 && code <= 90) return 3;  // capital
        if(code <= 126) return 4;               // punctuation
        return 5;                               // foreign characters etc
    };

    passy.analizePattern = function(password, pattern) {
        var lastmatch = -1;
        var score = -2;

        for(var i = 0; i < password.length; i++) {
            var match = pattern.indexOf(password.charAt(i));

            if(lastmatch === match - 1) {
                lastmatch = match;
                score++;
            }
        }

        return Math.max(0, score);
    };

    passy.analizePatterns = function(password) {
        var chars = password.toLowerCase();
        var score = 0;

        for(var i in $.passy.patterns) {
            var pattern = $.passy.patterns[i].toLowerCase();
            score += $.passy.analizePattern(chars, pattern);
        }

        // patterns are bad man!
        return score * -5;
    };

    passy.analizeDictionary = function(password) {
        var chars = password.toLowerCase();
        var score = 0;

        for(var i in $.passy.dictionary) {
            var word = $.passy.dictionary[i].toLowerCase();

            if(password.indexOf(word) >= 0) score++;
        }

        // using words are bad too!
        return score * -5;
    };

    passy.analizeScore = function(score) {
        if(score >= $.passy.threshold.extreme) return $.passy.strength.EXTREME;
        if(score >= $.passy.threshold.high) return $.passy.strength.HIGH;
        if(score >= $.passy.threshold.medium) return $.passy.strength.MEDIUM;

        return $.passy.strength.LOW;
    };

    passy.generate = function(len) {
        var chars = [
            '0123456789',
            'abcdefghijklmnopqrstuvwxyz',
            'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
            '!#$&()*+<=>@[]^'
        ];

        var password = [];
        var type, index;

        len = Math.max(len, $.passy.requirements.length.min);
        len = Math.min(len, $.passy.requirements.length.max);

        while(len--) {
            type = len % chars.length;
            index = Math.floor(Math.random() * chars[type].length);
            password.push(chars[type].charAt(index));
        }

        password.sort(function() {
            return Math.random() * 2 - 1;
        });

        return password.join('');
    };

    passy.contains = function(str, character) {
        if(character === $.passy.character.DIGIT) {
            return /\d/.test(str);
        } else if(character === $.passy.character.LOWERCASE) {
            return /[a-z]/.test(str);
        } else if(character === $.passy.character.UPPERCASE) {
            return /[A-Z]/.test(str);
        } else if(character === $.passy.character.PUNCTUATION) {
            return /[!"#$%&'()*+,\-./:;<=>?@[\\]\^_`{\|}~]/.test(str);
        }
    };

    passy.valid = function(str) {
        var valid = true;

        if(!$.passy.requirements) return true;

        if(str.length < $.passy.requirements.length.min) return false;
        if(str.length > $.passy.requirements.length.max) return false;

        for(var i in $.passy.character) {
            if($.passy.requirements.characters & $.passy.character[i]) {
                valid = $.passy.contains(str, $.passy.character[i]) && valid;
            }
        }

        return valid;
    };

    var methods = {
        init: function(callback) {
            var $this = $(this);

            $this.on('change keyup', function() {
                if(typeof callback !== 'function') return;

                var value = $this.val();
                callback.call($this, $.passy.analize(value), methods.valid.call($this));
            });
        },

        generate: function(len) {
            this.val($.passy.generate(len));
            this.change();
        },

        valid: function() {
            return $.passy.valid(this.val());
        }
    };

    $.fn.passy = function(opt) {
        if(methods[opt]) {
            return methods[opt].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof opt === 'function' || !opt) {
            return methods.init.apply(this, arguments);
        }

        return this;
    };

    $.extend({ passy: passy });
})(jQuery);
<commit_msg>Added header with license<commit_after>/*
 * jQuery Passy
 * Generating and analazing passwords, realtime.
 *
 * Tim Severien
 * http://timseverien.nl
 *
 * Copyright (c) 2013 Tim Severien
 * Released under the GPLv2 license.
 *
 */

(function($) {
	var passy = {
		character: { DIGIT: 1, LOWERCASE: 2, UPPERCASE: 4, PUNCTUATION: 8 },
		strength: { LOW: 0, MEDIUM: 1, HIGH: 2, EXTREME: 3 },

		dictionary: [],

		patterns: [
			'0123456789',
			'abcdefghijklmnopqrstuvwxyz',
			'qwertyuiopasdfghjklzxcvbnm',
			'azertyuiopqsdfghjklmwxcvbn',
			'!#$*+-.:?@^'
		],

		threshold: {
			medium: 16,
			high: 22,
			extreme: 36
		}
	};

	passy.requirements = {
		characters: passy.character.DIGIT | passy.character.LOWERCASE | passy.character.UPPERCASE,
		length: {
			min: 6,
			max: Infinity
		}
	};

	if(Object.seal) {
		Object.seal(passy.character);
		Object.seal(passy.strength);
	}

	if(Object.freeze) {
		Object.freeze(passy.character);
		Object.freeze(passy.strength);
	}

	passy.analize = function(password) {
		var score = Math.floor(password.length * 2);
		var i = password.length;

		score += $.passy.analizePatterns(password);
		score += $.passy.analizeDictionary(password);

		while(i--) score += $.passy.analizeCharacter(password.charAt(i));

		return $.passy.analizeScore(score);
	};

	passy.analizeCharacter = function(character) {
		var code = character.charCodeAt(0);

		if(code >= 97 && code <= 122) return 1;   // lower case
		if(code >= 48 && code <= 57) return 2;    // numeric
		if(code >= 65 && code <= 90) return 3;    // capital
		if(code <= 126) return 4;                 // punctuation
		return 5;                                 // foreign characters etc
	};

	passy.analizePattern = function(password, pattern) {
		var lastmatch = -1;
		var score = -2;

		for(var i = 0; i < password.length; i++) {
			var match = pattern.indexOf(password.charAt(i));

			if(lastmatch === match - 1) {
				lastmatch = match;
				score++;
			}
		}

		return Math.max(0, score);
	};

	passy.analizePatterns = function(password) {
		var chars = password.toLowerCase();
		var score = 0;

		for(var i in $.passy.patterns) {
			var pattern = $.passy.patterns[i].toLowerCase();
			score += $.passy.analizePattern(chars, pattern);
		}

		// patterns are bad man!
		return score * -5;
	};

	passy.analizeDictionary = function(password) {
		var chars = password.toLowerCase();
		var score = 0;

		for(var i in $.passy.dictionary) {
			var word = $.passy.dictionary[i].toLowerCase();

			if(password.indexOf(word) >= 0) score++;
		}

		// using words are bad too!
		return score * -5;
	};

	passy.analizeScore = function(score) {
		if(score >= $.passy.threshold.extreme) return $.passy.strength.EXTREME;
		if(score >= $.passy.threshold.high) return $.passy.strength.HIGH;
		if(score >= $.passy.threshold.medium) return $.passy.strength.MEDIUM;

		return $.passy.strength.LOW;
	};

	passy.generate = function(len) {
		var chars = [
			'0123456789',
			'abcdefghijklmnopqrstuvwxyz',
			'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
			'!#$&()*+<=>@[]^'
		];

		var password = [];
		var type, index;

		len = Math.max(len, $.passy.requirements.length.min);
		len = Math.min(len, $.passy.requirements.length.max);

		while(len--) {
			type = len % chars.length;
			index = Math.floor(Math.random() * chars[type].length);
			password.push(chars[type].charAt(index));
		}

		password.sort(function() {
			return Math.random() * 2 - 1;
		});

		return password.join('');
	};

	passy.contains = function(str, character) {
		if(character === $.passy.character.DIGIT) {
			return /\d/.test(str);
		} else if(character === $.passy.character.LOWERCASE) {
			return /[a-z]/.test(str);
		} else if(character === $.passy.character.UPPERCASE) {
			return /[A-Z]/.test(str);
		} else if(character === $.passy.character.PUNCTUATION) {
			return /[!"#$%&'()*+,\-./:;<=>?@[\\]\^_`{\|}~]/.test(str);
		}
	};

	passy.valid = function(str) {
		var valid = true;

		if(!$.passy.requirements) return true;

		if(str.length < $.passy.requirements.length.min) return false;
		if(str.length > $.passy.requirements.length.max) return false;

		for(var i in $.passy.character) {
			if($.passy.requirements.characters & $.passy.character[i]) {
				valid = $.passy.contains(str, $.passy.character[i]) && valid;
			}
		}

		return valid;
	};

	var methods = {
		init: function(callback) {
			var $this = $(this);

			$this.on('change keyup', function() {
				if(typeof callback !== 'function') return;

				var value = $this.val();
				callback.call($this, $.passy.analize(value), methods.valid.call($this));
			});
		},

		generate: function(len) {
			this.val($.passy.generate(len));
			this.change();
		},

		valid: function() {
			return $.passy.valid(this.val());
		}
	};

	$.fn.passy = function(opt) {
		if(methods[opt]) {
			return methods[opt].apply(this, Array.prototype.slice.call(arguments, 1));
		} else if (typeof opt === 'function' || !opt) {
			return methods.init.apply(this, arguments);
		}

		return this;
	};

	$.extend({ passy: passy });
})(jQuery);
<|endoftext|>