<commit_before>// Form Validation Functions  v2.0
// http://www.dithered.com/javascript/form_validation/index.html
// code by Chris Nott (chris@dithered.com)
// modified by Kruttik Aggarwal

function validateFields(formFields) {
   validForm=true;
   // loop thru all form elements
   for (var elementIndex = 0; elementIndex < formFields.length; elementIndex++) {
      var element = formFields[elementIndex];
   	  ValidationManager.removeError(element);
      // text and textarea types
      if (element.type == "text" || element.type == "textarea") {
         element.value = trimWhitespace(element.value)

         // required element
         if (element.required  && element.value == '') {
            ValidationManager.showError(element,element.requiredError);
            validForm=false;
            continue;

         }

         // maximum length
         if (element.maxlength && isValidLength(element.value, 0, element.maxlength) == false) {
            ValidationManager.showError(element,element.maxlengthError);
            validForm=false;
            continue;
         }

         // minimum length
         if (element.minlength && isValidLength(element.value, element.minlength, Number.MAX_VALUE) == false) {
            ValidationManager.showError(element,element.minlengthError);
            validForm=false;
            continue;
         }

         // pattern (credit card number, email address, zip or postal code, alphanumeric, numeric)
         if (element.pattern) {
            if ( ( (element.pattern.toLowerCase() == 'visa' || element.pattern.toLowerCase() == 'mastercard' || element.pattern.toLowerCase() == 'american express' || element.pattern.toLowerCase() == 'diners club' || element.pattern.toLowerCase() == 'discover' || element.pattern.toLowerCase() == 'enroute' || element.pattern.toLowerCase() == 'jcb' || element.pattern.toLowerCase() == 'credit card') && isValidCreditCard(element.value, element.pattern) == false) ||
                  (element.pattern.toLowerCase() == 'email' && isValidEmailStrict(element.value) == false) ||
                  (element.pattern.toLowerCase() == 'zip_postal_code' && isValidZipcode(element.value) == false && isValidPostalcode(element.value) == false) ||
                  (element.pattern.toLowerCase() == 'zipcode' && isValidZipcode(element.value) == false) ||
                  (element.pattern.toLowerCase() == 'postal code' && isValidPostalcode(element.value) == false) ||
                  (element.pattern.toLowerCase() == 'us_phone_no' &&
                     ( (element.prefix && element.suffix && isValidUSPhoneNumber(element.value, form[element.prefix].value, form[element.suffix].value) == false) ||
                        (!element.prefix && !element.suffix && isValidUSPhoneNumber(element.value) == false) ) ) ||
                  (element.pattern.toLowerCase() == 'alphanumeric' && isAlphanumeric(element.value, true) == false) ||
                  (element.pattern.toLowerCase() == 'numeric' && isNumeric(element.value, true) == false) ||
                  (element.pattern.toLowerCase() == 'alphabetic' && isAlphabetic(element.value, true) == false) ||
                  (element.pattern.toLowerCase().indexOf('date') == 0 && isCorrectDate(element.value) == false)) {
               ValidationManager.showError(element,element.patternError);
               validForm=false;
               continue;
            }
         }
      }

      // password
      else if (element.type == "password") {

         // required element
         if (element.required  && element.value == '') {
            ValidationManager.showError(element,element.requiredError);
            validForm=false;
            continue;
         }

         // maximum length
         if (element.maxlength && isValidLength(element.value, 0, element.maxlength) == false) {
            ValidationManager.showError(element,element.maxLengthError);
            validForm=false;
            continue;
         }

         // minimum length
         if (element.minlength && isValidLength(element.value, element.minlength, Number.MAX_VALUE) == false) {
            ValidationManager.showError(element,element.minLengthError);
            validForm=false;
            continue;
         }
      }

      // file upload
      if (element.type == "file") {

         // required element
         if (element.required  && element.value == '') {
            ValidationManager.showError(element,element.requiredError);
            validForm=false;
            continue;
         }
      }

      // select
      else if (element.type == "select-one" || element.type == "select-multiple" || element.type == "select") {
		//alert("12.4:select element")
         // required element
         if (element.required && (element.selectedIndex == -1 || element.options[element.selectedIndex].value == '')) {
            ValidationManager.showError(element,element.requiredError);
            validForm=false;
            continue;
         }

       // disallow empty value selection
         if (element.disallowEmptyValue && element.options[element.selectedIndex].value == '') {
            ValidationManager.showError(element,element.disallowEmptyValueError);
            validForm=false;
            continue;
         }

      }

      // radio buttons
      else if (element.type == "radio") {
         var radiogroup = form.elements[element.name];

         // required element
         if (radiogroup.length && radiogroup[0] && radiogroup[0].required) {
            var checkedRadioButton = -1;
            for (var radioIndex = 0; radioIndex < radiogroup.length; radioIndex++) {
               if (radiogroup[radioIndex].checked == true) {
                  checkedRadioButton = radioIndex;
                  break;
               }
            }

            // show error if required and flag group as having been tested
            if (checkedRadioButton == -1 && !radiogroup.tested) {
               ValidationManager.showError(element,radiogroup[0].requiredError);
               validForm=false;
               radiogroup.tested = true;
               continue;
            }

            // last radio button in group?  reset tested flag
            if (element == radiogroup[radiogroup.length - 1]) {
               radiogroup.tested = false;
            }
         }

         radiogroup = null;
      }
   }
   return validForm;
}

// Check that the number of characters in a string is between a max and a min
function isValidLength(string, min, max) {
   if (string.length < min || string.length > max) return false;
   else return true;
}

// Check that a credit card number is valid based using the LUHN formula (mod10 is 0)
function isValidCreditCard(number) {
   number = '' + number;

   if (number.length > 16 || number.length < 13 ) return false;
   else if (getMod10(number) != 0) return false;
   else if (arguments[1]) {
      var type = arguments[1];
      var first2digits = number.substring(0, 2);
      var first4digits = number.substring(0, 4);

      if (type.toLowerCase() == 'visa' && number.substring(0, 1) == 4 &&
         (number.length == 16 || number.length == 13 )) return true;
      else if (type.toLowerCase() == 'mastercard' && number.length == 16 &&
         (first2digits == '51' || first2digits == '52' || first2digits == '53' || first2digits == '54' || first2digits == '55')) return true;
      else if (type.toLowerCase() == 'american express' && number.length == 15 &&
         (first2digits == '34' || first2digits == '37')) return true;
      else if (type.toLowerCase() == 'diners club' && number.length == 14 &&
         (first2digits == '30' || first2digits == '36' || first2digits == '38')) return true;
      else if (type.toLowerCase() == 'discover' && number.length == 16 && first4digits == '6011') return true;
      else if (type.toLowerCase() == 'enroute' && number.length == 15 &&
         (first4digits == '2014' || first4digits == '2149')) return true;
      else if (type.toLowerCase() == 'jcb' && number.length == 16 &&
         (first4digits == '3088' || first4digits == '3096' || first4digits == '3112' || first4digits == '3158' || first4digits == '3337' || first4digits == '3528')) return true;

    // if the above card types are all the ones that the site accepts, change the line below to 'else return false'
    else return true;
   }
   else return true;
}

// Check that an email address is valid based on RFC 821 (?)
function isValidEmail(address) {
   if (address != '' && address.search) {
      if (address.search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/) != -1) return true;
      else return false;
   }

   // allow empty strings to return true - screen these with either a 'required' test or a 'length' test
   else return true;
}

// Check that an email address has the form something@something.something
// This is a stricter standard than RFC 821 (?) which allows addresses like postmaster@localhost
function isValidEmailStrict(address) {
   if (isValidEmail(address) == false) return false;
   var domain = address.substring(address.indexOf('@') + 1);
   if (domain.indexOf('.') == -1) return false;
   if (domain.indexOf('.') == 0 || domain.indexOf('.') == domain.length - 1) return false;
   return true;
}

// Check that a US zip code is valid
function isValidZipcode(zipcode) {
   zipcode = removeSpaces(zipcode);
   if (!(zipcode.length == 5 || zipcode.length == 9 || zipcode.length == 10)) return false;
   if ((zipcode.length == 5 || zipcode.length == 9) && !isNumeric(zipcode)) return false;
   if (zipcode.length == 10 && zipcode.search && zipcode.search(/^\d{5}-\d{4}$/) == -1) return false;
   return true;
}

// Check that a Canadian postal code is valid
function isValidPostalcode(postalcode) {
   if (postalcode.search) {
      postalcode = removeSpaces(postalcode);
      if (postalcode.length == 6 && postalcode.search(/^[a-zA-Z]\d[a-zA-Z]\d[a-zA-Z]\d$/) != -1) return true;
      else if (postalcode.length == 7 && postalcode.search(/^[a-zA-Z]\d[a-zA-Z]-\d[a-zA-Z]\d$/) != -1) return true;
      else return false;
   }
   return true;
}

// Check that a US or Canadian phone number is valid
function isValidUSPhoneNumber(areaCode, prefixNumber, suffixNumber) {
   if (arguments.length == 1) {
      var phoneNumber = arguments[0];
      phoneNumber = phoneNumber.replace(/\D+/g, '');
      var length = phoneNumber.length;
      if (phoneNumber.length >= 7) {
         var areaCode = phoneNumber.substring(0, length-7);
         var prefixNumber = phoneNumber.substring(length-7, length-4);
         var suffixNumber = phoneNumber.substring(length-4);
      }
      else return false;
   }
   else if (arguments.length == 3) {
      var areaCode = arguments[0];
      var prefixNumber = arguments[1];
      var suffixNumber = arguments[2];
   }
   else return true;

   if (areaCode.length != 3 || !isNumeric(areaCode) || prefixNumber.length != 3 || !isNumeric(prefixNumber) || suffixNumber.length != 4 || !isNumeric(suffixNumber)) return false;
   return true;
}

