//////////////////////////////////////////////////////////////// Recaptcha integration  We require recaptcha validation after a *number* of bad logins.  ////////////////////////////////////////////////////////////////
194120
function requireRecaptchaAfterTries(number) {
    /*
     * Recaptcha keypair
     * http://www.google.com/recaptcha/whyrecaptcha
     */
    var recaptchaKeys = {
        PUBLIC: '6Ler-9cSAAAAALgxcaiMpgfDb6tL36IvM2dCb7g7',
        PRIVATE: '6Ler-9cSAAAAAMO0RJB39zFvYwLHvykldkml2uWK'
    };
    return function (req, res, next) {
        var badAttempts = req.delayed && req.delayed.counter || -1;
        // Note: We show recaptcha form PRIOr to require it
        if (badAttempts >= number) {
            req.session.recaptchaForm = (new Recaptcha(recaptchaKeys.PUBLIC, recaptchaKeys.PRIVATE)).toHTML();
        }
        if ((req.requireRecaptcha = badAttempts > number)) {
            var data = {
                remoteip: req.connection.remoteAddress,
                challenge: req.body.recaptcha_challenge_field,
                response: req.body.recaptcha_response_field
            },
                recaptcha = new Recaptcha(recaptchaKeys.PUBLIC, recaptchaKeys.PRIVATE, data);
            recaptcha.verify(function (success, error) {
                req.isValidRecaptcha = {
                    success: success,
                    error: error
                };
                next();
            });
        } else {
            next();
        }
    };
}
1259200
public void validateEnterPassword(AccountPasswordForm form, MessageContext context) {

        // ensure that a current account password was entered
        if (StringUtils.isBlank(form.getCurrentPassword())) {
            context.addMessage(
                    new MessageBuilder()
                            .error()
                            .source("currentPassword")
                            .code("please.enter.current.password")
                            .defaultText("Please enter your current password")
                            .build());
        }

        // check to see if the provided password matches the current account
        // password
        else {

            ILocalAccountPerson account = accountDao.getPerson(form.getUserId());
            if (!passwordService.validatePassword(
                    form.getCurrentPassword(), account.getPassword())) {
                context.addMessage(
                        new MessageBuilder()
                                .error()
                                .source("currentPassword")
                                .code("current.password.doesnt.match")
                                .defaultText(
                                        "Provided password does not match the current account password")
                                .build());
            }
        }

        // ensure a new account password was entered
        if (StringUtils.isBlank(form.getNewPassword())) {
            context.addMessage(
                    new MessageBuilder()
                            .error()
                            .source("newPassword")
                            .code("please.enter.new.password")
                            .defaultText("Please enter a new password")
                            .build());
        }

        // ensure a new account password confirmation was entered
        if (StringUtils.isBlank(form.getConfirmNewPassword())) {
            context.addMessage(
                    new MessageBuilder()
                            .error()
                            .source("confirmNewPassword")
                            .code("please.enter.confirm.password")
                            .defaultText("Please confirm your new password")
                            .build());
        }

        // ensure the new password and new password confirmation match
        if (StringUtils.isNotBlank(form.getNewPassword())
                && StringUtils.isNotBlank(form.getConfirmNewPassword())
                && !form.getNewPassword().equals(form.getConfirmNewPassword())) {

            context.addMessage(
                    new MessageBuilder()
                            .error()
                            .source("confirmPassword")
                            .code("passwords.must.match")
                            .defaultText("Passwords must match")
                            .build());
        }
    }
