format: prettify entire project
This commit is contained in:
38
node_modules/relateurl/lib/parse/host.js
generated
vendored
38
node_modules/relateurl/lib/parse/host.js
generated
vendored
@ -1,26 +1,20 @@
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
function parseHost(urlObj, options)
|
||||
{
|
||||
// TWEAK :: condition only for speed optimization
|
||||
if (options.ignore_www)
|
||||
{
|
||||
var host = urlObj.host.full;
|
||||
|
||||
if (host)
|
||||
{
|
||||
var stripped = host;
|
||||
|
||||
if (host.indexOf("www.") === 0)
|
||||
{
|
||||
stripped = host.substr(4);
|
||||
}
|
||||
|
||||
urlObj.host.stripped = stripped;
|
||||
}
|
||||
}
|
||||
function parseHost(urlObj, options) {
|
||||
// TWEAK :: condition only for speed optimization
|
||||
if (options.ignore_www) {
|
||||
var host = urlObj.host.full;
|
||||
|
||||
if (host) {
|
||||
var stripped = host;
|
||||
|
||||
if (host.indexOf('www.') === 0) {
|
||||
stripped = host.substr(4);
|
||||
}
|
||||
|
||||
urlObj.host.stripped = stripped;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = parseHost;
|
||||
|
30
node_modules/relateurl/lib/parse/hrefInfo.js
generated
vendored
30
node_modules/relateurl/lib/parse/hrefInfo.js
generated
vendored
@ -1,20 +1,18 @@
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
function hrefInfo(urlObj)
|
||||
{
|
||||
var minimumPathOnly = (!urlObj.scheme && !urlObj.auth && !urlObj.host.full && !urlObj.port);
|
||||
var minimumResourceOnly = (minimumPathOnly && !urlObj.path.absolute.string);
|
||||
var minimumQueryOnly = (minimumResourceOnly && !urlObj.resource);
|
||||
var minimumHashOnly = (minimumQueryOnly && !urlObj.query.string.full.length);
|
||||
var empty = (minimumHashOnly && !urlObj.hash);
|
||||
|
||||
urlObj.extra.hrefInfo.minimumPathOnly = minimumPathOnly;
|
||||
urlObj.extra.hrefInfo.minimumResourceOnly = minimumResourceOnly;
|
||||
urlObj.extra.hrefInfo.minimumQueryOnly = minimumQueryOnly;
|
||||
urlObj.extra.hrefInfo.minimumHashOnly = minimumHashOnly;
|
||||
urlObj.extra.hrefInfo.empty = empty;
|
||||
function hrefInfo(urlObj) {
|
||||
var minimumPathOnly =
|
||||
!urlObj.scheme && !urlObj.auth && !urlObj.host.full && !urlObj.port;
|
||||
var minimumResourceOnly = minimumPathOnly && !urlObj.path.absolute.string;
|
||||
var minimumQueryOnly = minimumResourceOnly && !urlObj.resource;
|
||||
var minimumHashOnly = minimumQueryOnly && !urlObj.query.string.full.length;
|
||||
var empty = minimumHashOnly && !urlObj.hash;
|
||||
|
||||
urlObj.extra.hrefInfo.minimumPathOnly = minimumPathOnly;
|
||||
urlObj.extra.hrefInfo.minimumResourceOnly = minimumResourceOnly;
|
||||
urlObj.extra.hrefInfo.minimumQueryOnly = minimumQueryOnly;
|
||||
urlObj.extra.hrefInfo.minimumHashOnly = minimumHashOnly;
|
||||
urlObj.extra.hrefInfo.empty = empty;
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = hrefInfo;
|
||||
|
82
node_modules/relateurl/lib/parse/index.js
generated
vendored
82
node_modules/relateurl/lib/parse/index.js
generated
vendored
@ -1,58 +1,46 @@
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
var hrefInfo = require("./hrefInfo");
|
||||
var parseHost = require("./host");
|
||||
var parsePath = require("./path");
|
||||
var parsePort = require("./port");
|
||||
var parseQuery = require("./query");
|
||||
var parseUrlString = require("./urlstring");
|
||||
var pathUtils = require("../util/path");
|
||||
var hrefInfo = require('./hrefInfo');
|
||||
var parseHost = require('./host');
|
||||
var parsePath = require('./path');
|
||||
var parsePort = require('./port');
|
||||
var parseQuery = require('./query');
|
||||
var parseUrlString = require('./urlstring');
|
||||
var pathUtils = require('../util/path');
|
||||
|
||||
function parseFromUrl(url, options, fallback) {
|
||||
if (url) {
|
||||
var urlObj = parseUrl(url, options);
|
||||
|
||||
// Because the following occurs in the relate stage for "to" URLs,
|
||||
// such had to be mostly duplicated here
|
||||
|
||||
function parseFromUrl(url, options, fallback)
|
||||
{
|
||||
if (url)
|
||||
{
|
||||
var urlObj = parseUrl(url, options);
|
||||
|
||||
// Because the following occurs in the relate stage for "to" URLs,
|
||||
// such had to be mostly duplicated here
|
||||
|
||||
var pathArray = pathUtils.resolveDotSegments(urlObj.path.absolute.array);
|
||||
|
||||
urlObj.path.absolute.array = pathArray;
|
||||
urlObj.path.absolute.string = "/" + pathUtils.join(pathArray);
|
||||
|
||||
return urlObj;
|
||||
}
|
||||
else
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
var pathArray = pathUtils.resolveDotSegments(urlObj.path.absolute.array);
|
||||
|
||||
urlObj.path.absolute.array = pathArray;
|
||||
urlObj.path.absolute.string = '/' + pathUtils.join(pathArray);
|
||||
|
||||
return urlObj;
|
||||
} else {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
function parseUrl(url, options) {
|
||||
var urlObj = parseUrlString(url, options);
|
||||
|
||||
if (urlObj.valid === false) return urlObj;
|
||||
|
||||
function parseUrl(url, options)
|
||||
{
|
||||
var urlObj = parseUrlString(url, options);
|
||||
|
||||
if (urlObj.valid===false) return urlObj;
|
||||
|
||||
parseHost(urlObj, options);
|
||||
parsePort(urlObj, options);
|
||||
parsePath(urlObj, options);
|
||||
parseQuery(urlObj, options);
|
||||
hrefInfo(urlObj);
|
||||
|
||||
return urlObj;
|
||||
parseHost(urlObj, options);
|
||||
parsePort(urlObj, options);
|
||||
parsePath(urlObj, options);
|
||||
parseQuery(urlObj, options);
|
||||
hrefInfo(urlObj);
|
||||
|
||||
return urlObj;
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports =
|
||||
{
|
||||
from: parseFromUrl,
|
||||
to: parseUrl
|
||||
module.exports = {
|
||||
from: parseFromUrl,
|
||||
to: parseUrl,
|
||||
};
|
||||
|
150
node_modules/relateurl/lib/parse/path.js
generated
vendored
150
node_modules/relateurl/lib/parse/path.js
generated
vendored
@ -1,100 +1,74 @@
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
function isDirectoryIndex(resource, options)
|
||||
{
|
||||
var verdict = false;
|
||||
|
||||
options.directoryIndexes.every( function(index)
|
||||
{
|
||||
if (index === resource)
|
||||
{
|
||||
verdict = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return verdict;
|
||||
function isDirectoryIndex(resource, options) {
|
||||
var verdict = false;
|
||||
|
||||
options.directoryIndexes.every(function (index) {
|
||||
if (index === resource) {
|
||||
verdict = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
return verdict;
|
||||
}
|
||||
|
||||
function parsePath(urlObj, options) {
|
||||
var path = urlObj.path.absolute.string;
|
||||
|
||||
if (path) {
|
||||
var lastSlash = path.lastIndexOf('/');
|
||||
|
||||
function parsePath(urlObj, options)
|
||||
{
|
||||
var path = urlObj.path.absolute.string;
|
||||
|
||||
if (path)
|
||||
{
|
||||
var lastSlash = path.lastIndexOf("/");
|
||||
|
||||
if (lastSlash > -1)
|
||||
{
|
||||
if (++lastSlash < path.length)
|
||||
{
|
||||
var resource = path.substr(lastSlash);
|
||||
|
||||
if (resource!=="." && resource!=="..")
|
||||
{
|
||||
urlObj.resource = resource;
|
||||
path = path.substr(0, lastSlash);
|
||||
}
|
||||
else
|
||||
{
|
||||
path += "/";
|
||||
}
|
||||
}
|
||||
|
||||
urlObj.path.absolute.string = path;
|
||||
urlObj.path.absolute.array = splitPath(path);
|
||||
}
|
||||
else if (path==="." || path==="..")
|
||||
{
|
||||
// "..?var", "..#anchor", etc ... not "..index.html"
|
||||
path += "/";
|
||||
|
||||
urlObj.path.absolute.string = path;
|
||||
urlObj.path.absolute.array = splitPath(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Resource-only
|
||||
urlObj.resource = path;
|
||||
urlObj.path.absolute.string = null;
|
||||
}
|
||||
|
||||
urlObj.extra.resourceIsIndex = isDirectoryIndex(urlObj.resource, options);
|
||||
}
|
||||
// Else: query/hash-only or empty
|
||||
if (lastSlash > -1) {
|
||||
if (++lastSlash < path.length) {
|
||||
var resource = path.substr(lastSlash);
|
||||
|
||||
if (resource !== '.' && resource !== '..') {
|
||||
urlObj.resource = resource;
|
||||
path = path.substr(0, lastSlash);
|
||||
} else {
|
||||
path += '/';
|
||||
}
|
||||
}
|
||||
|
||||
urlObj.path.absolute.string = path;
|
||||
urlObj.path.absolute.array = splitPath(path);
|
||||
} else if (path === '.' || path === '..') {
|
||||
// "..?var", "..#anchor", etc ... not "..index.html"
|
||||
path += '/';
|
||||
|
||||
urlObj.path.absolute.string = path;
|
||||
urlObj.path.absolute.array = splitPath(path);
|
||||
} else {
|
||||
// Resource-only
|
||||
urlObj.resource = path;
|
||||
urlObj.path.absolute.string = null;
|
||||
}
|
||||
|
||||
urlObj.extra.resourceIsIndex = isDirectoryIndex(urlObj.resource, options);
|
||||
}
|
||||
// Else: query/hash-only or empty
|
||||
}
|
||||
|
||||
function splitPath(path) {
|
||||
// TWEAK :: condition only for speed optimization
|
||||
if (path !== '/') {
|
||||
var cleaned = [];
|
||||
|
||||
path.split('/').forEach(function (dir) {
|
||||
// Cleanup -- splitting "/dir/" becomes ["","dir",""]
|
||||
if (dir !== '') {
|
||||
cleaned.push(dir);
|
||||
}
|
||||
});
|
||||
|
||||
function splitPath(path)
|
||||
{
|
||||
// TWEAK :: condition only for speed optimization
|
||||
if (path !== "/")
|
||||
{
|
||||
var cleaned = [];
|
||||
|
||||
path.split("/").forEach( function(dir)
|
||||
{
|
||||
// Cleanup -- splitting "/dir/" becomes ["","dir",""]
|
||||
if (dir !== "")
|
||||
{
|
||||
cleaned.push(dir);
|
||||
}
|
||||
});
|
||||
|
||||
return cleaned;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Faster to skip the above block and just create an array
|
||||
return [];
|
||||
}
|
||||
return cleaned;
|
||||
} else {
|
||||
// Faster to skip the above block and just create an array
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = parsePath;
|
||||
|
49
node_modules/relateurl/lib/parse/port.js
generated
vendored
49
node_modules/relateurl/lib/parse/port.js
generated
vendored
@ -1,32 +1,25 @@
|
||||
"use strict";
|
||||
'use strict';
|
||||
|
||||
function parsePort(urlObj, options)
|
||||
{
|
||||
var defaultPort = -1;
|
||||
|
||||
for (var i in options.defaultPorts)
|
||||
{
|
||||
if ( i===urlObj.scheme && options.defaultPorts.hasOwnProperty(i) )
|
||||
{
|
||||
defaultPort = options.defaultPorts[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultPort > -1)
|
||||
{
|
||||
// Force same type as urlObj.port
|
||||
defaultPort = defaultPort.toString();
|
||||
|
||||
if (urlObj.port === null)
|
||||
{
|
||||
urlObj.port = defaultPort;
|
||||
}
|
||||
|
||||
urlObj.extra.portIsDefault = (urlObj.port === defaultPort);
|
||||
}
|
||||
function parsePort(urlObj, options) {
|
||||
var defaultPort = -1;
|
||||
|
||||
for (var i in options.defaultPorts) {
|
||||
if (i === urlObj.scheme && options.defaultPorts.hasOwnProperty(i)) {
|
||||
defaultPort = options.defaultPorts[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultPort > -1) {
|
||||
// Force same type as urlObj.port
|
||||
defaultPort = defaultPort.toString();
|
||||
|
||||
if (urlObj.port === null) {
|
||||
urlObj.port = defaultPort;
|
||||
}
|
||||
|
||||
urlObj.extra.portIsDefault = urlObj.port === defaultPort;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = parsePort;
|
||||
|
71
node_modules/relateurl/lib/parse/query.js
generated
vendored
71
node_modules/relateurl/lib/parse/query.js
generated
vendored
@ -1,53 +1,38 @@
|
||||
"use strict";
|
||||
'use strict';
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
function parseQuery(urlObj, options) {
|
||||
urlObj.query.string.full = stringify(urlObj.query.object, false);
|
||||
|
||||
|
||||
function parseQuery(urlObj, options)
|
||||
{
|
||||
urlObj.query.string.full = stringify(urlObj.query.object, false);
|
||||
|
||||
// TWEAK :: condition only for speed optimization
|
||||
if (options.removeEmptyQueries)
|
||||
{
|
||||
urlObj.query.string.stripped = stringify(urlObj.query.object, true);
|
||||
}
|
||||
// TWEAK :: condition only for speed optimization
|
||||
if (options.removeEmptyQueries) {
|
||||
urlObj.query.string.stripped = stringify(urlObj.query.object, true);
|
||||
}
|
||||
}
|
||||
|
||||
function stringify(queryObj, removeEmptyQueries) {
|
||||
var count = 0;
|
||||
var str = '';
|
||||
|
||||
for (var i in queryObj) {
|
||||
if (i !== '' && hasOwnProperty.call(queryObj, i) === true) {
|
||||
var value = queryObj[i];
|
||||
|
||||
function stringify(queryObj, removeEmptyQueries)
|
||||
{
|
||||
var count = 0;
|
||||
var str = "";
|
||||
|
||||
for (var i in queryObj)
|
||||
{
|
||||
if ( i!=="" && hasOwnProperty.call(queryObj, i)===true )
|
||||
{
|
||||
var value = queryObj[i];
|
||||
|
||||
if (value !== "" || !removeEmptyQueries)
|
||||
{
|
||||
str += (++count===1) ? "?" : "&";
|
||||
|
||||
i = encodeURIComponent(i);
|
||||
|
||||
if (value !== "")
|
||||
{
|
||||
str += i +"="+ encodeURIComponent(value).replace(/%20/g,"+");
|
||||
}
|
||||
else
|
||||
{
|
||||
str += i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
if (value !== '' || !removeEmptyQueries) {
|
||||
str += ++count === 1 ? '?' : '&';
|
||||
|
||||
i = encodeURIComponent(i);
|
||||
|
||||
if (value !== '') {
|
||||
str += i + '=' + encodeURIComponent(value).replace(/%20/g, '+');
|
||||
} else {
|
||||
str += i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = parseQuery;
|
||||
|
220
node_modules/relateurl/lib/parse/urlstring.js
generated
vendored
220
node_modules/relateurl/lib/parse/urlstring.js
generated
vendored
@ -1,8 +1,6 @@
|
||||
"use strict";
|
||||
|
||||
var _parseUrl = require("url").parse;
|
||||
|
||||
'use strict';
|
||||
|
||||
var _parseUrl = require('url').parse;
|
||||
|
||||
/*
|
||||
Customize the URL object that Node generates
|
||||
@ -16,131 +14,107 @@ var _parseUrl = require("url").parse;
|
||||
* urlObj.protocol is inaccurate; should be called "scheme"
|
||||
* urlObj.search is mostly useless
|
||||
*/
|
||||
function clean(urlObj)
|
||||
{
|
||||
var scheme = urlObj.protocol;
|
||||
|
||||
if (scheme)
|
||||
{
|
||||
// Remove ":" suffix
|
||||
if (scheme.indexOf(":") === scheme.length-1)
|
||||
{
|
||||
scheme = scheme.substr(0, scheme.length-1);
|
||||
}
|
||||
}
|
||||
|
||||
urlObj.host =
|
||||
{
|
||||
// TODO :: unescape(encodeURIComponent(s)) ? ... http://ecmanaut.blogspot.ca/2006/07/encoding-decoding-utf8-in-javascript.html
|
||||
full: urlObj.hostname,
|
||||
stripped: null
|
||||
};
|
||||
|
||||
urlObj.path =
|
||||
{
|
||||
absolute:
|
||||
{
|
||||
array: null,
|
||||
string: urlObj.pathname
|
||||
},
|
||||
relative:
|
||||
{
|
||||
array: null,
|
||||
string: null
|
||||
}
|
||||
};
|
||||
|
||||
urlObj.query =
|
||||
{
|
||||
object: urlObj.query,
|
||||
string:
|
||||
{
|
||||
full: null,
|
||||
stripped: null
|
||||
}
|
||||
};
|
||||
|
||||
urlObj.extra =
|
||||
{
|
||||
hrefInfo:
|
||||
{
|
||||
minimumPathOnly: null,
|
||||
minimumResourceOnly: null,
|
||||
minimumQueryOnly: null,
|
||||
minimumHashOnly: null,
|
||||
empty: null,
|
||||
|
||||
separatorOnlyQuery: urlObj.search==="?"
|
||||
},
|
||||
portIsDefault: null,
|
||||
relation:
|
||||
{
|
||||
maximumScheme: null,
|
||||
maximumAuth: null,
|
||||
maximumHost: null,
|
||||
maximumPort: null,
|
||||
maximumPath: null,
|
||||
maximumResource: null,
|
||||
maximumQuery: null,
|
||||
maximumHash: null,
|
||||
|
||||
minimumScheme: null,
|
||||
minimumAuth: null,
|
||||
minimumHost: null,
|
||||
minimumPort: null,
|
||||
minimumPath: null,
|
||||
minimumResource: null,
|
||||
minimumQuery: null,
|
||||
minimumHash: null,
|
||||
|
||||
overridesQuery: null
|
||||
},
|
||||
resourceIsIndex: null,
|
||||
slashes: urlObj.slashes
|
||||
};
|
||||
|
||||
urlObj.resource = null;
|
||||
urlObj.scheme = scheme;
|
||||
delete urlObj.hostname;
|
||||
delete urlObj.pathname;
|
||||
delete urlObj.protocol;
|
||||
delete urlObj.search;
|
||||
delete urlObj.slashes;
|
||||
|
||||
return urlObj;
|
||||
function clean(urlObj) {
|
||||
var scheme = urlObj.protocol;
|
||||
|
||||
if (scheme) {
|
||||
// Remove ":" suffix
|
||||
if (scheme.indexOf(':') === scheme.length - 1) {
|
||||
scheme = scheme.substr(0, scheme.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
urlObj.host = {
|
||||
// TODO :: unescape(encodeURIComponent(s)) ? ... http://ecmanaut.blogspot.ca/2006/07/encoding-decoding-utf8-in-javascript.html
|
||||
full: urlObj.hostname,
|
||||
stripped: null,
|
||||
};
|
||||
|
||||
urlObj.path = {
|
||||
absolute: {
|
||||
array: null,
|
||||
string: urlObj.pathname,
|
||||
},
|
||||
relative: {
|
||||
array: null,
|
||||
string: null,
|
||||
},
|
||||
};
|
||||
|
||||
urlObj.query = {
|
||||
object: urlObj.query,
|
||||
string: {
|
||||
full: null,
|
||||
stripped: null,
|
||||
},
|
||||
};
|
||||
|
||||
urlObj.extra = {
|
||||
hrefInfo: {
|
||||
minimumPathOnly: null,
|
||||
minimumResourceOnly: null,
|
||||
minimumQueryOnly: null,
|
||||
minimumHashOnly: null,
|
||||
empty: null,
|
||||
|
||||
separatorOnlyQuery: urlObj.search === '?',
|
||||
},
|
||||
portIsDefault: null,
|
||||
relation: {
|
||||
maximumScheme: null,
|
||||
maximumAuth: null,
|
||||
maximumHost: null,
|
||||
maximumPort: null,
|
||||
maximumPath: null,
|
||||
maximumResource: null,
|
||||
maximumQuery: null,
|
||||
maximumHash: null,
|
||||
|
||||
minimumScheme: null,
|
||||
minimumAuth: null,
|
||||
minimumHost: null,
|
||||
minimumPort: null,
|
||||
minimumPath: null,
|
||||
minimumResource: null,
|
||||
minimumQuery: null,
|
||||
minimumHash: null,
|
||||
|
||||
overridesQuery: null,
|
||||
},
|
||||
resourceIsIndex: null,
|
||||
slashes: urlObj.slashes,
|
||||
};
|
||||
|
||||
urlObj.resource = null;
|
||||
urlObj.scheme = scheme;
|
||||
delete urlObj.hostname;
|
||||
delete urlObj.pathname;
|
||||
delete urlObj.protocol;
|
||||
delete urlObj.search;
|
||||
delete urlObj.slashes;
|
||||
|
||||
return urlObj;
|
||||
}
|
||||
|
||||
function validScheme(url, options) {
|
||||
var valid = true;
|
||||
|
||||
options.rejectedSchemes.every(function (rejectedScheme) {
|
||||
valid = !(url.indexOf(rejectedScheme + ':') === 0);
|
||||
|
||||
function validScheme(url, options)
|
||||
{
|
||||
var valid = true;
|
||||
|
||||
options.rejectedSchemes.every( function(rejectedScheme)
|
||||
{
|
||||
valid = !(url.indexOf(rejectedScheme+":") === 0);
|
||||
|
||||
// Break loop
|
||||
return valid;
|
||||
});
|
||||
|
||||
return valid;
|
||||
// Break loop
|
||||
return valid;
|
||||
});
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function parseUrlString(url, options)
|
||||
{
|
||||
if ( validScheme(url,options) )
|
||||
{
|
||||
return clean( _parseUrl(url, true, options.slashesDenoteHost) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return {href:url, valid:false};
|
||||
}
|
||||
function parseUrlString(url, options) {
|
||||
if (validScheme(url, options)) {
|
||||
return clean(_parseUrl(url, true, options.slashesDenoteHost));
|
||||
} else {
|
||||
return { href: url, valid: false };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = parseUrlString;
|
||||
|
Reference in New Issue
Block a user