add additional comments to path class, really need to go and fill in all the dummy jsdoc descriptions...
This commit is contained in:
parent
c01d0abbd3
commit
b7971690f3
@ -45,6 +45,10 @@ export default class TraversalPath {
|
|||||||
this.data = {};
|
this.data = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
static get(parentPath: TraversalPath, context?: TraversalContext, parent, container, key, file?: File) {
|
static get(parentPath: TraversalPath, context?: TraversalContext, parent, container, key, file?: File) {
|
||||||
var targetNode = container[key];
|
var targetNode = container[key];
|
||||||
var paths = container._paths = container._paths || [];
|
var paths = container._paths = container._paths || [];
|
||||||
@ -68,6 +72,10 @@ export default class TraversalPath {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
static getScope(path: TraversalPath, scope: Scope, file?: File) {
|
static getScope(path: TraversalPath, scope: Scope, file?: File) {
|
||||||
var ourScope = scope;
|
var ourScope = scope;
|
||||||
|
|
||||||
@ -79,12 +87,20 @@ export default class TraversalPath {
|
|||||||
return ourScope;
|
return ourScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
queueNode(path) {
|
queueNode(path) {
|
||||||
if (this.context) {
|
if (this.context) {
|
||||||
this.context.queue.push(path);
|
this.context.queue.push(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
insertBefore(nodes) {
|
insertBefore(nodes) {
|
||||||
nodes = this._verifyNodeList(nodes);
|
nodes = this._verifyNodeList(nodes);
|
||||||
|
|
||||||
@ -146,6 +162,10 @@ export default class TraversalPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
isCompletionRecord() {
|
isCompletionRecord() {
|
||||||
var path = this;
|
var path = this;
|
||||||
|
|
||||||
@ -159,6 +179,10 @@ export default class TraversalPath {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
isStatementOrBlock() {
|
isStatementOrBlock() {
|
||||||
if (t.isLabeledStatement(this.parent) || t.isBlockStatement(this.container)) {
|
if (t.isLabeledStatement(this.parent) || t.isBlockStatement(this.container)) {
|
||||||
return false;
|
return false;
|
||||||
@ -167,6 +191,10 @@ export default class TraversalPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
insertAfter(nodes) {
|
insertAfter(nodes) {
|
||||||
nodes = this._verifyNodeList(nodes);
|
nodes = this._verifyNodeList(nodes);
|
||||||
|
|
||||||
@ -195,6 +223,10 @@ export default class TraversalPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
updateSiblingKeys(fromIndex, incrementBy) {
|
updateSiblingKeys(fromIndex, incrementBy) {
|
||||||
var paths = this.container._paths;
|
var paths = this.container._paths;
|
||||||
for (var i = 0; i < paths.length; i++) {
|
for (var i = 0; i < paths.length; i++) {
|
||||||
@ -205,25 +237,45 @@ export default class TraversalPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
setData(key, val) {
|
setData(key, val) {
|
||||||
return this.data[key] = val;
|
return this.data[key] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
getData(key, def) {
|
getData(key, def) {
|
||||||
var val = this.data[key];
|
var val = this.data[key];
|
||||||
if (!val && def) val = this.data[key] = def;
|
if (!val && def) val = this.data[key] = def;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
setScope(file?) {
|
setScope(file?) {
|
||||||
var target = this.context || this.parentPath;
|
var target = this.context || this.parentPath;
|
||||||
this.scope = TraversalPath.getScope(this, target && target.scope, file);
|
this.scope = TraversalPath.getScope(this, target && target.scope, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
clearContext() {
|
clearContext() {
|
||||||
this.context = null;
|
this.context = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
setContext(parentPath, context, key, file?) {
|
setContext(parentPath, context, key, file?) {
|
||||||
this.shouldSkip = false;
|
this.shouldSkip = false;
|
||||||
this.shouldStop = false;
|
this.shouldStop = false;
|
||||||
@ -255,6 +307,10 @@ export default class TraversalPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
remove() {
|
remove() {
|
||||||
this._remove();
|
this._remove();
|
||||||
this.removed = true;
|
this.removed = true;
|
||||||
@ -284,15 +340,27 @@ export default class TraversalPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
skip() {
|
skip() {
|
||||||
this.shouldSkip = true;
|
this.shouldSkip = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
this.shouldStop = true;
|
this.shouldStop = true;
|
||||||
this.shouldSkip = true;
|
this.shouldSkip = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
errorWithNode(msg, Error = SyntaxError) {
|
errorWithNode(msg, Error = SyntaxError) {
|
||||||
var loc = this.node.loc.start;
|
var loc = this.node.loc.start;
|
||||||
var err = new Error(`Line ${loc.line}: ${msg}`);
|
var err = new Error(`Line ${loc.line}: ${msg}`);
|
||||||
@ -312,6 +380,10 @@ export default class TraversalPath {
|
|||||||
throw new Error("Don't use `path.node = newNode;`, use `path.replaceWith(newNode)` or `path.replaceWithMultiple([newNode])`");
|
throw new Error("Don't use `path.node = newNode;`, use `path.replaceWith(newNode)` or `path.replaceWithMultiple([newNode])`");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
replaceInline(nodes) {
|
replaceInline(nodes) {
|
||||||
if (Array.isArray(nodes)) {
|
if (Array.isArray(nodes)) {
|
||||||
if (Array.isArray(this.container)) {
|
if (Array.isArray(this.container)) {
|
||||||
@ -326,6 +398,10 @@ export default class TraversalPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
_verifyNodeList(nodes) {
|
_verifyNodeList(nodes) {
|
||||||
if (nodes.constructor !== Array) {
|
if (nodes.constructor !== Array) {
|
||||||
nodes = [nodes];
|
nodes = [nodes];
|
||||||
@ -345,19 +421,43 @@ export default class TraversalPath {
|
|||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
insertOntoContainerStart(containerKey, nodes) {
|
insertOntoContainerStart(containerKey, nodes) {
|
||||||
nodes = this._verifyNodeList(nodes);
|
nodes = this._verifyNodeList(nodes);
|
||||||
|
|
||||||
|
// get the first path and insert our nodes before it, if it doesn't exist then it
|
||||||
|
// doesn't matter, our nodes will be inserted anyway
|
||||||
|
|
||||||
var container = this.node[containerKey];
|
var container = this.node[containerKey];
|
||||||
return TraversalPath.get(this, null, this.node, container, 0).insertBefore(nodes);
|
var path = TraversalPath.get(this, null, this.node, container, 0);
|
||||||
|
|
||||||
|
return path.insertBefore(nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
insertOntoContainerEnd(containerKey, nodes) {
|
insertOntoContainerEnd(containerKey, nodes) {
|
||||||
nodes = this._verifyNodeList(nodes);
|
nodes = this._verifyNodeList(nodes);
|
||||||
|
|
||||||
|
// get an invisible path that represents the last node + 1 and replace it with our
|
||||||
|
// nodes, effectively inlining it
|
||||||
|
|
||||||
var container = this.node[containerKey];
|
var container = this.node[containerKey];
|
||||||
var i = container.length;
|
var i = container.length;
|
||||||
return TraversalPath.get(this, null, this.node, container, i).replaceWith(nodes, true);
|
var path = TraversalPath.get(this, null, this.node, container, i);
|
||||||
|
|
||||||
|
return path.replaceWith(nodes, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
replaceWithMultiple(nodes: Array<Object>) {
|
replaceWithMultiple(nodes: Array<Object>) {
|
||||||
nodes = this._verifyNodeList(nodes);
|
nodes = this._verifyNodeList(nodes);
|
||||||
t.inheritsComments(nodes[0], this.node);
|
t.inheritsComments(nodes[0], this.node);
|
||||||
@ -366,6 +466,10 @@ export default class TraversalPath {
|
|||||||
if (!this.node) this.remove();
|
if (!this.node) this.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
replaceWith(replacement, arraysAllowed) {
|
replaceWith(replacement, arraysAllowed) {
|
||||||
if (this.removed) {
|
if (this.removed) {
|
||||||
throw new Error("You can't replace this node, we've already removed it");
|
throw new Error("You can't replace this node, we've already removed it");
|
||||||
@ -400,12 +504,20 @@ export default class TraversalPath {
|
|||||||
this.checkPaths(this);
|
this.checkPaths(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
checkPaths(paths) {
|
checkPaths(paths) {
|
||||||
var scope = this.scope;
|
var scope = this.scope;
|
||||||
var file = scope && scope.file;
|
var file = scope && scope.file;
|
||||||
if (file) file.checkPath(paths);
|
if (file) file.checkPath(paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
getStatementParent(): ?TraversalPath {
|
getStatementParent(): ?TraversalPath {
|
||||||
var path = this;
|
var path = this;
|
||||||
|
|
||||||
@ -424,6 +536,10 @@ export default class TraversalPath {
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
getLastStatements(): Array<TraversalPath> {
|
getLastStatements(): Array<TraversalPath> {
|
||||||
var paths = [];
|
var paths = [];
|
||||||
|
|
||||||
@ -445,6 +561,10 @@ export default class TraversalPath {
|
|||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
replaceExpressionWithStatements(nodes: Array) {
|
replaceExpressionWithStatements(nodes: Array) {
|
||||||
var toSequenceExpression = t.toSequenceExpression(nodes, this.scope);
|
var toSequenceExpression = t.toSequenceExpression(nodes, this.scope);
|
||||||
|
|
||||||
@ -471,6 +591,10 @@ export default class TraversalPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
call(key) {
|
call(key) {
|
||||||
var node = this.node;
|
var node = this.node;
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
@ -479,15 +603,24 @@ export default class TraversalPath {
|
|||||||
var fn = opts[key] || opts;
|
var fn = opts[key] || opts;
|
||||||
if (opts[node.type]) fn = opts[node.type][key] || fn;
|
if (opts[node.type]) fn = opts[node.type][key] || fn;
|
||||||
|
|
||||||
|
// call the function with the params (node, parent, scope, state)
|
||||||
var replacement = fn.call(this, node, this.parent, this.scope, this.state);
|
var replacement = fn.call(this, node, this.parent, this.scope, this.state);
|
||||||
if (replacement) this.replaceWith(replacement, true);
|
if (replacement) this.replaceWith(replacement, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
isBlacklisted(): boolean {
|
isBlacklisted(): boolean {
|
||||||
var blacklist = this.opts.blacklist;
|
var blacklist = this.opts.blacklist;
|
||||||
return blacklist && blacklist.indexOf(this.node.type) > -1;
|
return blacklist && blacklist.indexOf(this.node.type) > -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
visit(): boolean {
|
visit(): boolean {
|
||||||
if (this.isBlacklisted()) return false;
|
if (this.isBlacklisted()) return false;
|
||||||
if (this.opts.shouldSkip(this)) return false;
|
if (this.opts.shouldSkip(this)) return false;
|
||||||
@ -521,44 +654,82 @@ export default class TraversalPath {
|
|||||||
return TraversalPath.get(this.parentPath, null, this.parent, this.container, key, this.file);
|
return TraversalPath.get(this.parentPath, null, this.parent, this.container, key, this.file);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
get(key: string): TraversalPath {
|
get(key: string): TraversalPath {
|
||||||
var parts = key.split(".");
|
var parts = key.split(".");
|
||||||
if (parts.length === 1) { // "foo.bar"
|
if (parts.length === 1) { // "foo"
|
||||||
var node = this.node;
|
return this._getKey(key);
|
||||||
var container = node[key];
|
} else { // "foo.bar"
|
||||||
if (Array.isArray(container)) {
|
return this._getPattern(parts);
|
||||||
return container.map((_, i) => {
|
|
||||||
return TraversalPath.get(this, null, node, container, i);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return TraversalPath.get(this, null, node, node, key);
|
|
||||||
}
|
|
||||||
} else { // "foo"
|
|
||||||
var path = this;
|
|
||||||
for (var i = 0; i > parts.length; i++) {
|
|
||||||
var part = parts[i];
|
|
||||||
if (part === ".") {
|
|
||||||
path = path.parentPath;
|
|
||||||
} else {
|
|
||||||
path = path.get(parts[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
|
_getKey(key) {
|
||||||
|
var node = this.node;
|
||||||
|
var container = node[key];
|
||||||
|
|
||||||
|
if (Array.isArray(container)) {
|
||||||
|
// requested a container so give them all the paths
|
||||||
|
return container.map((_, i) => {
|
||||||
|
return TraversalPath.get(this, null, node, container, i);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return TraversalPath.get(this, null, node, node, key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
|
_getPattern(parts) {
|
||||||
|
var path = this;
|
||||||
|
for (var i = 0; i > parts.length; i++) {
|
||||||
|
var part = parts[i];
|
||||||
|
if (part === ".") {
|
||||||
|
path = path.parentPath;
|
||||||
|
} else {
|
||||||
|
path = path.get(parts[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
has(key): boolean {
|
has(key): boolean {
|
||||||
return !!this.node[key];
|
return !!this.node[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
is(key): boolean {
|
is(key): boolean {
|
||||||
return this.has(key);
|
return this.has(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
isnt(key): boolean {
|
isnt(key): boolean {
|
||||||
return !this.has(key);
|
return !this.has(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
getTypeAnnotation(): {
|
getTypeAnnotation(): {
|
||||||
inferred: boolean;
|
inferred: boolean;
|
||||||
annotation: ?Object;
|
annotation: ?Object;
|
||||||
@ -587,6 +758,10 @@ export default class TraversalPath {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
resolve(): ?TraversalPath {
|
resolve(): ?TraversalPath {
|
||||||
if (this.isVariableDeclarator()) {
|
if (this.isVariableDeclarator()) {
|
||||||
if (this.get("id").isIdentifier()) {
|
if (this.get("id").isIdentifier()) {
|
||||||
@ -638,6 +813,10 @@ export default class TraversalPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
inferType(path: TraversalPath): ?Object {
|
inferType(path: TraversalPath): ?Object {
|
||||||
path = path.resolve();
|
path = path.resolve();
|
||||||
if (!path) return;
|
if (!path) return;
|
||||||
@ -675,30 +854,58 @@ export default class TraversalPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
isScope(): boolean {
|
isScope(): boolean {
|
||||||
return t.isScope(this.node, this.parent);
|
return t.isScope(this.node, this.parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
isReferencedIdentifier(opts): boolean {
|
isReferencedIdentifier(opts): boolean {
|
||||||
return t.isReferencedIdentifier(this.node, this.parent, opts);
|
return t.isReferencedIdentifier(this.node, this.parent, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
isReferenced(): boolean {
|
isReferenced(): boolean {
|
||||||
return t.isReferenced(this.node, this.parent);
|
return t.isReferenced(this.node, this.parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
isBlockScoped(): boolean {
|
isBlockScoped(): boolean {
|
||||||
return t.isBlockScoped(this.node);
|
return t.isBlockScoped(this.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
isVar(): boolean {
|
isVar(): boolean {
|
||||||
return t.isVar(this.node);
|
return t.isVar(this.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
isPreviousType(type: string): boolean {
|
isPreviousType(type: string): boolean {
|
||||||
return t.isType(this.type, type);
|
return t.isType(this.type, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
isTypeGeneric(genericName: string, opts = {}): boolean {
|
isTypeGeneric(genericName: string, opts = {}): boolean {
|
||||||
var typeInfo = this.getTypeAnnotation();
|
var typeInfo = this.getTypeAnnotation();
|
||||||
var type = typeInfo.annotation;
|
var type = typeInfo.annotation;
|
||||||
@ -719,10 +926,18 @@ export default class TraversalPath {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
getBindingIdentifiers() {
|
getBindingIdentifiers() {
|
||||||
return t.getBindingIdentifiers(this.node);
|
return t.getBindingIdentifiers(this.node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Description
|
||||||
|
*/
|
||||||
|
|
||||||
traverse(visitor, state) {
|
traverse(visitor, state) {
|
||||||
traverse(this.node, visitor, this.scope, state, this);
|
traverse(this.node, visitor, this.scope, state, this);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user