------------------------------- witnesses
19963
function getWitnessesFromHub(cb){
	console.log('getWitnessesFromHub');
	if (!my_device_hub){
		console.log('getWitnessesFromHub: no hub yet');
		return setTimeout(function(){
			getWitnessesFromHub(cb);
		}, 2000);
	}
	network.findOutboundPeerOrConnect(conf.WS_PROTOCOL+my_device_hub, function(err, ws){
		if (err)
			return cb(err);
		network.sendRequest(ws, 'get_witnesses', null, false, function(ws, request, response){
			if (response.error)
				return cb(response.error);
			var arrWitnessesFromHub = response;
			cb(null, arrWitnessesFromHub);
		});
	});
}
1104178
private function checkDefinitions(): void {
    // Add many to many stuff if necessary
    foreach($this->unchecked as $def) {
      foreach($def->many_to_many as $relation) {
        //echo "Processing many to many for {$def->name}\n";

        // Set up left keys
        $related = $this->defs[$relation->entity_left];

        if(empty($relation->id_left)) {
          //echo "Setting {$relation->alias_join} id_left to {$related->id->alias}\n";
          $relation->idLeft($related->id->alias);
        }

        if(empty($relation->key_left)) {
          //echo "Setting {$relation->alias_join} key_left to " . keyify($related->name) . "\n";
          $relation->keyLeft(keyify($related->name));
        }
        //

        // Set up right keys
        $related = $this->defs[$relation->entity_right];

        if(empty($relation->id_right)) {
          //echo "Setting {$relation->alias_join} id_right to {$related->id->alias}\n";
          $relation->idRight($related->id->alias);
        }

        if(empty($relation->key_right)) {
          //echo "Setting {$relation->alias_join} key_right to " . keyify($related->name) . "\n";
          $relation->keyRight(keyify($related->name));
        }
        //

        // Left side relations
        $related = $this->defs[$relation->entity_left];

        //echo "Adding {$related->name} hasManyThrough {$relation->alias_join} to {$relation->alias_right}\n";
        $related->hasManyThrough(pluralize($relation->alias_right), $relation->entity_join, $relation->entity_right)
          ->idLocal($relation->id_left)
          ->idForeign($relation->id_right)
          ->keyLocal($relation->key_left)
          ->keyForeign($relation->key_right)
        ;

        if(!array_key_exists($relation->alias_join, $def->has_many)) {
          //echo "Adding {$related->name} hasMany {$def->name}\n";
          $related->hasMany($relation->alias_join, $def->full_name)
            ->localKey  ($relation->id_left)
            ->foreignKey($relation->key_left)
          ;
        }

        if(!array_key_exists($relation->alias_left, $def->belongs_to)) {
          //echo "Adding {$def->name} belongsTo {$related->name}\n";
          $def->belongsTo($relation->alias_left, $related->full_name);
        }
        //

        // Right side relations
        $related = $this->defs[$relation->entity_right];

        //echo "Adding {$related->name} hasManyThrough {$relation->alias_join} to {$relation->alias_left}\n";
        $related->hasManyThrough(pluralize($relation->alias_left), $relation->entity_join, $relation->entity_left)
          ->idLocal($relation->id_right)
          ->idForeign($relation->id_left)
          ->keyLocal($relation->key_right)
          ->keyForeign($relation->key_left)
        ;

        if(!array_key_exists($relation->alias_join, $def->has_many)) {
          //echo "Adding {$related->name} hasMany {$def->name}\n";
          $related->hasMany($relation->alias_join, $def->full_name)
            ->localKey  ($relation->id_right)
            ->foreignKey($relation->key_right)
          ;
        }

        if(!array_key_exists($relation->alias_right, $def->belongs_to)) {
          //echo "Adding {$def->name} belongsTo {$related->name}\n";
          $def->belongsTo($relation->alias_right, $related->full_name);
        }
        //
      }
    }

    // Add has many stuff if necessary
    foreach($this->unchecked as $def) {
      foreach($def->has_many as $relation) {
        //echo "Processing has many for {$def->name}\n";

        $related = $this->defs[$relation->foreign_entity];

        if(empty($relation->local_key)) {
          //echo "Setting {$relation->alias} local_key to {$def->id->alias}\n";
          $relation->localKey($def->id->alias);
        }

        if(empty($relation->foreign_key)) {
          //echo "Setting {$relation->alias} foreign_key to " . keyify($related->name) . "\n";
          $relation->foreignKey(keyify($related->name));
        }
      }
    }

    // Add belongs to stuff if necessary
    foreach($this->unchecked as $def) {
      foreach($def->belongs_to as $relation) {
        //echo "Processing belongs to for {$def->name}\n";

        $related = $this->defs[$relation->foreign_entity];

        if(empty($relation->local_key)) {
          //echo "Setting {$relation->alias} local_key to " . keyify($related->name) . "\n";
          $relation->localKey(keyify($related->name));
        }

        if(empty($relation->foreign_key)) {
          //echo "Setting {$relation->alias} foreign_key to {$def->id->alias}\n";
          $relation->foreignKey($related->id->alias);
        }

        if(!array_key_exists($relation->local_key, $related->required)) {
          //echo "Adding {$def->name} column {$relation->local_key} of type {$related->id->type}\n";
          $def->required($relation->local_key, $related->id->type);
        }
      }
    }

    // We've checked everything in the queue.  Clear it out.
    $this->unchecked = [];
  }