675817
function validateRSAA(action) {
  var validationErrors = [];
  const validCallAPIKeys = [
    'endpoint',
    'options',
    'method',
    'body',
    'headers',
    'credentials',
    'bailout',
    'types',
    'fetch',
    'ok'
  ];
  const validMethods = [
    'GET',
    'HEAD',
    'POST',
    'PUT',
    'PATCH',
    'DELETE',
    'OPTIONS'
  ];
  const validCredentials = ['omit', 'same-origin', 'include'];

  if (!isRSAA(action)) {
    validationErrors.push(
      'RSAAs must be plain JavaScript objects with an [RSAA] property'
    );
    return validationErrors;
  }

  const callAPI = action[RSAA];
  if (!isPlainObject(callAPI)) {
    validationErrors.push('[RSAA] property must be a plain JavaScript object');
  }
  for (let key in callAPI) {
    if (!~validCallAPIKeys.indexOf(key)) {
      validationErrors.push(`Invalid [RSAA] key: ${key}`);
    }
  }

  const {
    endpoint,
    method,
    headers,
    options,
    credentials,
    types,
    bailout,
    fetch,
    ok
  } = callAPI;
  if (typeof endpoint === 'undefined') {
    validationErrors.push('[RSAA] must have an endpoint property');
  } else if (typeof endpoint !== 'string' && typeof endpoint !== 'function') {
    validationErrors.push(
      '[RSAA].endpoint property must be a string or a function'
    );
  }
  if (typeof method === 'undefined') {
    validationErrors.push('[RSAA] must have a method property');
  } else if (typeof method !== 'string') {
    validationErrors.push('[RSAA].method property must be a string');
  } else if (!~validMethods.indexOf(method.toUpperCase())) {
    validationErrors.push(`Invalid [RSAA].method: ${method.toUpperCase()}`);
  }

  if (
    typeof headers !== 'undefined' &&
    !isPlainObject(headers) &&
    typeof headers !== 'function'
  ) {
    validationErrors.push(
      '[RSAA].headers property must be undefined, a plain JavaScript object, or a function'
    );
  }
  if (
    typeof options !== 'undefined' &&
    !isPlainObject(options) &&
    typeof options !== 'function'
  ) {
    validationErrors.push(
      '[RSAA].options property must be undefined, a plain JavaScript object, or a function'
    );
  }
  if (typeof credentials !== 'undefined') {
    if (typeof credentials !== 'string') {
      validationErrors.push(
        '[RSAA].credentials property must be undefined, or a string'
      );
    } else if (!~validCredentials.indexOf(credentials)) {
      validationErrors.push(`Invalid [RSAA].credentials: ${credentials}`);
    }
  }
  if (
    typeof bailout !== 'undefined' &&
    typeof bailout !== 'boolean' &&
    typeof bailout !== 'function'
  ) {
    validationErrors.push(
      '[RSAA].bailout property must be undefined, a boolean, or a function'
    );
  }

  if (typeof types === 'undefined') {
    validationErrors.push('[RSAA] must have a types property');
  } else if (!Array.isArray(types) || types.length !== 3) {
    validationErrors.push('[RSAA].types property must be an array of length 3');
  } else {
    const [requestType, successType, failureType] = types;
    if (
      typeof requestType !== 'string' &&
      typeof requestType !== 'symbol' &&
      !isValidTypeDescriptor(requestType)
    ) {
      validationErrors.push('Invalid request type');
    }
    if (
      typeof successType !== 'string' &&
      typeof successType !== 'symbol' &&
      !isValidTypeDescriptor(successType)
    ) {
      validationErrors.push('Invalid success type');
    }
    if (
      typeof failureType !== 'string' &&
      typeof failureType !== 'symbol' &&
      !isValidTypeDescriptor(failureType)
    ) {
      validationErrors.push('Invalid failure type');
    }
  }

  if (typeof fetch !== 'undefined') {
    if (typeof fetch !== 'function') {
      validationErrors.push('[RSAA].fetch property must be a function');
    }
  }

  if (typeof ok !== 'undefined') {
    if (typeof ok !== 'function') {
      validationErrors.push('[RSAA].ok property must be a function');
    }
  }

  return validationErrors;
}
317620
function validateInput(params, cb) {
	if (typeof params !== 'object')
		return new TypeError("params must be an object");
	if (typeof cb !== 'function')
		return new TypeError("callback must be a function");
	if (params.origin === "")
		return new Error("params.origin is required");
	if (params.destination === "")
		return new Error("params.destination is required");
	if (params.key === "")
		return new Error("params.key is required");
}
22815
public function addValidator()
    {
        $this->app->validator->extendImplicit('recaptcha', function ($attribute, $value, $parameters) {
            $captcha   = app('recaptcha.service');
            $challenge = app('request')->input($captcha->getResponseKey());

            return $captcha->check($challenge, $value);
        }, 'Please ensure that you are a human!');
    }
985419
def solve_recaptcha(self, google_key, page_url, timeout = 15 * 60):
		'''
		
		'''

		proxy = SocksProxy.ProxyLauncher([TWOCAPTCHA_IP])

		try:
			captcha_id = self.doGet('input', {
						'key'         : self.api_key,
						'method'      : "userrecaptcha",
						'googlekey'   : google_key,
						'pageurl'     : page_url,

						'proxy'       : proxy.get_wan_address(),
						'proxytype'   : "SOCKS5",

						'json'        : True,
					}
				)

			# Allow 15 minutes for the solution
			# I've been seeing times up to 160+ seconds in testing.
			return self._getresult(captcha_id=captcha_id, timeout=timeout)
		finally:
			proxy.stop()
173641
function checkPostOrPutOrPatchRequest(req, res, cb) {
            var _keys;
            var _reqElement;

            if (req.body) {
                _keys = Object.keys(req.body);
                _keys.forEach(function (keyElement) {
                    _reqElement = req.body[keyElement];
                    //console.log(/" [a-z]*="/i.spec(_reqElement));
                    _patterns.forEach(function (pattern) {
                        if (pattern.test(_reqElement) && _blocker.blockHost) {
                            _config.attack.handle(req, res);
                        }
                    });
                });
            }
            if (cb) {
                cb();
            }
        }
1235951
def check_recaptcha(view_func):
    """"""
    @wraps(view_func)
    def _wrapped_view(request, *args, **kwargs):
        request.recaptcha_is_valid = None
        if request.method == 'POST':
            recaptcha_response = request.POST.get('g-recaptcha-response')
            data = {
                'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
                'response': recaptcha_response
            }
            r = requests.post(
                'https://www.google.com/recaptcha/api/siteverify',
                data=data
            )
            result = r.json()
            if result['success']:
                request.recaptcha_is_valid = True
            else:
                request.recaptcha_is_valid = False
                error_message = 'Invalid reCAPTCHA. Please try again. '
                error_message += str(result['error-codes'])
                print(error_message)
        return view_func(request, *args, **kwargs)
    return _wrapped_view
562673
function(err, req, res, next) {
    err.message = err.message || 'Internal Server Error';
    err.code = err.code || res.code || 500;
    if (!_.isNumber(err.code)) {
      err.code = 500;
    }

    try {
      err.line = err.stack.split('\n')[1].match(/\(.+\)/)[0];
    } catch (e) {
      err.line = null;
    }

    var envelope = {
      meta: {
        code: err.code,
        error: {
          code: err.code,
          message: err.message,
          line: err.line
        }
      },
      data: err.message
    };

    // Set code and data
    res.code = err.code;
    res.data = envelope;

    return next();
  }
