Add first nodes with negative weights
This commit is contained in:
@@ -27,11 +27,11 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
#include "Util.h"
|
||||
|
||||
struct _PathData {
|
||||
_PathData(NodeID no, unsigned na, unsigned tu, unsigned le) : node(no), nameID(na), turnInstruction(tu), lengthOfSegment(le) { }
|
||||
_PathData(NodeID no, unsigned na, unsigned tu, unsigned le) : node(no), nameID(na), lengthOfSegment(le), turnInstruction(tu) { }
|
||||
NodeID node;
|
||||
unsigned nameID;
|
||||
unsigned turnInstruction;
|
||||
unsigned lengthOfSegment;
|
||||
short turnInstruction;
|
||||
};
|
||||
|
||||
typedef boost::unordered_map<std::string, NodeID> StringMap;
|
||||
|
||||
@@ -22,9 +22,11 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
#define GRIDEDGE_H_
|
||||
|
||||
struct _GridEdge {
|
||||
_GridEdge(NodeID n, _Coordinate sc, _Coordinate tc) : edgeBasedNode(n), startCoord(sc), targetCoord(tc) {}
|
||||
_GridEdge() : edgeBasedNode(UINT_MAX) {}
|
||||
_GridEdge(NodeID n, NodeID na, int w, _Coordinate sc, _Coordinate tc) : edgeBasedNode(n), nameID(na), weight(w), startCoord(sc), targetCoord(tc) {}
|
||||
_GridEdge() : edgeBasedNode(UINT_MAX), nameID(UINT_MAX), weight(INT_MAX) {}
|
||||
NodeID edgeBasedNode;
|
||||
NodeID nameID;
|
||||
int weight;
|
||||
_Coordinate startCoord;
|
||||
_Coordinate targetCoord;
|
||||
};
|
||||
|
||||
+44
-6
@@ -198,7 +198,7 @@ public:
|
||||
int tlat = 100000*lat2y(edge.lat2/100000.);
|
||||
int tlon = edge.lon2;
|
||||
AddEdge( _GridEdge(
|
||||
edge.id, edge.nameID,
|
||||
edge.id, edge.nameID, edge.weight,
|
||||
_Coordinate(slat, slon),
|
||||
_Coordinate(tlat, tlon) )
|
||||
);
|
||||
@@ -300,26 +300,55 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
_Coordinate tmp;
|
||||
_GridEdge smallestEdge;
|
||||
_Coordinate tmp, newEndpoint;
|
||||
double dist = (numeric_limits<double>::max)();
|
||||
BOOST_FOREACH(_GridEdge candidate, candidates) {
|
||||
double r = 0.;
|
||||
double tmpDist = ComputeDistance(startCoord, candidate.startCoord, candidate.targetCoord, tmp, &r);
|
||||
if((tmpDist == dist) && 1 == std::abs((int)candidate.edgeBasedNode-(int)resultNode.edgeBasedNode)) {
|
||||
if(DoubleEpsilonCompare(dist, tmpDist) && 1 == std::abs((int)candidate.edgeBasedNode-(int)resultNode.edgeBasedNode)) {
|
||||
resultNode.isBidirected = true;
|
||||
resultNode.edgeBasedNode = std::min(candidate.edgeBasedNode, resultNode.edgeBasedNode);
|
||||
resultNode.weight2 = candidate.weight;
|
||||
/* if(resultNode.weight1 != resultNode.weight2) {
|
||||
ERR("w1: " << resultNode.weight1 << ", w2: " << resultNode.weight2);
|
||||
assert(false);
|
||||
}*/
|
||||
if(candidate.edgeBasedNode < resultNode.edgeBasedNode) {
|
||||
resultNode.edgeBasedNode = candidate.edgeBasedNode;
|
||||
std::swap(resultNode.weight1, resultNode.weight2);
|
||||
}
|
||||
}
|
||||
if(tmpDist < dist) {
|
||||
resultNode.isBidirected = false;
|
||||
resultNode.Reset();
|
||||
resultNode.edgeBasedNode = candidate.edgeBasedNode;
|
||||
resultNode.nodeBasedEdgeNameID = candidate.nameID;
|
||||
resultNode.ratio = r;
|
||||
resultNode.weight1 = candidate.weight;
|
||||
dist = tmpDist;
|
||||
resultNode.location.lat = round(100000*(y2lat(static_cast<double>(tmp.lat)/100000.)));
|
||||
resultNode.location.lon = tmp.lon;
|
||||
foundNode = true;
|
||||
smallestEdge = candidate;
|
||||
newEndpoint = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// INFO("startcoord: " << smallestEdge.startCoord << ", tgtcoord" << smallestEdge.targetCoord << "result: " << newEndpoint);
|
||||
// INFO("length of old edge: " << LengthOfVector(smallestEdge.startCoord, smallestEdge.targetCoord));
|
||||
// INFO("Length of new edge: " << LengthOfVector(smallestEdge.startCoord, newEndpoint));
|
||||
// assert(!resultNode.isBidirected || (resultNode.weight1 == resultNode.weight2));
|
||||
// if(resultNode.weight1 != resultNode.weight2) {
|
||||
// INFO("-> Weight1: " << resultNode.weight1 << ", weight2: " << resultNode.weight2);
|
||||
// INFO("-> node: " << resultNode.edgeBasedNode << ", bidir: " << (resultNode.isBidirected ? "yes" : "no"));
|
||||
// }
|
||||
|
||||
double ratio = std::min(1., LengthOfVector(smallestEdge.startCoord, newEndpoint)/LengthOfVector(smallestEdge.startCoord, smallestEdge.targetCoord) );
|
||||
assert(ratio >= 0 && ratio <=1);
|
||||
// INFO("Old weight1: " << resultNode.weight1 << ", old weight2: " << resultNode.weight2);
|
||||
resultNode.weight1 *= ratio;
|
||||
if(resultNode.isBidirected) {
|
||||
resultNode.weight2 *= (1-ratio);
|
||||
// INFO("New weight1: " << resultNode.weight1 << ", new weight2: " << resultNode.weight2);
|
||||
}
|
||||
return foundNode;
|
||||
}
|
||||
|
||||
@@ -375,6 +404,15 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
inline double LengthOfVector(const _Coordinate & c1, const _Coordinate & c2) {
|
||||
double length1 = std::sqrt(c1.lat/100000.*c1.lat/100000. + c1.lon/100000.*c1.lon/100000.);
|
||||
double length2 = std::sqrt(c2.lat/100000.*c2.lat/100000. + c2.lon/100000.*c2.lon/100000.);
|
||||
return std::fabs(length1-length2);
|
||||
}
|
||||
|
||||
inline bool DoubleEpsilonCompare(const double d1, const double d2) {
|
||||
return (std::fabs(d1 - d2) < 0.000000001);
|
||||
}
|
||||
|
||||
unsigned FillCell(std::vector<GridEntry>& entriesWithSameRAMIndex, unsigned fileOffset ) {
|
||||
vector<char> * tmpBuffer = new vector<char>();
|
||||
|
||||
@@ -24,18 +24,21 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
#include "ExtractorStructs.h"
|
||||
|
||||
struct PhantomNode {
|
||||
PhantomNode() : isBidirected(false), edgeBasedNode(UINT_MAX), nodeBasedEdgeNameID(UINT_MAX), ratio(1.) {}
|
||||
PhantomNode() : isBidirected(false), edgeBasedNode(UINT_MAX), nodeBasedEdgeNameID(UINT_MAX), weight1(INT_MAX), weight2(INT_MAX) {}
|
||||
bool isBidirected;
|
||||
NodeID edgeBasedNode;
|
||||
unsigned nodeBasedEdgeNameID;
|
||||
double ratio;
|
||||
int weight1;
|
||||
int weight2;
|
||||
_Coordinate location;
|
||||
void Reset() {
|
||||
isBidirected = false;
|
||||
edgeBasedNode = UINT_MAX;
|
||||
ratio = 1.;
|
||||
nodeBasedEdgeNameID = UINT_MAX;
|
||||
weight1 = INT_MAX;
|
||||
weight2 = INT_MAX;
|
||||
location.Reset();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct PhantomNodes {
|
||||
|
||||
@@ -25,6 +25,8 @@ or see http://www.gnu.org/licenses/agpl.txt.
|
||||
|
||||
#include "ExtractorStructs.h"
|
||||
|
||||
#include "../Util/StringUtil.h"
|
||||
|
||||
class PolylineCompressor {
|
||||
private:
|
||||
inline void encodeVectorSignedNumber(vector<int> & numbers, string & output) {
|
||||
|
||||
@@ -76,10 +76,6 @@ public:
|
||||
result.lon = nodeHelpDesk->getLongitudeOfNode(id);
|
||||
}
|
||||
|
||||
unsigned int numberOfNodes() const {
|
||||
return nodeHelpDesk->getNumberOfNodes();
|
||||
}
|
||||
|
||||
inline void InitializeThreadLocalStorageIfNecessary() {
|
||||
if(!_forwardHeap.get())
|
||||
_forwardHeap.reset(new BinaryHeap< NodeID, NodeID, int, _HeapData >(nodeHelpDesk->getNumberOfNodes()));
|
||||
@@ -92,8 +88,8 @@ public:
|
||||
_backwardHeap->Clear();
|
||||
}
|
||||
|
||||
unsigned int ComputeRoute(PhantomNodes & phantomNodes, vector<_PathData> & path) {
|
||||
unsigned int _upperbound = UINT_MAX;
|
||||
int ComputeRoute(PhantomNodes & phantomNodes, vector<_PathData> & path) {
|
||||
int _upperbound = INT_MAX;
|
||||
if(!phantomNodes.AtLeastOnePhantomNodeIsUINTMAX())
|
||||
return _upperbound;
|
||||
|
||||
@@ -105,19 +101,19 @@ public:
|
||||
return _upperbound;
|
||||
}
|
||||
//insert start and/or target node of start edge
|
||||
_forwardHeap->Insert(phantomNodes.startPhantom.edgeBasedNode, 0, phantomNodes.startPhantom.edgeBasedNode);
|
||||
// INFO("Inserting start1: " << phantomNodes.startPhantom.edgeBasedNode);
|
||||
_forwardHeap->Insert(phantomNodes.startPhantom.edgeBasedNode, -phantomNodes.startPhantom.weight1, phantomNodes.startPhantom.edgeBasedNode);
|
||||
// INFO("[FORW] Inserting node " << phantomNodes.startPhantom.edgeBasedNode << " at distance " << -phantomNodes.startPhantom.weight1);
|
||||
if(phantomNodes.startPhantom.isBidirected) {
|
||||
_forwardHeap->Insert(phantomNodes.startPhantom.edgeBasedNode+1, 0, phantomNodes.startPhantom.edgeBasedNode+1);
|
||||
// INFO("Inserting start2: " << phantomNodes.startPhantom.edgeBasedNode+1);
|
||||
_forwardHeap->Insert(phantomNodes.startPhantom.edgeBasedNode+1, -phantomNodes.startPhantom.weight2, phantomNodes.startPhantom.edgeBasedNode+1);
|
||||
// INFO("[FORW] Inserting node " << phantomNodes.startPhantom.edgeBasedNode+1 << " at distance " << -phantomNodes.startPhantom.weight2);
|
||||
}
|
||||
|
||||
//insert start and/or target node of target edge id
|
||||
_backwardHeap->Insert(phantomNodes.targetPhantom.edgeBasedNode, 0, phantomNodes.targetPhantom.edgeBasedNode);
|
||||
// INFO("Inserting target1: " << phantomNodes.targetPhantom.edgeBasedNode);
|
||||
_backwardHeap->Insert(phantomNodes.targetPhantom.edgeBasedNode, -phantomNodes.targetPhantom.weight1, phantomNodes.targetPhantom.edgeBasedNode);
|
||||
// INFO("[BACK] Inserting node " << phantomNodes.targetPhantom.edgeBasedNode << " at distance " << -phantomNodes.targetPhantom.weight1);
|
||||
if(phantomNodes.targetPhantom.isBidirected) {
|
||||
_backwardHeap->Insert(phantomNodes.targetPhantom.edgeBasedNode+1, 0, phantomNodes.targetPhantom.edgeBasedNode+1);
|
||||
// INFO("Inserting target2: " << phantomNodes.targetPhantom.edgeBasedNode+1);
|
||||
_backwardHeap->Insert(phantomNodes.targetPhantom.edgeBasedNode+1, -phantomNodes.targetPhantom.weight2, phantomNodes.targetPhantom.edgeBasedNode+1);
|
||||
// INFO("[BACK] Inserting node " << phantomNodes.targetPhantom.edgeBasedNode+1 << " at distance " << -phantomNodes.targetPhantom.weight2);
|
||||
}
|
||||
|
||||
while(_forwardHeap->Size() + _backwardHeap->Size() > 0){
|
||||
@@ -130,7 +126,7 @@ public:
|
||||
}
|
||||
// INFO("bidirectional search iteration ended: " << _forwardHeap->Size() << "," << _backwardHeap->Size() << ", dist: " << _upperbound);
|
||||
|
||||
if ( _upperbound == UINT_MAX ) {
|
||||
if ( _upperbound == INT_MAX ) {
|
||||
return _upperbound;
|
||||
}
|
||||
NodeID pathNode = middle;
|
||||
@@ -156,7 +152,7 @@ public:
|
||||
unsigned int ComputeDistanceBetweenNodes(NodeID start, NodeID target) {
|
||||
InitializeThreadLocalStorageIfNecessary();
|
||||
NodeID middle(UINT_MAX);
|
||||
unsigned int _upperbound = UINT_MAX;
|
||||
int _upperbound = INT_MAX;
|
||||
_forwardHeap->Insert(start, 0, start);
|
||||
_backwardHeap->Insert(target, 0, target);
|
||||
while(_forwardHeap->Size() + _backwardHeap->Size() > 0){
|
||||
@@ -167,14 +163,13 @@ public:
|
||||
_RoutingStep(_backwardHeap, _forwardHeap, false, &middle, &_upperbound);
|
||||
}
|
||||
}
|
||||
|
||||
return _upperbound;
|
||||
}
|
||||
|
||||
unsigned int ComputeDistanceBetweenNodesWithStats(NodeID start, NodeID target, _Statistics & stats) {
|
||||
InitializeThreadLocalStorageIfNecessary();
|
||||
NodeID middle(UINT_MAX);
|
||||
unsigned int _upperbound = UINT_MAX;
|
||||
int _upperbound = INT_MAX;
|
||||
_forwardHeap->Insert(start, 0, start);
|
||||
_backwardHeap->Insert(target, 0, target);
|
||||
stats.insertedNodes += 2;
|
||||
@@ -190,11 +185,6 @@ public:
|
||||
return _upperbound;
|
||||
}
|
||||
|
||||
inline unsigned int findNearestNodeForLatLon(const _Coordinate & coord, _Coordinate & result) const {
|
||||
nodeHelpDesk->FindNearestNodeCoordForLatLon(coord, result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline bool FindRoutingStarts(const _Coordinate & start, const _Coordinate & target, PhantomNodes & routingStarts) {
|
||||
nodeHelpDesk->FindRoutingStarts(start, target, routingStarts);
|
||||
return true;
|
||||
@@ -205,7 +195,6 @@ public:
|
||||
}
|
||||
|
||||
inline NodeID GetNameIDForOriginDestinationNodeID(NodeID s, NodeID t) const {
|
||||
//INFO("Getting nameID for s=" << s << " and t=" << t);
|
||||
if(s == t)
|
||||
return 0;
|
||||
|
||||
@@ -213,7 +202,6 @@ public:
|
||||
if(e == UINT_MAX)
|
||||
e = _graph->FindEdge( t, s );
|
||||
if(UINT_MAX == e) {
|
||||
// INFO("edge not found for start " << s << ", target " << t)
|
||||
return 0;
|
||||
}
|
||||
assert(e != UINT_MAX);
|
||||
@@ -221,45 +209,22 @@ public:
|
||||
return ed.via;
|
||||
}
|
||||
|
||||
inline NodeID GetWeightForOriginDestinationNodeID(NodeID s, NodeID t) const {
|
||||
assert(s!=t);
|
||||
EdgeID e = _graph->FindEdge(s, t);
|
||||
if(e == UINT_MAX)
|
||||
e = _graph->FindEdge( t, s );
|
||||
assert(e != UINT_MAX);
|
||||
const EdgeData ed = _graph->GetEdgeData(e);
|
||||
return ed.distance;
|
||||
}
|
||||
|
||||
inline std::string & GetUnescapedNameForNameID(const NodeID nameID) const {
|
||||
return (nameID >= _names->size() ? _names->at(0) : _names->at(nameID));
|
||||
}
|
||||
|
||||
inline std::string GetEscapedNameForOriginDestinationNodeID(NodeID s, NodeID t) const {
|
||||
NodeID nameID = GetNameIDForOriginDestinationNodeID(s, t);
|
||||
return (GetEscapedNameForNameID(nameID));
|
||||
}
|
||||
|
||||
inline std::string GetEscapedNameForNameID(const NodeID nameID) const {
|
||||
return ((nameID >= _names->size() || nameID == 0) ? std::string("") : HTMLEntitize(_names->at(nameID)));
|
||||
}
|
||||
|
||||
inline short GetTypeOfEdgeForOriginDestinationNodeID(NodeID s, NodeID t) const {
|
||||
assert(s!=t);
|
||||
EdgeID e = _graph->FindEdge(s, t);
|
||||
if(e == UINT_MAX)
|
||||
e = _graph->FindEdge( t, s );
|
||||
assert(e != UINT_MAX);
|
||||
const EdgeData ed = _graph->GetEdgeData(e);
|
||||
return ed.type;
|
||||
}
|
||||
inline std::string GetEscapedNameForEdgeBasedEdgeID(const unsigned edgeID) const {
|
||||
|
||||
const unsigned nameID = _graph->GetEdgeData(edgeID).nameID1;
|
||||
return GetEscapedNameForNameID(nameID);
|
||||
}
|
||||
private:
|
||||
inline void _RoutingStep(HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, const bool & forwardDirection, NodeID *middle, unsigned int *_upperbound) {
|
||||
inline void _RoutingStep(HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, const bool & forwardDirection, NodeID *middle, int *_upperbound) {
|
||||
const NodeID node = _forwardHeap->DeleteMin();
|
||||
const unsigned int distance = _forwardHeap->GetKey(node);
|
||||
const int distance = _forwardHeap->GetKey(node);
|
||||
// INFO((forwardDirection ? "[FORW]" : "[BACK]") << " settling " << node << " with distance " << distance);
|
||||
if(_backwardHeap->WasInserted(node)){
|
||||
const unsigned int newDistance = _backwardHeap->GetKey(node) + distance;
|
||||
const int newDistance = _backwardHeap->GetKey(node) + distance;
|
||||
if(newDistance < *_upperbound){
|
||||
*middle = node;
|
||||
*_upperbound = newDistance;
|
||||
@@ -270,9 +235,9 @@ private:
|
||||
_forwardHeap->DeleteAll();
|
||||
return;
|
||||
}
|
||||
/* for ( typename GraphT::EdgeIterator edge = _graph->BeginEdges( node ); edge < _graph->EndEdges(node); edge++ ) {
|
||||
for ( typename GraphT::EdgeIterator edge = _graph->BeginEdges( node ); edge < _graph->EndEdges(node); edge++ ) {
|
||||
const NodeID to = _graph->GetTarget(edge);
|
||||
const EdgeWeight edgeWeight = _graph->GetEdgeData(edge).distance;
|
||||
const int edgeWeight = _graph->GetEdgeData(edge).distance;
|
||||
|
||||
assert( edgeWeight > 0 );
|
||||
|
||||
@@ -286,19 +251,20 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
for ( typename GraphT::EdgeIterator edge = _graph->BeginEdges( node ); edge < _graph->EndEdges(node); edge++ ) {
|
||||
const NodeID to = _graph->GetTarget(edge);
|
||||
const EdgeWeight edgeWeight = _graph->GetEdgeData(edge).distance;
|
||||
const int edgeWeight = _graph->GetEdgeData(edge).distance;
|
||||
|
||||
assert( edgeWeight > 0 );
|
||||
const int toDistance = distance + edgeWeight;
|
||||
assert(toDistance > 0);
|
||||
|
||||
bool forwardDirectionFlag = (forwardDirection ? _graph->GetEdgeData(edge).forward : _graph->GetEdgeData(edge).backward );
|
||||
if(forwardDirectionFlag) {
|
||||
const int toDistance = distance + edgeWeight;
|
||||
// INFO((forwardDirection ? "[FORW]" : "[BACK]") << " relaxing edge (" << node << "," << to << ") with distance " << toDistance << "=" << distance << "+" << edgeWeight);
|
||||
|
||||
//New Node discovered -> Add to Heap + Node Info Storage
|
||||
if ( !_forwardHeap->WasInserted( to ) ) {
|
||||
// INFO((forwardDirection ? "[FORW]" : "[BACK]") << " inserting node " << to << " at distance " << toDistance);
|
||||
_forwardHeap->Insert( to, toDistance, node );
|
||||
}
|
||||
//Found a shorter Path -> Update distance
|
||||
@@ -311,7 +277,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
inline void _RoutingStepWithStats(HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, const bool & forwardDirection, NodeID *middle, unsigned int *_upperbound, _Statistics & stats) {
|
||||
inline void _RoutingStepWithStats(HeapPtr & _forwardHeap, HeapPtr & _backwardHeap, const bool & forwardDirection, NodeID *middle, int *_upperbound, _Statistics & stats) {
|
||||
const NodeID node = _forwardHeap->DeleteMin();
|
||||
stats.deleteMins++;
|
||||
const unsigned int distance = _forwardHeap->GetKey(node);
|
||||
@@ -367,9 +333,9 @@ private:
|
||||
assert(source != target);
|
||||
//find edge first.
|
||||
typename GraphT::EdgeIterator smallestEdge = SPECIAL_EDGEID;
|
||||
EdgeWeight smallestWeight = UINT_MAX;
|
||||
int smallestWeight = INT_MAX;
|
||||
for(typename GraphT::EdgeIterator eit = _graph->BeginEdges(source);eit < _graph->EndEdges(source);eit++){
|
||||
const EdgeWeight weight = _graph->GetEdgeData(eit).distance;
|
||||
const int weight = _graph->GetEdgeData(eit).distance;
|
||||
if(_graph->GetTarget(eit) == target && weight < smallestWeight && _graph->GetEdgeData(eit).forward){
|
||||
smallestEdge = eit;
|
||||
smallestWeight = weight;
|
||||
@@ -378,7 +344,7 @@ private:
|
||||
|
||||
if(smallestEdge == SPECIAL_EDGEID){
|
||||
for(typename GraphT::EdgeIterator eit = _graph->BeginEdges(target);eit < _graph->EndEdges(target);eit++){
|
||||
const EdgeWeight weight = _graph->GetEdgeData(eit).distance;
|
||||
const int weight = _graph->GetEdgeData(eit).distance;
|
||||
if(_graph->GetTarget(eit) == source && weight < smallestWeight && _graph->GetEdgeData(eit).backward){
|
||||
smallestEdge = eit;
|
||||
smallestWeight = weight;
|
||||
@@ -387,7 +353,7 @@ private:
|
||||
|
||||
}
|
||||
|
||||
assert(smallestWeight != SPECIAL_EDGEID);
|
||||
assert(smallestWeight != INT_MAX);
|
||||
|
||||
const EdgeData& ed = _graph->GetEdgeData(smallestEdge);
|
||||
// INFO( (ed.shortcut ? "SHRT: " : "ORIG: ") << ed.distance << "," << ed.via);
|
||||
@@ -398,7 +364,7 @@ private:
|
||||
return false;
|
||||
} else {
|
||||
assert(!ed.shortcut);
|
||||
path.push_back(_PathData(ed.via) );
|
||||
path.push_back(_PathData(ed.via, ed.nameID1, ed.turnInstruction, ed.distance) );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user