1335855
@Override
  public boolean verifyMessage(InputStream publicKeyOfSender, InputStream message, InputStream signatureStream) {
    LOGGER.trace("verifyMessage(InputStream, InputStream, InputStream)");
    LOGGER.trace("Public Key: {}, Data: {}, Signature: {}",
        publicKeyOfSender == null ? "not set" : "set", message == null ? "not set" : "set", signatureStream == null ? "not set" : "set");
    boolean result = false;
    LOGGER.debug("Wrapping signature stream in ArmoredInputStream");
    try( InputStream armordPublicKeyStream = new ArmoredInputStream(signatureStream) ) {
      Object pgpObject;
      PGPObjectFactory pgpObjectFactory = new PGPObjectFactory(armordPublicKeyStream, new BcKeyFingerprintCalculator());
      LOGGER.debug("Iterating over PGP objects in stream");
      while( (pgpObject = pgpObjectFactory.nextObject()) != null ) {
        if( pgpObject instanceof PGPSignatureList ) {
          LOGGER.debug("Signature List found");
          PGPSignatureList signatureList = (PGPSignatureList)pgpObject;
          LOGGER.debug("Iterating over signature list");
          Iterator<PGPSignature> signatureIterator = signatureList.iterator();
          while( signatureIterator.hasNext() ) {
            LOGGER.debug("Checking next signature");
            final PGPSignature signature = signatureIterator.next();
            PGPPublicKey pgpPublicKey = findPublicKey(publicKeyOfSender, new KeyFilter<PGPPublicKey>() {
              @Override
              public boolean accept(PGPPublicKey pgpKey) {
                return pgpKey.getKeyID() == signature.getKeyID();
              }
            });
            if( pgpPublicKey != null ) {
              signature.init(new BcPGPContentVerifierBuilderProvider(), pgpPublicKey);
              LOGGER.debug("Processing signature data");
              IOUtils.process(message, new IOUtils.StreamHandler() {
                @Override
                public void handleStreamBuffer(byte[] buffer, int offset, int length) throws IOException {
                  signature.update(buffer, offset, length);
                }
              });
              result = signature.verify();
              LOGGER.info("Verify Signature: {}", result);
            } else {
              LOGGER.warn("No public key found for signature. Key ID: {}", signature.getKeyID());
            }
          }
        }
      }
    } catch (IOException | PGPException e) {
      LOGGER.error("{}", e.getMessage());
      result &= false;
    }
    return result;
  }
540186
protected void onSuperColumn(EntityMetadata m, boolean isRelation, List<String> relations, List<Object> entities,
        List<SuperColumn> superColumns, ByteBuffer key) {
        Object e = null;
        Object id = PropertyAccessorHelper.getObject(m.getIdAttribute().getJavaType(), key.array());

        ThriftRow tr = new ThriftRow(id, m.getTableName(), new ArrayList<Column>(0), superColumns,
            new ArrayList<CounterColumn>(0), new ArrayList<CounterSuperColumn>(0));

        e = getDataHandler().populateEntity(tr, m, KunderaCoreUtils.getEntity(e), relations, isRelation);
        if (log.isInfoEnabled()) {
            log.info("Populating data for super column family of clazz {} and row key {}.", m.getEntityClazz(),
                tr.getId());
        }

        if (e != null) {
            entities.add(e);
        }
    }
