You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-07 13:22:56 +03:00
Small style changes
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
var redis = require('redis'),
|
||||
client = redis.createClient();
|
||||
|
||||
// This command is magical. Client stashes the password and will issue on every connect.
|
||||
client.auth("somepass");
|
||||
// The client stashes the password and will reauthenticate on every connect.
|
||||
client.auth('somepass');
|
||||
|
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("../index"),
|
||||
var redis = require('../index'),
|
||||
client = redis.createClient(null, null, {
|
||||
command_queue_high_water: 5,
|
||||
command_queue_low_water: 1
|
||||
@@ -9,26 +9,26 @@ var redis = require("../index"),
|
||||
|
||||
function op() {
|
||||
if (remaining_ops <= 0) {
|
||||
console.error("Finished.");
|
||||
console.error('Finished.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
remaining_ops--;
|
||||
if (client.hset("test hash", "val " + remaining_ops, remaining_ops) === false) {
|
||||
console.log("Pausing at " + remaining_ops);
|
||||
if (client.hset('test hash', 'val ' + remaining_ops, remaining_ops) === false) {
|
||||
console.log('Pausing at ' + remaining_ops);
|
||||
paused = true;
|
||||
} else {
|
||||
process.nextTick(op);
|
||||
}
|
||||
}
|
||||
|
||||
client.on("drain", function () {
|
||||
client.on('drain', function () {
|
||||
if (paused) {
|
||||
console.log("Resuming at " + remaining_ops);
|
||||
console.log('Resuming at ' + remaining_ops);
|
||||
paused = false;
|
||||
process.nextTick(op);
|
||||
} else {
|
||||
console.log("Got drain while not paused at " + remaining_ops);
|
||||
console.log('Got drain while not paused at ' + remaining_ops);
|
||||
}
|
||||
});
|
||||
|
||||
|
@@ -1,14 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("../index"),
|
||||
var redis = require('../index'),
|
||||
client = redis.createClient();
|
||||
|
||||
client.eval("return 100.5", 0, function (err, res) {
|
||||
client.eval('return 100.5', 0, function (err, res) {
|
||||
console.dir(err);
|
||||
console.dir(res);
|
||||
});
|
||||
|
||||
client.eval([ "return 100.5", 0 ], function (err, res) {
|
||||
client.eval([ 'return 100.5', 0 ], function (err, res) {
|
||||
console.dir(err);
|
||||
console.dir(res);
|
||||
});
|
||||
|
@@ -1,14 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
var redis = require('redis'),
|
||||
client = redis.createClient();
|
||||
|
||||
// Extend the RedisClient prototype to add a custom method
|
||||
// This one converts the results from "INFO" into a JavaScript Object
|
||||
// This one converts the results from 'INFO' into a JavaScript Object
|
||||
|
||||
redis.RedisClient.prototype.parse_info = function (callback) {
|
||||
this.info(function (err, res) {
|
||||
var lines = res.toString().split("\r\n").sort();
|
||||
var lines = res.toString().split('\r\n').sort();
|
||||
var obj = {};
|
||||
lines.forEach(function (line) {
|
||||
var parts = line.split(':');
|
||||
|
@@ -2,10 +2,10 @@
|
||||
|
||||
// Read a file from disk, store it in Redis, then read it back from Redis.
|
||||
|
||||
var redis = require("redis"),
|
||||
var redis = require('redis'),
|
||||
client = redis.createClient(),
|
||||
fs = require("fs"),
|
||||
filename = "kids_in_cart.jpg";
|
||||
fs = require('fs'),
|
||||
filename = 'kids_in_cart.jpg';
|
||||
|
||||
// Get the file I use for testing like this:
|
||||
// curl http://ranney.com/kids_in_cart.jpg -o kids_in_cart.jpg
|
||||
@@ -14,18 +14,18 @@ var redis = require("redis"),
|
||||
// Read a file from fs, store it in Redis, get it back from Redis, write it back to fs.
|
||||
fs.readFile(filename, function (err, data) {
|
||||
if (err) throw err;
|
||||
console.log("Read " + data.length + " bytes from filesystem.");
|
||||
console.log('Read ' + data.length + ' bytes from filesystem.');
|
||||
|
||||
client.set(filename, data, redis.print); // set entire file
|
||||
client.get(filename, function (err, reply) { // get entire file
|
||||
if (err) {
|
||||
console.log("Get error: " + err);
|
||||
console.log('Get error: ' + err);
|
||||
} else {
|
||||
fs.writeFile("duplicate_" + filename, reply, function (err) {
|
||||
fs.writeFile('duplicate_' + filename, reply, function (err) {
|
||||
if (err) {
|
||||
console.log("Error on write: " + err);
|
||||
console.log('Error on write: ' + err);
|
||||
} else {
|
||||
console.log("File written.");
|
||||
console.log('File written.');
|
||||
}
|
||||
client.end();
|
||||
});
|
||||
|
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var client = require("redis").createClient();
|
||||
var client = require('redis').createClient();
|
||||
|
||||
client.mget(["sessions started", "sessions started", "foo"], function (err, res) {
|
||||
client.mget(['sessions started', 'sessions started', 'foo'], function (err, res) {
|
||||
console.dir(res);
|
||||
});
|
@@ -1,12 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
var client = require("../index").createClient(),
|
||||
util = require("util");
|
||||
var client = require('../index').createClient(),
|
||||
util = require('util');
|
||||
|
||||
client.monitor(function (err, res) {
|
||||
console.log("Entering monitoring mode.");
|
||||
console.log('Entering monitoring mode.');
|
||||
});
|
||||
|
||||
client.on("monitor", function (time, args) {
|
||||
console.log(time + ": " + util.inspect(args));
|
||||
client.on('monitor', function (time, args) {
|
||||
console.log(time + ': ' + util.inspect(args));
|
||||
});
|
||||
|
@@ -1,40 +1,40 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
var redis = require('redis'),
|
||||
client = redis.createClient(), set_size = 20;
|
||||
|
||||
client.sadd("bigset", "a member");
|
||||
client.sadd("bigset", "another member");
|
||||
client.sadd('bigset', 'a member');
|
||||
client.sadd('bigset', 'another member');
|
||||
|
||||
while (set_size > 0) {
|
||||
client.sadd("bigset", "member " + set_size);
|
||||
client.sadd('bigset', 'member ' + set_size);
|
||||
set_size -= 1;
|
||||
}
|
||||
|
||||
// multi chain with an individual callback
|
||||
client.multi()
|
||||
.scard("bigset")
|
||||
.smembers("bigset")
|
||||
.keys("*", function (err, replies) {
|
||||
.scard('bigset')
|
||||
.smembers('bigset')
|
||||
.keys('*', function (err, replies) {
|
||||
client.mget(replies, redis.print);
|
||||
})
|
||||
.dbsize()
|
||||
.exec(function (err, replies) {
|
||||
console.log("MULTI got " + replies.length + " replies");
|
||||
console.log('MULTI got ' + replies.length + ' replies');
|
||||
replies.forEach(function (reply, index) {
|
||||
console.log("Reply " + index + ": " + reply.toString());
|
||||
console.log('Reply ' + index + ': ' + reply.toString());
|
||||
});
|
||||
});
|
||||
|
||||
client.mset("incr thing", 100, "incr other thing", 1, redis.print);
|
||||
client.mset('incr thing', 100, 'incr other thing', 1, redis.print);
|
||||
|
||||
// start a separate multi command queue
|
||||
var multi = client.multi();
|
||||
multi.incr("incr thing", redis.print);
|
||||
multi.incr("incr other thing", redis.print);
|
||||
multi.incr('incr thing', redis.print);
|
||||
multi.incr('incr other thing', redis.print);
|
||||
|
||||
// runs immediately
|
||||
client.get("incr thing", redis.print); // 100
|
||||
client.get('incr thing', redis.print); // 100
|
||||
|
||||
// drains multi queue and runs atomically
|
||||
multi.exec(function (err, replies) {
|
||||
|
@@ -1,15 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
var redis = require('redis'),
|
||||
client = redis.createClient(), multi;
|
||||
|
||||
// start a separate command queue for multi
|
||||
multi = client.multi();
|
||||
multi.incr("incr thing", redis.print);
|
||||
multi.incr("incr other thing", redis.print);
|
||||
multi.incr('incr thing', redis.print);
|
||||
multi.incr('incr other thing', redis.print);
|
||||
|
||||
// runs immediately
|
||||
client.mset("incr thing", 100, "incr other thing", 1, redis.print);
|
||||
client.mset('incr thing', 100, 'incr other thing', 1, redis.print);
|
||||
|
||||
// drains multi queue and runs atomically
|
||||
multi.exec(function (err, replies) {
|
||||
@@ -23,9 +23,9 @@ multi.exec(function (err, replies) {
|
||||
});
|
||||
|
||||
client.multi([
|
||||
["mget", "multifoo", "multibar", redis.print],
|
||||
["incr", "multifoo"],
|
||||
["incr", "multibar"]
|
||||
['mget', 'multifoo', 'multibar', redis.print],
|
||||
['incr', 'multifoo'],
|
||||
['incr', 'multibar']
|
||||
]).exec(function (err, replies) {
|
||||
console.log(replies.toString());
|
||||
});
|
||||
|
@@ -1,33 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
var redis = require('redis'),
|
||||
client1 = redis.createClient(),
|
||||
client2 = redis.createClient(),
|
||||
client3 = redis.createClient(),
|
||||
client4 = redis.createClient(),
|
||||
msg_count = 0;
|
||||
|
||||
client1.on("psubscribe", function (pattern, count) {
|
||||
console.log("client1 psubscribed to " + pattern + ", " + count + " total subscriptions");
|
||||
client2.publish("channeltwo", "Me!");
|
||||
client3.publish("channelthree", "Me too!");
|
||||
client4.publish("channelfour", "And me too!");
|
||||
client1.on('psubscribe', function (pattern, count) {
|
||||
console.log('client1 psubscribed to ' + pattern + ', ' + count + ' total subscriptions');
|
||||
client2.publish('channeltwo', 'Me!');
|
||||
client3.publish('channelthree', 'Me too!');
|
||||
client4.publish('channelfour', 'And me too!');
|
||||
});
|
||||
|
||||
client1.on("punsubscribe", function (pattern, count) {
|
||||
console.log("client1 punsubscribed from " + pattern + ", " + count + " total subscriptions");
|
||||
client1.on('punsubscribe', function (pattern, count) {
|
||||
console.log('client1 punsubscribed from ' + pattern + ', ' + count + ' total subscriptions');
|
||||
client4.end();
|
||||
client3.end();
|
||||
client2.end();
|
||||
client1.end();
|
||||
});
|
||||
|
||||
client1.on("pmessage", function (pattern, channel, message) {
|
||||
console.log("("+ pattern +")" + " client1 received message on " + channel + ": " + message);
|
||||
client1.on('pmessage', function (pattern, channel, message) {
|
||||
console.log('('+ pattern +')' + ' client1 received message on ' + channel + ': ' + message);
|
||||
msg_count += 1;
|
||||
if (msg_count === 3) {
|
||||
client1.punsubscribe();
|
||||
}
|
||||
});
|
||||
|
||||
client1.psubscribe("channel*");
|
||||
client1.psubscribe('channel*');
|
||||
|
@@ -1,41 +1,41 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
var redis = require('redis'),
|
||||
client1 = redis.createClient(), msg_count = 0,
|
||||
client2 = redis.createClient();
|
||||
|
||||
// Most clients probably don't do much on "subscribe". This example uses it to coordinate things within one program.
|
||||
client1.on("subscribe", function (channel, count) {
|
||||
console.log("client1 subscribed to " + channel + ", " + count + " total subscriptions");
|
||||
// Most clients probably don't do much on 'subscribe'. This example uses it to coordinate things within one program.
|
||||
client1.on('subscribe', function (channel, count) {
|
||||
console.log('client1 subscribed to ' + channel + ', ' + count + ' total subscriptions');
|
||||
if (count === 2) {
|
||||
client2.publish("a nice channel", "I am sending a message.");
|
||||
client2.publish("another one", "I am sending a second message.");
|
||||
client2.publish("a nice channel", "I am sending my last message.");
|
||||
client2.publish('a nice channel', 'I am sending a message.');
|
||||
client2.publish('another one', 'I am sending a second message.');
|
||||
client2.publish('a nice channel', 'I am sending my last message.');
|
||||
}
|
||||
});
|
||||
|
||||
client1.on("unsubscribe", function (channel, count) {
|
||||
console.log("client1 unsubscribed from " + channel + ", " + count + " total subscriptions");
|
||||
client1.on('unsubscribe', function (channel, count) {
|
||||
console.log('client1 unsubscribed from ' + channel + ', ' + count + ' total subscriptions');
|
||||
if (count === 0) {
|
||||
client2.end();
|
||||
client1.end();
|
||||
}
|
||||
});
|
||||
|
||||
client1.on("message", function (channel, message) {
|
||||
console.log("client1 channel " + channel + ": " + message);
|
||||
client1.on('message', function (channel, message) {
|
||||
console.log('client1 channel ' + channel + ': ' + message);
|
||||
msg_count += 1;
|
||||
if (msg_count === 3) {
|
||||
client1.unsubscribe();
|
||||
}
|
||||
});
|
||||
|
||||
client1.on("ready", function () {
|
||||
client1.on('ready', function () {
|
||||
// if you need auth, do it here
|
||||
client1.incr("did a thing");
|
||||
client1.subscribe("a nice channel", "another one");
|
||||
client1.incr('did a thing');
|
||||
client1.subscribe('a nice channel', 'another one');
|
||||
});
|
||||
|
||||
client2.on("ready", function () {
|
||||
client2.on('ready', function () {
|
||||
// if you need auth, do it here
|
||||
});
|
||||
|
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
var redis = require('redis'),
|
||||
client = redis.createClient();
|
||||
|
||||
var cursor = '0';
|
||||
@@ -8,8 +8,8 @@ var cursor = '0';
|
||||
function scan() {
|
||||
client.scan(
|
||||
cursor,
|
||||
"MATCH", "q:job:*",
|
||||
"COUNT", "10",
|
||||
'MATCH', 'q:job:*',
|
||||
'COUNT', '10',
|
||||
function(err, res) {
|
||||
if (err) throw err;
|
||||
|
||||
@@ -17,22 +17,21 @@ function scan() {
|
||||
cursor = res[0];
|
||||
|
||||
// From <http://redis.io/commands/scan>:
|
||||
// "An iteration starts when the cursor is set to 0,
|
||||
// and terminates when the cursor returned by the server is 0."
|
||||
// 'An iteration starts when the cursor is set to 0,
|
||||
// and terminates when the cursor returned by the server is 0.'
|
||||
if (cursor === '0') {
|
||||
return console.log('Iteration complete');
|
||||
} else {
|
||||
// Remember: more or less than COUNT or no keys may be returned
|
||||
// See http://redis.io/commands/scan#the-count-option
|
||||
// Also, SCAN may return the same key multiple times
|
||||
// See http://redis.io/commands/scan#scan-guarantees
|
||||
|
||||
if (res[1].length > 0) {
|
||||
console.log('Array of matching keys', res[1]);
|
||||
}
|
||||
|
||||
return scan();
|
||||
}
|
||||
// Remember: more or less than COUNT or no keys may be returned
|
||||
// See http://redis.io/commands/scan#the-count-option
|
||||
// Also, SCAN may return the same key multiple times
|
||||
// See http://redis.io/commands/scan#scan-guarantees
|
||||
|
||||
if (res[1].length > 0) {
|
||||
console.log('Array of matching keys', res[1]);
|
||||
}
|
||||
|
||||
return scan();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@@ -1,26 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
var redis = require('redis'),
|
||||
client = redis.createClient();
|
||||
|
||||
client.on("error", function (err) {
|
||||
console.log("error event - " + client.host + ":" + client.port + " - " + err);
|
||||
client.on('error', function (err) {
|
||||
console.log('error event - ' + client.host + ':' + client.port + ' - ' + err);
|
||||
});
|
||||
|
||||
client.set("string key", "string val", redis.print);
|
||||
client.hset("hash key", "hashtest 1", "some value", redis.print);
|
||||
client.hset(["hash key", "hashtest 2", "some other value"], redis.print);
|
||||
client.hkeys("hash key", function (err, replies) {
|
||||
client.set('string key', 'string val', redis.print);
|
||||
client.hset('hash key', 'hashtest 1', 'some value', redis.print);
|
||||
client.hset(['hash key', 'hashtest 2', 'some other value'], redis.print);
|
||||
client.hkeys('hash key', function (err, replies) {
|
||||
if (err) {
|
||||
return console.error("error response - " + err);
|
||||
return console.error('error response - ' + err);
|
||||
}
|
||||
|
||||
console.log(replies.length + " replies:");
|
||||
console.log(replies.length + ' replies:');
|
||||
replies.forEach(function (reply, i) {
|
||||
console.log(" " + i + ": " + reply);
|
||||
console.log(' ' + i + ': ' + reply);
|
||||
});
|
||||
});
|
||||
|
||||
client.quit(function (err, res) {
|
||||
console.log("Exiting from quit command.");
|
||||
console.log('Exiting from quit command.');
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
var redis = require('redis'),
|
||||
client = redis.createClient();
|
||||
|
||||
client.sadd("mylist", 1);
|
||||
client.sadd("mylist", 2);
|
||||
client.sadd("mylist", 3);
|
||||
client.sadd('mylist', 1);
|
||||
client.sadd('mylist', 2);
|
||||
client.sadd('mylist', 3);
|
||||
|
||||
client.set("weight_1", 5);
|
||||
client.set("weight_2", 500);
|
||||
client.set("weight_3", 1);
|
||||
client.set('weight_1', 5);
|
||||
client.set('weight_2', 500);
|
||||
client.set('weight_3', 1);
|
||||
|
||||
client.set("object_1", "foo");
|
||||
client.set("object_2", "bar");
|
||||
client.set("object_3", "qux");
|
||||
client.set('object_1', 'foo');
|
||||
client.set('object_2', 'bar');
|
||||
client.set('object_3', 'qux');
|
||||
|
||||
client.sort("mylist", "by", "weight_*", "get", "object_*", redis.print);
|
||||
client.sort('mylist', 'by', 'weight_*', 'get', 'object_*', redis.print);
|
||||
// Prints Reply: qux,foo,bar
|
@@ -1,14 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
// Sending commands in response to other commands.
|
||||
// This example runs "type" against every key in the database
|
||||
// This example runs 'type' against every key in the database
|
||||
//
|
||||
var client = require("redis").createClient();
|
||||
var client = require('redis').createClient();
|
||||
|
||||
client.keys("*", function (err, keys) {
|
||||
client.keys('*', function (err, keys) {
|
||||
keys.forEach(function (key, pos) {
|
||||
client.type(key, function (err, keytype) {
|
||||
console.log(key + " is " + keytype);
|
||||
console.log(key + ' is ' + keytype);
|
||||
if (pos === (keys.length - 1)) {
|
||||
client.quit();
|
||||
}
|
||||
|
@@ -1,20 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
var client = require("redis").createClient();
|
||||
|
||||
function print_results(obj) {
|
||||
console.dir(obj);
|
||||
}
|
||||
var client = require('redis').createClient();
|
||||
|
||||
// build a map of all keys and their types
|
||||
client.keys("*", function (err, all_keys) {
|
||||
client.keys('*', function (err, all_keys) {
|
||||
var key_types = {};
|
||||
|
||||
all_keys.forEach(function (key, pos) { // use second arg of forEach to get pos
|
||||
client.type(key, function (err, type) {
|
||||
key_types[key] = type;
|
||||
if (pos === all_keys.length - 1) { // callbacks all run in order
|
||||
print_results(key_types);
|
||||
console.dir(key_types);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@@ -1,21 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient("/tmp/redis.sock"),
|
||||
profiler = require("v8-profiler");
|
||||
var redis = require('redis'),
|
||||
client = redis.createClient('/tmp/redis.sock'),
|
||||
profiler = require('v8-profiler');
|
||||
|
||||
client.on("connect", function () {
|
||||
console.log("Got Unix socket connection.");
|
||||
client.on('connect', function () {
|
||||
console.log('Got Unix socket connection.');
|
||||
});
|
||||
|
||||
client.on("error", function (err) {
|
||||
client.on('error', function (err) {
|
||||
console.log(err.message);
|
||||
});
|
||||
|
||||
client.set("space chars", "space value");
|
||||
client.set('space chars', 'space value');
|
||||
|
||||
setInterval(function () {
|
||||
client.get("space chars");
|
||||
client.get('space chars');
|
||||
}, 100);
|
||||
|
||||
function done() {
|
||||
@@ -26,6 +26,6 @@ function done() {
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
console.log("Taking snapshot.");
|
||||
console.log('Taking snapshot.');
|
||||
profiler.takeSnapshot();
|
||||
}, 5000);
|
||||
|
@@ -2,12 +2,12 @@
|
||||
|
||||
// A simple web server that generates dyanmic content based on responses from Redis
|
||||
|
||||
var http = require("http"), server,
|
||||
redis_client = require("redis").createClient();
|
||||
var http = require('http'), server,
|
||||
redis_client = require('redis').createClient();
|
||||
|
||||
server = http.createServer(function (request, response) {
|
||||
response.writeHead(200, {
|
||||
"Content-Type": "text/plain"
|
||||
'Content-Type': 'text/plain'
|
||||
});
|
||||
|
||||
var redis_info, total_requests;
|
||||
@@ -15,18 +15,18 @@ server = http.createServer(function (request, response) {
|
||||
redis_client.info(function (err, reply) {
|
||||
redis_info = reply; // stash response in outer scope
|
||||
});
|
||||
redis_client.incr("requests", function (err, reply) {
|
||||
redis_client.incr('requests', function (err, reply) {
|
||||
total_requests = reply; // stash response in outer scope
|
||||
});
|
||||
redis_client.hincrby("ip", request.connection.remoteAddress, 1);
|
||||
redis_client.hgetall("ip", function (err, reply) {
|
||||
redis_client.hincrby('ip', request.connection.remoteAddress, 1);
|
||||
redis_client.hgetall('ip', function (err, reply) {
|
||||
// This is the last reply, so all of the previous replies must have completed already
|
||||
response.write("This page was generated after talking to redis.\n\n" +
|
||||
"Redis info:\n" + redis_info + "\n" +
|
||||
"Total requests: " + total_requests + "\n\n" +
|
||||
"IP count: \n");
|
||||
response.write('This page was generated after talking to redis.\n\n' +
|
||||
'Redis info:\n' + redis_info + '\n' +
|
||||
'Total requests: ' + total_requests + '\n\n' +
|
||||
'IP count: \n');
|
||||
Object.keys(reply).forEach(function (ip) {
|
||||
response.write(" " + ip + ": " + reply[ip] + "\n");
|
||||
response.write(' ' + ip + ': ' + reply[ip] + '\n');
|
||||
});
|
||||
response.end();
|
||||
});
|
||||
|
Reference in New Issue
Block a user