A light-weight job scheduling library for Node.js
This is a fork of agenda js, it differs from the original version in following points:
db.agendaJogs.ensureIndex({
"name" : 1,
"nextRunAt" : 1,
"priority" : -1,
"lockedAt" : 1,
"disabled" : 1
})
manually or set ensureIndex: true
when initializing AgendaSince there are a few job queue solutions, here a table comparing them to help you use the one that better suits your needs.
Agenda is great if you need a MongoDB job scheduler, but try Bree if you need something simpler (built by a previous maintainer).
| Feature | Bull | Bee | Agenda |
|---|---|---|---|
| Backend | redis | redis | mongo |
| Priorities | ✓ | ✓ | |
| Concurrency | ✓ | ✓ | ✓ |
| Delayed jobs | ✓ | ✓ | |
| Global events | ✓ | ||
| Rate Limiter | ✓ | ||
| Pause/Resume | ✓ | ||
| Sandboxed worker | ✓ | ||
| Repeatable jobs | ✓ | ✓ | |
| Atomic ops | ✓ | ✓ | |
| Persistence | ✓ | ✓ | ✓ |
| UI | ✓ | ✓ | |
| REST API | ✓ | ||
| Optimized for | Jobs / Messages | Messages | Jobs |
Kudos for making the comparison chart goes to Bull maintainers.
Install via NPM
npm install @hokify/agenda
You will also need a working Mongo database (v3+) to point it to.
const mongoConnectionString = 'mongodb://<IP_ADDRESS>/agenda';
const agenda = new Agenda({db: {address: mongoConnectionString}});
// Or override the default collection name:
// const agenda = new Agenda({db: {address: mongoConnectionString, collection: 'jobCollectionName'}});
// or pass additional connection options:
// const agenda = new Agenda({db: {address: mongoConnectionString, collection: 'jobCollectionName', options: {ssl: true}}});
// or pass in an existing mongodb-native MongoClient instance
// const agenda = new Agenda({mongo: myMongoClient});
agenda.define('delete old users', async job => {
await User.remove({lastLogIn: {$lt: twoDaysAgo}});
});
(async function() { // IIFE to give access to async/await
await agenda.start();
await agenda.every('3 minutes', 'delete old users');
// Alternatively, you could also do:
await agenda.every('*/3 * * * *', 'delete old users');
})();
agenda.define('send email report', async job => {
const {to} = job.attrs.data;
await emailClient.send({
to,
from<EMAIL_ADDRESS>subject: 'Email Report',
body: '...'
});
}, {priority: 'high', concurrency: 10}, );
(async function() {
await agenda.start();
await agenda.schedule('in 20 minutes', 'send email report', {to: 'admin@example.com'});
})();
(async function() {
const weeklyReport = agenda.create('send email report', {to: 'example@example.com'});
await agenda.start();
await weeklyReport.repeatEvery('1 week').save();
})();
See also https://hokify.github.io/agenda/agenda/4.x/index.html
Agenda's basic control structure is an instance of an agenda. Agenda's are mapped to a database collection and load the jobs from within.
All configuration methods are chainable, meaning you can do something like:
const agenda = new Agenda();
agenda
.database(...)
.processEvery('3 minutes')
...;
Possible agenda config options:
{
name: string;
defaultConcurrency: number;
processEvery: number;
maxConcurrency: number;
defaultLockLimit: number;
lockLimit: number;
defaultLockLifetime: number;
ensureIndex: boolean;
sort: SortOptionObject<IJobParameters>;
db: {
collection: string;
address: string;
options: MongoClientOptions;
};
mongo: Db;
}
Agenda uses Human Interval for specifying the intervals. It supports the following units:
seconds
, minutes
, hours
, days
,weeks
, months
-- assumes 30 days, years
-- assumes 365 days
More sophisticated examples
agenda.processEvery('one minute');
agenda.processEvery('1.5 minutes');
agenda.processEvery('3 days and 4 hours');
agenda.processEvery('3 days, 4 hours and 36 seconds');
Specifies the database at the url
specified. If no collection name is given,
agendaJobs
is used.
By default useNewUrlParser
and useUnifiedTopology
is set to true
,
agenda.database('localhost:27017/agenda-test', 'agendaJobs');
You can also specify it during instantiation.
const agenda = new Agenda({db: {address: 'localhost:27017/agenda-test', collection: 'agendaJobs'}});
Agenda will emit a ready
event (see Agenda Events) when properly connected to the database.
It is safe to call agenda.start()
without waiting for this event, as this is handled internally.
If you're using the db
options, or call database
, then you may still need to listen for ready
before saving jobs.
Use an existing mongodb-native MongoClient/Db instance. This can help consolidate connections to a
database. You can instead use .database
to have agenda handle connecting for you.
You can also specify it during instantiation:
const agenda = new Agenda({mongo: mongoClientInstance.db('agenda-test')});
Note that MongoClient.connect() returns a mongoClientInstance since node-mongodb-native 3.0.0, while it used to return a dbInstance that could then be directly passed to agenda.
Takes a string name
and sets lastModifiedBy
to it in the job database.
Useful for if you have multiple job processors (agendas) and want to see which
job queue last ran the job.
agenda.name(os.hostname + '-' + process.pid);
You can also specify it during instantiation
const agenda = new Agenda({name: 'test queue'});
Takes a string interval
which can be either a traditional javascript number,
or a string such as 3 minutes
Specifies the frequency at which agenda will query the database looking for jobs
that need to be processed. Agenda internally uses setTimeout
to guarantee that
jobs run at (close to ~3ms) the right time.
Decreasing the frequency will result in fewer database queries, but more jobs being stored in memory.
Also worth noting is that if the job queue is shutdown, any jobs stored in memory
that haven't run will still be locked, meaning that you may have to wait for the
lock to expire. By default it is '5 seconds'
.
agenda.processEvery('1 minute');
You can also specify it during instantiation
const agenda = new Agenda({processEvery: '30 seconds'});
Takes a number
which specifies the max number of jobs that can be running at
any given moment. By default it is 20
.
agenda.maxConcurrency(20);
You can also specify it during instantiation
const agenda = new Agenda({maxConcurrency: 20});
Takes a number
which specifies the default number of a specific job that can be running at
any given moment. By default it is 5
.
agenda.defaultConcurrency(5);
You can also specify it during instantiation
const agenda = new Agenda({defaultConcurrency: 5});
Takes a number
which specifies the max number jobs that can be locked at any given moment. By default it is 0
for no max.
agenda.lockLimit(0);
You can also specify it during instantiation
const agenda = new Agenda({lockLimit: 0});
Takes a number
which specifies the default number of a specific job that can be locked at any given moment. By default it is 0
for no max.
agenda.defaultLockLimit(0);
You can also specify it during instantiation
const agenda = new Agenda({defaultLockLimit: 0});
Takes a number
which specifies the default lock lifetime in milliseconds. By
default it is 10 minutes. This can be overridden by specifying the
lockLifetime
option to a defined job.
A job will unlock if it is finished (ie. the returned Promise resolves/rejects
or done
is specified in the params and done()
is called) before the
lockLifetime
. The lock is useful if the job crashes or times out.
agenda.defaultLockLifetime(10000);
You can also specify it during instantiation
const agenda = new Agenda({defaultLockLifetime: 10000});
Takes a query
which specifies the sort query to be used for finding and locking the next job.
By default it is { nextRunAt: 1, priority: -1 }
, which obeys a first in first out approach, with respect to priority.
An instance of an agenda will emit the following events:
ready
- called when Agenda mongo connection is successfully opened and indices created. If you're passing agenda an existing connection, you shouldn't need to listen for this, as `agenda.start()` will not resolve until indices have been created.
If you're using the `db` options, or call `database`, then you may still need to listen for the `ready` event before saving jobs. `agenda.start()` will still wait for the connection to be opened.
error
- called when Agenda mongo connection process has thrown an errorawait agenda.start();
Before you can use a job, you must define its processing behavior.
Defines a job with the name of jobName
. When a job of jobName
gets run, it
will be passed to fn(job, done)
. To maintain asynchronous behavior, you may
either provide a Promise-returning function in fn
or provide done
as a
second parameter to fn
. If done
is specified in the function signature, you
must call done()
when you are processing the job. If your function is
synchronous or returns a Promise, you may omit done
from the signature.
options
is an optional argument which can overwrite the defaults. It can take
the following:
concurrency
: number
maximum number of that job that can be running at once (per instance of agenda)lockLimit
: number
maximum number of that job that can be locked at once (per instance of agenda)lockLifetime
: number
interval in ms of how long the job stays locked for (see multiple job processors for more info).
A job will automatically unlock once a returned promise resolves/rejects (or if done
is specified in the signature and done()
is called).priority
: (lowest|low|normal|high|highest|number)
specifies the priority
of the job. Higher priority jobs will run first. See the priority mapping
belowPriority mapping:
{
highest: 20,
high: 10,
normal: 0,
low: -10,
lowest: -20
}
Async Job:
agenda.define('some long running job', async job => {
const data = await doSomelengthyTask();
await formatThatData(data);
await sendThatData(data);
});
Async Job (using done
):
agenda.define('some long running job', (job, done) => {
doSomelengthyTask(data => {
formatThatData(data);
sendThatData(data);
done();
});
});
Sync Job:
agenda.define('say hello', job => {
console.log('Hello!');
});
define()
acts like an assignment: if define(jobName, ...)
is called multiple times (e.g. every time your script starts), the definition in the last call will overwrite the previous one. Thus, if you define
the jobName
only once in your code, it's safe for that call to execute multiple times.
Runs job name
at the given interval
. Optionally, data and options can be passed in.
Every creates a job of type single
, which means that it will only create one
job in the database, even if that line is run multiple times. This lets you put
it in a file that may get run multiple times, such as webserver.js
which may
reboot from time to time.
interval
can be a human-readable format String
, a cron format String
, or a Number
.
data
is an optional argument that will be passed to the processing function
under job.attrs.data
.
options
is an optional argument that will be passed to job.repeatEvery
.
In order to use this argument, data
must also be specified.
Returns the job
.
agenda.define('printAnalyticsReport', async job => {
const users = await User.doSomethingReallyIntensive();
processUserData(users);
console.log('I print a report!');
});
agenda.every('15 minutes', 'printAnalyticsReport');
Optionally, name
could be array of job names, which is convenient for scheduling
different jobs for same interval
.
agenda.every('15 minutes', ['printAnalyticsReport', 'sendNotifications', 'updateUserRecords']);
In this case, every
returns array of jobs
.
Schedules a job to run name
once at a given time. when
can be a Date
or a
String
such as tomorrow at 5pm
.
data
is an optional argument that will be passed to the processing function
under job.attrs.data
.
Returns the job
.
agenda.schedule('tomorrow at noon', 'printAnalyticsReport', {userCount: 100});
Optionally, name
could be array of job names, similar to the every
method.
agenda.schedule('tomorrow at noon', ['printAnalyticsReport', 'sendNotifications', 'updateUserRecords']);
In this case, schedule
returns array of jobs
.
Schedules a job to run name
once immediately.
data
is an optional argument that will be passed to the processing function
under job.attrs.data
.
Returns the job
.
agenda.now('do the hokey pokey');
Returns an instance of a jobName
with data
. This does NOT save the job in
the database. See below to learn how to manually work with jobs.
const job = agenda.create('printAnalyticsReport', {userCount: 100});
await job.save();
console.log('Job successfully saved');
Lets you query (then sort, limit and skip the result) all of the jobs in the agenda job's database. These are full mongodb-native find
, sort
, limit
and skip
commands. See mongodb-native's documentation for details.
const jobs = await agenda.jobs({name: 'printAnalyticsReport'}, {data:-1}, 3, 1);
// Work with jobs (see below)
Cancels any jobs matching the passed mongodb-native query, and removes them from the database. Returns a Promise resolving to the number of cancelled jobs, or rejecting on error.
const numRemoved = await agenda.cancel({name: 'printAnalyticsReport'});
This functionality can also be achieved by first retrieving all the jobs from the database using agenda.jobs()
, looping through the resulting array and calling job.remove()
on each. It is however preferable to use agenda.cancel()
for this use case, as this ensures the operation is atomic.
Removes all jobs in the database without defined behaviors. Useful if you change a definition name and want to remove old jobs. Returns a Promise resolving to the number of removed jobs, or rejecting on error.
 If you do, you will nuke your database of jobs.