1224489
function preparePowWitnessProof( last_stable_mci, handleResult )
{
	let arrUnstableMcJoints			= [];

	let arrLastMajorityWitnessedBallUnits	= []; // last ball units referenced from MC-majority-witnessed unstable MC units
	let sLastBallUnit			= null;
	let nLastBallMci			= null;

	_async.series
	([
		function( cb )
		{
			//	collect all unstable MC units
			let arrFoundTrustMEAuthors = [];
			_db.query
			(
				"SELECT unit, pow_type FROM units WHERE is_on_main_chain=1 AND is_stable=0 ORDER BY main_chain_index DESC",
				function( rows )
				{
					_async.eachSeries( rows, function( row, cb2 )
					{
						_storage.readJointWithBall( _db, row.unit, function( objJoint )
						{
							delete objJoint.ball; // the unit might get stabilized while we were reading other units

							//
							//	* unstable mc joints
							//
							arrUnstableMcJoints.push( objJoint );

							for ( let i = 0; i < objJoint.unit.authors.length; i++ )
							{
								let address = objJoint.unit.authors[ i ].address;
								if ( _constants.POW_TYPE_TRUSTME === row.pow_type && -1 === arrFoundTrustMEAuthors.indexOf( address ) )
								{
									arrFoundTrustMEAuthors.push( address );
								}
							}

							//	collect last balls of majority witnessed units
							//	( genesis lacks sLastBallUnit )
							if ( objJoint.unit.last_ball_unit && arrFoundTrustMEAuthors.length >= _constants.MAJORITY_OF_WITNESSES )
							{
								arrLastMajorityWitnessedBallUnits.push( objJoint.unit.last_ball_unit );
							}

							//	...
							cb2();
						});
					}, cb );
				}
			);
		},
		function( cb )
		{
			//	select the newest last ball unit
			if ( arrLastMajorityWitnessedBallUnits.length === 0 )
			{
				return cb( "your witness list might be too much off, too few witness authored units" );
			}

			_db.query
			(
				"SELECT unit, main_chain_index FROM units WHERE unit IN(?) ORDER BY main_chain_index DESC LIMIT 1",
				[ arrLastMajorityWitnessedBallUnits ],
				function( rows )
				{
					//
					//	* last ball mci and unit
					//
					sLastBallUnit	= rows[ 0 ].unit;
					nLastBallMci	= rows[ 0 ].main_chain_index;

					( last_stable_mci >= nLastBallMci )
						? cb( "already_current" )
						: cb();
				}
			);
		}
	], function( err )
	{
		if ( err )
		{
			return handleResult(err);
		}

		//	...
		handleResult( null, arrUnstableMcJoints, sLastBallUnit, nLastBallMci );
	});
}
1070127
public function observe()
  {
    if ( $this->check() ){
      $sql = <<<MYSQL
  SELECT o.id, o.id_user, o.request, o.params,
  GROUP_CONCAT(HEX(aliases.id) SEPARATOR ',') AS aliases,
  GROUP_CONCAT(HEX(aliases.id_user) SEPARATOR ',') AS users,
  GROUP_CONCAT(aliases.result SEPARATOR ',') AS results
  FROM bbn_observers AS o
    LEFT JOIN bbn_observers AS aliases
      ON aliases.id_alias = o.id
  WHERE o.id_alias IS NULL
  AND o.next < NOW()
  GROUP BY o.id
  HAVING COUNT(aliases.id) > 0
  OR o.id_user IS NOT NULL
MYSQL;

      $diff = [];
      //MAX: 2000
      $this->db->query('SET @@group_concat_max_len = ?', 2000 * 32);
      foreach ( $this->db->get_rows($sql) as $d ){
        $aliases = $d['aliases'] ? array_map('strtolower', explode(',', $d['aliases'])) : [];
        $users = $d['users'] ? array_map('strtolower', explode(',', $d['users'])) : [];
        $results = $d['results'] ? explode(',', $d['results']) : [];
        if ( \bbn\str::is_json($d['request']) ){
          $d['request'] = json_decode($d['request'], true);
          $real_result = $this->_exec_array($d['request']);
        }
        else{
          $real_result = $this->_exec($d['request'], $d['params']);
        }
        $db_result = $this->get_result($d['id']);
        // Only if users are attached to the
        echo '+';
        if ( $real_result !== $db_result ){
          $this->db->update('bbn_observers', ['result' => $real_result], ['id' => $d['id']]);
          if ( $d['id_user'] ){
            if ( !isset($diff[$d['id_user']]) ){
              $diff[$d['id_user']] = [];
            }
            $diff[$d['id_user']][] = [
              'id' => $d['id'],
              'result' => $real_result
            ];
          }
        }
        foreach ( $aliases as $i => $a ){
          if ( $real_result !== $results[$i] ){
            $this->db->update('bbn_observers', ['result' => $real_result], ['id' => $a]);
            $t = $users[$i];
            if ( !isset($diff[$t]) ){
              $diff[$t] = [];
            }
            $diff[$t][] = [
              'id' => $a,
              'result' => $real_result
            ];
          }
        }
        bbn\x::log(['-------------------', $d, $diff], 'error');
        $this->_update_next($d['id']);
      }
      echo '.';
      $this->db->flush();
      if ( count($diff) ){
        bbn\x::dump('Returning diff!', $diff);
        return $diff;
      }
      if ( ob_get_contents() ){
        ob_end_flush();
      }
      return true;
    }
    bbn\x::dump('Canceling observer: '.date('H:i:s Y-m-d'));
    return false;
  }