// Check that a string contains only letters and numbers
function isAlphanumeric(string, ignoreWhiteSpace) {
   if (string.search) {
      if ((ignoreWhiteSpace && string.search(/[^\w\s]/) != -1) || (!ignoreWhiteSpace && string.search(/\W/) != -1)) return false;
   }
   return true;
}

// Check that a string contains only letters
function isAlphabetic(string, ignoreWhiteSpace) {
   if (string.search) {
      if ((ignoreWhiteSpace && string.search(/[^a-zA-Z\s]/) != -1) || (!ignoreWhiteSpace && string.search(/[^a-zA-Z]/) != -1)) return false;
   }
   return true;
}

// Check that a string contains only numbers
function isNumeric(string, ignoreWhiteSpace) {
   if (string.search) {
      if ((ignoreWhiteSpace && string.search(/[^\d\s]/) != -1) || (!ignoreWhiteSpace && string.search(/\D/) != -1)) return false;
   }
   return true;
}

// Check that a string contains only numbers
function isCorrectDate(string) {
   DEFAULT_DATE_FORMAT="mm/dd/yyyy";
   if(string=="")
   	return true;
   string=trimWhitespace(string);
   if(string.indexOf("(")>0 && string.indexOf(")")>string.lastIndexOf("(")){
   	   format=string.substring(string.indexOf("(")+1,tring.lastIndexOf("(")-1);
   	   date=string.substring(0,string.indexOf("(")-1);
   }else{
   	   format=DEFAULT_DATE_FORMAT;
   	   date=string;
   }
   return isDate(date,format)
}