const numRemoved = await agenda.purge();
To get agenda to start processing jobs from the database you must start it. This
will schedule an interval (based on processEvery
) to check for new jobs and
run them. You can also stop the queue.
Starts the job queue processing, checking processEvery
time to see if there
are new jobs. Must be called after processEvery
, and before any job scheduling (e.g. every
).
Stops the job queue processing. Unlocks currently running jobs.
This can be very useful for graceful shutdowns so that currently running/grabbed jobs are abandoned so that other job queues can grab them / they are unlocked should the job queue start again. Here is an example of how to do a graceful shutdown.
async function graceful() {
await agenda.stop();
process.exit(0);
}
process.on('SIGTERM', graceful);
process.on('SIGINT' , graceful);
Sometimes you may want to have multiple node instances / machines process from the same queue. Agenda supports a locking mechanism to ensure that multiple queues don't process the same job.
You can configure the locking mechanism by specifying lockLifetime
as an
interval when defining the job.
agenda.define('someJob', (job, cb) => {
// Do something in 10 seconds or less...
}, {lockLifetime: 10000});
This will ensure that no other job processor (this one included) attempts to run the job again for the next 10 seconds. If you have a particularly long running job, you will want to specify a longer lockLifetime.
By default it is 10 minutes. Typically you shouldn't have a job that runs for 10 minutes, so this is really insurance should the job queue crash before the job is unlocked.
When a job is finished (i.e. the returned promise resolves/rejects or done
is
specified in the signature and done()
is called), it will automatically unlock.
A job instance has many instance methods. All mutating methods must be followed
with a call to await job.save()
in order to persist the changes to the database.
Specifies an interval
on which the job should repeat. The job runs at the time of defining as well in configured intervals, that is "run now and in intervals".
interval
can be a human-readable format String
, a cron format String
, or a Number
.
options
is an optional argument containing:
options.timezone
: should be a string as accepted by moment-timezone and is considered when using an interval in the cron string format.
options.skipImmediate
: true
| false
(default) Setting this true
will skip the immediate run. The first run will occur only in configured interval.
job.repeatEvery('10 minutes');
await job.save();
job.repeatEvery('3 minutes', {
skipImmediate: true
});
await job.save();
job.repeatEvery('0 6 * * *', {
timezone: 'America/New_York'
});
await job.save();
Specifies a time
when the job should repeat. Possible values
job.repeatAt('3:30pm');
await job.save();
Specifies the next time
at which the job should run.
job.schedule('tomorrow at 6pm');
await job.save();
Specifies the priority
weighting of the job. Can be a number or a string from
the above priority table.
job.priority('low');
await job.save();
Ensure that only one instance of this job exists with the specified properties
options
is an optional argument which can overwrite the defaults. It can take
the following:
insertOnly
: boolean
will prevent any properties from persisting if the job already exists. Defaults to false.job.unique({'data.type': 'active', 'data.userId': '123', nextRunAt: date});
await job.save();
IMPORTANT: To avoid high CPU usage by MongoDB, make sure to create an index on the used fields, like data.type
and data.userId
for the example above.
Sets job.attrs.failedAt
to now
, and sets job.attrs.failReason
to reason
.
Optionally, reason
can be an error, in which case job.attrs.failReason
will
be set to error.message
job.fail('insufficient disk space');
// or
job.fail(new Error('insufficient disk space'));
await job.save();
Runs the given job
and calls callback(err, job)
upon completion. Normally
you never need to call this manually.
job.run((err, job) => {
console.log('I don\'t know why you would need to do this...');
});
Saves the job.attrs
into the database. Returns a Promise resolving to a Job instance, or rejecting on error.
try {
await job.save();
cosole.log('Successfully saved job to collection');
} catch (e) {
console.error('Error saving job to collection');
}
Removes the job
from the database. Returns a Promise resolving to the number of jobs removed, or rejecting on error.
try {
await job.remove();
console.log('Successfully removed job from collection');
} catch (e) {
console.error('Error removing job from collection');
}
Disables the job
. Upcoming runs won't execute.
Enables the job
if it got disabled before. Upcoming runs will execute.
Resets the lock on the job. Useful to indicate that the job hasn't timed out when you have very long running jobs. The call returns a promise that resolves when the job's lock has been renewed.
agenda.define('super long job', async job => {
await doSomeLongTask();
await job.touch();
await doAnotherLongTask();
await job.touch();
await finishOurLongTasks();
});
An instance of an agenda will emit the following events:
start
- called just before a job startsstart:job name
- called just before the specified job startsagenda.on('start', job => {
console.log('Job %s starting', job.attrs.name);
});
complete
- called when a job finishes, regardless of if it succeeds or failscomplete:job name
- called when a job finishes, regardless of if it succeeds or failsagenda.on('complete', job => {
console.log(`Job ${job.attrs.name} finished`);
});
success
- called when a job finishes successfullysuccess:job name
- called when a job finishes successfullyagenda.on('success:send email', job => {
console.log(`Sent Email Successfully to ${job.attrs.data.to}`);
});
fail
- called when a job throws an errorfail:job name
- called when a job throws an erroragenda.on('fail:send email', (err, job) => {
console.log(`Job failed with error: ${err.message}`);
});
Jobs are run with priority in a first in first out order (so they will be run in the order they were scheduled AND with respect to highest priority).
For example, if we have two jobs named "send-email" queued (both with the same priority), and the first job is queued at 3:00 PM and second job is queued at 3:05 PM with the same priority
value, then the first job will run first if we start to send "send-email" jobs at 3:10 PM. However if the first job has a priority of 5
and the second job has a priority of 10
, then the second will run first (priority takes precedence) at 3:10 PM.
The default MongoDB sort object is { nextRunAt: 1, priority: -1 }
and can be changed through the option sort
when configuring Agenda.
lockLimit
and maxConcurrency
?Agenda will lock jobs 1 by one, setting the lockedAt
property in mongoDB, and creating an instance of the Job
class which it caches into the _lockedJobs
array. This defaults to having no limit, but can be managed using lockLimit. If all jobs will need to be run before agenda's next interval (set via agenda.processEvery
), then agenda will attempt to lock all jobs.
Agenda will also pull jobs from _lockedJobs
and into _runningJobs
. These jobs are actively being worked on by user code, and this is limited by maxConcurrency
(defaults to 20).
If you have multiple instances of agenda processing the same job definition with a fast repeat time you may find they get unevenly loaded. This is because they will compete to lock as many jobs as possible, even if they don't have enough concurrency to process them. This can be resolved by tweaking the maxConcurrency
and lockLimit
properties.
Agenda doesn't have a preferred project structure and leaves it to the user to choose how they would like to use it. That being said, you can check out the example project structure below.
Thanks! I'm flattered, but it's really not necessary. If you really want to, you can find my gittip here.
Agenda itself does not have a web interface built in but we do offer stand-alone web interface Agendash:
The decision to use Mongo instead of Redis is intentional. Redis is often used for non-essential data (such as sessions) and without configuration doesn't guarantee the same level of persistence as Mongo (should the server need to be restarted/crash).
Agenda decides to focus on persistence without requiring special configuration of Redis (thereby degrading the performance of the Redis server on non-critical data, such as sessions).
Ultimately if enough people want a Redis driver instead of Mongo, I will write one. (Please open an issue requesting it). For now, Agenda decided to focus on guaranteed persistence.
Ultimately Agenda can work from a single job queue across multiple machines, node processes, or forks. If you are interested in having more than one worker, Bars3s has written up a fantastic example of how one might do it:
const cluster = require('cluster');
const os = require('os');
const httpServer = require('./app/http-server');
const jobWorker = require('./app/job-worker');
const jobWorkers = [];
const webWorkers = [];
if (cluster.isMaster) {
const cpuCount = os.cpus().length;
// Create a worker for each CPU
for (let i = 0; i < cpuCount; i += 1) {
addJobWorker();
addWebWorker();
}
cluster.on('exit', (worker, code, signal) => {
if (jobWorkers.indexOf(worker.id) !== -1) {
console.log(`job worker ${worker.process.pid} exited (signal: ${signal}). Trying to respawn...`);
removeJobWorker(worker.id);
addJobWorker();
}
if (webWorkers.indexOf(worker.id) !== -1) {
console.log(`http worker ${worker.process.pid} exited (signal: ${signal}). Trying to respawn...`);
removeWebWorker(worker.id);
addWebWorker();
}
});
} else {
if (process.env.web) {
console.log(`start http server: ${cluster.worker.id}`);
// Initialize the http server here
httpServer.start();
}
if (process.env.job) {
console.log(`start job server: ${cluster.worker.id}`);
// Initialize the Agenda here
jobWorker.start();
}
}
function addWebWorker() {
webWorkers.push(cluster.fork({web: 1}).id);
}
function addJobWorker() {
jobWorkers.push(cluster.fork({job: 1}).id);
}
function removeWebWorker(id) {
webWorkers.splice(webWorkers.indexOf(id), 1);
}
function removeJobWorker(id) {
jobWorkers.splice(jobWorkers.indexOf(id), 1);
}
Agenda is configured by default to automatically reconnect indefinitely, emitting an error event when no connection is available on each process tick, allowing you to restore the Mongo instance without having to restart the application.
However, if you are using an existing Mongo client
you'll need to configure the reconnectTries
and reconnectInterval
connection settings
manually, otherwise you'll find that Agenda will throw an error with the message "MongoDB connection is not recoverable,
application restart required" if the connection cannot be recovered within 30 seconds.
Agenda will only process jobs that it has definitions for. This allows you to selectively choose which jobs a given agenda will process.
Consider the following project structure, which allows us to share models with the rest of our code base, and specify which jobs a worker processes, if any at all.
- server.js
- worker.js
lib/
- agenda.js
controllers/
- user-controller.js
jobs/
- email.js
- video-processing.js
- image-processing.js
models/
- user-model.js
- blog-post.model.js
Sample job processor (eg. jobs/email.js
)
let email = require('some-email-lib'),
User = require('../models/user-model.js');
module.exports = function(agenda) {
agenda.define('registration email', async job => {
const user = await User.get(job.attrs.data.userId);
await email(user.email(), 'Thanks for registering', 'Thanks for registering ' + user.name());
});
agenda.define('reset password', async job => {
// Etc
});
// More email related jobs
};
lib/agenda.js
const Agenda = require('agenda');
const connectionOpts = {db: {address: 'localhost:27017/agenda-test', collection: 'agendaJobs'}};
const agenda = new Agenda(connectionOpts);
const jobTypes = process.env.JOB_TYPES ? process.env.JOB_TYPES.split(',') : [];
jobTypes.forEach(type => {
require('./jobs/' + type)(agenda);
});
if (jobTypes.length) {
agenda.start(); // Returns a promise, which should be handled appropriately
}
module.exports = agenda;
lib/controllers/user-controller.js
let app = express(),
User = require('../models/user-model'),
agenda = require('../worker.js');
app.post('/users', (req, res, next) => {
const user = new User(req.body);
user.save(err => {
if (err) {
return next(err);
}
agenda.now('registration email', {userId: user.primary()});
res.send(201, user.toJson());
});
});
worker.js
require('./lib/agenda.js');
Now you can do the following in your project:
node server.js
Fire up an instance with no JOB_TYPES
, giving you the ability to process jobs,
but not wasting resources processing jobs.
JOB_TYPES=email node server.js
Allow your http server to process email jobs.
JOB_TYPES=email node worker.js
Fire up an instance that processes email jobs.
JOB_TYPES=video-processing,image-processing node worker.js
Fire up an instance that processes video-processing/image-processing jobs. Good for a heavy hitting server.
If you think you have encountered a bug, please feel free to report it here:
Please provide us with as much details as possible such as:
DEBUG="agenda:*" node index.js
DEBUG="agenda:*" node index.js
set DEBUG=agenda:*
$env:DEBUG = "agenda:*"
While not necessary, attaching a text file with this debug information would be extremely useful in debugging certain issues and is encouraged.
When running Agenda on Azure cosmosDB, you might run into this issue caused by Agenda's sort query used for finding and locking the next job. To fix this, you can pass custom sort option: sort: { nextRunAt: 1 }
Generated using TypeDoc