565682
def approvewitness(self, witnesses, account=None, **kwargs):
        
        if not account:
            if "default_account" in self.config:
                account = self.config["default_account"]
        if not account:
            raise ValueError("You need to provide an account")
        account = Account(account, blockchain_instance=self)
        options = account["options"]

        if not isinstance(witnesses, (list, set, tuple)):
            witnesses = {witnesses}

        for witness in witnesses:
            witness = Witness(witness, blockchain_instance=self)
            options["votes"].append(witness["vote_id"])

        options["votes"] = list(set(options["votes"]))
        options["num_witness"] = len(
            list(filter(lambda x: float(x.split(":")[0]) == 1, options["votes"]))
        )

        op = operations.Account_update(
            **{
                "fee": {"amount": 0, "asset_id": "1.3.0"},
                "account": account["id"],
                "new_options": options,
                "extensions": {},
                "prefix": self.prefix,
            }
        )
        return self.finalizeOp(op, account["name"], "active", **kwargs)
1001355
public synchronized void incrAllCounters(Counters other) {
    for (Group otherGroup: other) {
      Group group = getGroup(otherGroup.getName());
      group.displayName = otherGroup.displayName;
      for (Counter otherCounter : otherGroup) {
        Counter counter = group.getCounterForName(otherCounter.getName());
        counter.setDisplayName(otherCounter.getDisplayName());
        counter.increment(otherCounter.getValue());
      }
    }
  }
