Model Redesign: Added Reference Frames
Added Inverse Functions UI Redesign Cleaned Code
This commit is contained in:
@@ -8,6 +8,13 @@
|
||||
|
||||
@import Foundation;
|
||||
#import "NSString+MPExpressionElement.h"
|
||||
#import "MPToken.h"
|
||||
|
||||
typedef NS_ENUM(NSUInteger, MPReferenceFrame) {
|
||||
MPElementReferenceFrame,
|
||||
MPSymbolReferenceFrame,
|
||||
MPTokenReferenceFrame
|
||||
};
|
||||
|
||||
@class MPExpression, MPFunction, MPRangePath, MPExpressionEvaluator, MPParseError;
|
||||
@protocol MPExpressionElement;
|
||||
@@ -127,6 +134,34 @@
|
||||
@property (nonatomic, weak) MPFunction *parent;
|
||||
|
||||
|
||||
/*!
|
||||
@method rootExpression
|
||||
@brief Returns the root expression from the receiver's expression tree.
|
||||
|
||||
@discussion The root expression is the ultimate parent of all expressions and
|
||||
functions in the expression tree. A root expression does not have
|
||||
a parent.
|
||||
|
||||
@return The root expression from the receiver's expression tree.
|
||||
*/
|
||||
- (MPExpression *)rootExpression;
|
||||
|
||||
|
||||
/*!
|
||||
@method indexPath
|
||||
@brief Returns the index path of the receiver in the expression tree.
|
||||
|
||||
@discussion The index path is calculated by going up the expression tree
|
||||
collecting the respective index of the receiver. The indexes are
|
||||
expressed in the indexed reference frame. If any of the indexes
|
||||
exceed the respective receiver's bounds a @c NSRangeException is
|
||||
raised.
|
||||
|
||||
@return The index path of the receiver in the expression tree.
|
||||
*/
|
||||
- (NSIndexPath *)indexPath;
|
||||
|
||||
|
||||
/*!
|
||||
@method numberOfElements
|
||||
@brief Returns the number of elements in the receiver.
|
||||
@@ -139,7 +174,7 @@
|
||||
|
||||
@return The current number of elements in the receiver.
|
||||
*/
|
||||
- (NSUInteger)numberOfElements;
|
||||
- (NSUInteger)countItemsInReferenceFrame:(MPReferenceFrame)referenceFrame;
|
||||
|
||||
|
||||
/*!
|
||||
@@ -160,7 +195,23 @@
|
||||
|
||||
@return The element at @c anIndex.
|
||||
*/
|
||||
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)anIndex;
|
||||
- (id)itemAtIndex:(NSUInteger)anIndex
|
||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||
|
||||
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)anIndex
|
||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||
|
||||
/*!
|
||||
@method indexOfElement:
|
||||
@brief Returns the index of @c element or @c NSNotFound if it was not
|
||||
found.
|
||||
|
||||
@param element
|
||||
The element to find.
|
||||
|
||||
@return The index of @c element expressed in the indexed reference frame.
|
||||
*/
|
||||
- (NSUInteger)indexOfElement:(id<MPExpressionElement>)element;
|
||||
|
||||
|
||||
/*!
|
||||
@@ -185,7 +236,8 @@
|
||||
The length of the returned array is equal to the length of the
|
||||
specified range.
|
||||
*/
|
||||
- (NSArray *)elementsInIndexedRange:(NSRange)range;
|
||||
- (NSArray *)itemsInRange:(NSRange)range
|
||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||
|
||||
|
||||
/*!
|
||||
@@ -197,7 +249,51 @@
|
||||
|
||||
@return An array of all elements from the receiver.
|
||||
*/
|
||||
- (NSArray *)elements;
|
||||
- (NSArray *)allItemsInReferenceFrame:(MPReferenceFrame)referenceFrame;
|
||||
|
||||
|
||||
/*!
|
||||
@method elementAtIndexPath:
|
||||
@brief Returns the element at the specified index path.
|
||||
|
||||
@discussion This method @em walks down the expression tree (including
|
||||
functions) using the specified index path and finds the
|
||||
corresponding element. The returned object can be an @c NSString,
|
||||
a @c MPFunction or an @c MPExpression depending on the element @c
|
||||
indexPath points to. If any of the indexes exceed the bounds of
|
||||
the respective receiver an @c NSRangeException is raised.
|
||||
|
||||
If the index path does not contain any indexes the receiver
|
||||
itself is returned.
|
||||
|
||||
@param indexPath
|
||||
The index path the required object is located at. The indexes are
|
||||
expressed in the indexed reference frame.
|
||||
|
||||
@return The element located at @c indexPath. The element is not copied
|
||||
before it is returned. Be aware of the fact that any mutations
|
||||
made to the returned object are reflected in the receiver.
|
||||
*/
|
||||
- (id)elementAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
- (NSUInteger)convertIndex:(NSUInteger)index
|
||||
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
||||
toReferenceFrame:(MPReferenceFrame)toReferenceFrame;
|
||||
|
||||
- (NSUInteger)convertIndex:(NSUInteger)index
|
||||
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
||||
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
||||
offset:(NSUInteger *)offset;
|
||||
|
||||
- (NSRange)convertRange:(NSRange)aRange
|
||||
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
||||
toReferenceFrame:(MPReferenceFrame)toReferenceFrame;
|
||||
|
||||
- (NSRange)convertRange:(NSRange)aRange
|
||||
fromReferenceFrame:(MPReferenceFrame)fromReferenceFrame
|
||||
toReferenceFrame:(MPReferenceFrame)toReferenceFrame
|
||||
leadingOffset:(NSUInteger *)leadingOffset
|
||||
trailingOffset:(NSUInteger *)trailingOffset;
|
||||
|
||||
|
||||
#pragma mark Mutating Expressions
|
||||
@@ -228,9 +324,16 @@
|
||||
The elements that should replace the symbols specified by @c
|
||||
range.
|
||||
*/
|
||||
- (void)replaceSymbolsInRange:(NSRange)range
|
||||
withElements:(NSArray *)elements;
|
||||
- (void)replaceItemsInRange:(NSRange)range
|
||||
referenceFrame:(MPReferenceFrame)referenceFrame
|
||||
withElements:(NSArray *)elements;
|
||||
|
||||
- (MPExpression *)subexpressionFromIndex:(NSUInteger)from
|
||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||
- (MPExpression *)subexpressionToIndex:(NSUInteger)to
|
||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||
- (MPExpression *)subexpressionWithRange:(NSRange)range
|
||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||
|
||||
#pragma mark Evaluating Expressions
|
||||
|
||||
@@ -256,17 +359,6 @@
|
||||
- (NSDecimalNumber *)evaluateWithError:(MPParseError *__autoreleasing *)error;
|
||||
|
||||
|
||||
/*!
|
||||
@property evaluator
|
||||
@brief Returns an object that can evaluate the receiver.
|
||||
|
||||
@discussion To just evaluate an expression it is recommended to send it an
|
||||
@c evaluateWithError: message. You can however use this property
|
||||
instead if you need more control over the evaluation process.
|
||||
*/
|
||||
@property (readonly, nonatomic, strong) MPExpressionEvaluator *evaluator;
|
||||
|
||||
|
||||
#pragma mark Notifications
|
||||
// All notification methods should create a new rangePath with the receiver's index added to the beginning of the path and then ascend the message to it's parent
|
||||
|
||||
@@ -291,8 +383,8 @@
|
||||
The number of elements replacing the elements specified by @c
|
||||
rangePath.
|
||||
*/
|
||||
- (void)didChangeElementsInIndexedRangePath:(MPRangePath *)rangePath
|
||||
replacementLength:(NSUInteger)replacementLength;
|
||||
- (void)didChangeElementsInRangePath:(MPRangePath *)rangePath
|
||||
replacementLength:(NSUInteger)replacementLength;
|
||||
|
||||
|
||||
#pragma mark Basic NSObject Methods
|
||||
@@ -301,412 +393,63 @@
|
||||
|
||||
@end
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------- */
|
||||
/* Extension Methods */
|
||||
/* --------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
@interface MPExpression (MPExpressionExtension)
|
||||
@interface MPExpression (MPExpressionConvenience)
|
||||
|
||||
|
||||
#pragma mark Querying Expressions
|
||||
|
||||
- (NSUInteger)countElements;
|
||||
- (NSUInteger)countSymbols;
|
||||
- (NSUInteger)countTokens;
|
||||
|
||||
/*!
|
||||
@method length
|
||||
@brief Returns the length of the receiver.
|
||||
|
||||
@discussion The length of an expression is calculated by going over each
|
||||
element in the receiver and sending it a @c -length message. This
|
||||
method should be used to determine the number of digits or
|
||||
symbols in an expression.
|
||||
|
||||
The result of this method is expressed in the located reference
|
||||
frame. The respective method for the indexed reference frame is
|
||||
@c -numberOfSymbols.
|
||||
|
||||
@return The length of the receiver. This is the number of symbols in all
|
||||
elements in the receiver where a function element is counted as a
|
||||
single symbol.
|
||||
*/
|
||||
- (NSUInteger)length;
|
||||
|
||||
|
||||
/*!
|
||||
@method rootExpression
|
||||
@brief Returns the root expression from the receiver's expression tree.
|
||||
|
||||
@discussion The root expression is the ultimate parent of all expressions and
|
||||
functions in the expression tree. A root expression does not have
|
||||
a parent.
|
||||
|
||||
@return The root expression from the receiver's expression tree.
|
||||
*/
|
||||
- (MPExpression *)rootExpression;
|
||||
|
||||
|
||||
/*!
|
||||
@method indexPath
|
||||
@brief Returns the index path of the receiver in the expression tree.
|
||||
|
||||
@discussion The index path is calculated by going up the expression tree
|
||||
collecting the respective index of the receiver. The indexes are
|
||||
expressed in the indexed reference frame. If any of the indexes
|
||||
exceed the respective receiver's bounds a @c NSRangeException is
|
||||
raised.
|
||||
|
||||
@return The index path of the receiver in the expression tree.
|
||||
*/
|
||||
- (NSIndexPath *)indexPath;
|
||||
|
||||
|
||||
// Subscripting is supported in the indexed reference frame
|
||||
- (id)objectAtIndexedSubscript:(NSUInteger)idx;
|
||||
|
||||
|
||||
#pragma mark Working With Expressions
|
||||
|
||||
|
||||
/*!
|
||||
@method elementAtLocation:
|
||||
@brief Returns the element that is located at @c location.
|
||||
|
||||
@discussion This method finds an element in the located reference frame. If
|
||||
@c location is greater or equal to the @c length of the receiver
|
||||
a @c NSRangeException is raised.
|
||||
|
||||
@param location
|
||||
The location of the element to find expressed in the located
|
||||
reference frame.
|
||||
|
||||
@return The element located at @c location.
|
||||
*/
|
||||
- (id<MPExpressionElement>)elementAtLocation:(NSUInteger)location;
|
||||
|
||||
|
||||
/*!
|
||||
@method elementAtIndexPath:
|
||||
@brief Returns the element at the specified index path.
|
||||
|
||||
@discussion This method @em walks down the expression tree (including
|
||||
functions) using the specified index path and finds the
|
||||
corresponding element. The returned object can be an @c NSString,
|
||||
a @c MPFunction or an @c MPExpression depending on the element @c
|
||||
indexPath points to. If any of the indexes exceed the bounds of
|
||||
the respective receiver an @c NSRangeException is raised.
|
||||
|
||||
If the index path does not contain any indexes the receiver
|
||||
itself is returned.
|
||||
|
||||
@param indexPath
|
||||
The index path the required object is located at. The indexes are
|
||||
expressed in the indexed reference frame.
|
||||
|
||||
@return The element located at @c indexPath. The element is not copied
|
||||
before it is returned. Be aware of the fact that any mutations
|
||||
made to the returned object are reflected in the receiver.
|
||||
*/
|
||||
- (id)elementAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
|
||||
/*!
|
||||
@method elementsInIndexedRangePath:
|
||||
@brief Returns the elements in the specified range path.
|
||||
|
||||
@discussion This method works similar to @c elementAtIndexPath: except that
|
||||
it queries multiple elements at once.
|
||||
|
||||
@param rangePath
|
||||
The range path the requested objects are located at. The complete
|
||||
range path is expressed in the indexed reference frame.
|
||||
|
||||
@return An array of objects specified by the range path. The returned
|
||||
elements are not copied before they are returned. Be aware that
|
||||
any mutations made to the returned objects are reflected in the
|
||||
receiver.
|
||||
*/
|
||||
- (NSArray *)elementsInIndexedRangePath:(MPRangePath *)rangePath;
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
@method indexOfElement:
|
||||
@brief Returns the index of @c element or @c NSNotFound if it was not
|
||||
found.
|
||||
|
||||
@param element
|
||||
The element to find.
|
||||
|
||||
@return The index of @c element expressed in the indexed reference frame.
|
||||
*/
|
||||
- (NSUInteger)indexOfElement:(id<MPExpressionElement>)element;
|
||||
|
||||
|
||||
#pragma mark Converting Between Indexes and Locations
|
||||
|
||||
|
||||
/*!
|
||||
@method indexOfElementAtLocation:offset:
|
||||
@brief Calculates the index of the element the specified location points
|
||||
to.
|
||||
|
||||
@discussion The @c location is in the located reference frame whereas the
|
||||
returned value is an index. This method converts from the former
|
||||
to the latter.
|
||||
|
||||
This method prefers higher indexes. This means that if the
|
||||
returned @c offset would be equal to the length of the element at
|
||||
the calculated index, insead index+1 is returned and the @c
|
||||
offset is set to @c 0.
|
||||
|
||||
If the @c location exceeds the receiver's bounds a @c
|
||||
NSRangeException will be raised.
|
||||
|
||||
@param location
|
||||
The location of which you want the corresponding element index.
|
||||
|
||||
@param offset
|
||||
An output parameter that gets set to the offst into the symbol
|
||||
whose index is returned. If location for example points to the
|
||||
symbol @c '2' in the string element @c '123' the offset @c would
|
||||
be set to @c 1.
|
||||
|
||||
@return The index of the element the location points to.
|
||||
*/
|
||||
- (NSUInteger)indexOfElementAtLocation:(NSUInteger)location offset:(out NSUInteger *)offset;
|
||||
|
||||
|
||||
/*!
|
||||
@method locationOfElementAtIndex:
|
||||
@brief Calculates the location of the element at @c index.
|
||||
|
||||
@discussion @c index is expressed in the indexed reference frame. Use this
|
||||
method to convert an index into the located reference frame.
|
||||
|
||||
If the index exceeds the receiver's number of elements a @c
|
||||
NSRangeException will be raised.
|
||||
|
||||
@param index
|
||||
The index of the element that is to be converted into the length
|
||||
reference frame.
|
||||
|
||||
@return The number of symbols (in the length reference frame) before the
|
||||
element at @c index.
|
||||
*/
|
||||
- (NSUInteger)locationOfElementAtIndex:(NSUInteger)index;
|
||||
|
||||
|
||||
/*!
|
||||
@method indexedRangeForRange:
|
||||
@brief Converts @c aRange from the located reference frame into the
|
||||
indexed reference frame.
|
||||
|
||||
@discussion If the range exceeds the receiver's bounds a @c NSRangeException
|
||||
is raised.
|
||||
|
||||
@param aRange
|
||||
The range to be converted. Expressed in the located reference
|
||||
frame.
|
||||
|
||||
@return @c aRange converted into the indexed reference frame.
|
||||
*/
|
||||
- (NSRange)indexedRangeForRange:(NSRange)aRange;
|
||||
|
||||
|
||||
/*!
|
||||
@method rangeForIndexedRange:
|
||||
@brief Converts @c aRange from the indexed reference frame into the
|
||||
located reference frame.
|
||||
|
||||
@discussion In the range exceeds the receiver's bounds a @c NSRangeException
|
||||
is raised.
|
||||
|
||||
@param aRange
|
||||
The range to be converted. Expressed in the indexed reference
|
||||
frame.
|
||||
|
||||
@return @c aRange converted into the located reference frame.
|
||||
*/
|
||||
- (NSRange)rangeForIndexedRange:(NSRange)aRange;
|
||||
- (id<MPExpressionElement>)elementAtIndex:(NSUInteger)index;
|
||||
- (id<MPExpressionElement>)symbolAtIndex:(NSUInteger)index;
|
||||
- (id<MPToken>)tokenAtIndex:(NSUInteger)index;
|
||||
|
||||
|
||||
#pragma mark Mutating Expressions
|
||||
|
||||
|
||||
- (MPExpression *)subexpressionFromIndex:(NSUInteger)from;
|
||||
- (MPExpression *)subexpressionToIndex:(NSUInteger)to;
|
||||
- (MPExpression *)subexpressionWithIndexedRange:(NSRange)range;
|
||||
|
||||
|
||||
/*!
|
||||
@method subexpressionFromLocation:
|
||||
@brief Creates a new expression from the specified location (inclusive)
|
||||
to the end of the receiver.
|
||||
@method appendElement:
|
||||
@brief Appends @c anElement to the receiver.
|
||||
|
||||
@discussion The elements in the newly created expression are copied to the
|
||||
new expression. The location is specified in the located
|
||||
reference frame.
|
||||
|
||||
If the given location exceeds the receiver's bounds a @c
|
||||
NSRangeException is raised.
|
||||
|
||||
@param from
|
||||
The first location to be included in the new expression.
|
||||
|
||||
@return A new expression from the given location to the end of the
|
||||
receiver.
|
||||
*/
|
||||
- (MPExpression *)subexpressionFromLocation:(NSUInteger)from;
|
||||
|
||||
|
||||
/*!
|
||||
@method subexpressionToLocation:
|
||||
@brief Creates a new expression from the beginning to the specified
|
||||
location (exclusive).
|
||||
|
||||
@discussion The elements in the newly created expression are copied to the
|
||||
new expression. The location is specified in the located
|
||||
reference frame.
|
||||
|
||||
If the given location exceeds the receiver's bounds a @c
|
||||
NSRangeException is raised.
|
||||
|
||||
@param to
|
||||
The first location not to be included in the new expression (or
|
||||
the length of the new expression).
|
||||
|
||||
@return A new expression with the first @c to symbols of the receiver.
|
||||
*/
|
||||
- (MPExpression *)subexpressionToLocation:(NSUInteger)to;
|
||||
|
||||
|
||||
/*!
|
||||
@method subexpressionWithRange:
|
||||
@brief Creates a new expression with the symbols in the specified range.
|
||||
|
||||
@discussion The elements in the newly created expression are copied to the
|
||||
new exoression. The range is specified in the located reference
|
||||
frame.
|
||||
|
||||
If the given range exceeds the receiver's bounds a @c
|
||||
NSRangeException is raised.
|
||||
|
||||
@param range
|
||||
The range from which to create the new expression.
|
||||
|
||||
@return A new expression with the symbols in the specified range.
|
||||
*/
|
||||
- (MPExpression *)subexpressionWithRange:(NSRange)range;
|
||||
|
||||
|
||||
- (void)replaceElementsInIndexedRange:(NSRange)range
|
||||
withElements:(NSArray *)elements;
|
||||
|
||||
- (void)replaceSymbolsInRangePath:(MPRangePath *)rangePath
|
||||
withElements:(NSArray *)elements;
|
||||
|
||||
|
||||
/*!
|
||||
@method appendElement:
|
||||
@brief Appends @c anElement to the receiver.
|
||||
|
||||
@param anElement
|
||||
The element to append to the receiver.
|
||||
@param anElement
|
||||
The element to append to the receiver.
|
||||
*/
|
||||
- (void)appendElement:(id<MPExpressionElement>)anElement;
|
||||
|
||||
|
||||
/*!
|
||||
@method appendElements:
|
||||
@brief Appends the objects from @c elements to the receiver.
|
||||
@method appendElements:
|
||||
@brief Appends the objects from @c elements to the receiver.
|
||||
|
||||
@param elements
|
||||
The elements to append to the receiver.
|
||||
@param elements
|
||||
The elements to append to the receiver.
|
||||
*/
|
||||
- (void)appendElements:(NSArray *)elements;
|
||||
|
||||
|
||||
- (void)insertElement:(id<MPExpressionElement>)anElement
|
||||
atIndex:(NSUInteger)index;
|
||||
atIndex:(NSUInteger)index
|
||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||
|
||||
- (void)insertElements:(NSArray *)elements
|
||||
atIndex:(NSUInteger)index;
|
||||
|
||||
|
||||
|
||||
/*!
|
||||
@method insertElement:atLocation:
|
||||
@brief Inserts @c anElement at @c location.
|
||||
|
||||
@discussion The location is specified in the length reference frame.
|
||||
|
||||
If the given location exceeds the receiver's bounds a @c
|
||||
NSRangeException is raised.
|
||||
|
||||
@param anElement
|
||||
The element to be inserted into the receiver.
|
||||
|
||||
@param location
|
||||
The location @c anElement should be inserted at.
|
||||
*/
|
||||
- (void)insertElement:(id<MPExpressionElement>)anElement
|
||||
atLocation:(NSUInteger)location;
|
||||
atIndex:(NSUInteger)index
|
||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||
|
||||
|
||||
/*!
|
||||
@method insertElements:atLocation:
|
||||
@brief Inserts the elements from @c elements at @c location.
|
||||
@method deleteElementsInRange:
|
||||
@brief Removes the elements specified by @c range from the receiver.
|
||||
|
||||
@discussion The location is specified in the length reference frame.
|
||||
@discussion The range is specified in the length reference frame.
|
||||
|
||||
If the given location exceeds the receiver's bounds a @c
|
||||
NSRangeException is raised.
|
||||
If @c range exceeds the receiver's bounds a @c NSRangeException
|
||||
is raised.
|
||||
|
||||
@param elements
|
||||
The elements to be inserted into the receiver.
|
||||
|
||||
@param location
|
||||
The location the elements in @c elements should be inserted into
|
||||
the receiver.
|
||||
@param range
|
||||
The range to remove from the receiver.
|
||||
*/
|
||||
- (void)insertElements:(NSArray *)elements
|
||||
atLocation:(NSUInteger)location;
|
||||
|
||||
|
||||
- (void)deleteElementsInIndexedRange:(NSRange)range;
|
||||
|
||||
/*!
|
||||
@method deleteElementsInRange:
|
||||
@brief Removes the elements specified by @c range from the receiver.
|
||||
|
||||
@discussion The range is specified in the length reference frame.
|
||||
|
||||
If @c range exceeds the receiver's bounds a @c NSRangeException
|
||||
is raised.
|
||||
|
||||
@param range
|
||||
The range to remove from the receiver.
|
||||
*/
|
||||
- (void)deleteElementsInRange:(NSRange)range;
|
||||
|
||||
|
||||
/*!
|
||||
@method mutableElements
|
||||
@brief Returns a proxy mutable array object that responds to all methods
|
||||
defined by @c NSMutableArray.
|
||||
|
||||
@discussion Mutations on the proxy object also change the receiver. The proxy
|
||||
object does not respond to coding methods. Copying the proxy
|
||||
object will not duplicate it.
|
||||
|
||||
@return A proxy object that responds to all methods defined by @c
|
||||
NSMutableArray.
|
||||
*/
|
||||
// - (NSMutableArray *)mutableElements;
|
||||
|
||||
/* Subscripting is supported for elements in the indexed reference frame */
|
||||
- (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx;
|
||||
- (void)deleteElementsInRange:(NSRange)range
|
||||
referenceFrame:(MPReferenceFrame)referenceFrame;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user