--- layout: default title: "Manifesto for System Craftsmanship" ---
As aspiring System Crafters, we are raising the bar of professional system and infrastructure development even further, by extending Software Craftsmanship movement, to create more value in the DevOps ecosystem. Through this work we have come to value:
That is, in pursuit of the items that the Software Craftsmanship Manifesto has, we have found the extension of the first item indispensible.
>>Sign the Manifesto<<


Premium user with premium knife in stats - Better Battlelog Forums #1804
Sitemap
20. June 2012 20:13
Topicstarter
ORFK
Global Moderator
Hello all together
some premium user told me a feature request.
they would be happy if on the weapon stats page from premium user it would be displayed the premium knife and not the normal one.
Its just a Detail and not really needed but would be nice.
21. June 2012 00:18
José Ortega
Global Moderator
Box Cutter for president.
21. June 2012 00:35
Topicstarter
ORFK
Global Moderator
its a carpet knife :-P
21. June 2012 09:32
Nano
Global Moderator
ORFK wrote:
its a carpet knife :-P
It's a
http://store.cadenceinc.com/ProductCatalog/L-2
21. June 2012 10:37
Topicstarter
ORFK
Global Moderator
noooo i think its an
http://www.iba.ch/Produkte/Heften/Scheren/Japanmesser
22. June 2012 07:56
BrainFooLong
Administrator
I think that is really a thing for DICE and not for BBLog.
They introduced premium and they should make that.


Redis Tips -- Use Sorted Set To Storage A Dynamically Changing List
When I was developing an instant messenger (IM) system, I found that high concurrency is an essential feature while numerous clients are online chatting simultaneously. Therefore I use Redis to cache data in order to release pressure on database.
A typical scene of IM is chatting with someone else, as shown in the following figure.
This conversion contains several messages , which are stored in database in ascending order of their timing. As is shown in the following table.
+----+------------------+--------+---------------------+
| id | content | isread | pubtime |
+----+------------------+--------+---------------------+
| 1 | hello | 1 | 2014-05-22 11:53:00 |
| 2 | Hi! | 1 | 2014-05-22 11:54:00 |
| 3 | Nice to meet you | 1 | 2014-05-22 11:55:00 |
| 4 | Me too | 0 | 2014-05-22 11:56:00 |
+----+------------------+--------+---------------------+
The “isread” field represents whether the message is read by someone.
Store Data In A Key ?
The following figure shows how we use Redis as cache container.
When we need to retrieve some data , the first step is to check whether the data is in the cache container. If cache is hit, We get the data and return; If cache is missing , we query the data from database and store it in cache so that we can get it faster next time.
We can store a conversion in a key, so we can get all the containing messages from cache in one attempt.
But this method has several disadvantages:
- When a new message arrives, the cache has to be refreshed to add latest message.
- When a message is set to Already Read status, the cache has to be destroyed to keep accuracy.
- When a message is deleted by its owner, the cache has to be refreshed again to remove that item.
The main reason for these disadvantages is that a conversion is a dynamically changing list. Each change will cause the cache out of date.
#Store List In Sorted Set#
What Sorted Set is ? I quote the following content from Redis official website (See this):
Redis Sorted Sets are, similarly to Redis Sets, non repeating collections of Strings. The difference is that every member of a Sorted Set is associated with score, that is used in order to take the sorted set ordered, from the smallest to the greatest score. While members are unique, scores may be repeated.
We can store Ids of each message as index, and store each message separately, as shown in the following figure.
We deal with each case as follows:
- Send Message and Receive Message. Add Id of message into the cache.
- Delete Message. Remove Id of message from the cache.
- Set Message Read. Leave the cache unchanged and Edit the corresponding message’s cache.
#Code Sample#
Some Useful functions:
//Add one or more members to a sorted set, or update its score if it already exists
function zAdd(key, score, member)
//Return a range of members in a sorted set, by index
function zRange(key, start, stop)
//Remove one or more members from a sorted set
function zRem(key, member)
//Set multiple keys to multiple values
function mSet(key,value, ...)
//Get the values of all the given keys
function mGet(key, ...)
Store message Id as index, and its “pubtime” as score.
pubtimestamp = strtotime(pubtime);
zAdd(key,pubtimestamp,id);
Store messages with mSet Command:
mSet(key,value, ...);
Retrieve messages like this:
indexes = zRange(key, start, stop)
msgs = mGet(indexes)