1349322
@Override
    public void collate(VariantGraph graph, List<? extends Iterable<Token>> witnesses) {
        // phase 1: matching phase
        if (LOG.isLoggable(Level.FINE)) {
            LOG.fine("Building token index from the tokens of all witnesses");
        }

        this.tokenIndex = new TokenIndex(comparator, witnesses);
        tokenIndex.prepare();

        // phase 2: alignment phase
        this.vertex_array = new VariantGraph.Vertex[tokenIndex.token_array.length];
        boolean firstWitness = true;

        for (Iterable<Token> tokens : witnesses) {
            final Witness witness = StreamUtil.stream(tokens)
                    .findFirst()
                    .map(Token::getWitness)
                    .orElseThrow(() -> new IllegalArgumentException("Empty witness"));

            // first witness has a fast path
            if (firstWitness) {
                super.merge(graph, tokens, Collections.emptyMap());
                updateTokenToVertexArray(tokens, witness);
                firstWitness = false;
                continue;
            }

            // align second, third, fourth witness etc.
            if (LOG.isLoggable(Level.FINER)) {
                LOG.log(Level.FINER, "{0} + {1}: {2} vs. {3}", new Object[]{graph, witness, graph.vertices(), tokens});
            }

            // Phase 2a: Gather matches from the token index
            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "{0} + {1}: Gather matches between variant graph and witness from token index", new Object[]{graph, witness});
            }

            allPossibleIslands = TokenIndexToMatches.createMatches(tokenIndex, vertex_array, graph, tokens);

            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "{0} + {1}: Aligning witness and graph", new Object[]{graph, witness});
            }

            // Phase 2b: do the actual alignment
            IslandConflictResolver resolver = new IslandConflictResolver(new IslandCollection(allPossibleIslands));
            preferredIslands = resolver.createNonConflictingVersion().getIslands();

            // we need to convert the islands into Map<Token, Vertex> for further processing
            Map<Token, VariantGraph.Vertex> alignments = new HashMap<>();
            for (Island island : preferredIslands) {
                for (Coordinate c : island) {
                    alignments.put(c.match.token, c.match.vertex);
                }
            }

            if (LOG.isLoggable(Level.FINER)) {
                for (Map.Entry<Token, VariantGraph.Vertex> tokenLink : alignments.entrySet()) {
                    LOG.log(Level.FINER, "{0} + {1}: Aligned token (incl transposed): {2} = {3}", new Object[]{graph, witness, tokenLink.getValue(), tokenLink.getKey()});
                }
            }

            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "{0} + {1}: Detect phrase matches", new Object[]{graph, witness});
            }

            // Phase 2c: detect phrases and transpositions
            phraseMatches = phraseMatchDetector.detect(alignments, graph, tokens);

            if (LOG.isLoggable(Level.FINER)) {
                for (List<Match> phraseMatch : phraseMatches) {
                    LOG.log(Level.FINER, "{0} + {1}: Phrase match: {2}", new Object[]{graph, witness, phraseMatch});
                }
            }

            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "{0} + {1}: Detect transpositions", new Object[]{graph, witness});
            }

            transpositions = transpositionDetector.detect(phraseMatches, graph);

            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "transpositions:{0}", transpositions);
            }

            if (LOG.isLoggable(Level.FINER)) {
                for (List<Match> transposition : transpositions) {
                    LOG.log(Level.FINER, "{0} + {1}: Transposition: {2}", new Object[]{graph, witness, transposition});
                }
            }

            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "{0} + {1}: Determine aligned tokens by filtering transpositions", new Object[]{graph, witness});
            }

            // Filter out transposed tokens from aligned tokens
            for (List<Match> transposedPhrase : transpositions) {
                for (Match match : transposedPhrase) {
                    alignments.remove(match.token);
                }
            }

            if (LOG.isLoggable(Level.FINER)) {
                for (Map.Entry<Token, VariantGraph.Vertex> alignment : alignments.entrySet()) {
                    LOG.log(Level.FINER, "{0} + {1}: Alignment: {2} = {3}", new Object[]{graph, witness, alignment.getValue(), alignment.getKey()});
                }
            }

            // Phase 2d: and merge
            merge(graph, tokens, alignments);

            // we filter out small transposed phrases over large distances
            List<List<Match>> falseTranspositions = new ArrayList<>();

            // rank the variant graph
            VariantGraphRanking ranking = VariantGraphRanking.of(graph);

            for (List<Match> transposedPhrase : transpositions) {
                Match match = transposedPhrase.get(0);
                VariantGraph.Vertex v1 = witnessTokenVertices.get(match.token);
                VariantGraph.Vertex v2 = match.vertex;
                int distance = Math.abs(ranking.apply(v1) - ranking.apply(v2)) - 1;
                if (distance > transposedPhrase.size() * 3) {
                    falseTranspositions.add(transposedPhrase);
                }
            }

            transpositions.removeAll(falseTranspositions);

            // merge transpositions
            if (mergeTranspositions) {
                mergeTranspositions(graph, transpositions);
            }

            updateTokenToVertexArray(tokens, witness);

            if (LOG.isLoggable(Level.FINER)) {
                LOG.log(Level.FINER, "!{0}: {1}", new Object[]{graph, StreamUtil.stream(graph.vertices()).map(Object::toString).collect(Collectors.joining(", "))});
            }
        }
    }
1256965
public static <W extends WitnessType<W>,ST,A> EitherT<W,ST,A> fromAnyM(final AnyM<W,A> anyM) {
        return of(anyM.map(Either::right));
    }
831393
public static <W extends WitnessType<W>,A> EvalT<W,A> fromAnyM(final AnyM<W,A> anyM) {
        return of(anyM.map(Eval::now));
    }
1152122
@Override
	protected void onBeforeRender() {
		super.onBeforeRender();

		List<FeedbackMessage> msgs = model.getObject();
		messages = new HashMap<Component, List<FeedbackMessage>>();
		
		for(FeedbackMessage msg : msgs){
			if(!messages.containsKey(msg.getReporter())) messages.put(msg.getReporter(), new ArrayList<FeedbackMessage>());
			messages.get(msg.getReporter()).add(msg);
			msg.markRendered();
		}
	}