784693
function checkIfMatch(req, res, next) {
    var clientETags;
    var cur;
    var etag = res.etag || res.getHeader('etag') || '';
    var ifMatch;
    var matched = false;

    if ((ifMatch = req.headers['if-match'])) {

        clientETags = ifMatch.split(/\s*,\s*/);

        for (var i = 0; i < clientETags.length; i++) {
            cur = clientETags[i];

            // only strong comparison

            cur = cur.replace(/^W\//, '');
            cur = cur.replace(/^"(\w*)"$/, '$1');

            if (cur === '*' || cur === etag) {
                matched = true;
                break;
            }
        }

        if (!matched) {
            var err = new PreconditionFailedError(IF_MATCH_FAIL,
                ifMatch,
                etag);
            return (next(err));
        }
    }

    return (next());
}
920968
function handleValidation(req, res, next) {
      var payload = JSON.stringify(req.body);
      var nodeVersion = Number(process.version.replace(/^v/, '').split(/\./)[0]);

      var utf8safe = nodeVersion >= 6 ? payload : unescape(encodeURIComponent(payload));
      var hash = crypto.createHmac('sha1', secret).update(utf8safe).digest('hex');
      var signature = req.get('layer-webhook-signature');

      if (hash === signature) next();
      else {
        loggerError('Computed HMAC Signature ' + hash + ' did not match signed header ' + signature + '. Returning Error.  Config:', JSON.stringify(payload.config || {}));
        res.sendStatus(403);
      }
    }
83200
function handleConfigChange() {
  var newRecaptchaValue = document.querySelector(
      'input[name="recaptcha"]:checked').value;
  var newEmailSignInMethodValue = document.querySelector(
      'input[name="emailSignInMethod"]:checked').value;
  location.replace(
      location.pathname + '#recaptcha=' + newRecaptchaValue +
      '&emailSignInMethod=' + newEmailSignInMethodValue);

  // Reset the inline widget so the config changes are reflected.
  ui.reset();
  ui.start('#firebaseui-container', getUiConfig());
}
1001926
function(err) {
    var validationErrMsg = self.handleError(err)
    if (!validationErrMsg) return false
    else { 
      self._merge(validationErrors, validationErrMsg, prefix)
      isValid = false
      return true
    }
  }
408441
function javascript_validation() {
    $js = '  if (payment_value == "' . $this->code . '") {' . "\n" .
    $js .= '    var echeck_custname = document.checkout_payment.authorizenet_echeck_bank_accountholder.value;' . "\n";
    $js .= '    var echeck_bank_aba = document.checkout_payment.authorizenet_echeck_bank_aba_code.value;' . "\n";
    $js .= '    var echeck_bank_acctnum = document.checkout_payment.authorizenet_echeck_bank_acct_num.value;' . "\n";
    $js .= '    var echeck_bank_name = document.checkout_payment.authorizenet_echeck_bank_name.value;' . "\n";
    $js .= '    if (echeck_custname == "" || echeck_custname.length < ' . CC_OWNER_MIN_LENGTH . ') {' . "\n" .
    '      error_message = error_message + "' . MODULE_PAYMENT_AUTHORIZENET_ECHECK_TEXT_JS_ACCT_OWNER . '";' . "\n" .
    '      error = 1;' . "\n" .
    '    }' . "\n" .
    '    if (echeck_bank_aba == "" || echeck_bank_aba.length < ' . 6 . ') {' . "\n" .
    '      error_message = error_message + "' . MODULE_PAYMENT_AUTHORIZENET_ECHECK_TEXT_JS_ROUTING_CODE . '";' . "\n" .
    '      error = 1;' . "\n" .
    '    }' . "\n" .
    '    if (echeck_bank_acctnum == "" || echeck_bank_acctnum.length < ' . 6 . ') {' . "\n" .
    '      error_message = error_message + "' . MODULE_PAYMENT_AUTHORIZENET_ECHECK_TEXT_JS_ACCT_NUMBER . '";' . "\n" .
    '      error = 1;' . "\n" .
    '    }' . "\n" .
    '    if (echeck_bank_name == "" || echeck_bank_name.length < ' . 6 . ') {' . "\n" .
    '      error_message = error_message + "' . MODULE_PAYMENT_AUTHORIZENET_ECHECK_TEXT_JS_BANK_NAME . '";' . "\n" .
    '      error = 1;' . "\n" .
    '    }' . "\n";


    if (MODULE_PAYMENT_AUTHORIZENET_ECHECK_WFSS_ENABLED == 'True') {
      //MODULE_PAYMENT_AUTHORIZENET_ECHECK_TEXT_JS_CUST_TAX_ID
      //MODULE_PAYMENT_AUTHORIZENET_ECHECK_TEXT_JS_DL_NUMBER
      //MODULE_PAYMENT_AUTHORIZENET_ECHECK_TEXT_JS_DL_DOB
    }


    $js .= '  }' . "\n";

    return $js;
  }
958995
private function verifyRecaptcha()
    {
        if (!isset($this->recaptchaClientKey)) {
            return true;
        }

        $recaptcha = $this->request->input('g-recaptcha-response');
        if (!$recaptcha) {
            return false;
        }

        $request = new Request();
        $request->setUrl('https://www.google.com/recaptcha/api/siteverify');
        $request->setBody([
            'secret' => $this->recaptchaClientSecret,
            'response' => $recaptcha,
            'remoteip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null
        ]);

        $client = Client::getInstance();

        $response = $client->post($request);
        if (!$response->getBody()) {
            return false;
        }

        $responseData = json_decode($response->getBody(), true);
        return isset($responseData['success']) && $responseData['success'];
    }
675523
function validateAuthentifiers(conn, address, this_asset, arrDefinition, objUnit, objValidationState, assocAuthentifiers, cb){
	
	function evaluate(arr, path, cb2){
		var op = arr[0];
		var args = arr[1];
		switch(op){
			case 'or':
				// ['or', [list of options]]
				var res = false;
				var index = -1;
				async.eachSeries(
					args,
					function(arg, cb3){
						index++;
						evaluate(arg, path+'.'+index, function(arg_res){
							res = res || arg_res;
							cb3(); // check all members, even if required minimum already found
							//res ? cb3("found") : cb3();
						});
					},
					function(){
						cb2(res);
					}
				);
				break;
				
			case 'and':
				// ['and', [list of requirements]]
				var res = true;
				var index = -1;
				async.eachSeries(
					args,
					function(arg, cb3){
						index++;
						evaluate(arg, path+'.'+index, function(arg_res){
							res = res && arg_res;
							cb3(); // check all members, even if required minimum already found
							//res ? cb3() : cb3("found");
						});
					},
					function(){
						cb2(res);
					}
				);
				break;
				
			case 'r of set':
				// ['r of set', {required: 2, set: [list of options]}]
				var count = 0;
				var index = -1;
				async.eachSeries(
					args.set,
					function(arg, cb3){
						index++;
						evaluate(arg, path+'.'+index, function(arg_res){
							if (arg_res)
								count++;
							cb3(); // check all members, even if required minimum already found, so that we don't allow invalid sig on unchecked path
							//(count < args.required) ? cb3() : cb3("found");
						});
					},
					function(){
						cb2(count >= args.required);
					}
				);
				break;
				
			case 'weighted and':
				// ['weighted and', {required: 15, set: [{value: boolean_expr, weight: 10}, {value: boolean_expr, weight: 20}]}]
				var weight = 0;
				var index = -1;
				async.eachSeries(
					args.set,
					function(arg, cb3){
						index++;
						evaluate(arg.value, path+'.'+index, function(arg_res){
							if (arg_res)
								weight += arg.weight;
							cb3(); // check all members, even if required minimum already found
							//(weight < args.required) ? cb3() : cb3("found");
						});
					},
					function(){
						cb2(weight >= args.required);
					}
				);
				break;
				
			case 'sig':
				// ['sig', {algo: 'secp256k1', pubkey: 'base64'}]
				//console.log(op, path);
				var signature = assocAuthentifiers[path];
				if (!signature)
					return cb2(false);
				arrUsedPaths.push(path);
				var algo = args.algo || 'secp256k1';
				if (algo === 'secp256k1'){
					if (objValidationState.bUnsigned && signature[0] === "-") // placeholder signature
						return cb2(true);
					var res = ecdsaSig.verify(objValidationState.unit_hash_to_sign, signature, args.pubkey);
					if (!res)
						fatal_error = "bad signature at path "+path;
					cb2(res);
				}
				break;
				
			case 'hash':
				// ['hash', {algo: 'sha256', hash: 'base64'}]
				if (!assocAuthentifiers[path])
					return cb2(false);
				arrUsedPaths.push(path);
				var algo = args.algo || 'sha256';
				if (algo === 'sha256'){
					var res = (args.hash === crypto.createHash("sha256").update(assocAuthentifiers[path], "utf8").digest("base64"));
					if (!res)
						fatal_error = "bad hash at path "+path;
					cb2(res);
				}
				break;
				
			case 'address':
				// ['address', 'BASE32']
				var other_address = args;
				storage.readDefinitionByAddress(conn, other_address, objValidationState.last_ball_mci, {
					ifFound: function(arrInnerAddressDefinition){
						evaluate(arrInnerAddressDefinition, path, cb2);
					},
					ifDefinitionNotFound: function(definition_chash){
						var arrDefiningAuthors = objUnit.authors.filter(function(author){
							return (author.address === other_address && author.definition && objectHash.getChash160(author.definition) === definition_chash);
						});
						if (arrDefiningAuthors.length === 0) // no definition in the current unit
							return cb2(false);
						if (arrDefiningAuthors.length > 1)
							throw Error("more than 1 address definition");
						var arrInnerAddressDefinition = arrDefiningAuthors[0].definition;
						evaluate(arrInnerAddressDefinition, path, cb2);
					}
				});
				break;
				
			case 'definition template':
				// ['definition template', ['unit', {param1: 'value1'}]]
				var unit = args[0];
				var params = args[1];
				conn.query(
					"SELECT payload FROM messages JOIN units USING(unit) \n\
					WHERE unit=? AND app='definition_template' AND main_chain_index<=? AND +sequence='good' AND is_stable=1",
					[unit, objValidationState.last_ball_mci],
					function(rows){
						if (rows.length !== 1)
							throw Error("not 1 template");
						var template = rows[0].payload;
						var arrTemplate = JSON.parse(template);
						var arrFilledTemplate = replaceInTemplate(arrTemplate, params);
						evaluate(arrFilledTemplate, path, cb2);
					}
				);
				break;
				
			case 'seen address':
				// ['seen address', 'BASE32']
				var seen_address = args;
				conn.query(
					"SELECT 1 FROM unit_authors CROSS JOIN units USING(unit) \n\
					WHERE address=? AND main_chain_index<=? AND sequence='good' AND is_stable=1 \n\
					LIMIT 1",
					[seen_address, objValidationState.last_ball_mci],
					function(rows){
						cb2(rows.length > 0);
					}
				);
				break;
				
			case 'seen definition change':
				// ['seen definition change', ['BASE32', 'BASE32']]
				var changed_address = args[0];
				var new_definition_chash = args[1];
				if (changed_address === 'this address')
					changed_address = address;
				if (new_definition_chash === 'this address')
					new_definition_chash = address;
				var and_definition_chash = (new_definition_chash === 'any') ? '' : 'AND definition_chash='+db.escape(new_definition_chash);
				conn.query(
					"SELECT 1 FROM address_definition_changes CROSS JOIN units USING(unit) \n\
					WHERE address=? "+and_definition_chash+" AND main_chain_index<=? AND sequence='good' AND is_stable=1 \n\
					LIMIT 1",
					[changed_address, objValidationState.last_ball_mci],
					function(rows){
						cb2(rows.length > 0);
					}
				);
				break;
				
			case 'seen':
				// ['seen', {what: 'input', asset: 'asset or base', type: 'transfer'|'issue', amount_at_least: 123, amount_at_most: 123, amount: 123, address: 'BASE32'}]
				var filter = args;
				var sql = "SELECT 1 FROM "+filter.what+"s CROSS JOIN units USING(unit) \n\
					LEFT JOIN assets ON asset=assets.unit \n\
					WHERE main_chain_index<=? AND sequence='good' AND is_stable=1 AND (asset IS NULL OR is_private=0) ";
				var params = [objValidationState.last_ball_mci];
				if (filter.asset){
					if (filter.asset === 'base')
						sql += " AND asset IS NULL ";
					else{
						sql += " AND asset=? ";
						params.push(filter.asset);
					}
				}
				if (filter.type){
					sql += " AND type=? ";
					params.push(filter.type);
				}
				if (filter.address){
					sql += " AND address=? ";
					params.push((filter.address === 'this address') ? address : filter.address);
				}
				if (filter.what === 'output'){
					if (filter.amount_at_least){
						sql += " AND amount>=? ";
						params.push(filter.amount_at_least);
					}
					if (filter.amount_at_most){
						sql += " AND amount<=? ";
						params.push(filter.amount_at_most);
					}
					if (filter.amount){
						sql += " AND amount=? ";
						params.push(filter.amount);
					}
				}
				sql += " LIMIT 1";
				conn.query(sql, params, function(rows){
					cb2(rows.length > 0);
				});
				break;
				
			case 'attested':
				// ['attested', ['BASE32', ['BASE32']]]
				var attested_address = args[0];
				var arrAttestors = args[1];
				if (attested_address === 'this address')
					attested_address = address;
				storage.filterAttestedAddresses(
					conn, {arrAttestorAddresses: arrAttestors}, objValidationState.last_ball_mci, [attested_address], function(arrFilteredAddresses){
						cb2(arrFilteredAddresses.length > 0);
					}
				);
				break;
				
			case 'cosigned by':
				// ['cosigned by', 'BASE32']
				var cosigner_address = args;
				var arrAuthorAddresses = objUnit.authors.map(function(author){ return author.address; });
				console.log(op+" "+arrAuthorAddresses.indexOf(cosigner_address));
				cb2(arrAuthorAddresses.indexOf(cosigner_address) >= 0);
				break;
				
			case 'not':
				// useful for conditions such as: after timestamp but there's still no searched value in datafeed
				// sig, hash, and address cannot be negated
				evaluate(args, path, function(not_res){
					cb2(!not_res);
				});
				break;
				
			case 'in data feed':
				// ['in data feed', [['BASE32'], 'data feed name', '=', 'expected value']]
				var arrAddresses = args[0];
				var feed_name = args[1];
				var relation = args[2];
				var value = args[3];
				var min_mci = args[4] || 0;
				var value_condition;
				var index;
				var params = [arrAddresses, feed_name];
				if (typeof value === "string"){
					index = 'byNameStringValue';
					var isNumber = /^-?\d+\.?\d*$/.test(value);
					if (isNumber){
						var bForceNumericComparison = (['>','>=','<','<='].indexOf(relation) >= 0);
						var plus_0 = bForceNumericComparison ? '+0' : '';
						value_condition = '(value'+plus_0+relation+value+' OR int_value'+relation+value+')';
					//	params.push(value, value);
					}
					else{
						value_condition = 'value'+relation+'?';
						params.push(value);
					}
				}
				else{
					index = 'byNameIntValue';
					value_condition = 'int_value'+relation+'?';
					params.push(value);
				}
				params.push(objValidationState.last_ball_mci, min_mci);
				conn.query(
					"SELECT 1 FROM data_feeds "+db.forceIndex(index)+" CROSS JOIN units USING(unit) CROSS JOIN unit_authors USING(unit) \n\
					WHERE address IN(?) AND feed_name=? AND "+value_condition+" \n\
						AND main_chain_index<=? AND main_chain_index>=? AND sequence='good' AND is_stable=1 LIMIT 1",
					params,
					function(rows){
						console.log(op+" "+feed_name+" "+rows.length);
						cb2(rows.length > 0);
					}
				);
				break;
				
			case 'in merkle':
				// ['in merkle', [['BASE32'], 'data feed name', 'expected value']]
				if (!assocAuthentifiers[path])
					return cb2(false);
				arrUsedPaths.push(path);
				var arrAddresses = args[0];
				var feed_name = args[1];
				var element = args[2];
				var min_mci = args[3] || 0;
				var serialized_proof = assocAuthentifiers[path];
				var proof = merkle.deserializeMerkleProof(serialized_proof);
				if (!merkle.verifyMerkleProof(element, proof)){
					fatal_error = "bad merkle proof at path "+path;
					return cb2(false);
				}
				conn.query(
					"SELECT 1 FROM data_feeds CROSS JOIN units USING(unit) JOIN unit_authors USING(unit) \n\
					WHERE address IN(?) AND feed_name=? AND value=? AND main_chain_index<=? AND main_chain_index>=? AND sequence='good' AND is_stable=1 \n\
					LIMIT 1",
					[arrAddresses, feed_name, proof.root, objValidationState.last_ball_mci, min_mci],
					function(rows){
						if (rows.length === 0)
							fatal_error = "merkle proof at path "+path+" not found";
						cb2(rows.length > 0);
					}
				);
				break;
				
			case 'timestamp':
				var relation = args[0];
				var timestamp = args[1];
				switch(relation){
					case '>': return cb2(objValidationState.last_ball_timestamp > timestamp);
					case '>=': return cb2(objValidationState.last_ball_timestamp >= timestamp);
					case '<': return cb2(objValidationState.last_ball_timestamp < timestamp);
					case '<=': return cb2(objValidationState.last_ball_timestamp <= timestamp);
					case '=': return cb2(objValidationState.last_ball_timestamp === timestamp);
					case '!=': return cb2(objValidationState.last_ball_timestamp !== timestamp);
					default: throw Error('unknown relation in mci: '+relation);
				}
				break;
				
			case 'mci':
				var relation = args[0];
				var mci = args[1];
				switch(relation){
					case '>': return cb2(objValidationState.last_ball_mci > mci);
					case '>=': return cb2(objValidationState.last_ball_mci >= mci);
					case '<': return cb2(objValidationState.last_ball_mci < mci);
					case '<=': return cb2(objValidationState.last_ball_mci <= mci);
					case '=': return cb2(objValidationState.last_ball_mci === mci);
					case '!=': return cb2(objValidationState.last_ball_mci !== mci);
					default: throw Error('unknown relation in mci: '+relation);
				}
				break;
				
			case 'age':
				var relation = args[0];
				var age = args[1];
				augmentMessagesAndContinue(function(){
					var arrSrcUnits = [];
					for (var i=0; i<objValidationState.arrAugmentedMessages.length; i++){
						var message = objValidationState.arrAugmentedMessages[i];
						if (message.app !== 'payment' || !message.payload)
							continue;
						var inputs = message.payload.inputs;
						for (var j=0; j<inputs.length; j++){
							var input = inputs[j];
							if (input.type !== 'transfer') // assume age is satisfied for issue, headers commission, and witnessing commission
								continue;
							if (!input.address) // augment should add it
								throw Error('no input address');
							if (input.address === address && arrSrcUnits.indexOf(input.unit) === -1)
								arrSrcUnits.push(input.unit);
						}
					}
					if (arrSrcUnits.length === 0) // not spending anything from our address
						return cb2(false);
					conn.query(
						"SELECT 1 FROM units \n\
						WHERE unit IN(?) AND ?"+relation+"main_chain_index AND main_chain_index<=? AND +sequence='good' AND is_stable=1",
						[arrSrcUnits, objValidationState.last_ball_mci - age, objValidationState.last_ball_mci],
						function(rows){
							var bSatisfies = (rows.length === arrSrcUnits.length);
							console.log(op+" "+bSatisfies);
							cb2(bSatisfies);
						}
					);
				});
				break;
				
			case 'has':
			case 'has one':
				// ['has', {what: 'input', asset: 'asset or base', type: 'transfer'|'issue', amount_at_least: 123, amount_at_most: 123, amount: 123, address: 'BASE32'}]
				// when an address is included (referenced from another address), "this address" refers to the outer address
				augmentMessagesAndEvaluateFilter(op, args, function(res){
					console.log(op+" "+res, args);
					cb2(res);
				});
				break;
				
			case 'has equal':
			case 'has one equal':
				// ['has equal', {equal_fields: ['address', 'amount'], search_criteria: [{what: 'output', asset: 'asset1', address: 'BASE32'}, {what: 'input', asset: 'asset2', type: 'issue', address: 'ANOTHERBASE32'}]}]
				augmentMessagesAndEvaluateFilter("has", args.search_criteria[0], function(res1, arrFirstObjects){
					if (!res1)
						return cb2(false);
					augmentMessagesAndEvaluateFilter("has", args.search_criteria[1], function(res2, arrSecondObjects){
						if (!res2)
							return cb2(false);
						var count_equal_pairs = 0;
						for (var i=0; i<arrFirstObjects.length; i++)
							for (var j=0; j<arrSecondObjects.length; j++)
								if (!args.equal_fields.some(function(field){ return (arrFirstObjects[i][field] !== arrSecondObjects[j][field]); }))
									count_equal_pairs++;
						if (count_equal_pairs === 0)
							return cb2(false);
						if (op === "has one equal" && count_equal_pairs === 1)
							return cb2(true);
						if (op === "has equal" && count_equal_pairs > 0)
							return cb2(true);
						cb2(false);
					});
				});
				break;
				
			case 'sum':
				// ['sum', {filter: {what: 'input', asset: 'asset or base', type: 'transfer'|'issue', address: 'BASE32'}, at_least: 123, at_most: 123, equals: 123}]
				augmentMessagesAndEvaluateFilter("has", args.filter, function(res, arrFoundObjects){
					var sum = 0;
					if (res)
						for (var i=0; i<arrFoundObjects.length; i++)
							sum += arrFoundObjects[i].amount;
					console.log("sum="+sum);
					if (typeof args.equals === "number" && sum === args.equals)
						return cb2(true);
					if (typeof args.at_least === "number" && sum < args.at_least)
						return cb2(false);
					if (typeof args.at_most === "number" && sum > args.at_most)
						return cb2(false);
					cb2(true);
				});
				break;
				
			case 'has definition change':
				// ['has definition change', ['BASE32', 'BASE32']]
				var changed_address = args[0];
				var new_definition_chash = args[1];
				if (changed_address === 'this address')
					changed_address = address;
				if (new_definition_chash === 'this address')
					new_definition_chash = address;
				cb2(objUnit.messages.some(function(message){
					if (message.app !== 'address_definition_change')
						return false;
					if (!message.payload)
						return false;
					if (new_definition_chash !== 'any' && message.payload.definition_chash !== new_definition_chash)
						return false;
					var payload_address = message.payload.address || objUnit.authors[0].address;
					return (payload_address === changed_address);
				}));
				break;
			
			case 'formula':
				var formula = args;
				augmentMessagesOrIgnore(formula, function (messages) {
					evalFormulaBB.evaluate(conn, formula, messages, objValidationState, address, function (result) {
						if (typeof result === 'boolean') {
							cb2(result);
						} else if (typeof result === 'string') {
							cb2(!!result);
						} else if (BigNumber.isBigNumber(result)) {
							cb2(!result.eq(0))
						} else {
							cb(false);
						}
					});
				});
				break;
		}
	}
	
	function augmentMessagesOrIgnore(formula, cb){
		if (objValidationState.arrAugmentedMessages || /input/.test(formula)){
			augmentMessagesAndContinue(function () {
				cb(objValidationState.arrAugmentedMessages);
			});
		}else{
			cb(objUnit.messages);
		}
	}
	
	function augmentMessagesAndContinue(next){
		if (!objValidationState.arrAugmentedMessages)
			augmentMessages(next);
		else
			next();
	}
	
	function augmentMessagesAndEvaluateFilter(op, filter, handleResult){
		function doEvaluateFilter(){
			//console.log("augmented: ", objValidationState.arrAugmentedMessages[0].payload);
			evaluateFilter(op, filter, handleResult);
		}
		if (!objValidationState.arrAugmentedMessages && filter.what === "input" && (filter.address || typeof filter.amount === "number" || typeof filter.amount_at_least === "number" || typeof filter.amount_at_most === "number"))
			augmentMessages(doEvaluateFilter);
		else
			doEvaluateFilter();
	}
	
	
	function evaluateFilter(op, filter, handleResult){
		var arrFoundObjects = [];
		for (var i=0; i<objUnit.messages.length; i++){
			var message = objUnit.messages[i];
			if (message.app !== "payment" || !message.payload) // we consider only public payments
				continue;
			var payload = message.payload;
			if (filter.asset){
				if (filter.asset === "base"){
					if (payload.asset)
						continue;
				}
				else if (filter.asset === "this asset"){
					if (payload.asset !== this_asset)
						continue;
				}
				else{
					if (payload.asset !== filter.asset)
						continue;
				}
			}
			if (filter.what === "input"){
				for (var j=0; j<payload.inputs.length; j++){
					var input = payload.inputs[j];
					if (input.type === "headers_commission" || input.type === "witnessing")
						continue;
					if (filter.type){
						var type = input.type || "transfer";
						if (type !== filter.type)
							continue;
					}
					var augmented_input = objValidationState.arrAugmentedMessages ? objValidationState.arrAugmentedMessages[i].payload.inputs[j] : null;
					if (filter.address){
						if (filter.address === 'this address'){
							if (augmented_input.address !== address)
								continue;
						}
						else if (filter.address === 'other address'){
							if (augmented_input.address === address)
								continue;
						}
						else { // normal address
							if (augmented_input.address !== filter.address)
								continue;
						}
					}
					if (filter.amount && augmented_input.amount !== filter.amount)
						continue;
					if (filter.amount_at_least && augmented_input.amount < filter.amount_at_least)
						continue;
					if (filter.amount_at_most && augmented_input.amount > filter.amount_at_most)
						continue;
					arrFoundObjects.push(augmented_input || input);
				}
			} // input
			else if (filter.what === "output"){
				for (var j=0; j<payload.outputs.length; j++){
					var output = payload.outputs[j];
					if (filter.address){
						if (filter.address === 'this address'){
							if (output.address !== address)
								continue;
						}
						else if (filter.address === 'other address'){
							if (output.address === address)
								continue;
						}
						else { // normal address
							if (output.address !== filter.address)
								continue;
						}
					}
					if (filter.amount && output.amount !== filter.amount)
						continue;
					if (filter.amount_at_least && output.amount < filter.amount_at_least)
						continue;
					if (filter.amount_at_most && output.amount > filter.amount_at_most)
						continue;
					arrFoundObjects.push(output);
				}
			} // output
		}
		if (arrFoundObjects.length === 0)
			return handleResult(false);
		if (op === "has one" && arrFoundObjects.length === 1)
			return handleResult(true);
		if (op === "has" && arrFoundObjects.length > 0)
			return handleResult(true, arrFoundObjects);
		handleResult(false);
	}

	
	function augmentMessages(onDone){
		console.log("augmenting");
		var arrAuthorAddresses = objUnit.authors.map(function(author){ return author.address; });
		objValidationState.arrAugmentedMessages = _.cloneDeep(objUnit.messages);
		async.eachSeries(
			objValidationState.arrAugmentedMessages,
			function(message, cb3){
				if (message.app !== 'payment' || !message.payload) // we are looking only for public payments
					return cb3();
				var payload = message.payload;
				if (!payload.inputs) // skip now, will choke when checking the message
					return cb3();
				console.log("augmenting inputs");
				async.eachSeries(
					payload.inputs,
					function(input, cb4){
						console.log("input", input);
						if (input.type === "issue"){
							if (!input.address)
								input.address = arrAuthorAddresses[0];
							cb4();
						}
						else if (!input.type){
							input.type = "transfer";
							conn.query(
								"SELECT amount, address FROM outputs WHERE unit=? AND message_index=? AND output_index=?",
								[input.unit, input.message_index, input.output_index],
								function(rows){
									if (rows.length === 1){
										console.log("src", rows[0]);
										input.amount = rows[0].amount;
										input.address = rows[0].address;
									} // else will choke when checking the message
									else
										console.log(rows.length+" src outputs found");
									cb4();
								}
							);
						}
						else // ignore headers commissions and witnessing
							cb4();
					},
					cb3
				);
			},
			onDone
		);
	}
	
	var bAssetCondition = (assocAuthentifiers === null);
	if (bAssetCondition && address || !bAssetCondition && this_asset)
		throw Error("incompatible params");
	var arrAuthentifierPaths = bAssetCondition ? null : Object.keys(assocAuthentifiers);
	var fatal_error = null;
	var arrUsedPaths = [];
	
	// we need to re-validate the definition every time, not just the first time we see it, because:
	// 1. in case a referenced address was redefined, complexity might change and exceed the limit
	// 2. redefinition of a referenced address might introduce loops that will drive complexity to infinity
	// 3. if an inner address was redefined by keychange but the definition for the new keyset not supplied before last ball, the address
	// becomes temporarily unusable
	validateDefinition(conn, arrDefinition, objUnit, objValidationState, arrAuthentifierPaths, bAssetCondition, function(err){
		if (err)
			return cb(err);
		//console.log("eval def");
		evaluate(arrDefinition, 'r', function(res){
			if (fatal_error)
				return cb(fatal_error);
			if (!bAssetCondition && arrUsedPaths.length !== Object.keys(assocAuthentifiers).length)
				return cb("some authentifiers are not used, res="+res+", used="+arrUsedPaths+", passed="+JSON.stringify(assocAuthentifiers));
			cb(null, res);
		});
	});
}
828009
function captcha($font,$size=24,$len=5,
		$key=NULL,$path='',$fg=0xFFFFFF,$bg=0x000000) {
		if ((!$ssl=extension_loaded('openssl')) && ($len<4 || $len>13)) {
			user_error(sprintf(self::E_Length,$len),E_USER_ERROR);
			return FALSE;
		}
		if (!function_exists('imagettftext')) {
			user_error(self::E_TTF,E_USER_ERROR);
			return FALSE;
		}
		$fw=Base::instance();
		foreach ($fw->split($path?:$fw->UI.';./') as $dir)
			if (is_file($path=$dir.$font)) {
				$seed=strtoupper(substr(
					$ssl?bin2hex(openssl_random_pseudo_bytes($len)):uniqid(),
					-$len));
				$block=$size*3;
				$tmp=[];
				for ($i=0,$width=0,$height=0;$i<$len;$i++) {
					// Process at 2x magnification
					$box=imagettfbbox($size*2,0,$path,$seed[$i]);
					$w=$box[2]-$box[0];
					$h=$box[1]-$box[5];
					$char=imagecreatetruecolor($block,$block);
					imagefill($char,0,0,$bg);
					imagettftext($char,$size*2,0,
						($block-$w)/2,$block-($block-$h)/2,
						$fg,$path,$seed[$i]);
					$char=imagerotate($char,mt_rand(-30,30),
						imagecolorallocatealpha($char,0,0,0,127));
					// Reduce to normal size
					$tmp[$i]=imagecreatetruecolor(
						($w=imagesx($char))/2,($h=imagesy($char))/2);
					imagefill($tmp[$i],0,0,IMG_COLOR_TRANSPARENT);
					imagecopyresampled($tmp[$i],
						$char,0,0,0,0,$w/2,$h/2,$w,$h);
					imagedestroy($char);
					$width+=$i+1<$len?$block/2:$w/2;
					$height=max($height,$h/2);
				}
				$this->data=imagecreatetruecolor($width,$height);
				imagefill($this->data,0,0,IMG_COLOR_TRANSPARENT);
				for ($i=0;$i<$len;$i++) {
					imagecopy($this->data,$tmp[$i],
						$i*$block/2,($height-imagesy($tmp[$i]))/2,0,0,
						imagesx($tmp[$i]),imagesy($tmp[$i]));
					imagedestroy($tmp[$i]);
				}
				imagesavealpha($this->data,TRUE);
				if ($key)
					$fw->$key=$seed;
				return $this->save();
			}
		user_error(self::E_Font,E_USER_ERROR);
		return FALSE;
	}