// Remove characters that might cause security problems from a string
function removeBadCharacters(string) {
   if (string.replace) {
      string.replace(/[<>\"\'%;\)\(&\+]/, '');
   }
   return string;
}

// Remove all spaces from a string
function removeSpaces(string) {
   var newString = '';
   for (var i = 0; i < string.length; i++) {
      if (string.charAt(i) != ' ') newString += string.charAt(i);
   }
   return newString;
}

// Remove leading and trailing whitespace from a string
function trimWhitespace(string) {
   var newString  = '';
   var substring  = '';
   beginningFound = false;

   // copy characters over to a new string
   // retain whitespace characters if they are between other characters
   for (var i = 0; i < string.length; i++) {

      // copy non-whitespace characters
      if (string.charAt(i) != ' ' && string.charCodeAt(i) != 9) {

         // if the temporary string contains some whitespace characters, copy them first
         if (substring != '') {
            newString += substring;
            substring = '';
         }
         newString += string.charAt(i);
         if (beginningFound == false) beginningFound = true;
      }

      // hold whitespace characters in a temporary string if they follow a non-whitespace character
      else if (beginningFound == true) substring += string.charAt(i);
   }
   return newString;
}

// Returns a checksum digit for a number using mod 10
function getMod10(number) {

   // convert number to a string and check that it contains only digits
   // return -1 for illegal input
   number = '' + number;
   number = removeSpaces(number);
   if (!isNumeric(number)) return -1;

   // calculate checksum using mod10
   var checksum = 0;
   for (var i = number.length - 1; i >= 0; i--) {
      var isOdd = ((number.length - i) % 2 != 0) ? true : false;
      digit = number.charAt(i);

      if (isOdd) checksum += parseInt(digit);
      else {
         var evenDigit = parseInt(digit) * 2;
         if (evenDigit >= 10) checksum += 1 + (evenDigit - 10);
         else checksum += evenDigit;
      }
   }
   return (checksum % 10);
}
<commit_msg>phone number validation now allows blank strings...thereby making the field non-mandatory.<commit_after>// Form Validation Functions  v2.0
// http://www.dithered.com/javascript/form_validation/index.html
// code by Chris Nott (chris@dithered.com)
// modified by Kruttik Aggarwal

function validateFields(formFields) {
   validForm=true;
   // loop thru all form elements
   for (var elementIndex = 0; elementIndex < formFields.length; elementIndex++) {
      var element = formFields[elementIndex];
   	  ValidationManager.removeError(element);
      // text and textarea types
      if (element.type == "text" || element.type == "textarea") {
         element.value = trimWhitespace(element.value)

         // required element
         if (element.required  && element.value == '') {
            ValidationManager.showError(element,element.requiredError);
            validForm=false;
            continue;

         }

         // maximum length
         if (element.maxlength && isValidLength(element.value, 0, element.maxlength) == false) {
            ValidationManager.showError(element,element.maxlengthError);
            validForm=false;
            continue;
         }

         // minimum length
         if (element.minlength && isValidLength(element.value, element.minlength, Number.MAX_VALUE) == false) {
            ValidationManager.showError(element,element.minlengthError);
            validForm=false;
            continue;
         }

         // pattern (credit card number, email address, zip or postal code, alphanumeric, numeric)
         if (element.pattern) {
            if ( ( (element.pattern.toLowerCase() == 'visa' || element.pattern.toLowerCase() == 'mastercard' || element.pattern.toLowerCase() == 'american express' || element.pattern.toLowerCase() == 'diners club' || element.pattern.toLowerCase() == 'discover' || element.pattern.toLowerCase() == 'enroute' || element.pattern.toLowerCase() == 'jcb' || element.pattern.toLowerCase() == 'credit card') && isValidCreditCard(element.value, element.pattern) == false) ||
                  (element.pattern.toLowerCase() == 'email' && isValidEmailStrict(element.value) == false) ||
                  (element.pattern.toLowerCase() == 'zip_postal_code' && isValidZipcode(element.value) == false && isValidPostalcode(element.value) == false) ||
                  (element.pattern.toLowerCase() == 'zipcode' && isValidZipcode(element.value) == false) ||
                  (element.pattern.toLowerCase() == 'postal code' && isValidPostalcode(element.value) == false) ||
                  (element.pattern.toLowerCase() == 'us_phone_no' &&
                     ( (element.prefix && element.suffix && isValidUSPhoneNumber(element.value, form[element.prefix].value, form[element.suffix].value) == false) ||
                        (!element.prefix && !element.suffix && isValidUSPhoneNumber(element.value) == false) ) ) ||
                  (element.pattern.toLowerCase() == 'alphanumeric' && isAlphanumeric(element.value, true) == false) ||
                  (element.pattern.toLowerCase() == 'numeric' && isNumeric(element.value, true) == false) ||
                  (element.pattern.toLowerCase() == 'alphabetic' && isAlphabetic(element.value, true) == false) ||
                  (element.pattern.toLowerCase().indexOf('date') == 0 && isCorrectDate(element.value) == false)) {
               ValidationManager.showError(element,element.patternError);
               validForm=false;
               continue;
            }
         }
      }

      // password
      else if (element.type == "password") {

         // required element
         if (element.required  && element.value == '') {
            ValidationManager.showError(element,element.requiredError);
            validForm=false;
            continue;
         }

         // maximum length
         if (element.maxlength && isValidLength(element.value, 0, element.maxlength) == false) {
            ValidationManager.showError(element,element.maxLengthError);
            validForm=false;
            continue;
         }

         // minimum length
         if (element.minlength && isValidLength(element.value, element.minlength, Number.MAX_VALUE) == false) {
            ValidationManager.showError(element,element.minLengthError);
            validForm=false;
            continue;
         }
      }

      // file upload
      if (element.type == "file") {

         // required element
         if (element.required  && element.value == '') {
            ValidationManager.showError(element,element.requiredError);
            validForm=false;
            continue;
         }
      }

      // select
      else if (element.type == "select-one" || element.type == "select-multiple" || element.type == "select") {
		//alert("12.4:select element")
         // required element
         if (element.required && (element.selectedIndex == -1 || element.options[element.selectedIndex].value == '')) {
            ValidationManager.showError(element,element.requiredError);
            validForm=false;
            continue;
         }

       // disallow empty value selection
         if (element.disallowEmptyValue && element.options[element.selectedIndex].value == '') {
            ValidationManager.showError(element,element.disallowEmptyValueError);
            validForm=false;
            continue;
         }

      }

      // radio buttons
      else if (element.type == "radio") {
         var radiogroup = form.elements[element.name];

         // required element
         if (radiogroup.length && radiogroup[0] && radiogroup[0].required) {
            var checkedRadioButton = -1;
            for (var radioIndex = 0; radioIndex < radiogroup.length; radioIndex++) {
               if (radiogroup[radioIndex].checked == true) {
                  checkedRadioButton = radioIndex;
                  break;
               }
            }

            // show error if required and flag group as having been tested
            if (checkedRadioButton == -1 && !radiogroup.tested) {
               ValidationManager.showError(element,radiogroup[0].requiredError);
               validForm=false;
               radiogroup.tested = true;
               continue;
            }

            // last radio button in group?  reset tested flag
            if (element == radiogroup[radiogroup.length - 1]) {
               radiogroup.tested = false;
            }
         }

         radiogroup = null;
      }
   }
   return validForm;
}

// Check that the number of characters in a string is between a max and a min
function isValidLength(string, min, max) {
   if (string.length < min || string.length > max) return false;
   else return true;
}

// Check that a credit card number is valid based using the LUHN formula (mod10 is 0)
function isValidCreditCard(number) {
   number = '' + number;

   if (number.length > 16 || number.length < 13 ) return false;
   else if (getMod10(number) != 0) return false;
   else if (arguments[1]) {
      var type = arguments[1];
      var first2digits = number.substring(0, 2);
      var first4digits = number.substring(0, 4);

      if (type.toLowerCase() == 'visa' && number.substring(0, 1) == 4 &&
         (number.length == 16 || number.length == 13 )) return true;
      else if (type.toLowerCase() == 'mastercard' && number.length == 16 &&
         (first2digits == '51' || first2digits == '52' || first2digits == '53' || first2digits == '54' || first2digits == '55')) return true;
      else if (type.toLowerCase() == 'american express' && number.length == 15 &&
         (first2digits == '34' || first2digits == '37')) return true;
      else if (type.toLowerCase() == 'diners club' && number.length == 14 &&
         (first2digits == '30' || first2digits == '36' || first2digits == '38')) return true;
      else if (type.toLowerCase() == 'discover' && number.length == 16 && first4digits == '6011') return true;
      else if (type.toLowerCase() == 'enroute' && number.length == 15 &&
         (first4digits == '2014' || first4digits == '2149')) return true;
      else if (type.toLowerCase() == 'jcb' && number.length == 16 &&
         (first4digits == '3088' || first4digits == '3096' || first4digits == '3112' || first4digits == '3158' || first4digits == '3337' || first4digits == '3528')) return true;

    // if the above card types are all the ones that the site accepts, change the line below to 'else return false'
    else return true;
   }
   else return true;
}

// Check that an email address is valid based on RFC 821 (?)
function isValidEmail(address) {
   if (address != '' && address.search) {
      if (address.search(/^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/) != -1) return true;
      else return false;
   }

   // allow empty strings to return true - screen these with either a 'required' test or a 'length' test
   else return true;
}

// Check that an email address has the form something@something.something
// This is a stricter standard than RFC 821 (?) which allows addresses like postmaster@localhost
function isValidEmailStrict(address) {
   if (isValidEmail(address) == false) return false;
   var domain = address.substring(address.indexOf('@') + 1);
   if (domain.indexOf('.') == -1) return false;
   if (domain.indexOf('.') == 0 || domain.indexOf('.') == domain.length - 1) return false;
   return true;
}

// Check that a US zip code is valid
function isValidZipcode(zipcode) {
   zipcode = removeSpaces(zipcode);
   if (!(zipcode.length == 5 || zipcode.length == 9 || zipcode.length == 10)) return false;
   if ((zipcode.length == 5 || zipcode.length == 9) && !isNumeric(zipcode)) return false;
   if (zipcode.length == 10 && zipcode.search && zipcode.search(/^\d{5}-\d{4}$/) == -1) return false;
   return true;
}

// Check that a Canadian postal code is valid
function isValidPostalcode(postalcode) {
   if (postalcode.search) {
      postalcode = removeSpaces(postalcode);
      if (postalcode.length == 6 && postalcode.search(/^[a-zA-Z]\d[a-zA-Z]\d[a-zA-Z]\d$/) != -1) return true;
      else if (postalcode.length == 7 && postalcode.search(/^[a-zA-Z]\d[a-zA-Z]-\d[a-zA-Z]\d$/) != -1) return true;
      else return false;
   }
   return true;
}

// Check that a US or Canadian phone number is valid
function isValidUSPhoneNumber(areaCode, prefixNumber, suffixNumber) {
   if (arguments.length == 1) {
      var phoneNumber = arguments[0];
      //return true if no value is entered.
      if(phoneNumber.length == 0){
      	return true;
      }
      phoneNumber = phoneNumber.replace(/\D+/g, '');
      var length = phoneNumber.length;
      if (phoneNumber.length >= 7) {
         var areaCode = phoneNumber.substring(0, length-7);
         var prefixNumber = phoneNumber.substring(length-7, length-4);
         var suffixNumber = phoneNumber.substring(length-4);
      }
      else return false;
   }
   else if (arguments.length == 3) {
      var areaCode = arguments[0];
      var prefixNumber = arguments[1];
      var suffixNumber = arguments[2];
   }
   else return true;

   if (areaCode.length != 3 || !isNumeric(areaCode) || prefixNumber.length != 3 || !isNumeric(prefixNumber) || suffixNumber.length != 4 || !isNumeric(suffixNumber)) return false;
   return true;
}

// Check that a string contains only letters and numbers
function isAlphanumeric(string, ignoreWhiteSpace) {
   if (string.search) {
      if ((ignoreWhiteSpace && string.search(/[^\w\s]/) != -1) || (!ignoreWhiteSpace && string.search(/\W/) != -1)) return false;
   }
   return true;
}

// Check that a string contains only letters
function isAlphabetic(string, ignoreWhiteSpace) {
   if (string.search) {
      if ((ignoreWhiteSpace && string.search(/[^a-zA-Z\s]/) != -1) || (!ignoreWhiteSpace && string.search(/[^a-zA-Z]/) != -1)) return false;
   }
   return true;
}

// Check that a string contains only numbers
function isNumeric(string, ignoreWhiteSpace) {
   if (string.search) {
      if ((ignoreWhiteSpace && string.search(/[^\d\s]/) != -1) || (!ignoreWhiteSpace && string.search(/\D/) != -1)) return false;
   }
   return true;
}

// Check that a string contains only numbers
function isCorrectDate(string) {
   DEFAULT_DATE_FORMAT="mm/dd/yyyy";
   if(string=="")
   	return true;
   string=trimWhitespace(string);
   if(string.indexOf("(")>0 && string.indexOf(")")>string.lastIndexOf("(")){
   	   format=string.substring(string.indexOf("(")+1,tring.lastIndexOf("(")-1);
   	   date=string.substring(0,string.indexOf("(")-1);
   }else{
   	   format=DEFAULT_DATE_FORMAT;
   	   date=string;
   }
   return isDate(date,format)
}

// Remove characters that might cause security problems from a string
function removeBadCharacters(string) {
   if (string.replace) {
      string.replace(/[<>\"\'%;\)\(&\+]/, '');
   }
   return string;
}

// Remove all spaces from a string
function removeSpaces(string) {
   var newString = '';
   for (var i = 0; i < string.length; i++) {
      if (string.charAt(i) != ' ') newString += string.charAt(i);
   }
   return newString;
}

// Remove leading and trailing whitespace from a string
function trimWhitespace(string) {
   var newString  = '';
   var substring  = '';
   beginningFound = false;

   // copy characters over to a new string
   // retain whitespace characters if they are between other characters
   for (var i = 0; i < string.length; i++) {

      // copy non-whitespace characters
      if (string.charAt(i) != ' ' && string.charCodeAt(i) != 9) {

         // if the temporary string contains some whitespace characters, copy them first
         if (substring != '') {
            newString += substring;
            substring = '';
         }
         newString += string.charAt(i);
         if (beginningFound == false) beginningFound = true;
      }

      // hold whitespace characters in a temporary string if they follow a non-whitespace character
      else if (beginningFound == true) substring += string.charAt(i);
   }
   return newString;
}

// Returns a checksum digit for a number using mod 10
function getMod10(number) {

   // convert number to a string and check that it contains only digits
   // return -1 for illegal input
   number = '' + number;
   number = removeSpaces(number);
   if (!isNumeric(number)) return -1;

   // calculate checksum using mod10
   var checksum = 0;
   for (var i = number.length - 1; i >= 0; i--) {
      var isOdd = ((number.length - i) % 2 != 0) ? true : false;
      digit = number.charAt(i);

      if (isOdd) checksum += parseInt(digit);
      else {
         var evenDigit = parseInt(digit) * 2;
         if (evenDigit >= 10) checksum += 1 + (evenDigit - 10);
         else checksum += evenDigit;
      }
   }
   return (checksum % 10);
}
<|endoftext|>


<commit_before>// All DCP countries are ACP countries, also need to include the SRAP data
function bootstrapParties(partiesObject) {
  var parties = _.select(partiesObject, function(model) {
    return model.acp || model.srap;
  })
  return new Parties(parties);
}

//
// Parties
//
Party = Backbone.Model.extend({
  initialize: function(attrs, options) {
    if (attrs.iso2 != undefined){
      this.set('id', 'party:' + attrs.iso2);
    } else if (attrs.short_name){
      this.set('id', 'party:' + attrs.short_name);
    } else {
      throw 'Cannot create id for Party'
    }
  },
  decorateRegionSubregion: function(filters){
    var region, regionTitle, subregion, subregionTitle;

    region = this.get('region');
    regionTitle = filters.findWhere({attribute: 'region', value: region}).get('title')

    subregion = this.get('subregion');
    subregionTitle = filters.findWhere({attribute: 'subregion', value: subregion}).get('title')

    return {
      regionTitle: regionTitle,
      subregionTitle: subregionTitle
    }
  },
  decorateForDetailView: function(views, filters) {
    var _this = this;
    return _.chain(views)
      .map(function(view) {
        var filterAttribute = view.filterAttribute; // e.g. 'iif_or_plan'

        var filterDef = filters.definitions.findWhere({
          name: filterAttribute
        });
        var attributeTitle = filterDef.get('title'); // e.g. 'IIFs established'

        var choiceValue = _this.get(filterAttribute); // e.g. 'iif' - i.e. the model's value for the filterAttribute
        var choice = filters.findWhere({
          attribute: filterAttribute,
          value: choiceValue
        })
        if (choice == undefined || choiceTitle == '') {
          return
        }

        var attributeColour = choice.get('colour');
        var choiceTitle = choice.get('title');

        return {
          attributeTitle: attributeTitle,
          choiceTitle: choiceTitle,
          colour: attributeColour,
        }
      })
      .compact()
      .value();
  }
})

PartiesQueryCollection = Backbone.QueryCollection.extend({
  comparator: 'short_name',
  model: Party
})

Parties = PartiesQueryCollection.extend({
  initialize: function(models, options) {
    this._superset = new PartiesQueryCollection(models);
  },
  resetWithQuery: function(queryObject, filterAttribute) {
    queryObject["$and"] || (queryObject["$and"] = {});
    queryObject["$and"][filterAttribute]= {$ne: ''};
    var queryResult = this._superset.query(queryObject);
    this.reset(queryResult);
  },
  prepareMapRegionsData: function(attribute) {
    var partiesJSON = this.toJSON();
    // Get models with attribute
    // Reject SRAPs
    var models = _.chain(partiesJSON)
      .reject(function(i) {return i[attribute] === ''})
      .where({use_centre_point: false, srap: false })
      .value();
    // return mapped to ISO2
    var iso2s = _.pluck(models, 'iso2');
    var attributes = _.pluck(models, attribute);
    return _.object(iso2s, attributes)
  },
  prepareMapMarkersData: function(attribute) {
    var partiesJSON = this.toJSON();
    var models = _.chain(partiesJSON)
      .reject(function(i) {return i[attribute] === ''})
      .where({use_centre_point: true, srap: false, })
      .value();

    var markers = {};
    _.each(models, function(model){
      var marker = {
        name: model.short_name,
        latLng: [model.lat, model.lon],
        value: model[attribute]
      };
      markers[model.iso2] = marker;
    });
    return markers;
  }
});<commit_msg>refact creation of an object<commit_after>// All DCP countries are ACP countries, also need to include the SRAP data
function bootstrapParties(partiesObject) {
  var parties = _.select(partiesObject, function(model) {
    return model.acp || model.srap;
  })
  return new Parties(parties);
}

//
// Parties
//
Party = Backbone.Model.extend({
  initialize: function(attrs, options) {
    if (attrs.iso2 != undefined){
      this.set('id', 'party:' + attrs.iso2);
    } else if (attrs.short_name){
      this.set('id', 'party:' + attrs.short_name);
    } else {
      throw 'Cannot create id for Party'
    }
  },
  decorateRegionSubregion: function(filters){
    var region, regionTitle, subregion, subregionTitle;

    region = this.get('region');
    regionTitle = filters.findWhere({attribute: 'region', value: region}).get('title')

    subregion = this.get('subregion');
    subregionTitle = filters.findWhere({attribute: 'subregion', value: subregion}).get('title')

    return {
      regionTitle: regionTitle,
      subregionTitle: subregionTitle
    }
  },
  decorateForDetailView: function(views, filters) {
    var _this = this;
    return _.chain(views)
      .map(function(view) {
        var filterAttribute = view.filterAttribute; // e.g. 'iif_or_plan'

        var filterDef = filters.definitions.findWhere({
          name: filterAttribute
        });
        var attributeTitle = filterDef.get('title'); // e.g. 'IIFs established'

        var choiceValue = _this.get(filterAttribute); // e.g. 'iif' - i.e. the model's value for the filterAttribute
        var choice = filters.findWhere({
          attribute: filterAttribute,
          value: choiceValue
        })
        if (choice == undefined || choiceTitle == '') {
          return
        }

        var attributeColour = choice.get('colour');
        var choiceTitle = choice.get('title');

        return {
          attributeTitle: attributeTitle,
          choiceTitle: choiceTitle,
          colour: attributeColour,
        }
      })
      .compact()
      .value();
  }
})

PartiesQueryCollection = Backbone.QueryCollection.extend({
  comparator: 'short_name',
  model: Party
})

Parties = PartiesQueryCollection.extend({
  initialize: function(models, options) {
    // Create a Backbone.QueryCollection from the original models
    this._superset = new PartiesQueryCollection(models);
  },
  resetWithQuery: function(queryObject, filterAttribute) {
    queryObject["$and"] || (queryObject["$and"] = {});
    queryObject["$and"][filterAttribute]= {$ne: ''};

    // Pass the query to the Backbone.QueryCollection
    // and reset the Filters Collection to the result
    var queryResult = this._superset.query(queryObject);
    this.reset(queryResult);
  },
  prepareMapRegionsData: function(attribute) {
    // Get models with attribute set
    // Reject SRAPs
    var models = _.chain(this.toJSON())
      .reject(function(i) {return i[attribute] === ''})
      .where({use_centre_point: false, srap: false})
      .value();

    // return mapped to ISO2
    var iso2s = _.pluck(models, 'iso2');
    var attributes = _.pluck(models, attribute);
    return _.object(iso2s, attributes)
  },
  prepareMapMarkersData: function(attribute) {
    var models, markers;

    models = _.chain(this.toJSON())
      .reject(function(i) {return i[attribute] === ''})
      .where({use_centre_point: true, srap: false})
      .value();

    return _.object(
      _.map(models, function(model){
        return [model.iso2, {
          name: model.short_name,
          latLng: [model.lat, model.lon],
          value: model[attribute]
        }];
      })
    );
  }
});<|endoftext|>


<commit_before>module.exports = {

	//---------------------------------------------------------------------
	// Action Name
	//
	// This is the name of the action displayed in the editor.
	//---------------------------------------------------------------------

	name: "License",

	//---------------------------------------------------------------------
	// Action Section
	//
	// This is the section the action will fall into.
	//---------------------------------------------------------------------

	section: "#Mod Information",

	//---------------------------------------------------------------------
	// Action Subtitle
	//
	// This function generates the subtitle displayed next to the name.
	//---------------------------------------------------------------------

	subtitle: function (data) {
		return `Does nothing - Click "Edit" for more information`;
	},

	//---------------------------------------------------------------------
	// DBM Mods Manager Variables (Optional but nice to have!)
	//
	// These are variables that DBM Mods Manager uses to show information
	// about the mods for people to see in the list.
	//---------------------------------------------------------------------

	// Who made the mod (If not set, defaults to "DBM Mods")
	author: "DBM Network",

	// The version of the mod (Defaults to 1.0.0)
	version: "1.9.5", //Added in 1.8.5

	// A short description to show on the mod line for this mod (Must be on a single line)
	short_description: "MIT License",

	// If it depends on any other mods by name, ex: WrexMODS if the mod uses something from WrexMods

	//---------------------------------------------------------------------

	//---------------------------------------------------------------------
	// Action Storage Function
	//
	// Stores the relevant variable info for the editor.
	//---------------------------------------------------------------------

	//variableStorage: function(data, varType) {},

	//---------------------------------------------------------------------
	// Action Fields
	//
	// These are the fields for the action. These fields are customized
	// by creating elements with corresponding IDs in the HTML. These
	// are also the names of the fields stored in the action's JSON data.
	//---------------------------------------------------------------------

	fields: [],

	//---------------------------------------------------------------------
	// Command HTML
	//
	// This function returns a string containing the HTML used for
	// editting actions.
	//
	// The "isEvent" parameter will be true if this action is being used
	// for an event. Due to their nature, events lack certain information,
	// so edit the HTML to reflect this.
	//
	// The "data" parameter stores constants for select elements to use.
	// Each is an array: index 0 for commands, index 1 for events.
	// The names are: sendTargets, members, roles, channels,
	//                messages, servers, variables
	//---------------------------------------------------------------------

	html: function (isEvent, data) {
		return `

DBM Mods has no official affiliation with Discord or Discord Bot Maker.

MIT License

Copyright (c) 2017-2019 DBM Network

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

`
	},

	//---------------------------------------------------------------------
	// Action Editor Init Code
	//
	// When the HTML is first applied to the action editor, this code
	// is also run. This helps add modifications or setup reactionary
	// functions for the DOM elements.
	//---------------------------------------------------------------------

	init: function () { },

	//---------------------------------------------------------------------
	// Action Bot Function
	//
	// This is the function for the action within the Bot's Action class.
	// Keep in mind event calls won't have access to the "msg" parameter,
	// so be sure to provide checks for variable existance.
	//---------------------------------------------------------------------

	action: function (cache) { },

	//---------------------------------------------------------------------
	// Action Bot Mod
	//
	// Upon initialization of the bot, this code is run. Using the bot's
	// DBM namespace, one can add/modify existing functions if necessary.
	// In order to reduce conflictions between mods, be sure to alias
	// functions you wish to overwrite.
	//---------------------------------------------------------------------

	mod: function (DBM) {

		const fs = require('fs');
		const error = {
			'filler1': '======================================================',
			'filler2': '==================== DBM NETWORK ====================',
			'filler3': '=====================================================',

			'noderejection1': 'Error (0x012756): nodeRejection (DeprecatedServices)',
			'noderejection2': 'Please contact the discord mod support to resolve ',
			'noderejection3': 'this issue.',
			'noderejection4': 'Reference ID: blw82u0juxxbr7v2xdx209wii8o68wqt',

			'beta1': 'The DBM Network Mods are only meant to run on the',
			'beta2': 'Beta version of DBM! Please upgrade on steam, then',
			'beta3': 'try again, you may haveto make a new project and copy',
			'beta4': 'your data over!',

			'nwjs1': 'Mods are not guaranteed to work if you are running inside of DBM!',
			'nwjs2': 'Please use the command prompt or terminal and try again!',
		};
		if (process.argv[0].includes('\\steamapps\\common\\Discord Bot Maker')) {
			/* const files = fs.readdirSync(process.argv[0].replace('Discord Bot Maker.exe', ''))
			if (files.split(',').some(f => ['LAUNCHER.exe', 'LAUNCHER_x64.exe', 'SmartSteamEmu', 'SmartSteamEmu.dll', 'SmartSteamEmu.ini', 'SmartSteamEmu64.dll', 'GAMESTORRENT.CO.url', 'IGG - GAMES.COM.url'].includes(f))) {
				console.log('ERROR YOU HAVE CRACKED')
			} */
		}
		if (process.argv[0].includes('Discord Bot Maker')) {
			console.error(error.filler1);
			console.error(error.filler2);
			console.error(error.nwjs1);
			console.error(error.nwjs2);
			console.error(error.filler1);
			process.exit(1);
		} else if (process.argv[0].includes('Discord.Bot.Maker')) {
			console.error(error.filler3);
			console.error(error.filler2);
			console.error(error.noderejection1);
			console.error(error.noderejection2);
			console.error(error.noderejection3);
			console.error(error.noderejection4);
			console.error(error.filler3);
			process.exit(1);
		} else if (fs.readFileSync('./bot.js', 'utf8').length <= 2000 || !DBM.Audio) {
			console.error(error.filler3);
			console.error(error.filler2);
			console.error(error.beta1);
			console.error(error.beta2);
			console.error(error.beta3);
			console.error(error.beta4);
			console.error(error.filler3);
			process.exit(1);
		}
	}

}; // End of module
<commit_msg>removed a strange bug we noticed<commit_after>module.exports = {

	//---------------------------------------------------------------------
	// Action Name
	//
	// This is the name of the action displayed in the editor.
	//---------------------------------------------------------------------

	name: "License",

	//---------------------------------------------------------------------
	// Action Section
	//
	// This is the section the action will fall into.
	//---------------------------------------------------------------------

	section: "#Mod Information",

	//---------------------------------------------------------------------
	// Action Subtitle
	//
	// This function generates the subtitle displayed next to the name.
	//---------------------------------------------------------------------

	subtitle: function (data) {
		return `Does nothing - Click "Edit" for more information`;
	},

	//---------------------------------------------------------------------
	// DBM Mods Manager Variables (Optional but nice to have!)
	//
	// These are variables that DBM Mods Manager uses to show information
	// about the mods for people to see in the list.
	//---------------------------------------------------------------------

	// Who made the mod (If not set, defaults to "DBM Mods")
	author: "DBM Network",

	// The version of the mod (Defaults to 1.0.0)
	version: "1.9.5", //Added in 1.8.5

	// A short description to show on the mod line for this mod (Must be on a single line)
	short_description: "MIT License",

	// If it depends on any other mods by name, ex: WrexMODS if the mod uses something from WrexMods

	//---------------------------------------------------------------------

	//---------------------------------------------------------------------
	// Action Storage Function
	//
	// Stores the relevant variable info for the editor.
	//---------------------------------------------------------------------

	//variableStorage: function(data, varType) {},

	//---------------------------------------------------------------------
	// Action Fields
	//
	// These are the fields for the action. These fields are customized
	// by creating elements with corresponding IDs in the HTML. These
	// are also the names of the fields stored in the action's JSON data.
	//---------------------------------------------------------------------

	fields: [],

	//---------------------------------------------------------------------
	// Command HTML
	//
	// This function returns a string containing the HTML used for
	// editting actions.
	//
	// The "isEvent" parameter will be true if this action is being used
	// for an event. Due to their nature, events lack certain information,
	// so edit the HTML to reflect this.
	//
	// The "data" parameter stores constants for select elements to use.
	// Each is an array: index 0 for commands, index 1 for events.
	// The names are: sendTargets, members, roles, channels,
	//                messages, servers, variables
	//---------------------------------------------------------------------

	html: function (isEvent, data) {
		return `

DBM Mods has no official affiliation with Discord or Discord Bot Maker.

MIT License

Copyright (c) 2017-2019 DBM Network

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

`
	},

	//---------------------------------------------------------------------
	// Action Editor Init Code
	//
	// When the HTML is first applied to the action editor, this code
	// is also run. This helps add modifications or setup reactionary
	// functions for the DOM elements.
	//---------------------------------------------------------------------

	init: function () { },

	//---------------------------------------------------------------------
	// Action Bot Function
	//
	// This is the function for the action within the Bot's Action class.
	// Keep in mind event calls won't have access to the "msg" parameter,
	// so be sure to provide checks for variable existance.
	//---------------------------------------------------------------------

	action: function (cache) { },

	//---------------------------------------------------------------------
	// Action Bot Mod
	//
	// Upon initialization of the bot, this code is run. Using the bot's
	// DBM namespace, one can add/modify existing functions if necessary.
	// In order to reduce conflictions between mods, be sure to alias
	// functions you wish to overwrite.
	//---------------------------------------------------------------------

	mod: function (DBM) { }

}; // End of module
<|endoftext|>


<commit_before>'use strict';

const api = require('./api-util');

const MIN_IMAGE_SIZE = 64;
const MAX_IMAGE_WIDTH = 1280;

const SELECTORS = [
    'figure[typeof^=mw:Image]',
    'figure[typeof^=mw:Video]',
    'span[typeof^=mw:Image]',
    'span[typeof^=mw:Video]'
];

/**
 * A MediaWiki media type as represented in Parsoid HTML.
 * @param {!String} resourceSelector the selector for the child element containing the core resource
 * @param {!String} name the image type as referred to internally and in the endpoint response
 */
class MediaType {
    constructor(resourceSelector, name) {
        this.resourceSelector = resourceSelector;
        this.name = name;
    }
}

const Image = new MediaType('img', 'image');
const Video = new MediaType('video', 'video');
const Unknown = new MediaType(null, 'unknown');

function getMediaType(typeofAttr) {
    switch (typeofAttr.slice(0, 8)) {
        case 'mw:Image':
            return Image;
        case 'mw:Video':
            return Video;
        default:
            return Unknown;
    }
}

function getExtMetadataValues(extmetadata) {
    const ext = {};
    Object.keys(extmetadata).forEach((key) => {
        ext[key] = extmetadata[key].value;
    });
    return ext;
}

/**
 * Get file page titles from a NodeList of media elements from Parsoid HTML
 * @param {!NodeList} selection NodeList containing media items from Parsoid HTML
 * @return {!Array} array containing the information on the media items on the page, in order of
 *          appearance
 */
function getMediaItemInfoFromPage(selection) {
    return [].map.call(selection, (elem) => {
        const mediaType = getMediaType(elem.getAttribute('typeof'));
        const resourceElem = elem.querySelector(mediaType.resourceSelector);
        let startTime;
        let endTime;
        if (mediaType === Video) {
            const dataMw = JSON.parse(elem.getAttribute('data-mw'));
            if (dataMw) {
                startTime = dataMw.starttime;
                endTime = dataMw.endtime;
            }
        }
        return {
            title: resourceElem && resourceElem.getAttribute('resource').replace(/^.\//, ''),
            type: mediaType.name,
            start_time: startTime,
            end_time: endTime
        };
    });
}

function makeResults(items) {
    return items.map((item) => {
        const info =  item.videoinfo[0];
        return {
            title: item.title,
            url: info.url,
            thumbUrl: info.thumburl,
            mime: info.mime,
            width: info.width,
            height: info.height,
            size: info.size,
            derivatives: info.derivatives,
            ext: getExtMetadataValues(info.extmetadata)
        };
    });
}

function filterResult(item) {
    // Reject gallery items if they're too small.
    // Also reject SVG and PNG items by default, because they're likely to be
    // logos and/or presentational images.
    return item.url
        && item.width >= MIN_IMAGE_SIZE
        && item.height >= MIN_IMAGE_SIZE
        && !item.mime.includes('svg')
        && !item.mime.includes('png');
}

/**
 * Gets the gallery content from MW API
 * TODO: ensure that all media items are correctly accounted for on very large articles
 */
function getMetadataFromApi(app, req, titles) {
    const query = {
        action: 'query',
        format: 'json',
        formatversion: 2,
        prop: 'videoinfo',
        viprop: 'url|dimensions|mime|extmetadata|derivatives',
        viurlwidth: MAX_IMAGE_WIDTH,
        titles: titles.join('|'),
        continue: ''
    };
    return api.mwApiGet(app, req.params.domain, query).then((response) => {
        const pages = response.body.query && response.body.query.pages;
        const items = pages ? makeResults(pages) : [];
        return { items };
    });
}

module.exports = {
    getMediaItemInfoFromPage,
    getMetadataFromApi,
    filterResult,
    SELECTORS
};
<commit_msg>Media: Add figure-inline selectors to media selector list<commit_after>'use strict';

const api = require('./api-util');

const MIN_IMAGE_SIZE = 64;
const MAX_IMAGE_WIDTH = 1280;

const SELECTORS = [
    'figure[typeof^=mw:Image]',
    'figure[typeof^=mw:Video]',
    'span[typeof^=mw:Image]',
    'span[typeof^=mw:Video]',
    'figure-inline[typeof^=mw:Image]',
    'figure-inline[typeof^=mw:Video]'
];

/**
 * A MediaWiki media type as represented in Parsoid HTML.
 * @param {!String} resourceSelector the selector for the child element containing the core resource
 * @param {!String} name the image type as referred to internally and in the endpoint response
 */
class MediaType {
    constructor(resourceSelector, name) {
        this.resourceSelector = resourceSelector;
        this.name = name;
    }
}

const Image = new MediaType('img', 'image');
const Video = new MediaType('video', 'video');
const Unknown = new MediaType(null, 'unknown');

function getMediaType(typeofAttr) {
    switch (typeofAttr.slice(0, 8)) {
        case 'mw:Image':
            return Image;
        case 'mw:Video':
            return Video;
        default:
            return Unknown;
    }
}

function getExtMetadataValues(extmetadata) {
    const ext = {};
    Object.keys(extmetadata).forEach((key) => {
        ext[key] = extmetadata[key].value;
    });
    return ext;
}

/**
 * Get file page titles from a NodeList of media elements from Parsoid HTML
 * @param {!NodeList} selection NodeList containing media items from Parsoid HTML
 * @return {!Array} array containing the information on the media items on the page, in order of
 *          appearance
 */
function getMediaItemInfoFromPage(selection) {
    return [].map.call(selection, (elem) => {
        const mediaType = getMediaType(elem.getAttribute('typeof'));
        const resourceElem = elem.querySelector(mediaType.resourceSelector);
        let startTime;
        let endTime;
        if (mediaType === Video) {
            const dataMw = JSON.parse(elem.getAttribute('data-mw'));
            if (dataMw) {
                startTime = dataMw.starttime;
                endTime = dataMw.endtime;
            }
        }
        return {
            title: resourceElem && resourceElem.getAttribute('resource').replace(/^.\//, ''),
            type: mediaType.name,
            start_time: startTime,
            end_time: endTime
        };
    });
}

function makeResults(items) {
    return items.map((item) => {
        const info =  item.videoinfo[0];
        return {
            title: item.title,
            url: info.url,
            thumbUrl: info.thumburl,
            mime: info.mime,
            width: info.width,
            height: info.height,
            size: info.size,
            derivatives: info.derivatives,
            ext: getExtMetadataValues(info.extmetadata)
        };
    });
}

function filterResult(item) {
    // Reject gallery items if they're too small.
    // Also reject SVG and PNG items by default, because they're likely to be
    // logos and/or presentational images.
    return item.url
        && item.width >= MIN_IMAGE_SIZE
        && item.height >= MIN_IMAGE_SIZE
        && !item.mime.includes('svg')
        && !item.mime.includes('png');
}

/**
 * Gets the gallery content from MW API
 * TODO: ensure that all media items are correctly accounted for on very large articles
 */
function getMetadataFromApi(app, req, titles) {
    const query = {
        action: 'query',
        format: 'json',
        formatversion: 2,
        prop: 'videoinfo',
        viprop: 'url|dimensions|mime|extmetadata|derivatives',
        viurlwidth: MAX_IMAGE_WIDTH,
        titles: titles.join('|'),
        continue: ''
    };
    return api.mwApiGet(app, req.params.domain, query).then((response) => {
        const pages = response.body.query && response.body.query.pages;
        const items = pages ? makeResults(pages) : [];
        return { items };
    });
}

module.exports = {
    getMediaItemInfoFromPage,
    getMetadataFromApi,
    filterResult,
    SELECTORS
};
<|endoftext|>


<commit_before>/*global beforeEach,afterEach,describe,it*/
import { reset, check, expect, expectCount } from './helpers/chaiCounter'
import controller from './helpers/controller'
import copy from '../src/factories/copy'

beforeEach(reset)
afterEach(check)

let output
let resolveTest

const getAsync = args => new Promise(resolve => setTimeout(() => resolve('x'), 1))
const setAsync = (args, value) => new Promise(resolve => setTimeout(() => {
  output = value
  resolve()
}, 1))

controller.addSignals({
  customCopy: { chain: [copy(args => 'x', (args, val) => expect(val).to.equal('x'))], sync: true },
  asyncFromCopy: [
    [
      copy(getAsync, (args, val) => output = val),
      { success: [ () => resolveTest() ], error: [] }
    ]
  ],
  asyncToCopy: [
    [
      copy(args => 'x', setAsync),
      { success: [ () => resolveTest() ], error: [] }
    ]
  ],
  asyncFromToCopy: [
    [
      copy(getAsync, setAsync),
      { success: [ () => resolveTest() ], error: [] }
    ]
  ]
})
const signals = controller.getSignals()

describe('custom operators', function () {
  beforeEach(function () {
    output = null
  })

  it('gets the last', function () {
    expectCount(1)
    signals.customCopy()
  })

  it('should copy from an async source', function (done) {
    expectCount(0)
    resolveTest = () => done(output !== 'x' ? new Error('expected x') : undefined)
    signals.asyncFromCopy()
  })

  it('should copy to an async destination', function (done) {
    expectCount(0)
    resolveTest = () => done(output !== 'x' ? new Error('expected x') : undefined)
    signals.asyncToCopy()
  })

  it('should copy from an async source to an async destination', function (done) {
    expectCount(0)
    resolveTest = () => done(output !== 'x' ? new Error('expected x') : undefined)
    signals.asyncFromToCopy()
  })
})
<commit_msg>Add polyfills to customOperations tests<commit_after>/*global beforeEach,afterEach,describe,it*/
import './helpers/polyfills'
import { reset, check, expect, expectCount } from './helpers/chaiCounter'
import controller from './helpers/controller'
import copy from '../src/factories/copy'

beforeEach(reset)
afterEach(check)

let output
let resolveTest

const getAsync = args => new Promise(resolve => setTimeout(() => resolve('x'), 1))
const setAsync = (args, value) => new Promise(resolve => setTimeout(() => {
  output = value
  resolve()
}, 1))

controller.addSignals({
  customCopy: { chain: [copy(args => 'x', (args, val) => expect(val).to.equal('x'))], sync: true },
  asyncFromCopy: [
    [
      copy(getAsync, (args, val) => output = val),
      { success: [ () => resolveTest() ], error: [] }
    ]
  ],
  asyncToCopy: [
    [
      copy(args => 'x', setAsync),
      { success: [ () => resolveTest() ], error: [] }
    ]
  ],
  asyncFromToCopy: [
    [
      copy(getAsync, setAsync),
      { success: [ () => resolveTest() ], error: [] }
    ]
  ]
})
const signals = controller.getSignals()

describe('custom operators', function () {
  beforeEach(function () {
    output = null
  })

  it('gets the last', function () {
    expectCount(1)
    signals.customCopy()
  })

  it('should copy from an async source', function (done) {
    expectCount(0)
    resolveTest = () => done(output !== 'x' ? new Error('expected x') : undefined)
    signals.asyncFromCopy()
  })

  it('should copy to an async destination', function (done) {
    expectCount(0)
    resolveTest = () => done(output !== 'x' ? new Error('expected x') : undefined)
    signals.asyncToCopy()
  })

  it('should copy from an async source to an async destination', function (done) {
    expectCount(0)
    resolveTest = () => done(output !== 'x' ? new Error('expected x') : undefined)
    signals.asyncFromToCopy()
  })
})
<|endoftext|>


<commit_before>//Filter experiment or computation templates

Application.Filters.filter('byKey', function () {
    return function (items, key, value) {
        var matches = [];
        if (items) {
            if (key === 'assigned_to') {
                items.forEach(function (item) {
                    var i = _.indexOf(item[key], function (entry) {
                        return value === entry;
                    });
                    if (i > -1) {
                        matches.push(item);
                    }
                });
            } else {
                items.forEach(function (item) {
                    if (item[key] === value) {
                        matches.push(item);
                    }
                });
            }
        }
        return matches;
    };
});

Application.Filters.filter('removeKey', function () {
    return function (properties, keyToRemove) {
        var matches = {};
        if (properties) {
            angular.forEach(properties, function (value, key) {
                if (key !== keyToRemove) {
                    matches[key] = value;
                }
            });
        }
        return matches;
    };
});
<commit_msg>update to the filer<commit_after>//Filter experiment or computation templates

Application.Filters.filter('byKey', function () {
    return function (items, key, value) {
        var matches = [];
        if (items) {
            if (key === 'assigned_to') { //assigned_to field is an array.
                items.forEach(function (item) {
                    var i = _.indexOf(item[key], function (entry) {
                        return value === entry;
                    });
                    if (i > -1) {
                        if(item.status === 'open'){
                            matches.push(item);
                        }
                    }
                });
            } else {
                items.forEach(function (item) {
                    if (item[key] === value) {
                        matches.push(item);
                    }
                });
            }
        }
        return matches;
    };
});

Application.Filters.filter('removeKey', function () {
    return function (properties, keyToRemove) {
        var matches = {};
        if (properties) {
            angular.forEach(properties, function (value, key) {
                if (key !== keyToRemove) {
                    matches[key] = value;
                }
            });
        }
        return matches;
    };
});
<|endoftext|>


<commit_before>#!/usr/bin/env node
/**
 * @license Copyright 2019 The Lighthouse Authors. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
 */
'use strict';

/**
 * @fileoverview A smokehouse frontend for running from the command line. Parse
 * flags, start fixture webservers, then run smokehouse.
 */

/* eslint-disable no-console */

const path = require('path');
const cloneDeep = require('lodash.clonedeep');
const yargs = require('yargs');
const log = require('lighthouse-logger');
const {runSmokehouse} = require('../smokehouse.js');
const {updateTestDefnFormat} = require('./back-compat-util.js');

const coreTestDefnsPath = path.join(__dirname, '../test-definitions/core-tests.js');

/**
 * Possible Lighthouse runners. Loaded dynamically so e.g. a CLI run isn't
 * contingent on having built all the bundles.
 */
const runnerPaths = {
  cli: '../lighthouse-runners/cli.js',
  bundle: '../lighthouse-runners/bundle.js',
};

/**
 * Determine batches of smoketests to run, based on the `requestedIds`.
 * @param {Array<Smokehouse.TestDfn>} allTestDefns
 * @param {Array<string>} requestedIds
 * @param {{invertMatch: boolean}} options
 * @return {Array<Smokehouse.TestDfn>}
 */
function getDefinitionsToRun(allTestDefns, requestedIds, {invertMatch}) {
  let smokes = [];
  const usage = `    ${log.dim}yarn smoke ${allTestDefns.map(t => t.id).join(' ')}${log.reset}\n`;

  if (requestedIds.length === 0 && !invertMatch) {
    smokes = [...allTestDefns];
    console.log('Running ALL smoketests. Equivalent to:');
    console.log(usage);
  } else {
    smokes = allTestDefns.filter(test => {
      // Include all tests that *include* requested id.
      // e.g. a requested 'pwa' will match 'pwa-airhorner', 'pwa-caltrain', etc
      let isRequested = requestedIds.some(requestedId => test.id.includes(requestedId));
      if (invertMatch) isRequested = !isRequested;
      return isRequested;
    });
    console.log(`Running ONLY smoketests for: ${smokes.map(t => t.id).join(' ')}\n`);
  }

  const unmatchedIds = requestedIds.filter(requestedId => {
    return !allTestDefns.map(t => t.id).some(id => id.includes(requestedId));
  });
  if (unmatchedIds.length) {
    console.log(log.redify(`Smoketests not found for: ${unmatchedIds.join(' ')}`));
    console.log(usage);
  }

  if (!smokes.length) {
    throw new Error('no smoketest found to run');
  }

  return smokes;
}

/**
 * Prune the `networkRequests` from the test expectations when `takeNetworkRequestUrls`
 * is not defined. Custom servers may not have this method available in-process.
 * Also asserts that any expectation with `networkRequests` is run serially. For core
 * tests, we don't currently have a good way to map requests to test definitions if
 * the tests are run in parallel.
 * @param {Array<Smokehouse.TestDfn>} testDefns
 * @param {Function|undefined} takeNetworkRequestUrls
 * @return {Array<Smokehouse.TestDfn>}
 */
function pruneExpectedNetworkRequests(testDefns, takeNetworkRequestUrls) {
  const pruneNetworkRequests = !takeNetworkRequestUrls;

  const clonedDefns = cloneDeep(testDefns);
  for (const {id, expectations, runSerially} of clonedDefns) {
    if (!runSerially && expectations.networkRequests) {
      throw new Error(`'${id}' must be set to 'runSerially: true' to assert 'networkRequests'`);
    }

    if (pruneNetworkRequests && expectations.networkRequests) {
      // eslint-disable-next-line max-len
      const msg = `'networkRequests' cannot be asserted in test '${id}'. They should only be asserted on tests from an in-process server`;
      if (process.env.CI) {
        // If we're in CI, we require any networkRequests expectations to be asserted.
        throw new Error(msg);
      }

      console.warn(log.redify('Warning:'),
          `${msg}. Pruning expectation: ${JSON.stringify(expectations.networkRequests)}`);
      expectations.networkRequests = undefined;
    }
  }

  return clonedDefns;
}

/**
 * CLI entry point.
 */
async function begin() {
  const rawArgv = yargs
    .help('help')
    .usage('node $0 [<options>] <test-ids>')
    .example('node $0 -j=1 pwa seo', 'run pwa and seo tests serially')
    .example('node $0 --invert-match byte', 'run all smoke tests but `byte`')
    .option('_', {
      array: true,
      type: 'string',
    })
    .options({
      'debug': {
        type: 'boolean',
        default: false,
        describe: 'Save test artifacts and output verbose logs',
      },
      'fraggle-rock': {
        type: 'boolean',
        default: false,
        describe: 'Use the new Fraggle Rock runner',
      },
      'jobs': {
        type: 'number',
        alias: 'j',
        describe: 'Manually set the number of jobs to run at once. `1` runs all tests serially',
      },
      'retries': {
        type: 'number',
        describe: 'The number of times to retry failing tests before accepting. Defaults to 0',
      },
      'runner': {
        default: 'cli',
        choices: ['cli', 'bundle'],
        describe: 'The method of running Lighthouse',
      },
      'tests-path': {
        type: 'string',
        describe: 'The path to a set of test definitions to run. Defaults to core smoke tests.',
      },
      'invert-match': {
        type: 'boolean',
        default: false,
        describe: 'Run all available tests except the ones provided',
      },
    })
    .wrap(yargs.terminalWidth())
    .argv;

  // Augmenting yargs type with auto-camelCasing breaks in tsc@4.1.2 and @types/yargs@15.0.11,
  // so for now cast to add yarg's camelCase properties to type.
  const argv = /** @type {typeof rawArgv & CamelCasify<typeof rawArgv>} */ (rawArgv);

  const jobs = Number.isFinite(argv.jobs) ? argv.jobs : undefined;
  const retries = Number.isFinite(argv.retries) ? argv.retries : undefined;

  const runnerPath = runnerPaths[/** @type {keyof typeof runnerPaths} */ (argv.runner)];
  if (argv.runner === 'bundle') {
    console.log('\n✨ Be sure to have recently run this: yarn build-all');
  }
  const lighthouseRunner = require(runnerPath).runLighthouse;

  // Find test definition file and filter by requestedTestIds.
  let testDefnPath = argv.testsPath || coreTestDefnsPath;
  testDefnPath = path.resolve(process.cwd(), testDefnPath);
  const requestedTestIds = argv._;
  const rawTestDefns = require(testDefnPath);
  const allTestDefns = updateTestDefnFormat(rawTestDefns);
  const invertMatch = argv.invertMatch;
  const testDefns = getDefinitionsToRun(allTestDefns, requestedTestIds, {invertMatch});

  let isPassing;
  let server;
  let serverForOffline;
  let takeNetworkRequestUrls = undefined;

  try {
    // If running the core tests, spin up the test server.
    if (testDefnPath === coreTestDefnsPath) {
      ({server, serverForOffline} = require('../../fixtures/static-server.js'));
      server.listen(10200, 'localhost');
      serverForOffline.listen(10503, 'localhost');
      takeNetworkRequestUrls = server.takeRequestUrls.bind(server);
    }

    const prunedTestDefns = pruneExpectedNetworkRequests(testDefns, takeNetworkRequestUrls);
    const options = {
      jobs,
      retries,
      isDebug: argv.debug,
      useFraggleRock: argv.fraggleRock,
      lighthouseRunner,
      takeNetworkRequestUrls,
    };

    isPassing = (await runSmokehouse(prunedTestDefns, options)).success;
  } finally {
    if (server) await server.close();
    if (serverForOffline) await serverForOffline.close();
  }

  const exitCode = isPassing ? 0 : 1;
  process.exit(exitCode);
}

begin().catch(e => {
  console.error(e);
  process.exit(1);
});
<commit_msg>tests(smoke): print command to rerun failures (#12924)<commit_after>#!/usr/bin/env node
/**
 * @license Copyright 2019 The Lighthouse Authors. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
 */
'use strict';

/**
 * @fileoverview A smokehouse frontend for running from the command line. Parse
 * flags, start fixture webservers, then run smokehouse.
 */

/* eslint-disable no-console */

const path = require('path');
const cloneDeep = require('lodash.clonedeep');
const yargs = require('yargs');
const log = require('lighthouse-logger');
const {runSmokehouse} = require('../smokehouse.js');
const {updateTestDefnFormat} = require('./back-compat-util.js');

const coreTestDefnsPath = path.join(__dirname, '../test-definitions/core-tests.js');

/**
 * Possible Lighthouse runners. Loaded dynamically so e.g. a CLI run isn't
 * contingent on having built all the bundles.
 */
const runnerPaths = {
  cli: '../lighthouse-runners/cli.js',
  bundle: '../lighthouse-runners/bundle.js',
};

/**
 * Determine batches of smoketests to run, based on the `requestedIds`.
 * @param {Array<Smokehouse.TestDfn>} allTestDefns
 * @param {Array<string>} requestedIds
 * @param {{invertMatch: boolean}} options
 * @return {Array<Smokehouse.TestDfn>}
 */
function getDefinitionsToRun(allTestDefns, requestedIds, {invertMatch}) {
  let smokes = [];
  const usage = `    ${log.dim}yarn smoke ${allTestDefns.map(t => t.id).join(' ')}${log.reset}\n`;

  if (requestedIds.length === 0 && !invertMatch) {
    smokes = [...allTestDefns];
    console.log('Running ALL smoketests. Equivalent to:');
    console.log(usage);
  } else {
    smokes = allTestDefns.filter(test => {
      // Include all tests that *include* requested id.
      // e.g. a requested 'pwa' will match 'pwa-airhorner', 'pwa-caltrain', etc
      let isRequested = requestedIds.some(requestedId => test.id.includes(requestedId));
      if (invertMatch) isRequested = !isRequested;
      return isRequested;
    });
    console.log(`Running ONLY smoketests for: ${smokes.map(t => t.id).join(' ')}\n`);
  }

  const unmatchedIds = requestedIds.filter(requestedId => {
    return !allTestDefns.map(t => t.id).some(id => id.includes(requestedId));
  });
  if (unmatchedIds.length) {
    console.log(log.redify(`Smoketests not found for: ${unmatchedIds.join(' ')}`));
    console.log(usage);
  }

  if (!smokes.length) {
    throw new Error('no smoketest found to run');
  }

  return smokes;
}

/**
 * Prune the `networkRequests` from the test expectations when `takeNetworkRequestUrls`
 * is not defined. Custom servers may not have this method available in-process.
 * Also asserts that any expectation with `networkRequests` is run serially. For core
 * tests, we don't currently have a good way to map requests to test definitions if
 * the tests are run in parallel.
 * @param {Array<Smokehouse.TestDfn>} testDefns
 * @param {Function|undefined} takeNetworkRequestUrls
 * @return {Array<Smokehouse.TestDfn>}
 */
function pruneExpectedNetworkRequests(testDefns, takeNetworkRequestUrls) {
  const pruneNetworkRequests = !takeNetworkRequestUrls;

  const clonedDefns = cloneDeep(testDefns);
  for (const {id, expectations, runSerially} of clonedDefns) {
    if (!runSerially && expectations.networkRequests) {
      throw new Error(`'${id}' must be set to 'runSerially: true' to assert 'networkRequests'`);
    }

    if (pruneNetworkRequests && expectations.networkRequests) {
      // eslint-disable-next-line max-len
      const msg = `'networkRequests' cannot be asserted in test '${id}'. They should only be asserted on tests from an in-process server`;
      if (process.env.CI) {
        // If we're in CI, we require any networkRequests expectations to be asserted.
        throw new Error(msg);
      }

      console.warn(log.redify('Warning:'),
          `${msg}. Pruning expectation: ${JSON.stringify(expectations.networkRequests)}`);
      expectations.networkRequests = undefined;
    }
  }

  return clonedDefns;
}

/**
 * CLI entry point.
 */
async function begin() {
  const rawArgv = yargs
    .help('help')
    .usage('node $0 [<options>] <test-ids>')
    .example('node $0 -j=1 pwa seo', 'run pwa and seo tests serially')
    .example('node $0 --invert-match byte', 'run all smoke tests but `byte`')
    .option('_', {
      array: true,
      type: 'string',
    })
    .options({
      'debug': {
        type: 'boolean',
        default: false,
        describe: 'Save test artifacts and output verbose logs',
      },
      'fraggle-rock': {
        type: 'boolean',
        default: false,
        describe: 'Use the new Fraggle Rock runner',
      },
      'jobs': {
        type: 'number',
        alias: 'j',
        describe: 'Manually set the number of jobs to run at once. `1` runs all tests serially',
      },
      'retries': {
        type: 'number',
        describe: 'The number of times to retry failing tests before accepting. Defaults to 0',
      },
      'runner': {
        default: 'cli',
        choices: ['cli', 'bundle'],
        describe: 'The method of running Lighthouse',
      },
      'tests-path': {
        type: 'string',
        describe: 'The path to a set of test definitions to run. Defaults to core smoke tests.',
      },
      'invert-match': {
        type: 'boolean',
        default: false,
        describe: 'Run all available tests except the ones provided',
      },
    })
    .wrap(yargs.terminalWidth())
    .argv;

  // Augmenting yargs type with auto-camelCasing breaks in tsc@4.1.2 and @types/yargs@15.0.11,
  // so for now cast to add yarg's camelCase properties to type.
  const argv = /** @type {typeof rawArgv & CamelCasify<typeof rawArgv>} */ (rawArgv);

  const jobs = Number.isFinite(argv.jobs) ? argv.jobs : undefined;
  const retries = Number.isFinite(argv.retries) ? argv.retries : undefined;

  const runnerPath = runnerPaths[/** @type {keyof typeof runnerPaths} */ (argv.runner)];
  if (argv.runner === 'bundle') {
    console.log('\n✨ Be sure to have recently run this: yarn build-all');
  }
  const lighthouseRunner = require(runnerPath).runLighthouse;

  // Find test definition file and filter by requestedTestIds.
  let testDefnPath = argv.testsPath || coreTestDefnsPath;
  testDefnPath = path.resolve(process.cwd(), testDefnPath);
  const requestedTestIds = argv._;
  const rawTestDefns = require(testDefnPath);
  const allTestDefns = updateTestDefnFormat(rawTestDefns);
  const invertMatch = argv.invertMatch;
  const testDefns = getDefinitionsToRun(allTestDefns, requestedTestIds, {invertMatch});

  let smokehouseResult;
  let server;
  let serverForOffline;
  let takeNetworkRequestUrls = undefined;

  try {
    // If running the core tests, spin up the test server.
    if (testDefnPath === coreTestDefnsPath) {
      ({server, serverForOffline} = require('../../fixtures/static-server.js'));
      server.listen(10200, 'localhost');
      serverForOffline.listen(10503, 'localhost');
      takeNetworkRequestUrls = server.takeRequestUrls.bind(server);
    }

    const prunedTestDefns = pruneExpectedNetworkRequests(testDefns, takeNetworkRequestUrls);
    const options = {
      jobs,
      retries,
      isDebug: argv.debug,
      useFraggleRock: argv.fraggleRock,
      lighthouseRunner,
      takeNetworkRequestUrls,
    };

    smokehouseResult = (await runSmokehouse(prunedTestDefns, options));
  } finally {
    if (server) await server.close();
    if (serverForOffline) await serverForOffline.close();
  }

  if (!smokehouseResult.success) {
    const failedTestResults = smokehouseResult.testResults.filter(r => r.failed);
    const cmd = `yarn smoke ${failedTestResults.map(r => r.id).join(' ')}`;
    console.log(`rerun failures: ${cmd}`);
  }

  const exitCode = smokehouseResult.success ? 0 : 1;
  process.exit(exitCode);
}

begin().catch(e => {
  console.error(e);
  process.exit(1);
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Button, FormGroup, ControlLabel, FormControl, HelpBlock } from 'react-bootstrap';
import FaceTracker from './face-tracker';
import FieldGroup from './fieldgroup';

const CHECKING = 1;
const LOADING = 2;
const OK = 3;
const GO_AWAY = 4;

class Check extends Component {

  constructor(){
    super();
    this.state = {
      step: CHECKING,
      name: ""
    }
  }

  componentDidMount(){
    this.checkForFace();
  }

  checkForFace(){
    this.faceDetectedCallback = () => this.onFaceDetected()
    this.refs.tracker.addFaceListener(this.faceDetectedCallback)
  }

  onFaceDetected(){
    this.refs.tracker.removeFaceListener(this.faceDetectedCallback)

    // send to server

    this.setState({
      step: LOADING
    })
  }

  onFaceValid(resp){
    this.setState({
      step: OK,
      name: resp.name
    })
    setTimeout(()=>this.checkForFace(), 1000)
  }
  onFaceInvalid(resp){
    this.setState({
      step: GO_AWAY
    })
    setTimeout(()=>this.checkForFace(), 1000)
  }

  render() {
    var message;
    switch(this.state.step){
      case CHECKING: message =

Please come closer

; break;
      case LOADING: message =

Loading

; break;
      case OK: message =

Enjoy your ride, {this.state.name}

;break;
      case GO_AWAY: message =

Just Go Away

;break;
    }

    return (

        <FaceTracker ref="tracker"/>

        {message}

    );
  }
}

export default Check;
<commit_msg>check<commit_after>import React, { Component } from 'react';
import { Button, FormGroup, ControlLabel, FormControl, HelpBlock } from 'react-bootstrap';
import FaceTracker from './face-tracker';
import FieldGroup from './fieldgroup';

const CHECKING = 1;
const LOADING = 2;
const OK = 3;
const GO_AWAY = 4;

class Check extends Component {

  constructor(){
    super();
    this.state = {
      step: CHECKING,
      name: ""
    }
  }

  componentDidMount(){
    this.checkForFace();
  }

  checkForFace(){
    this.faceDetectedCallback = () => this.onFaceDetected()
    this.refs.tracker.addFaceListener(this.faceDetectedCallback)
  }

  onFaceDetected(){
    this.refs.tracker.removeFaceListener(this.faceDetectedCallback)

    const tracker = this.refs.tracker;
    if(tracker.getNumberOfFaces() === 1){
      var face = tracker.getFace()
    } else {
      alert('there should only be one face');
      return;
    }
    let formData = new FormData(form);
    formData.append("image", dataURItoBlob(face));

    fetch(Environment.backendUrl + '/verify', {
      method: 'POST',
      body: formData
    })
      .then(response => response.text())
      .then(responseText => {
        if(responseText.contains('STOP'))
          this.onFaceInvalid(responseText)
        else this.onFaceValid(responseText)
      })
      .catch((error) => this.setState({
        message: "Error, please try again! Error was: " + error
      }))
    this.setState({
      step: LOADING
    })
  }

  onFaceValid(resp){
    this.setState({
      step: OK,
      name: resp
    })
    setTimeout(()=>this.checkForFace(), 1000)
  }
  onFaceInvalid(resp){
    this.setState({
      step: GO_AWAY
    })
    setTimeout(()=>this.checkForFace(), 1000)
  }

  render() {
    var message;
    switch(this.state.step){
      case CHECKING: message =

Please come closer

; break;
      case LOADING: message =

Loading

; break;
      case OK: message =

Enjoy your ride, {this.state.name}

;break;
      case GO_AWAY: message =

Just Go Away

;break;
    }

    return (

        <FaceTracker ref="tracker"/>

        {message}

    );
  }
}

export default Check;

function dataURItoBlob(dataURI) {
    let binary = atob(dataURI.split(',')[1]);
    let array = [];
    for (let i = 0; i < binary.length; i++) {
      array.push(binary.charCodeAt(i));
    }
    return new Blob([new Uint8Array(array)], { type: 'image/jpeg' });
  }
<|endoftext|>