WITNESS LIST Intergovernmental Relations Committee April 30, 2003 - 8:30A SB 5 Registering, but not testifying: For: Agamalian, Brandon Mngr. Govt. Relations (City of Fort Worth), Fort Worth, TX Gershon, Mike Attorney (City of Cleburne), Austin, TX Hazlewood, Mayor Thomas Mayor (City of Cleburne), Cleburne, TX Kelley, Terry General Manager (Johnson Co. Rural Water Supply Corp.), Cleburne, TX Nolan, Chester City Manager (City of Cleburne), Cleburne, TX Rosworth, Bill Attorney (Johnson Co. Rural Water Supply Corp), Cleburne, TX Zachos, Stephen Attorney (City of Fort Worth), Austin, TX SB 192 FOR: Frasier, Margo Sheriff (Sheriff's Association of Texas), Austin, TX Registering, but not testifying: For: Elfant, Bruce Travis Constable (Justices of the Peace and Constables Association), Austin, TX Higgins, Mike Chief of Staff (Texas State Assoc. of Firefighters), Austin, TX Ingersoll, Deborah Consultant (Texas State Troopers Assoc.), Austin, TX McNeil, Carvel Peace Officer (Houston Police Patrolmens Union), Houston, TX Sanders, Stephen Retired Police Officer (Texas Fraternal Order of Police), Austin, TX Wilkison, Charley Political/Legislative Director (CLEAT), Austin, TX SB 562 Registering, but not testifying: Against: Frasier, Margo Sheriff (Sheriff's Association of Texas), Austin, TX SB 856 AGAINST: Anderson, Sparky Program Director (Clean Water Action), Austin, TX Registering, but not testifying: For: Goleman, Kinnan Attorney (Hickory Underground Water Dist. #1), Austin, TX SB 1262 Registering, but not testifying: For: Aghamalian, Brandon Mngr. Govt. Relations (City of Fort Worth), Fort Worth, TX SB 1414 FOR: Bray MD, MPH, Patricia Occupational Medicine Physician (Texas State Firefighhters Association, Interntl. Assn. of Firefighters), Baltimore, MA Brazeil, Thomas Firefighter Captain (Self), Lufkin, TX Ford, Charles Retired DPS (Texas State Troopers), Lindale, TX Mason, Laura Fire Inspector Investigator (Self), Whitehouse, TX AGAINST: Chitwood, Byron Mayor (City of Greenville), Greenville, TX Horton, Susan Legislative Council (Texas Municipal League), Brady, TX Robinson, Barry Human Resources Director (Self), Greenville, TX ON: Bow, Jonathan General Counsel (State Office of Risk Management), Austin, TX Bresnen, Steve Attorney (Texas Association of Firefighters & Fort Worth Professional Firefighters), Austin, TX Registering, but not testifying: For: DeLord, Ron President (CLEAT), Austin, TX Dickson, Donald Attorney (Texas State Troopers Association), Austin, TX Higgins, Mike Cheif of Staff (Texas State Assoc. of Firefighters), Austin, TX Ingersoll, Deborah Consultant (Texas State Tropers Assn.), Austin, TX Keith, Larry Firefighter (Texas State Association of Firefighters), Austin, TX McNeil, Carvel Peace Officer (Houston Police Patrolmen's Unit) Miller, Lisa Legislative Consultant (State Fireman's and Fire Marshalls Assn. of TX), Austin, TX Salinas, Froy (Texas State Troopers Assn.), Austin, TX Sanders, Stephen Retired Police Officer (Texas Fraternal Order of Police), Austin, TX Villarreal, Johnny Firefighter (Houston Firefighters Local 341), Houston, TX Welch, Dinah Director State Affairs (Texas Hospital Assn.), Austin, TX Willman, James General Counsel (Texas Nurses Assn.), Austin, TX Against: Aghamalian, Brandon Manager of Gevt. Relations (City of Fort Worth), Fort Worth, TX SB 1459 FOR: Montgomery, Mike Harris Co. Fire Marshall (Harris County Fire and Emergency Services), Houston, TX SB 1460 FOR: Montgomery, Mike Harris County Fire Marshall (Harris Co. Fire and Emergency Services), Houston, TX Registering, but not testifying: For: Broussard, Simon Asst. Fire Marshall (Self), Austin, TX Katz, Howard Attorney (Harris Co. ESD 9), Houston, TX Mendez, Mark Assistant County Administrator (Tarrant County Commissioners Court), Fort Worth, TX On: Carlton, John Attorney (Texas State Asociation of Fire and Emergency Districts), Austin, TX Higgins, Mike Chief of Staff (Texas State Assoc. of Firefighters), Austin, TX Higgins, Mike Chief of Staff (Texas State Assoc. of Firefighters), Austin, TX SB 1461 FOR: Miller, Lisa Legislative Consultant (State Fireman's and Fire Marshal's Assn. of Texas), Austin, TX Montgomery, Mike Harris County Fire Marshal (Harris County Fire And Emergency Services), Houston, TX Registering, but not testifying: On: Carlton, John Attorney (Texas State Association of Fire and Emergency Districts), Austin, TX Higgins, Mike Chief of Staff (Texas State Assoc. of Firefighters), Austin, TX SB 1472 FOR: Gruber, Mike Lawyer (Dallas Zoological Society), Dallas, TX Registering, but not testifying: For: Geiger, Richard Attorney (Self), Dallas, TX Haggerty, Michael Attorney (Dallas Zoological Society), Dallas, TX Howard, Jim President (Dallas Zoological Society), Dallas, TX Semons, Chris Consultant (Dallas Zoological Society), Dallas, TX SB 1520 Registering, but not testifying: For: Shaw, Jim Exec. Dir. (Capital Area Housing Finance Corp.), Austin, TX Talerico, Jeanne Exec. Dir. (Texas Assn. of Local Housing Finance Agencies), Austin, TX SB 1536 Registering, but not testifying: For: Brown, Jasper Paramedic (Austin Travis Co. EMS), Austin, TX Frasier, Margo Sheriff (Travis County Sheriff's Office, Sheriff's Assoc. of Texas), Austin, TX Hobby, Danny Emergency Wireless Manager for Travis Co (Travis County), Austin, TX On: Voights, Betty Exec. Dir. (Capitol Area Planning Council), Austin, TX SB 1733 FOR: Gonsoulin, Samuel Deputy Constable (Harris County Deputies Organization), Houston, TX Registering, but not testifying: For: Christenson, Ed Deputy Sheriff (Harris County Deputies Organization), Houston, TX DeLord, Ron President (CLEAT), Austin, TX McNeil, Carvel Peace Officer (Houston Police Patrolman's Union), Houston, TX Sanders, Stephen Retired Police Officer (Texas Fraternal Order of Police), Austin, TX SB 1811 Registering, but not testifying: For: Luck, Oliver CEO (Harris Co.-Houston Sports Authority), Houston, TX SB 1901 FOR: Lary, Trey Attorney (Self), Houston, TX


Cancel
Add to Home Screen
Website Name
Address
Add to Home Screen
Loading...
You appear to be offline
Retry
Apps


| |
ActiveTcl User Guide
|
|
|
- NAME
- fconfigure - Set and get options on a channel
- SYNOPSIS
- fconfigure channelId
- fconfigure channelId name
- fconfigure channelId name value ?name
value ...?
- DESCRIPTION
- -blocking
boolean
- -buffering
newValue
- -buffersize
newSize
- -encoding
name
- -eofchar
char
- -eofchar
{inChar outChar}
- -translation
mode
- -translation
{inMode outMode}
- auto
- binary
- cr
- crlf
- lf
- STANDARD
CHANNELS
- SERIAL PORT
CONFIGURATION OPTIONS
- -mode
baud,parity,data,stop
- -handshake
type
- -queue
- -timeout
msec
- -ttycontrol
{signal boolean signal boolean ...}
- -ttystatus
- -xchar
{xonChar xoffChar}
- -pollinterval
msec
- -sysbuffer
inSize
- -sysbuffer
{inSize outSize}
- -lasterror
- SERIAL PORT
SIGNALS
- TXD(output)
- RXD(input)
- RTS(output)
- CTS(input)
- DTR(output)
- DSR(input)
- DCD(input)
- RI(input)
- BREAK
- ERROR CODES (Windows
only)
- RXOVER:
- TXFULL
- OVERRUN
- RXPARITY
- FRAME
- BREAK
- SEE ALSO
- KEYWORDS
fconfigure - Set and get options on a channel
fconfigure channelId
fconfigure channelId name
fconfigure channelId name value ?name value
...?
The fconfigure command sets and retrieves options for
channels.
ChannelId identifies the channel for which to set or
query an option and must refer to an open channel such as a Tcl
standard channel (stdin, stdout, or stderr),
the return value from an invocation of open or socket, or the result of a channel
creation command provided by a Tcl extension.
If no name or value arguments are supplied, the
command returns a list containing alternating option names and
values for the channel. If name is supplied but no
value then the command returns the current value of the
given option. If one or more pairs of name and value
are supplied, the command sets each of the named options to the
corresponding value; in this case the return value is an
empty string.
The options described below are supported for all channels. In
addition, each channel type may add options that only it supports.
See the manual entry for the command that creates each type of
channels for the options that that specific type of channel
supports. For example, see the manual entry for the socket command for its additional
options.
- -blocking boolean
- The -blocking option determines whether I/O operations
on the channel can cause the process to block indefinitely. The
value of the option must be a proper boolean value. Channels are
normally in blocking mode; if a channel is placed into nonblocking
mode it will affect the operation of the gets, read, puts, flush, and close commands; see the documentation
for those commands for details. For nonblocking mode to work
correctly, the application must be using the Tcl event loop (e.g.
by calling Tcl_DoOneEvent or invoking the
vwait command).
- -buffering newValue
- If newValue is full then the I/O system will
buffer output until its internal buffer is full or until the flush command is invoked. If
newValue is line, then the I/O system will
automatically flush output for the channel whenever a newline
character is output. If newValue is none, the I/O
system will flush automatically after every output operation. The
default is for -buffering to be set to full except
for channels that connect to terminal-like devices; for these
channels the initial setting is line. Additionally,
stdin and stdout are initially set to line,
and stderr is set to none.
- -buffersize newSize
- Newvalue must be an integer; its value is used to set
the size of buffers, in bytes, subsequently allocated for this
channel to store input or output. Newvalue must be between
ten and one million, allowing buffers of ten to one million bytes
in size.
- -encoding name
- This option is used to specify the encoding of the channel, so
that the data can be converted to and from Unicode for use in Tcl.
For instance, in order for Tcl to read characters from a Japanese
file in shiftjis and properly process and display the
contents, the encoding would be set to shiftjis. Thereafter,
when reading from the channel, the bytes in the Japanese file would
be converted to Unicode as they are read. Writing is also supported
- as Tcl strings are written to the channel they will automatically
be converted to the specified encoding on output.
If a file contains pure binary data (for instance, a JPEG
image), the encoding for the channel should be configured to be
binary. Tcl will then
assign no interpretation to the data in the file and simply read or
write raw bytes. The Tcl binary command can be used to
manipulate this byte-oriented data.
The default encoding for newly opened channels is the same
platform- and locale-dependent system encoding used for interfacing
with the operating system.
- -eofchar char
- -eofchar {inChar
outChar}
- This option supports DOS file systems that use Control-z (\x1a)
as an end of file marker. If char is not an empty string,
then this character signals end-of-file when it is encountered
during input. For output, the end-of-file character is output when
the channel is closed. If char is the empty string, then
there is no special end of file character marker. For read-write
channels, a two-element list specifies the end of file marker for
input and output, respectively. As a convenience, when setting the
end-of-file character for a read-write channel you can specify a
single value that will apply to both reading and writing. When
querying the end-of-file character of a read-write channel, a
two-element list will always be returned. The default value for
-eofchar is the empty string in all cases except for files
under Windows. In that case the -eofchar is Control-z (\x1a)
for reading and the empty string for writing.
- -translation mode
- -translation {inMode
outMode}
- In Tcl scripts the end of a line is always represented using a
single newline character (\n). However, in actual files and devices
the end of a line may be represented differently on different
platforms, or even for different devices on the same platform. For
example, under UNIX newlines are used in files, whereas
carriage-return-linefeed sequences are normally used in network
connections. On input (i.e., with gets and read) the Tcl I/O system automatically
translates the external end-of-line representation into newline
characters. Upon output (i.e., with puts), the I/O system translates
newlines to the external end-of-line representation. The default
translation mode, auto, handles all the common cases
automatically, but the -translation option provides explicit
control over the end of line translations.
The value associated with -translation is a single item
for read-only and write-only channels. The value is a two-element
list for read-write channels; the read translation mode is the
first element of the list, and the write translation mode is the
second element. As a convenience, when setting the translation mode
for a read-write channel you can specify a single value that will
apply to both reading and writing. When querying the translation
mode of a read-write channel, a two-element list will always be
returned. The following values are currently supported:
- auto
- As the input translation mode, auto treats any of
newline (lf), carriage return (cr), or carriage
return followed by a newline (crlf) as the end of line
representation. The end of line representation can even change from
line-to-line, and all cases are translated to a newline. As the
output translation mode, auto chooses a platform specific
representation; for sockets on all platforms Tcl chooses
crlf, for all Unix flavors, it chooses lf, for the
Macintosh platform it chooses cr and for the various flavors
of Windows it chooses crlf. The default setting for
-translation is auto for both input and output.
- binary
- No end-of-line translations are performed. This is nearly
identical to lf mode, except that in addition binary mode also sets the
end-of-file character to the empty string (which disables it) and
sets the encoding to binary (which disables encoding
filtering). See the description of -eofchar and
-encoding for more information.
- cr
- The end of a line in the underlying file or device is
represented by a single carriage return character. As the input
translation mode, cr mode converts carriage returns to
newline characters. As the output translation mode, cr mode
translates newline characters to carriage returns. This mode is
typically used on Macintosh platforms.
- crlf
- The end of a line in the underlying file or device is
represented by a carriage return character followed by a linefeed
character. As the input translation mode, crlf mode converts
carriage-return-linefeed sequences to newline characters. As the
output translation mode, crlf mode translates newline
characters to carriage-return-linefeed sequences. This mode is
typically used on Windows platforms and for network
connections.
- lf
- The end of a line in the underlying file or device is
represented by a single newline (linefeed) character. In this mode
no translations occur during either input or output. This mode is
typically used on UNIX platforms.
The Tcl standard channels (stdin, stdout, and
stderr) can be configured through this command like every
other channel opened by the Tcl library. Beyond the standard
options described above they will also support any special option
according to their current type. If, for example, a Tcl application
is started by the inet super-server common on Unix system
its Tcl standard channels will be sockets and thus support the
socket options.
If channelId refers to a serial port, then the following
additional configuration options are available on Windows and Unix
systems with a POSIX serial interface:
- -mode
baud,parity,data,stop
- This option is a set of 4 comma-separated values: the baud
rate, parity, number of data bits, and number of stop bits for this
serial port. The baud rate is a simple integer that
specifies the connection speed. Parity is one of the
following letters: n, o, e, m,
s; respectively signifying the parity options of ``none'',
``odd'', ``even'', ``mark'', or ``space''. Data is the
number of data bits and should be an integer from 5 to 8, while
stop is the number of stop bits and should be the integer 1
or 2.
- -handshake type
- (Windows and Unix). This option is used to setup automatic
handshake control. Note that not all handshake types maybe
supported by your operating system. The type parameter is
case-independent. If type is none then any handshake
is switched off. rtscts activates hardware handshake.
Hardware handshake signals are described below. For software
handshake xonxoff the handshake characters can be redefined
with -xchar. An additional hardware handshake dtrdsr
is available only under Windows. There is no default handshake
configuration, the initial value depends on your operating system
settings. The -handshake option cannot be queried.
- -queue
- (Windows and Unix). The -queue option can only be
queried. It returns a list of two integers representing the current
number of bytes in the input and output queue respectively.
- -timeout msec
- (Windows and Unix). This option is used to set the timeout for
blocking read operations. It specifies the maximum interval between
the reception of two bytes in milliseconds. For Unix systems the
granularity is 100 milliseconds. The -timeout option does
not affect write operations or nonblocking reads. This option
cannot be queried.
- -ttycontrol {signal boolean signal
boolean ...}
- (Windows and Unix). This option is used to setup the handshake
output lines (see below) permanently or to send a BREAK over the
serial line. The signal names are case-independent. {RTS
1 DTR 0} sets the RTS output to high and the DTR output to low.
The BREAK condition (see below) is enabled and disabled with
{BREAK 1} and {BREAK 0} respectively. It's not a good
idea to change the RTS (or DTR) signal with active
hardware handshake rtscts (or dtrdsr). The result is
unpredictable. The -ttycontrol option cannot be
queried.
- -ttystatus
- (Windows and Unix). The -ttystatus option can only be
queried. It returns the current modem status and handshake input
signals (see below). The result is a list of signal,value pairs
with a fixed order, e.g. {CTS 1 DSR 0 RING 1 DCD 0}. The
signal names are returned upper case.
- -xchar {xonChar xoffChar}
- (Windows and Unix). This option is used to query or change the
software handshake characters. Normally the operating system
default should be DC1 (0x11) and DC3 (0x13) representing the ASCII
standard XON and XOFF characters.
- -pollinterval msec
- (Windows only). This option is used to set the maximum time
between polling for fileevents. This affects the time interval
between checking for events throughout the Tcl interpreter (the
smallest value always wins). Use this option only if you want to
poll the serial port more or less often than 10 msec (the
default).
- -sysbuffer inSize
- -sysbuffer {inSize
outSize}
- (Windows only). This option is used to change the size of
Windows system buffers for a serial channel. Especially at higher
communication rates the default input buffer size of 4096 bytes can
overrun for latent systems. The first form specifies the input
buffer size, in the second form both input and output buffers are
defined.
- -lasterror
- (Windows only). This option is query only. In case of a serial
communication error, read
or puts returns a general
Tcl file I/O error. fconfigure -lasterror can be called to
get a list of error details. See below for an explanation of the
various error codes.
RS-232 is the most commonly used standard electrical interface
for serial communications. A negative voltage (-3V..-12V) define a
mark (on=1) bit and a positive voltage (+3..+12V) define a space
(off=0) bit (RS-232C). The following signals are specified for
incoming and outgoing data, status lines and handshaking. Here we
are using the terms workstation for your computer and
modem for the external device, because some signal names
(DCD, RI) come from modems. Of course your external device may use
these signal lines for other purposes.
- TXD(output)
- Transmitted Data: Outgoing serial data.
- RXD(input)
- Received Data:Incoming serial data.
- RTS(output)
- Request To Send: This hardware handshake line informs
the modem that your workstation is ready to receive data. Your
workstation may automatically reset this signal to indicate that
the input buffer is full.
- CTS(input)
- Clear To Send: The complement to RTS. Indicates that the
modem is ready to receive data.
- DTR(output)
- Data Terminal Ready: This signal tells the modem that
the workstation is ready to establish a link. DTR is often enabled
automatically whenever a serial port is opened.
- DSR(input)
- Data Set Ready: The complement to DTR. Tells the
workstation that the modem is ready to establish a link.
- DCD(input)
- Data Carrier Detect: This line becomes active when a
modem detects a "Carrier" signal.
- RI(input)
- Ring Indicator: Goes active when the modem detects an
incoming call.
- BREAK
- A BREAK condition is not a hardware signal line, but a logical
zero on the TXD or RXD lines for a long period of time, usually 250
to 500 milliseconds. Normally a receive or transmit data signal
stays at the mark (on=1) voltage until the next character is
transferred. A BREAK is sometimes used to reset the communications
line or change the operating mode of communications hardware.
A lot of different errors may occur during serial read
operations or during event polling in background. The external
device may have been switched off, the data lines may be noisy,
system buffers may overrun or your mode settings may be wrong.
That's why a reliable software should always catch serial read operations. In
cases of an error Tcl returns a general file I/O error. Then
fconfigure -lasterror may help to locate the problem. The
following error codes may be returned.
- RXOVER:
- Windows input buffer overrun. The data comes faster than your
scripts reads it or your system is overloaded. Use fconfigure
-sysbuffer to avoid a temporary bottleneck and/or make your
script faster.
- TXFULL
- Windows output buffer overrun. Complement to RXOVER. This error
should practically not happen, because Tcl cares about the output
buffer status.
- OVERRUN
- UART buffer overrun (hardware) with data lost. The data comes
faster than the system driver receives it. Check your advanced
serial port settings to enable the FIFO (16550) buffer and/or setup
a lower(1) interrupt threshold value.
- RXPARITY
- A parity error has been detected by your UART. Wrong parity
settings with fconfigure -mode or a noisy data line (RXD)
may cause this error.
- FRAME
- A stop-bit error has been detected by your UART. Wrong mode
settings with fconfigure -mode or a noisy data line (RXD)
may cause this error.
- BREAK
- A BREAK condition has been detected by your UART (see
above).
close, flush, gets, puts, read, socket, Tcl_StandardChannels
blocking, buffering, carriage return, end of line, flushing, linemode, newline, nonblocking, platform, translation, encoding, filter, byte array, binary
Copyright © 1995-1996 Sun Microsystems, Inc.
Copyright © 1995-1997 Roger E. Critchlow Jr.


| Class and Description |
|---|
| City
This class represents the a City as returned during the search process.
|
| CurrentWeather
This class represents the current weather condition as retrieved by the provider.
|
| HistoricalWeather
Ths class holds the historical weather information retrieved from the weather provider
|
| WeatherForecast
Forecast weather.
|
| WeatherHourForecast
This class holds the hourly weather forecast.
|
| Class and Description |
|---|
| BaseWeather
Base weather class that holds the unit system
|
| BaseWeather.WeatherUnit |
| City
This class represents the a City as returned during the search process.
|
| City.CityBuilder |
| DayForecast
Single day weather forecast.
|
| DayForecast.ForecastTemp |
| HistoricalHourWeather
This class holds the historical weather information for a single hour as retrieved from the weather provider
|
| HourForecast
This class holds the hour forecast information.
|
| Location
This class holds information about location as returned from the weather provider
|
| Location.Astronomy |
| Weather
This class represents the Weather in the Location selected
|
| Weather.Clouds |
| Weather.Condition |
| Weather.Rain |
| Weather.Snow |
| Weather.Temperature |
| Weather.Wind |
| WeatherForecastData
This is the basic class for weather forecast data.
|
| Class and Description |
|---|
| City
This class represents the a City as returned during the search process.
|
| CurrentWeather
This class represents the current weather condition as retrieved by the provider.
|
| HistoricalWeather
Ths class holds the historical weather information retrieved from the weather provider
|
| WeatherForecast
Forecast weather.
|
| WeatherHourForecast
This class holds the hourly weather forecast.
|
| Class and Description |
|---|
| City
This class represents the a City as returned during the search process.
|
| CurrentWeather
This class represents the current weather condition as retrieved by the provider.
|
| HistoricalWeather
Ths class holds the historical weather information retrieved from the weather provider
|
| WeatherForecast
Forecast weather.
|
| WeatherHourForecast
This class holds the hourly weather forecast.
|
| Class and Description |
|---|
| City
This class represents the a City as returned during the search process.
|
| CurrentWeather
This class represents the current weather condition as retrieved by the provider.
|
| HistoricalWeather
Ths class holds the historical weather information retrieved from the weather provider
|
| WeatherForecast
Forecast weather.
|
| WeatherHourForecast
This class holds the hourly weather forecast.
|
| Class and Description |
|---|
| City
This class represents the a City as returned during the search process.
|
| CurrentWeather
This class represents the current weather condition as retrieved by the provider.
|
| HistoricalWeather
Ths class holds the historical weather information retrieved from the weather provider
|
| WeatherForecast
Forecast weather.
|
| WeatherHourForecast
This class holds the hourly weather forecast.
|
| Class and Description |
|---|
| City
This class represents the a City as returned during the search process.
|
| CurrentWeather
This class represents the current weather condition as retrieved by the provider.
|
| HistoricalWeather
Ths class holds the historical weather information retrieved from the weather provider
|
| WeatherForecast
Forecast weather.
|
| WeatherHourForecast
This class holds the hourly weather forecast.
|
| Class and Description |
|---|
| BaseWeather.WeatherUnit |


BlackHole - Dashboard
loading...
Devices Connected
loading...
Total Alarms
loading...
Total Messages
loading...
Server's DateTime
loading...
Version
Timeline
Automatic
List of Devices
Name
Address
Battery
In
Out
Vibration
Strain
Torch
Graph
Status
Last Connection
Vibration
Strain


LeRoy Gardner III
Code Platoon Application
← → for slide navigation
Best viewed on computer - not mobile device.
I enjoy tech things
It's great taking bits, bytes, and words into real digital things.
I meant catalytic cracker below...not converter. One is in the refinery and the other is in one's car.
Explaining problem from the code challenges on next slide! Press → key
Explaining figuring out "Or" in the coding exercises!
I've studied for two past degrees:
- Thinking out loud: ~ leroygardner.dev ~ LeRoy @ Medium
- I enjoy health and fitness: I coach wrestling, compete in BJJ, and we used to own strength training facility for 5 years called Soul Ruckus Athletics.
- I enjoy reading: technology, history, military, business, and some fiction.
- I am interested in building things with software.
- I prefer music, scotch or coffee, and good company to many other things..
- Uzbekistan
- Germany
- Kyrgyzstan
- Singapore
- S. Korea
- Japan
- Djibouti
- Studied in the Ruby on Rails Program.
- Jesse Wolgamatt is an awesome instructor.
- Active Duty until 2009
- Now in the Reserves
I coached Wrestling while on Active Duty:
- Wait, what?! Yep.
- Now I am a Human Resource Officer aka Staff Guy aka [insert derisive nickname here]...
I like hardware, software and many things between. I've made some RaspberryPi projects and even worked on my Drone.
"My dog, our old barbell club, Germany and Andy Warhol."


cdemi's
06 August 2019 |
Software Development #Software |
The 8 tips to help you settle into your new team (thoughtworks.com) |
| As a long-time Thoughtworker, I have had the privilege of working on many projects and with a diverse set of teams. Moving from one team to the next helped me observe and learn how to co-exist and thrive in several (interesting) groups of technologists! I have broken down my experience into 8 tips to follow when joining a new team. While most of these suggestions are from a consultant’s perspective and are within the context of moving between teams, they apply to someone moving into a new job or role as well.... Read more |
Making Instagram.com faster: Part 1 (instagram-engineering.com) |
| In recent years instagram.com has seen a lot of changes — we’ve launched stories, filters, creation tools, notifications, and direct…... Read more |
.NET #dotNet |
.NET/ASP.NET Documentation Update for July 2019 (reddit.com) |
| This is a status update on the .NET documentation that were updated significantly during the month of July.... Read more |
Theming in Visual Studio just got a lot easier (devblogs.microsoft.com) Extensions Visual Studio |
| Sometimes the default themes for Visual Studio just aren’t enough. Lucky for us, we’ve just redesigned the process of creating and importing custom themes. One of the only ways to import themes was to download the older Color Theme Editor extension.... Read more |
User Experience #UX |
Building a More Seamless Web Booking Flow for Uber (eng.uber.com) |
| We redesigned Uber's web-based booking flow for riders who prefer a browser over the app, simplifying pickup options and speeding up interactivity.... Read more |
DevOps |
Optimizing Kubernetes Clusters on Spot Instances for Cost and Performance (youtu.be) |
| Skyscanner saves 74% using spot instances and containers on the Kubernetes cluster.... Read more |
Evolution of Netflix Conductor: (medium.com) |
| v2.0 and beyond... Read more |
Cloud |
We’re making Azure Archive Storage better with new lower pricing (azure.microsoft.com) |
| As part of our commitment to provide the most cost-effective storage offering, we’re excited to share that we have dropped Azure Archive Storage prices by up to 50 percent in some regions. The new pricing is effective immediately.... Read more |
Data |
Comparing Apache Hive vs. Spark (logz.io) |
| A comparison of Hive vs. Spark examining features, capabilities, integrations, architecture, history and more. Find the best tool for big data processing!... Read more |
PartiQL: Introducing Amazon's New Query Language for 'All' Data (awsinsider.net) amazon web services aws data lake cloud partiql query big data |
| AWS has announced PartiQL, a new query language that the company says is designed to work with all data types, structures and storage situations. ... Read more |
Hardware |
Backblaze Hard Drive Stats Q2 2019 (backblaze.com) |
| This review looks at the Q2 2019 and lifetime hard drive failure rates of the data drive models currently in operation in our data centers.... Read more |
Quality Assurance #QA |
Scaling Static Analyses at Facebook (cacm.acm.org) |
| 100,000: issues in Facebook's codebase fixed from bugs found by static analysis. Key lessons for designing static analysis tools deployed to find bugs in hundreds of millions of lines of code. ... Read more |
eSports |
A teenager just made $3 million by playing Fortnite (fastcompany.com) fortnight |
| He won the Fortnite World Cup this weekend. ... Read more |
Healthcare #Medical |
With a tap on your phone, get help in an emergency (blog.google) |
| Share information about the assistance you require to an emergency operator without speaking.... Read more |
Microsoft unites with Google, Amazon, and more for healthcare interoperability (neowin.net) microsoft google amazon ibm oracle cloud providers cloud azure health healthcare healthcare interoperability |
| Microsoft has reaffirmed its commitment to healthcare interoperability, along with other cloud providers like Amazon, Google, and IBM. This collaboration initially began almost a year ago.... Read more |
|
This newsletter is made with 💖 by cdemi and sponsored by moo Research. You can find this MIT Licensed open-source project on GitHub cdemi/NewsletterCurator. You can also find an archive of all sent newsletters on GitHub at https://newsletters.cdemi.io/. If you want to unsubscribe from this newsletter, please click here. If you're new and you want to subscribe to this newsletter, please click here. |


My name is Bishwo Thapa Magar.
Currently I am studying Web business technology at Kyoto College of Graduates Studies for Informatics. Permanent address: Baglung Municipality-10,Baglung,NepalTemporary address: Osaka shi higasi yodogawa ku higasi nakajima 4-1-11 syanboru dai 3 shinosaka 804Contact<EMAIL_ADDRESS>number:08033564049
| S.N | Board | Institutions Name | Major | Passed out |
|---|---|---|---|---|
| 1 | School Leaving Certificate | Dhaulagiri Boarding School,Baglung | Journalism | 2004 |
| 2 | Higher Secondary Education Board | Aadarsha Vidya Mandir Higher Secondary School,Baglung | Business Math | 2007 |
| 3 | Bachelor Degree | Shankar Dev Campus,Kathmandu | Marketing | 2012 |
| 4 | Master Degree | Shankar Dev Campus,Kathmandu | Finance(Capital structure) | 2018 |
| S.N | Photos Name | Type | Place of photo taken | Country |
|---|---|---|---|---|
| 1 | View of Baglung | Jpg | Bhakunde | Nepal |
| 2 | Annapurna Range | Jpg | Bhakunde | Nepal |
| 3 | Baraha lake | Jpg | Bhakunde | Nepal |


|
OpenMesh
|
Files | |
| file | BaseDecimaterT.hh [code] |
| file | CollapseInfoT.hh [code] |
| Provides data class CollapseInfoT for storing all information about a halfedge collapse. | |
| file | DecimaterT.hh [code] |
| file | DecimaterT_impl.hh [code] |
| file | McDecimaterT.hh [code] |
| file | McDecimaterT_impl.hh [code] |
| file | MixedDecimaterT.hh [code] |
| file | MixedDecimaterT_impl.hh [code] |
| file | ModAspectRatioT.hh [code] |
| file | ModAspectRatioT_impl.hh [code] |
| file | ModBaseT.hh [code] |
| Base class for all decimation modules. | |
| file | ModEdgeLengthT.hh [code] |
| file | ModEdgeLengthT_impl.hh [code] |
| file | ModHausdorffT.hh [code] |
| file | ModHausdorffT_impl.hh [code] |
| file | ModNormalDeviationT.hh [code] |
| file | ModNormalFlippingT.hh [code] |
| file | ModProgMeshT.hh [code] |
| file | ModProgMeshT_impl.hh [code] |
| file | ModQuadricT.hh [code] |
| file | ModQuadricT_impl.hh [code] |
| Bodies of template member function. | |
| file | ModRoundnessT.hh [code] |
| file | Observer.cc |
| file | Observer.hh [code] |
| This file contains an observer class which is used to monitor the progress of an decimater. | |


meaning life .*** coping religious negative personal well-being PWB positive religion presence PWB. psychological relations relation sense dimensions < related people purpose search mediator results life. individuals significant Meaning Religion Steger associations Study human meaning, religiousness York] [New study terms total .** Psychology Social Wong score Park Personal coping, important measures partial significance Personality Religious Zika affect associated life, lives mediational relationships studies used .). Positive correlations meaningful psychology research −.*** However, Krok PWB, People Press] approach degree different mastery, mediated participants provide role −.; (Pargament Life [./-...] assess association autonomy, based beliefs daily environmental experience fair negatively others, research, satisfaction scale spiritual subjective well-being. (Chamberlain According Frazier PIL, Pargament Polish Psychological Table correlated defined dimensions. evidence existential form global growth, life: positively support test −.** (Ryff CL, God Keyes MF, Ryff Sobel Studies achievement, assessed conducted confirmed current development did dimensions: effects eudaimonic events. examine examined experiences factors level linked meaning: measure mediating methods order partially questionnaire religion, self-acceptance, self-acceptance. showed significance. social statistical statistically strong styles suggest systems theories understand understanding version well-being, women (Steger Chamberlain Emmons Happiness Issues KI, PTP, Research Results Therefore, Well-Being [./] [./j.-...x] [./s---] activities age aging analyses appears appraisals aspects assesses beliefs, challenges consists context correlation domain element empirical enable extent factor goals, happiness hypothesis implicit individual intimacy, life" meaning. model older one’s overarching people’s perceive present range reflects regarding relationship, requirement requirement, researchers reveal sample second seeking self-transcendence, seven turned use various ways


vignettes/wflow-03-migrating.Rmd
wflow-03-migrating.Rmd
This vignette is for those users that already have an existing project and wish to incorporate workflowr to create a research website. Migrating an existing project to use workflowr varies from straightforward to difficult depending on the scenario and your comfort level with Git. This vignette assumes that you have the background knowledge of workflowr explained in the Getting started vignette. Even if you have no need for a new workflowr project, please run through that vignette first as an exercise to familiarize yourself with the workflowr philosophy and functions.
If you have a collection of R Markdown files, but no version control or other files, the quickest solution is to use the function wflow_quickstart()
. The code below 1) starts a new workflowr project in ~/projects/new-project/
, 2) copies the existing Rmd files in ~/projects/misc/
to the analysis/
subdirectory of the new project, 3) builds and commits the website, and 4) configures the project to use GitHub (which is why the GitHub username is required).
library("workflowr")
wflow_quickstart("~/projects/misc/*Rmd", username = "<github-username>",
directory = "~/projects/new-project/")
Alternatively, you can manually perform each step to migrate your existing analysis by starting a workflowr project in a new directory and then moving the R Markdown files to the analysis/
subdirectory. In the hypothetical example below, the original R Markdown files are located in the directory ~/projects/misc/
and the workflowr project will be created in the new directory ~/projects/new-project/
.
library("workflowr")
# Create project directory and change working directory to this location
wflow_start("~/projects/new-project")
# Copy the files to the analysis subdirectory of the workflowr project
file.copy(from = Sys.glob("~/projects/misc/*Rmd"), to = "analysis")
Next run wflow_build()
to see if your files run without error. Lastly, build and commit the website using wflow_publish()
:
When you are ready to share the results online, you can run wflow_use_github()
or wflow_use_gitlab()
.
If your project already has lots of infrastructure, it is most convenient to add the workflowr files directory to your already existing directory. This is controlled with the argument existing
. In the hypothetical example below, the existing project is located at ~/projects/mature-project/
.
The above command will add the workflowr files to your existing project and also commit them to version control (it will initialize a Git repo if it doesn’t already exist). If you’d prefer to not use version control for your project or you’d prefer to commit the workflowr files yourself manually, you can set git = FALSE
(this is also useful if you want to first test to see what would happen without committing the results).
By default wflow_start()
will not overwrite your existing files (e.g. if you already have a README.md
). If you’d prefer to overwrite your files with the default workflowr files, set overwrite = TRUE
.
To add your R Markdown files to the research website, you can move them to the subdirectory analysis/
(note you can do this before or after running wflow_start()
).
Next run wflow_build()
to see if your files run without error. Lastly, build and commit the website using wflow_publish()
:
If your project is organized as an R package, you can still add a website using workflowr. In the hypothetical example below, the existing package is located at ~/projects/my-package/
.
The above command will add the workflowr files to your existing project and also commit them to version control (it will initialize a Git repo if it doesn’t already exist). If you’d prefer to not use version control for your project or you’d prefer to commit the workflowr files yourself manually, you can set git = FALSE
(this is also useful if you want to first test to see what would happen without committing the results).
You’ll want R to ignore the workflowr directories when building the R package. Thus add the following to the .Rbuildignore
file:
^analysis$
^docs$
^data$
^code$
^output$
^_workflowr.yml$
Furthermore, to prevent R from compressing the files in data/
(which is harmless but time-consuming), you can set LazyData: false
in the file DESCRIPTION
. However, if you do want to distribute data files with your R package, you’ll need to instead rename the workflowr subdirectory and update the R Markdown files to search for files in the updated directory name (and also update .Rbuildignore
to ignore this new directory and not data/
). Then you can save the data files to distribute with the package in data/
. For more details, see the relevant sections in the CRAN manual Writing R Extensions and Hadley’s R Packages.
If your primary purpose for creating a website to accompany your package is to share the package documentation, please check out the package pkgdown. It creates a website from the vignettes and function documentation files (i.e. the Rd files in man/
). In contrast, if the purpose of the website is to demonstrate results you obtained using the package, use workflowr.
If you created a workflowr project prior to its release to CRAN (any version less than 1.0), you can migrate the project to use the 1.0+ features by running wflow_update()
:
# Install the latest version from CRAN
install.packages("workflowr")
library("workflowr")
# Preview the files that would be changed
wflow_update()
# Update the files
wflow_update(dry_run = FALSE)
# Republish your analyses with the latest features
wflow_publish(republish = TRUE)
A few notes:
You do not have to upgrade if you don’t want. To continue using the Beta version of workflowr, follow the workflowrBeta installation instructions.
For your updated project, the code in the R Markdown files will continue to be executed from the R Markdown directory (typically analysis/
). However, if you create a new workflowr project, the default directory for executing the code will be the root directory of the project (see ?wflow_html
for background and instructions for changing this behavior).