82317
function buildListOfMcUnitsWithPotentiallyDifferentWitnesslists(conn, objUnit, last_ball_unit, arrWitnesses, handleList){

	function addAndGoUp(unit){
		readStaticUnitProps(conn, unit, function(props){
			// the parent has the same witness list and the parent has already passed the MC compatibility test
			if (objUnit.witness_list_unit && objUnit.witness_list_unit === props.witness_list_unit)
				return handleList(true, arrMcUnits);
			else
				arrMcUnits.push(unit);
			if (unit === last_ball_unit)
				return handleList(true, arrMcUnits);
			if (!props.best_parent_unit)
				throw Error("no best parent of unit "+unit+"?");
			addAndGoUp(props.best_parent_unit);
		});
	}

	var arrMcUnits = [];
	determineBestParent(conn, objUnit, arrWitnesses, function(best_parent_unit){
		if (!best_parent_unit)
			return handleList(false);
		addAndGoUp(best_parent_unit);
	});
}
116240
public static <W extends WitnessType<W>,A> OptionalT<W,A> fromAnyM(final AnyM<W,A> anyM) {
        return of(anyM.map(Optional::ofNullable));
    }
270156
function processPowWitnessProof( arrUnstableMcJoints, bFromCurrent, handleResult )
{
	//	unstable MC joints
	let arrParentUnits			= null;
	let arrFoundTrustMEAuthors		= [];
	let arrLastMajorityWitnessedBallUnits	= [];
	let assocLastBallByLastBallUnit		= {};
	let arrTrustMEJoints			= [];

	//
	//	arrUnstableMcJoints were collected by SQL below:
	//	SELECT unit, pow_type FROM units WHERE is_on_main_chain=1 AND is_stable=0 ORDER BY main_chain_index DESC
	//
	for ( let i = 0; i < arrUnstableMcJoints.length; i ++ )
	{
		let objJoint	= arrUnstableMcJoints[ i ];
		let objUnit	= objJoint.unit;

		if ( objJoint.ball )
		{
			return handleResult( "unstable mc but has ball" );
		}
		if ( ! _validation.hasValidHashes( objJoint ) )
		{
			return handleResult( "invalid hash" );
		}
		if ( arrParentUnits && arrParentUnits.indexOf( objUnit.unit ) === -1 )
		{
			return handleResult( "not in parents" );
		}

		//	...
		let bAddedJoint = false;
		if ( _constants.POW_TYPE_TRUSTME === objUnit.pow_type )
		{
			for ( let j = 0; j < objUnit.authors.length; j++ )
			{
				let address = objUnit.authors[ j ].address;

				if ( -1 === arrFoundTrustMEAuthors.indexOf( address ) )
				{
					arrFoundTrustMEAuthors.push( address );
				}

				//
				//	TODO
				//	@20180902 17:53 by XING
				//	move line "bAddedJoint = true;" into braces above
				//
				if ( ! bAddedJoint )
				{
					arrTrustMEJoints.push( objJoint );
				}
				bAddedJoint = true;
			}
		}

		arrParentUnits = objUnit.parent_units;
		if ( objUnit.last_ball_unit && arrFoundTrustMEAuthors.length >= _constants.MAJORITY_OF_WITNESSES )
		{
			arrLastMajorityWitnessedBallUnits.push( objUnit.last_ball_unit );
			assocLastBallByLastBallUnit[ objUnit.last_ball_unit ] = objUnit.last_ball;
		}
	}
	return handleResult(null, null, assocLastBallByLastBallUnit);
	//	end of forEach arrUnstableMcJoints


	if ( arrFoundTrustMEAuthors.length < _constants.MAJORITY_OF_WITNESSES )
	{
		return handleResult( "not enough witnesses" );
	}
	if ( 0 === arrLastMajorityWitnessedBallUnits.length )
	{
		throw Error( "processWitnessProof: no last ball units" );
	}


	let assocDefinitions		= {};	//	keyed by definition chash
	let assocDefinitionChashes	= {};	//	keyed by address

	//
	//	checks signatures and updates definitions
	//
	function validateUnit( objUnit, bRequireDefinitionOrChange, cb2 )
	{
		let bFound = false;
		_async.eachSeries
		(
			objUnit.authors,
			function( author, cb3 )
			{
				let sAddress = author.address;
				if ( -1 === arrFoundTrustMEAuthors.indexOf( sAddress ) )
				{
					//	not a witness - skip it
					return cb3();
				}

				//
				//	the latest definition chash of the witness
				//
				let definition_chash = assocDefinitionChashes[ sAddress ];
				if ( ! definition_chash )
				{
					throw Error( "definition chash not known for address " + sAddress );
				}
				if ( author.definition )
				{
					//
					//	do transaction for the first time
					//
					if ( _object_hash.getChash160( author.definition ) !== definition_chash )
					{
						return cb3( "definition doesn't hash to the expected value" );
					}

					assocDefinitions[ definition_chash ] = author.definition;
					bFound = true;
				}


				function handleAuthor()
				{
					//	FIX
					_validation.validateAuthorSignaturesWithoutReferences
					(
						author,
						objUnit,
						assocDefinitions[ definition_chash ],	//	definition JSON
						function( err )
						{
							if ( err )
							{
								return cb3( err );
							}

							//
							//	okay, definition is valid
							//
							for ( let i = 0; i < objUnit.messages.length; i++ )
							{
								let message = objUnit.messages[ i ];
								if ( 'address_definition_change' === message.app
									&& ( message.payload.address === sAddress ||
										1 === objUnit.authors.length && objUnit.authors[ 0 ].address === sAddress ) )
								{
									assocDefinitionChashes[ sAddress ] = message.payload.definition_chash;
									bFound = true;
								}
							}

							//	...
							cb3();
						}
					);
				}

				if ( assocDefinitions[ definition_chash ] )
				{
					return handleAuthor();
				}

				//
				//	only an address with money
				//	there is no transaction any more
				//
				_storage.readDefinition( _db, definition_chash,
				{
					ifFound : function( arrDefinition )
					{
						assocDefinitions[ definition_chash ] = arrDefinition;
						handleAuthor();
					},
					ifDefinitionNotFound : function( sDefinitionCHash )
					{
						throw Error( "definition " + definition_chash + " not found, address " + sAddress );
					}
				});
			},
			function( err )
			{
				if ( err )
				{
					return cb2( err );
				}

				if ( bRequireDefinitionOrChange && ! bFound )
				{
					//
					//	bRequireDefinitionOrChange always be false
					//	so, you will never arrive here so far
					//
					return cb2( "neither definition nor change" );
				}

				//	...
				cb2();
			}

		); // each authors
	}


	//
	//	...
	//
	let unlock = null;
	_async.series
	([
		function( cb )
		{
			//	read latest known definitions of witness addresses
			if ( ! bFromCurrent )
			{
				for ( let i = 0; i < arrFoundTrustMEAuthors.length; i ++ )
				{
					let address = arrFoundTrustMEAuthors[ i ];
					assocDefinitionChashes[ address ] = address;
				}
				return cb();
			}

			//
			//	try to obtain definitions
			//
			_async.eachSeries
			(
				arrFoundTrustMEAuthors,
				function( sAddress, cb2 )
				{
					_storage.readDefinitionByAddress( _db, sAddress, null,
					{
						ifFound : function( arrDefinition )
						{
							let definition_chash = _object_hash.getChash160( arrDefinition );
							assocDefinitions[ definition_chash ]	= arrDefinition;
							assocDefinitionChashes[ sAddress ]	= definition_chash;
							cb2();
						},
						ifDefinitionNotFound : function( definition_chash )
						{
							assocDefinitionChashes[ sAddress ]	= definition_chash;
							cb2();
						}
					});
				},
				cb
			);
		},
		function( cb )
		{
			//
			//	check signatures of unstable witness joints
			//
			_async.eachSeries
			(
				arrTrustMEJoints.reverse(),	//	they came in reverse chronological order, reverse() reverses in place
				function( objJoint, pfnEachNext )
				{
					validateUnit( objJoint.unit, false, pfnEachNext );
				},
				cb
			);
		},
	], function( err )
	{
		err ? handleResult( err ) : handleResult( null, arrLastMajorityWitnessedBallUnits, assocLastBallByLastBallUnit );
	});
}
644737
def jacobi_witness(x, n):
    '''
    '''
    j = jacobi(x, n) % n
    f = pow(x, n >> 1, n)
    return j != f
193501
@Override public void onNewTraces(List<Trace> traces) {
    int tracesRemoved = updateTraceBuffer(traces);
    List<Trace> tracesToNotify = getCurrentTraces();
    view.showTraces(tracesToNotify, tracesRemoved);
  }