Ashi Garami / Single Leg X Guard
Opponent standing:
from Open Guard, get both legs on the inside, keep 1 knee up and slide in under opponents hips, grab calfs to assist
right leg wraps around outside to ops hip, heel in, toes out, left foot hides behind top of thigh/glut area, left knee
protects the right foot, right foot presses down into knee and knee pushes up into foot. right hand can loop around
ops foot or just use elbow to lock it in place.


Blog
Stay classy!
Defining a Class in Ruby
Oct. 18, 2015
As programming languages go, Ruby is object-oriented in a big way. Everything in Ruby is an object, and everything you do to anything is a method called on an object. Tying these objects and methods together are special object categories, called classes. Every object belongs to some class. Even a plain old string, like "Hello, World!"
, is an example (or more properly, an instance) of the String class. And because that string is an instance of the String class, there are literally dozens of String-class methods that you can call on it, like String#length:
- $ "Hello, World!".length
- => 13
But you're not limited to the built-in array of classes, like String, Array, Hash, and Integer. Ruby is happy to let you create your own classes, from which you can create your own objects. Let's take a look at how a new class is defined in Ruby.
Head of the Class
A class definition is very similar to a method definition. The first line is a keyword, class
, followed by the name of the class, which must start with a capital letter. The last line is the keyword end
, and everything in between defines the variables and methods common to all members of the class. Throughout this blog post, I'll build an example class, Bank
, which models my 8-year-old daughter's piggy-bank. Here's how it begins:
- class Bank
- # Define variables and methods here.
- end
The first thing that appears inside a class definition are its attribute accessors—special methods that create instance variables (more on instance variables in a minute) and make them accessable beyond the object's class methods. There are three options for attribute accessors: attr_reader
, which makes it possible to return the value of the variable from outside the object, but not to alter it; attr_writer
, which lets you change the value of the variable, but not read it; and attr_accessor
, which lets you both read from and write to the variable. For our Bank class, I know I'll need two variables, "balance" and "unmatched_deposits," and since I want to be able to read their values from outside the object, but not change them, I'll give them both read-only attribute accessors:
- class Bank
- attr_reader :balance
- attr_reader :unmatched_deposits
- end
Note that the attribute accessor methods use colons to name instance variables with symbols. Our Bank class definition now has two variables, but those variables have no values. To set their initial values, we'll need to write a special method for the class, called #initialize
. This is the class method that gets called behind the scenes when you create a new object belonging to that class (technically, "instantiating" the object). #initialize
sets the values of the instance variables for that object, either to default values, or to values that are passed into the #initialize
method as arguments. We'll have one of each in our Bank class.
- class Bank
- attr_reader :balance
- attr_reader :unmatched_deposits
- def initialize(balance)
- @balance = balance
- @unmatched_deposits = 0
- end
- end
When we create an instance of our Bank class, we obviously need to know the starting balance—the amount you're putting in at the beginning. My daughter has a very good reason to keep a running total of her deposits as well, for reasons that will become apparent down the page. For now, trust me when I name that instance variable "unmatched_deposits" and set it to a default value of 0.
Notice that these two variables, @balance
and @unmateched_deposits
, begin with an "at-sign." In Ruby, the at-sign signifies instance variables, which are variables that are attached to specific instances of a class. Thus, every bank object that we create using this Bank class will have it's own @balance and @unmatched_deposits values. Unlike local variables, which are forgotten as soon as the method that created them ends, instance variables persist as long as the object they belong to exists. Also, they may be accessed—read from or written to—by any class method that is called on the object.
If your class has instance variables that won't need to be accessed by anything except the object's class methods, you don't have to use attribute accessors to create them. Instead, you can just add them inside the #initialize
method, and set their starting values there. For example, if we needed to set an interest rate for our Bank objects (that would make them pretty special piggy banks!) we could create an instance variable and set its default value in the #initialize
method, with a line like this: @interest_rate = 0
. We could still define a class method to report or change the interest rate, but we wouldn't be able to access it any other way, because we didn't give it an attribute accessor. If we were to try to access it, we'd crash the program with a NoMethodError.
Making Bank
We now have enough of a Bank class to create a piggy bank, and to find out how much money is in it. We can do that by instantiating a bank object, and then calling the attribute reader #balance
on it.
- $ piggy_bank = Bank.new(10.00)
- => #<Bank:0x00000001be35d8>
- $ piggy_bank.balance
- => 10.0
Here we've created a piggy_bank object, which is a member of the Bank class, and given it a starting balance of $10.00. The value returned by creating the object is its object ID, a unique number that marks that object's location in the computer's memory. Then we checked the balance in the piggy_bank, by calling #balance
on it, which returned the current balance as a number with a floating-point decimal value, commonly called a float.
Methods to our madness
Unfortunately, we can't do anything with our Bank objects yet, except create them. To be able to put money in or take it back out, we need to add more methods to the Bank class. Because these will be class methods, they will be able to access and manipulate the piggy_bank's instance variables. Let's define methods to deposit money into the bank, and take it out again:
- class Bank
- attr_reader :balance
- attr_reader :unmatched_deposits
- def initialize(balance)
- @balance = balance
- @unmatched_deposits = 0
- end
- def deposit(amount)
- @balance += amount
- end
- def withdraw(amount)
- @balance -= amount
- end
- end
Each of these methods takes the argument it receives when it's called, and applies it to the instance variable @balance
. Because @balance
is an instance variable, it's available to Bank class methods like #deposit
and #withdraw
without needing to be passed in as an argument. Let's see what happens when my daughter adds $3.25 to the $10 already in her piggy_bank, and then takes $2.50 back out.
- $ piggy_bank.balance
- => 10.0
- $ piggy_bank.deposit(3.25)
- => 13.25
- $ piggy_bank.withdraw(2.50)
- => 10.75
As you see, our Bank#deposit
and Bank#withdraw
methods change the value of the @balance
instance variable, and return the new balance in the account.
Dancing and chewing gum at the same time
Of course, we might want to have class methods that do more than one thing at a time, to more than one instance variable. This is perfectly possible, and an excellent example of it can be seen in the deal that my daughter worked out with her grandfather. Remember that instance variable we set up in the beginning, @unmatched_deposits
? Here's where we get to use it.
My daughter has convinced my dad to match any money she saves in her piggy bank whenever he comes to visit. So we need to modify the Bank#deposit method to keep a running total of deposits my daughter makes. We also need to define a new method that adds the matching funds that my father deposits in her bank and resets the @unmatched_deposits
total back to 0. Let's do both of those now:
- class Bank
- attr_reader :balance
- attr_reader :unmatched_deposits
- def initialize(balance)
- @balance = balance
- @unmatched_deposits = 0
- end
- def deposit(amount)
- @balance += amount
- @unmatched_deposits += amount # New line of code
- end
- def withdraw(amount)
- @balance -= amount
- end
- def match_deposits # New method
- matching_deposit = @unmatched_deposits
- @unmatched_deposits = 0
- @balance += matching_deposit
- # So grandpa knows how much to kick in:
- return matching_deposit
- end
- end
By now, we've put together a pretty robust little class. Let's see what happens when my daugher works her magic on her granddad. We'll assume the deposit-matching is a new deal, and not go back in time to match her earlier deposits.
- $ piggy_bank.balance
- => 10.75
- $ piggy_bank.unmatched_deposits
- => 0.0
- $ piggy_bank.deposit(5.00)
- => 15.75
- $ piggy_bank.unmatched_deposits
- => 5.0
- $ piggy_bank.deposit(7.50)
- => 23.25
- $ piggy_bank.unmatched_deposits
- => 12.5
- $ piggy_bank.match_deposits
- => 12.5
- $ piggy_bank.balance
- => 35.75
- $ piggy_bank.unmatched_deposits
- => 0.0
It's good to be eight years old, isn't it?
You've got class!
There's lots more you can do with classes in Ruby. In fact, there's almost nothing you can do without them.  Stay classy!


User Story: I can get the IP address, language and operating system for my browser from the /api/whoami path.
/api/whoami


Think twice!
Are you sure you want to delete this item from the list?
TODO LIST
Very important
Quite important
Not important
Add
Toggle list
Revert
Very important
Quite important
Not important


Bio
Hello, my name is James Gerstenberger and I am currently studying to become a software developer. I am passionate about science, nature and animals and love sports. I especially love soccer and am a big fan of the Premier League team Arsenal. Go Gunners!
Work Experience
- Technology Development Lead, DeepCell Industries (February 2017-September 2020)
- Lab Technician, Alder Biopharmaceuticals (February 2016-April 2017)
Education
- Certificate Codefellows (April, 2021)
- Bachelor's of Behavioral Neuroscience, Western Washington University (December, 2015)
Goals
In general I strive to be a good person and to be there for my friends and family. With everything going on in the world right now my main goal is to become a software developer so I can be financially stable and help contribute to the world in a positive way.
My Favorite Activities
- Spending time with friends and family
- Soccer
- Frisbee
- Snowboarding
- Hanging out with pets
- Watching anime
- Playing guitar
- Researching science
- Hiking
- Working out