Testing Node and Express
This tutorial looks at how to test an Express CRUD app with Mocha and Chai. Although we’ll be writing both unit and integration tests, the focus will be on the latter so that the tests run against the database in order to test the full functionality of our app. Postgres will be used, but feel free to use your favorite relational database.
Let’s get to it!
Contents
- Objectives
- Why Test?
- Project Setup
- Database Setup
- Test Structure
- Schema Migrations
- Database Seed
- Integration Tests
- Unit Tests
- Test Fixtures
- Validation
- Refactor
- Conclusion
Objectives
By the end of this tutorial, you will be able to…
- Discuss the benefits of automating tests
- Set up a project with knex.js
- Write schema migration files with knex to create new database tables
- Generate database seed files with knex and apply the seeds to the database
- Perform the basic CRUD functions on a RESTful resource with knex methods
- Set up the testing structure with Mocha and Chai
- Write integration tests
- Write unit tests
- Write tests, and then write just enough code to pass the tests
- Create Express routes
- Practice test driven development
- Create a CRUD app, following RESTful best practices
- Generate fake test data (test fixtures) with faker.js
- Validate request parameters with express-validator
Why Test?
Are you currently manually testing your app?
When you push new code do you manually test all features in your app to ensure the new code doesn’t break existing functionality? How about when you’re fixing a bug? Do you manually test your app? How many times - ten, twenty, thirty times?
Stop wasting time!
If you do any sort of manual testing write an automated test instead. Your future self will thank you.
Need more convincing? Testing…
- Helps break down problems into manageable pieces
- Forces you to write cleaner code
- Prevents over coding
- Let’s you sleep at night (because you actually know that your code works)
Project Setup
To quickly create an app boilerplate install the following generator:
$ npm install -g<EMAIL_ADDRESS>Make sure you have Mocha, Chai, Gulp, and Yeoman installed globally as well:
$ npm install -g<EMAIL_ADDRESS><EMAIL_ADDRESS><EMAIL_ADDRESS><EMAIL_ADDRESS>Create a new project directory, and then run the generator to scaffold a new app:
$ yo galvanize-express
NOTE: Add your name for the MIT License and opt not to add Gulp Notify.
Open the project in your favorite text editor, and then review the project structure as the dependencies are installed:
$ npm install
Finally, let’s run the app to make sure all is well:
$ gulp
Navigate to http://localhost:3000/ in your favorite browser. You should see:
Welcome to Express!
The sum is 3
Database Setup
Make sure the Postgres database server is running, and then create two new databases in psql, for development and testing:
# create database express_tdd;
CREATE DATABASE
# create database express_tdd_testing;
CREATE DATABASE
#
Install Knex and pg:
$ npm install<EMAIL_ADDRESS><EMAIL_ADDRESS>--save-dev
Run knex init
to generate a new knexfile.js file in the project root, which is used to store database config. Update the file like so:
module.exports = {
development: {
client: 'postgresql',
connection: 'postgres://localhost:5432/express_tdd',
migrations: {
directory: __dirname + '/src/server/db/migrations'
},
seeds: {
directory: __dirname + '/src/server/db/seeds'
}
},
test: {
client: 'postgresql',
connection: 'postgres://localhost:5432/express_tdd_testing',
migrations: {
directory: __dirname + '/src/server/db/migrations'
},
seeds: {
directory: __dirname + '/src/server/db/seeds'
}
}
};
Here, different database configuration is used based on the app’s environment, either development
or test
. The environment variable NODE_ENV
is used to change the environment. NODE_ENV
defaults to development
, so when we run our tests, we’ll need to update the variable to test
in order to pull in the proper config.
Next, let’s init the database connection. Create a new folder within “server” called “db” and then add a file called knex.js:
const environment = process.env.NODE_ENV;
const config = require('../../../knexfile.js')[environment];
module.exports = require('knex')(config);
The database connection is established by passing the proper environment (via the environment variable NODE_ENV
) to knexfile.js which returns the associated object that is passed to the knex
library in the third line above.
NOTE: Now is a great time to init a new git repo and make your first commit!
Test Structure
With that complete, let’s look at the current test structure. In the project root, you’ll notice a “test” directory, which as you probably guessed contains the test specs. Two sample tests have been created, plus there is some basic configuration set up for JSHint and JSCS so that the code is linted against the style config and conventions defined in the .jscsrc and jshintrc files, respectively.
Run the tests:
$ npm test
They all should pass:
jscs
✓ should pass for working directory (357ms)
routes : index
GET /
✓ should render the index (88ms)
GET /404
✓ should throw an error
jshint
✓ should pass for working directory (247ms)
controllers : index
sum()
✓ should return a total
✓ should return an error
6 passing (724ms)
Glance at the sample tests. Notice how we updated the environment variable at the top of each test:
process.env.NODE_ENV = 'test';
Remember what this does? Scroll back up to the previous section if you forgot. Now, when we run the tests, knex is initialized with the test
config.
Schema Migrations
To keep the code simple, let’s use one CRUD resource - users
:
| Endpoint | HTTP Method | CRUD Method | Result |
|---|---|---|---|
| users | GET | CREATE | get all users |
| users/:id | GET | CREATE | get a single user |
| users | POST | READ | add a single user |
| users/:id | PUT | UPDATE | update a single user |
| users/:id | DELETE | DELETE | delete a single user |
Init a new knex migration:
$ knex migrate:make users
This command created a new migration file in the “src/server/db/migrations” folder. Now we can create the table along with the individual fields:
| Field Name | Data Type | Constraints |
|---|---|---|
| id | integer | not null, unique |
| username | string | not null, unique |
| string | not null, unique | |
| created_at | timestamp | Not null, default to current date and time |
Add the following code to the migration file:
exports.up = (knex, Promise) => {
return knex.schema.createTable('users', (table) => {
table.increments();
table.string('username').unique().notNullable();
table.string('email').unique().notNullable();
table.timestamp('created_at').defaultTo(knex.fn.now());
});
};
exports.down = (knex, Promise) => {
return knex.schema.dropTable('users');
};
Apply the migration:
$ knex migrate:latest --env development
Make sure the schema was applied within psql:
# \c express_tdd
You are now connected to database "express_tdd".
# \dt
List of relations
Schema | Name | Type | Owner
--------+----------------------+-------+---------------
public | knex_migrations | table | michaelherman
public | knex_migrations_lock | table | michaelherman
public | users | table | michaelherman
(3 rows)
# select * from users;
id | username | email | created_at
----+----------+-------+------------
(0 rows)
Database Seed
We need to seed the database to add dummy data to the database so we have something to work with. Init a new seed, which will add a new seed file to “src/server/db/seeds/”:
$ knex seed:make users
Update the file:
exports.seed = (knex, Promise) => {
// Deletes ALL existing entries
return knex('users').del()
.then(() => {
return Promise.all([
// Inserts seed entries
knex('users').insert({
username: 'michael',
email<EMAIL_ADDRESS>}),
knex('users').insert({
username: 'michaeltwo',
email<EMAIL_ADDRESS>})
]);
});
};
Run the seed:
$ knex seed:run --env development
Then make sure the data is in the database:
# select * from users;
id | username | email | created_at
----+------------+------------------------+-------------------------------
1 | michael |<EMAIL_ADDRESS>| 2016-09-08 15:08:00.31772-06
2 | michaeltwo |<EMAIL_ADDRESS>| 2016-09-08 15:08:00.320299-06
(2 rows)
Set up complete.
Integration Tests
We’ll be taking a test first approach to development, roughly following these steps for each endpoint:
- Write test
- Run the test (it should fail)
- Write code
- Run the test (it should pass)
Start by thinking about the expected input (JSON payload) and output (JSON object) for each RESTful endpoint:
| Endpoint | HTTP | Input | Output |
|---|---|---|---|
| users | GET | none | array of objects |
| users/:id | GET | none | single object |
| users | POST | user object | single object |
| users/:id | PUT | user object | single object |
| users/:id | DELETE | none | single object |
The input user object will always look something like:
{
"username": "michael",
"email"<EMAIL_ADDRESS>}
Likewise, the output will always have the following structure:
{
"status": "success",
"data": "either an array of objects or a single object"
}
Create a new file in the “test/integration” directory called “routes.users.test.js” and add the following code:
process.env.NODE_ENV = 'test';
const chai = require('chai');
const should = chai.should();
const chaiHttp = require('chai-http');
chai.use(chaiHttp);
const server = require('../../src/server/app');
const knex = require('../../src/server/db/knex');
describe('routes : users', () => {
beforeEach((done) => {
knex.migrate.rollback()
.then(() => {
knex.migrate.latest()
.then(() => {
knex.seed.run()
.then(() => {
done();
})
});
});
});
afterEach((done) => {
knex.migrate.rollback()
.then(() => {
done();
});
});
});
What’s happening here? Think about it on your own. Turn to Google if necessary. Still have questions? Comment below.
With that, let’s start writing some code…
GET ALL Users
Add the first test:
describe('GET /api/v1/users', () => {
it('should respond with all users', (done) => {
chai.request(server)
.get('/api/v1/users')
.end((err, res) => {
// there should be no errors
should.not.exist(err);
// there should be a 200 status code
res.status.should.equal(200);
// the response should be JSON
res.type.should.equal('application/json');
// the JSON response body should have a
// key-value pair of {"status": "success"}
res.body.status.should.eql('success');
// the JSON response body should have a
// key-value pair of {"data": [2 user objects]}
res.body.data.length.should.eql(2);
// the first object in the data array should
// have the right keys
res.body.data[0].should.include.keys(
'id', 'username', 'email', 'created_at'
);
done();
});
});
});
Take note of the inline code comments. Need more explanation? Read over Testing Node.js With Mocha and Chai. Run the test to make sure it fails. Now write the code to get the test pass, following these steps:
Update the route config (src/server/config/route-config.js)
(function (routeConfig) {
'use strict';
routeConfig.init = function (app) {
// *** routes *** //
const routes = require('../routes/index');
const userRoutes = require('../routes/users');
// *** register routes *** //
app.use('/', routes);
app.use('/api/v1/users', userRoutes);
};
})(module.exports);
Now we have a new set of routes set up that we can use within src/server/routes/users.js, which we need to add…
Set up new routes
Create the users.js file in “src/server/routes/”, and then add in the route boilerplate:
const express = require('express');
const router = express.Router();
const knex = require('../db/knex');
module.exports = router;
Now we can add in the route handler with the knex methods for retrieving all users from the users
table:
router.get('/', (req, res, next) => {
knex('users').select('*')
.then((users) => {
res.status(200).json({
status: 'success',
data: users
});
})
.catch((err) => {
res.status(500).json({
status: 'error',
data: err
});
});
});
Run the tests:
$ npm test
You should see the test passing:
routes : users
GET /api/v1/users
✓ should respond with all users
GET Single User
Moving on, we can just copy and paste the previous test and use that boilerplate to write the next test:
describe('GET /api/v1/users/:id', () => {
it('should respond with a single user', (done) => {
chai.request(server)
.get('/api/v1/users/1')
.end((err, res) => {
// there should be no errors
should.not.exist(err);
// there should be a 200 status code
res.status.should.equal(200);
// the response should be JSON
res.type.should.equal('application/json');
// the JSON response body should have a
// key-value pair of {"status": "success"}
res.body.status.should.eql('success');
// the JSON response body should have a
// key-value pair of {"data": 1 user object}
res.body.data[0].should.include.keys(
'id', 'username', 'email', 'created_at'
);
done();
});
});
});
Run the test. Watch it fail. Write the code to get it to pass:
router.get('/:id', (req, res, next) => {
const userID = parseInt(req.params.id);
knex('users')
.select('*')
.where({
id: userID
})
.then((users) => {
res.status(200).json({
status: 'success',
data: users
});
})
.catch((err) => {
res.status(500).json({
status: 'error',
data: err
});
});
});
POST
Test:
describe('POST /api/v1/users', () => {
it('should respond with a success message along with a single user that was added', (done) => {
chai.request(server)
.post('/api/v1/users')
.send({
username: 'ryan',
email<EMAIL_ADDRESS>})
.end((err, res) => {
// there should be no errors
should.not.exist(err);
// there should be a 201 status code
// (indicating that something was "created")
res.status.should.equal(201);
// the response should be JSON
res.type.should.equal('application/json');
// the JSON response body should have a
// key-value pair of {"status": "success"}
res.body.status.should.eql('success');
// the JSON response body should have a
// key-value pair of {"data": 1 user object}
res.body.data[0].should.include.keys(
'id', 'username', 'email', 'created_at'
);
done();
});
});
});
Code:
router.post('/', (req, res, next) => {
const newUsername = req.body.username;
const newEmail = req.body.email;
knex('users')
.insert({
username: newUsername,
email: newEmail
})
.returning('*')
.then((user) => {
res.status(201).json({
status: 'success',
data: user
});
})
.catch((err) => {
res.status(500).json({
status: 'error',
data: err
});
});
});
PUT
Test:
describe('PUT /api/v1/users', () => {
it('should respond with a success message along with a single user that was updated', (done) => {
knex('users')
.select('*')
.then((user) => {
const userObject = user[0];
chai.request(server)
.put(`/api/v1/users/${userObject.id}`)
.send({
username: 'updatedUser',
email<EMAIL_ADDRESS>})
.end((err, res) => {
// there should be no errors
should.not.exist(err);
// there should be a 200 status code
res.status.should.equal(200);
// the response should be JSON
res.type.should.equal('application/json');
// the JSON response body should have a
// key-value pair of {"status": "success"}
res.body.status.should.eql('success');
// the JSON response body should have a
// key-value pair of {"data": 1 user object}
res.body.data[0].should.include.keys(
'id', 'username', 'email', 'created_at'
);
// ensure the user was in fact updated
var newUserObject = res.body.data[0];
newUserObject.username.should.not.eql(userObject.username);
newUserObject.email.should.not.eql(userObject.email);
// redundant
newUserObject.username.should.eql('updatedUser');
newUserObject.email.should.eql('updated@user.com');
done();
});
});
});
});
Code:
router.put('/:id', (req, res, next) => {
const userID = parseInt(req.params.id);
const updatedUsername = req.body.username;
const updatedEmail = req.body.email;
knex('users')
.update({
username: updatedUsername,
email: updatedEmail
})
.where({
id: userID
})
.returning('*')
.then((user) => {
res.status(200).json({
status: 'success',
data: user
});
})
.catch((err) => {
res.status(500).json({
status: 'error',
data: err
});
});
});
DELETE
Test:
describe('DELETE /api/v1/users/:id', () => {
it('should respond with a success message along with a single user that was deleted', (done) => {
knex('users')
.select('*')
.then((users) => {
const userObject = users[0];
const lengthBeforeDelete = users.length;
chai.request(server)
.delete(`/api/v1/users/${userObject.id}`)
.end((err, res) => {
// there should be no errors
should.not.exist(err);
// there should be a 200 status code
res.status.should.equal(200);
// the response should be JSON
res.type.should.equal('application/json');
// the JSON response body should have a
// key-value pair of {"status": "success"}
res.body.status.should.eql('success');
// the JSON response body should have a
// key-value pair of {"data": 1 user object}
res.body.data[0].should.include.keys(
'id', 'username', 'email', 'created_at'
);
// ensure the user was in fact deleted
knex('users').select('*')
.then((updatedUsers) => {
updatedUsers.length.should.eql(lengthBeforeDelete - 1);
done();
});
});
});
});
});
Code:
router.delete('/:id', (req, res, next) => {
const userID = parseInt(req.params.id);
knex('users')
.del()
.where({
id: userID
})
.returning('*')
.then((user) => {
res.status(200).json({
status: 'success',
data: user
});
})
.catch((err) => {
res.status(500).json({
status: 'error',
data: err
});
});
});
Run all your tests. All should pass.
Unit Tests
New business requirement!
We need a route to return all users created after a certain date. Since we already know how to write routes, let’s add a helper function that takes an array of users and a year that then returns an array of users created on or after the specified date. We can then use this function in a future route handler.
Steps:
- Write a unit test
- Run the tests (the unit test should fail)
- Write the code to pass the test
- Run the tests (all should pass!)
Write a unit test
Create a new file called controllers.users.test.js within the “test/unit/” directory:
process.env.NODE_ENV = 'test';
const chai = require('chai');
const should = chai.should();
const usersController = require('../../src/server/controllers/users');
describe('controllers : users', () => {
describe('filterByYear()', () => {
// add code here
});
});
Now add the body of the test:
const userArray = [
{
id: 1,
username: 'michael',
email<EMAIL_ADDRESS>created_at: '2016-09-10T16:44:28.015Z'
},
{
id: 2,
username: 'mike',
email<EMAIL_ADDRESS>created_at: '2015-09-10T16:44:28.015Z'
},
{
id: 3,
username: 'mike',
email<EMAIL_ADDRESS>created_at: '2014-09-10T16:44:28.015Z'
}
];
it('should return all users created on or after (>=) specified year',
(done) => {
usersController.filterByYear(userArray, 2015, (err, total) => {
should.not.exist(err);
total.length.should.eql(2);
done();
});
});
What’s happening?
Within the it
block we passed in the userArray
, a year, and a callback function to a function called filterByYear()
. This then asserts that a error does not exist and that the length of the response (total
) is 2.
Run the tests. Watch them fail. Add the code…
Write the code to pass the unit test
Create a new controller within “src/server/controllers” called users.js:
function filterByYear(arrayOfUsers, year, callback) {
const response = arrayOfUsers.filter((user) => {
const date = new Date(user.created_at);
return date.getFullYear() >= year;
});
callback(null, response);
}
module.exports = {
filterByYear
};
Confused? Add an inline comment above each line, describing what the code does and, in some cases, why the code does what it does.
Run the tests. Do they pass? They should.
Now you can use that function in a new route to finish the business requirement. Do this on your own. Be sure to write the integration test first!
Test Fixtures
faker.js is a powerful library for generating fake data. In our case, we can use faker to generate test data for our unit tests. Such data is often called a test fixture.
Install faker:
npm install<EMAIL_ADDRESS>--save-dev
Code
Since we don’t really (or maybe really don’t?) know what the test is going to look like, let’s start with writing a quick script to generate test data. Create a new file within the “test” directory called generate.test.data.js, and then add the following code to it:
const faker = require('faker');
function createUserObject(
yearOne, yearTwo, amountToCreate, callback) {
const userArray = [];
for (var i = 1; i <= amountToCreate; i++) {
userArray.push({
id: faker.random.uuid(),
username: faker.internet.userName(),
email: faker.internet.email(),
created_at: faker.date.between(yearOne, yearTwo)
});
}
callback(null, userArray);
}
This function generates an array of user objects, each object is generated randomly using faker.js methods. We could use that data directly in the test, but let’s first save the data to a fixture file for easy use. Update the file like so:
const faker = require('faker');
const fs = require('fs');
const path = require('path');
function createUserObject(
yearOne, yearTwo, amountToCreate, callback) {
const userArray = [];
for (var i = 1; i <= amountToCreate; i++) {
userArray.push({
id: faker.random.uuid(),
username: faker.internet.userName(),
email: faker.internet.email(),
created_at: faker.date.between(yearOne, yearTwo)
});
}
callback(null, userArray);
}
createUserObject(2010, 2014, 10, (err, beforeDates) => {
if (!err) {
createUserObject(2015, 2016, 5, (err, onOrAfterDates) => {
const userArray = beforeDates.concat(onOrAfterDates);
fs.writeFile(
path.join(__dirname, 'test.data.json'),
JSON.stringify(userArray, null, 2),
(err) => {
if (!err) {
return true;
}
});
});
}
return false;
});
Now we can generate two arrays -
- One with data before a specific date
- The other with data on or after that specific date
Before saving to a file, we concatenated the two arrays into one. You’ll see why this was necessary when the test is created. For now, run the script from the project root:
$ node test/generate.test.data.js
You should see a new fixture file called test.data.json in the “test” folder. The data in this file can now be used in a test.
Test
Add the following test to controllers.users.test.js:
describe('filterByYear() with helper', () => {
it('should return all users created on or after (>=) specified year',
(done) => {
const testDataFile = path.join(
__dirname, '..', 'test.data.json');
fs.readFile(testDataFile, 'utf8', (err, data) => {
usersController.filterByYear(
JSON.parse(data), 2015, (err, total) => {
should.not.exist(err);
total.length.should.eql(5);
done();
});
});
});
});
Make sure to require in fs
and path
at the top:
const fs = require('fs');
const path = require('path');
Run the tests again!
Validation
Thus far we have not tested for possible errors. For example, what happens if the email address provided with a POST request is not properly formatted? Or if an invalid ID is used with a PUT request?
We can start by validating parameters with express-validator.
Install
$ npm install<EMAIL_ADDRESS>--save
Then require
the module at the top of src/server/config/main-config.js:
const expressValidator = require('express-validator');
Mount the validator to the app middleware just below the body parser:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(expressValidator());
Test
Add the first test to the GET /api/v1/users/:id'
describe block:
it('should throw an error if the user id is null', (done) => {
chai.request(server)
.get(`/api/v1/users/${null}`)
.end((err, res) => {
res.status.should.equal(400);
res.body.message.should.eql('Validation failed');
res.body.failures.length.should.eql(1);
done();
});
});
Add the second test to the POST /api/v1/users
describe block:
it('should throw an error when a username is not provided', (done) => {
chai.request(server)
.post('/api/v1/users')
.send({
username: null,
email: '111111'
})
.end((err, res) => {
res.status.should.equal(400);
res.body.message.should.eql('Validation failed');
res.body.failures.length.should.eql(2);
// ensure the user was not added
knex('users')
.select('*')
.where({
email: '111111'
})
.then((user) => {
user.length.should.eql(0);
done();
});
});
});
Code
To add the proper validation, create a new file called validation.js within the “routes” directory:
function validateUserResources(req, res, next) {
if (req.method === 'GET') {
req.checkParams('id', 'Must be valid').notEmpty().isInt();
} else if (req.method === 'POST') {
req.checkBody('username', 'Username cannot be empty').notEmpty();
req.checkBody('email', 'Must be a valid email').isEmail();
} else if (req.method === 'PUT') {
req.checkParams('id', 'Must be valid').notEmpty().isInt();
req.checkBody('username', 'Username cannot be empty').notEmpty();
req.checkBody('email', 'Must be a valid email').isEmail();
} else if (req.method === 'DELETE') {
req.checkParams('id', 'Must be valid').notEmpty().isInt();
}
const errors = req.validationErrors();
if (errors) {
return res.status(400).json({
message: 'Validation failed',
failures: errors
});
} else {
return next();
}
}
module.exports = {
validateUserResources
};
Here, with express-validator, parameters are validated using either req.checkParams
or req.checkBody
and then errors are aggregated together with req.validationErrors()
.
Require this module in the user routes:
const validate = require('./validation');
Add the validateUserResources
to all the route handlers except the handler to GET ALL users, like so:
router.get('/:id',
validate.validateUserResources,
(req, res, next) => {
...
})
Finish the remaining route handlers, and then run the tests. All should pass:
jscs
✓ should pass for working directory (633ms)
routes : index
GET /
✓ should render the index (71ms)
GET /404
✓ should throw an error
routes : users
GET /api/v1/users
✓ should respond with all users (53ms)
GET /api/v1/users/:id
✓ should respond with a single user
✓ should throw an error if the user id is null
POST /api/v1/users
✓ should respond with a success message along with a single user that was added (129ms)
✓ should throw an error when a username is not provided
PUT /api/v1/users/:id
✓ should respond with a success message along with a single user that was updated
DELETE /api/v1/users/:id
✓ should respond with a success message along with a single user that was deleted
jshint
✓ should pass for working directory (661ms)
controllers : index
sum()
✓ should return a total
✓ should return an error
controllers : users
filterByYear()
✓ should return all users created on or after (>=) specified year
filterByYear() with helper
✓ should return all users created on or after (>=) specified year
15 passing (3s)
We are still not handling all errors. What else could go wrong? Think about edge cases. Then write tests. Do this on your own.
Refactor
Finally, let’s make our code a bit more modular by refactoring out unnecessary logic from the route handlers.
Within the “db” folder, add a file called queries.users.js:
const knex = require('./knex');
function getAllUsers(callback) {
return knex('users').select('*')
.then((users) => {
callback(null, users);
})
.catch((err) => {
callback(err);
});
}
module.exports = {
getAllUsers
};
This function now handles all the knex logic, and it can now be used anywhere in the project. Be sure to update the route handler:
router.get('/', (req, res, next) => {
userQueries.getAllUsers((err, users) => {
if (err) {
res.status(500).json({
status: 'error',
data: err
});
} else {
res.status(200).json({
status: 'success',
data: users
});
}
});
});
Don’t forget to add the requirement:
const userQueries = require('../db/queries.users');
Run the tests again. They all should still pass! Notice how we were able to refactor with confidence (without fear of the code breaking) since we had proper test coverage. Finish refactoring out all of the knex logic to queries.users.js. Test again when done.
Conclusion
Turn back to the objectives. Read each aloud to yourself. Can you put each one into action?
The testing process may seem daunting and unnecessary at first, but you will see just how necessary it is as your projects grow and become more complex. Continue to practice by incorporating tests whenever you begin a new project.
The full code can be found in the express-testing-mocha-knex repository.


Ripple (XRP) Price Facing Significant Resistance, Time To Sell?
- Ripple price is currently struggling to surpass the $0.2560 and $0.2600 levels against the US dollar.
- The price is likely to decline unless there is a clear break above the $0.2600 resistance.
- This week’s major bearish trend line is active with resistance near $0.2575 on the hourly chart of the XRP/USD pair (data source from Kraken).
- A clear break below the $0.2500 support might start another decrease in the near term.
Ripple price is facing a lot of key hurdles against the US Dollar and bitcoin. XRP price is likely to struggle near $0.2600 and it could resume its decline.
Ripple Price Analysis
After forming a support near the $0.2420 level, ripple started an upside correction against the US Dollar. XRP/USD recovered above the $0.2500 resistance area and even climbed above $0.2560.
However, the price failed to gain strength above the $0.2600 resistance and the 100 hourly simple moving average. A high was formed near $0.2585 and the price recently trimmed its recent gains.
It declined below the $0.2500 level and tested the $0.2480 support. A low was formed near $0.2478 and the price seems to be trading in a range. Moreover, it broke the 23.6% Fib retracement level of the recent decline from the $0.2585 high to $0.2478 low.
On the upside, the price is facing a lot of hurdles near the $0.2520 and $0.2560 levels. An immediate resistance is near the $0.2520 level. Besides, the 50% Fib retracement level of the recent decline from the $0.2585 high to $0.2478 low is near the $0.2532 level.
The next key resistance is near the $0.2545 level and the 100 hourly simple moving average. More importantly, this week’s major bearish trend line is active with resistance near $0.2575 on the hourly chart of the XRP/USD pair.
Therefore, the price is likely to struggle near the $0.2545 and $0.2560 levels. The main resistance is still near the $0.2600 area, above which the price is likely to start a strong rise towards $0.2750 or even $0.2820.
On the downside, an initial support is near the $0.2480 level. If the price fails to stay above $0.2480, it could continue to move down towards the $0.2420 support area.
Looking at the chart, ripple price is clearly facing a lot of hurdles on the upside near $0.2560 and $0.2600. As long as there is no close above $0.2600, the bears remain in control.
Technical Indicators
Hourly MACD – The MACD for XRP/USD is struggling to gain momentum in the bullish zone.
Hourly RSI (Relative Strength Index) – The RSI for XRP/USD is currently declining and is just below the 50 level.
Major Support Levels – $0.2480, $0.2420 and $0.2400.
Major Resistance Levels – $0.2545, $0.2560 and $0.2600.


SARS Background Ok, so not the Severe Acute Respiratory sort of SARS, but in fact a form of computer…
In fact, SARS is what I’ve nicknamed my new “supercomputer”. SARS stands for Small Array of Raspberry piS. I built this as I’ve also been interested in multi core computing, even before dual core and multi core chips were the norm (this is back in the pre-64 bit chips as well, when AMD Athlon chips were king!
ChromeOS is to Windows like Android was to iOS circa 2008
I think this is a fairly accurate article.
It’ll be interesting to see where Chrome OS gets to in the future. Afterall, new Chromebooks have been announced.
So I’ve been using Bittorrent Sync for a while now and thought I’d write some thoughts on it.
A brief description of it would be that it’s the sync elements of Dropbox, but running on your own server. It doesn’t have the web interface (but that can be added with third party applications, such as Owncloud) but does one thing, and one thing well.
Basics BTSync is advertised as server-less Dropbox.
Day One is a journalling app for iOS and OSX and is an great app for keeping track of things during the day - be that photos or text. It’s a great app and I’ve been using it, almost as long as I’ve been using a Mac. I love the fact that I can view and add enteries on all my iOS devices and my Mac and that the data storage format is open (it’s all XML files).
I’ve seen a lot spoken on various places online, such as MacStories and more recently in #iPadOnly, about Byword so I thought it was about time I give it a go, both on iOS and OSX as I’m a keen user of Markdown.
Byword Mac Byword focuses on simplicity and minimalism and offers you a blank screen to get started. Digging into the options lets you view the meagre amount of settings, something I was after.
I’ve had the Chromebook for a while and I’ve used it off and on over that time. A few niggles would creep in here and there, namely due to the offline access. Yet, this didn’t prove to be to problematic most of the time. It’s main use seemed to be as a second machine as the girlfriend would often use it when she was round to browse on, whilst I would use the iPad.
So I’ve been using a Chromebook now for a few weeks and I thought I’d say a few words on it.  However, whilst that’s pretty apt, I thought I’d mention my thoughts on it.
Chromebook I purchased the Samsung Series 3 Chromebook, partly due to it’s similarities to the Macbook Air.
So this year has been a bit of an up and down ride. Though I can probably say that it’s been better than last year, though as I’ve felt the rollercoaster ride recently, I thought I’d sit down and do a summary of the year so I can see exactly what I’ve achieved.
Achievements Getting a job, working for company I enjoy working for and enjoy what I’m doing.
Boring (A Review)
The mark of a great device is that it should just become sort of boring. A tool. One that is reliable. One that you just grab and use when you need it to perform the tasks for which it is built, and that you then put down satisfied that you have it even if you are no longer OMGing every time. I think this just about sums up my iPad.
My long standing dislike of emails (well, email software) is well known as I moan about it here and here. Well this came to a head this week again when I decided to slim down my hard drive due to boot camping again.
Part of this involved running JDiskReport to see what was taking up space. As part of this, I ended up moving my iPad to back up to iCloud and will then eventually remove all the apps from being kept on my machine (as that’s a fairly hefty 7GB - which adds up when you only have 320 to play with and you want at least 60 of that for Windows!


mart
City Tours / Tour Tickets / Tour Guides
Blue Tshirt
$26
Woman shirt
$31
Yellow tshirt
$21
Cool lingerie
$56


'There's Nothing To Do In Kilcoo But Play Football, Go To Mass And Have A Few Sheep'
by PJ BrowneKilcoo reached their third ever Ulster Club Football Championship final with victory over Fermanagh champions Derrygonnelly Harps at the Athletic Grounds in Armagh.
The Down team will face Donegal's Naomh Conaill in the decider.
Centre-back Aaron Branagan, who scored 1-1 as his side won by two points, was named Man of the Match on Sunday afternoon.
"Me scoring goals, that's a small miracle," Branagan jokingly told RTÉ after the game.
"We tend to leave it late to push on in games. We know how to get over the line and we know how to dog out games. It was well refereed.
"That's the way we like it, nice and tough."
Kilcoo is a small village 15 miles east of Newry.
"It's absolutely everything," said Branagan when asked what Gaelic football means to his home.
I was actually talking to a boy this morning. He said, 'There's nothing else to do in Kilcoo but play football, go to mass and have a few sheep'. That's really it.
Aaron is one of five Branagan brothers on the Kilcoo team which is managed Derryman Mickey Moran.
"To best honest, they talk more about sheep," Branagan said of his brothers.
"Football gets a wee bit of talk as well. It's nice to play with your brothers.
"Mickey is something else. I always say he's like the grandad I never had. He's the best. Everything he says, everybody is totally attentive.
"He knows what to do, how to get us over the line. He calms us down. There's no shouting."


SweetFreeStuff.com
///////////////////////////////////////////
Free Pair of Riders by Lee Jeans (Refer Friends)
Posted: 30 Sep 2014 11:34 AM PDT
http://feedproxy.google.com/&edburner&utm_medium=email
Refer 10 friends to like their Facebook page and get a Free Pair of Riders
by Lee Jeans.
The post Free Pair of Riders by Lee Jeans (Refer Friends) appeared first on
SweetFreeStuff.com.
///////////////////////////////////////////
Free Dannon Creamery Dairy Dessert at Meijer
Posted: 30 Sep 2014 10:51 AM PDT
http://feedproxy.google.com/&edburner&utm_medium=email
Login or sign up and enter offer code: Creamery14 to get the coupon. Good
through October 2nd. Free Dannon Creamery Dairy Dessert at Meijer
The post Free Dannon Creamery Dairy Dessert at Meijer appeared first on
SweetFreeStuff.com.
///////////////////////////////////////////
Free Always Discreet Sample Pack
Posted: 30 Sep 2014 04:32 AM PDT
http://feedproxy.google.com/&edburner&utm_medium=email
Free Always Discreet Sample Pack
The post Free Always Discreet Sample Pack appeared first on
SweetFreeStuff.com.
///////////////////////////////////////////
Free Subscription to Mens Health Magazine
Posted: 30 Sep 2014 04:21 AM PDT
http://feedproxy.google.com/&edburner&utm_medium=email
Free Subscription to Mens Health Magazine
The post Free Subscription to Mens Health Magazine appeared first on
SweetFreeStuff.com.
///////////////////////////////////////////
Free Nordic Naturals Wellness Sample Kit
Posted: 30 Sep 2014 04:15 AM PDT
http://feedproxy.google.com/&edburner&utm_medium=email
Click Free Sample on the lower right side of the page,
The post Free Nordic Naturals Wellness Sample Kit appeared first on
SweetFreeStuff.com.
///////////////////////////////////////////
Free Chicken Fajita Taco at Taco Cabana Oct 1st from 4-7pm
Posted: 30 Sep 2014 03:54 AM PDT
http://feedproxy.google.com/&edburner&utm_medium=email
Free Chicken Fajita Taco at Taco Cabana Oct 1st from 4-7pm
The post Free Chicken Fajita Taco at Taco Cabana Oct 1st from 4-7pm
appeared first on SweetFreeStuff.com.
///////////////////////////////////////////
Free Custom Disney Family Decal
Posted: 30 Sep 2014 03:36 AM PDT
http://feedproxy.google.com/&edburner&utm_medium=email
Free Custom Disney Family Decal
The post Free Custom Disney Family Decal appeared first on
SweetFreeStuff.com.
///////////////////////////////////////////
Free Sample of Bragg Seasonings
Posted: 30 Sep 2014 02:33 AM PDT
http://feedproxy.google.com/&edburner&utm_medium=email
- click the sample button on the left side of the page.
The post Free Sample of Bragg Seasonings appeared first on
SweetFreeStuff.com.
///////////////////////////////////////////
Free Subscription to Family Circle Magazine
Posted: 29 Sep 2014 11:20 PM PDT
http://feedproxy.google.com/&edburner&utm_medium=email
The post Free Subscription to Family Circle Magazine appeared first on
SweetFreeStuff.com.
///////////////////////////////////////////
Free Huggies Diapers and Wipes Sample Pack (Costco Members)
Posted: 29 Sep 2014 11:30 AM PDT
http://feedproxy.google.com/&edburner&utm_medium=email
Receive a free sample pack of: Three Huggies Snug Dry Diapers and One pack
of Huggies Natural Care Plus Wipes. Costco Member ID required. Free Huggies
Diapers and Wipes Sample Pack (Costco Members)
The post Free Huggies Diapers and Wipes Sample Pack (Costco Members)
appeared first on SweetFreeStuff.com.


Yocto/Trace
Path tracer implementation for support for textured mesh lights, GGX/Phong materials, environment mapping. The interface supports progressive parallel execution with any splitting strategy, by generating per-sample random number sequences or fully deterministic hash-based sampling.
The raytraced scene is a list of instances of basic shapes. Each shape is a collection of points, lines or triangles with associated normals. Shapes are instanced by creating instances with soecific local-to-world trasforms. Instancing shares memory so large scenes can be created easily. Shaope data is in fact shared with the application and not copied internally.
Materials are represented as sums of an emission term, a diffuse term and a specular microfacet term (GGX or Phong). Only opaque for now. We pick a proper material type for each shape element type (points, lines, triangles).
Lights are defined as any shape with a material emission term. Additionally one can also add an environment map. But even if you can, you might want to add a large triangle mesh with inward normals instead. The latter is more general (you can even more an arbitrary shape sun). For now only the first env is used.
We generate our own random numbers guarantying that there is one random sequence per path. This means you can run the path tracer in any order serially or in parallel.
For now, we support a straightforward path tracer with explicit direct illumination using MIS. Also added simpler shaders for a quick preview and a direct-only renderer.
The library can support raytracing either by building an internal acceleration structure with Yocto/Bvh or with user supplied intersection routines for custom intersection.
This library depends in yocto_math.h and yocto_utils.h/.cpp for concurrency. Eventually the concurrency calls will be move to std functions when more readily available. Optionally depend on yocto_bvh.h/.cpp for internal acceleration. Disable this by setting YTRACE_NO_BVH.
Usage for Scene Creation
- create a scene with
make_scene()
- add cameras with
add_camera()
,set_camera()
- add add texture with
add_texture()
- create material with
add_XXX_material()
- add shapes with
add_XXX_shape()
- add instances with
add_instance()
- add environment maps with
add_environment()
Usage for Rendering
- either build the ray-tracing acceleration structure with
init_intersection()
or supply your own withset_intersection_callbacks()
- if desired, add logging with
set_logging_callbacks()
- prepare lights for rendering
init_lights()
- define rendering params with the
trace_params
structure - render blocks of samples with
trace_block()
Usage for Progressive Rendering
- either build the ray-tracing acceleration structure with
init_intersection()
or supply your own withset_intersection_callbacks()
- if desired, add logging with
set_logging_callbacks()
- prepare lights for rendering
init_lights()
- define rendering params with the
trace_params
structure - initoialize the prograssive rendering state with
init_state()
- either render sames successively with
trace_next_samples()
or starts an asynchronousn renderer - get the rendered image with
get_traced_image()
History
- v 0.26: thin glass material
- v 0.25: added refraction (still buggy in some cases)
- v 0.24: corrected transaprency bug
- v 0.23: simpler logging
- v 0.22: added additional buffers
- v 0.21: added filters
- v 0.20: state-based api
- v 0.19: explicit material models
- v 0.18: simpler texture creation functions
- v 0.17: move to rgba per-vertex color
- v 0.16: use yocto_math in the interface and remove inline compilation
- v 0.15: move to add api
- v 1.16: internally use yocto_bvh if desired
- v 1.15: added gltf/generic material properties (deprecate old interface)
- v 1.14: normal mapping
- v 1.13: simpler Fresnel handling
- v 1.12: significantly better path tracing
- v 1.11: add progressive sampling to rendering params
- v 0.10: switch to .h/.cpp pair
- v 0.9: doxygen comments
- v 0.8: opaque API (allows for changing internals without altering API)
- v 0.7: internally use pointers for performance transparency
- v 0.6: minor API change for blocks
- v 0.5: [major API change] move to modern C++ interface
- v 0.4: C++ API
- v 0.3: removal of C interface
- v 0.2: use of STL containers
- v 0.1: C++ implementation
- v 0.0: initial release in C99
Namespace ytrace
Path tracer with MIS support.
Struct scene
struct scene;
Trace scene.
Function make_scene()
scene* make_scene();
Initialize the scene with the proper number of objects.
Function free_scene()
void free_scene(scene*& scn);
Free scene.
Function add_camera()
int add_camera(scene* scn, const ym::frame3f& frame, float yfov, float aspect,
float aperture = 0, float focus = 1);
Adds a camera in the scene.
- Parameters:
- scn: scene
- frame: local-to-world frame (x, y, z, o in column major order)
- yfov: field of view
- aspect: aspect ratio
- aperture: lens aperture
- focus: focus plane distance (cannot be zero)
- Returns:
- camera id
Function set_camera()
void set_camera(scene* scn, int cid, const ym::frame3f& frame, float yfov,
float aspect, float aperture = 0, float focus = 1);
Sets a camera in the scene.
- Parameters:
- scn: scene
- cid: camera id
- frame: local-to-world frame (x, y, z, o in column major order)
- yfov: field of view
- aspect: aspect ratio
- aperture: lens aperture
- focus: focus plane distance (cannot be zero)
Function add_texture()
int add_texture(scene* scn, int width, int height, const ym::vec4f* hdr);
Adds a texture in the scene.
- Parameters:
- scn: scene
- tid: texture id
- width: width
- height: height
- hdr: hdr pixels
- Returns:
- texture id
Function add_texture()
int add_texture(scene* scn, int width, int height, const ym::vec4b* ldr);
Sets a texture in the scene.
- Parameters:
- scn: scene
- tid: texture id
- width: width
- height: height
- ldr: ldr pixels (sRGB)
- Returns:
- texture id
Function add_texture()
inline int add_texture(scene* scn, const ym::image4f* img);
Adds a texture in the scene.
- Parameters:
- scn: scene
- hdr: hdr image
- Returns:
- texture id
Function add_texture()
inline int add_texture(scene* scn, const ym::image4b* img);
Sets a texture in the scene.
- Parameters:
- scn: scene
- ldr: ldr image (sRGB)
- Returns:
- texture id
Function add_material()
int add_material(scene* scn);
Adds a black material to the scene. Use set_material_XXX() functions to customize it.
- Parameters:
- scn: scene
- Returns:
- material id
Function set_material_emission()
void set_material_emission(
scene* scn, int mid, const ym::vec3f& ke, int ke_txt);
Sets the material emission.
- Parameters:
- scn: scene
- mid: material id
- ke: emission, term
- ke_txt: emission texture (-1 for none)
Function set_material_normal()
void set_material_normal(scene* scn, int mid, int norm_txt, float scale = 1);
Sets the material normal map.
- Parameters:
- scn: scene
- mid: material id
- norm_txt: normal map (-1 for none)
- scale: normal scale
Function set_material_occlusion()
void set_material_occlusion(scene* scn, int mid, int occ_txt, float scale = 1);
Sets the material normal map.
- Parameters:
- scn: scene
- mid: material id
- occ_txt: occlusion map (-1 for none)
- scale: occlusion scale
Function set_material_microfacet()
void set_material_microfacet(scene* scn, int mid, const ym::vec3f& kd,
const ym::vec3f& ks, const ym::vec3f& kt, float rs, float op, int kd_txt,
int ks_txt, int kt_txt, int rs_txt, int op_txt, bool use_phong = false);
Sets a material reflectance as a microfacet model in the scene.
- Parameters:
- scn: scene
- mid: material id
- kd: diffuse term
- ks: specular term
- kt: transmission term
- rs: specular roughness
- kd_txt, ks_txt, kt_txt, rs_txt: texture indices (-1 for none)
- use_phong: whether to use phong
Function set_material_gltf_metallic_roughness()
void set_material_gltf_metallic_roughness(scene* scn, int mid,
const ym::vec3f& kb, float km, float rs, float op, int kd_txt, int km_txt);
Sets a gltf metallic roughness material reflectance.
- Parameters:
- scn: scene
- mid: material id
- kb: base color term
- km: metallic term
- rs: specular roughness
- kd_txt, km_txt: texture indices (-1 for none)
Function set_material_gltf_specular_glossiness()
void set_material_gltf_specular_glossiness(scene* scn, int mid,
const ym::vec3f& kd, const ym::vec3f& ks, float rs, float op, int kd_txt,
int ks_txt);
Sets a gltf metallic specular glossiness reflectance.
- Parameters:
- scn: scene
- mid: material id
- ke: emission, term
- kd: diffuse term
- ks: specular term
- rs: specular glossiness
- kd_txt, ks_txt: texture indices (-1 for none)
Function set_material_thin_glass()
void set_material_thin_glass(scene* scn, int mid, const ym::vec3f& ks,
const ym::vec3f& kt, int ks_txt, int kt_txt);
Sets a thin glass material
- Parameters:
- scn: scene
- mid: material id
- ks: reflection
- kt: transmission
- ks_txt, kt_txt: texture indices (-1 for none)
Function set_material_double_sided()
void set_material_double_sided(scene* scn, int mid, bool double_sided);
Sets the material emission.
- Parameters:
- scn: scene
- mid: material id
- double_sided: whether the material is double sided
Function add_environment()
int add_environment(
scene* scn, const ym::frame3f& frame, const ym::vec3f& ke, int txt_id = -1);
Sets an environment in the scene.
- Parameters:
- scn: scene
- frame: local-to-world frame (x, y, z, o in column major order)
- ke: emission
- ke_txt: emission texture (-1 for none)
- Returns:
- environment id
Function add_triangle_shape()
int add_triangle_shape(scene* scn, int ntriangles, const ym::vec3i* triangles,
int nverts, const ym::vec3f* pos, const ym::vec3f* norm,
const ym::vec2f* texcoord = nullptr, const ym::vec4f* color = nullptr,
const ym::vec4f* tangsp = nullptr);
Sets a shape in the scene.
- Parameters:
- scn: scene
- frame: local-to-world frame (x, y, z, o in column major order)
- mid: material id
- npoints/nlines/ntriangles: number of elements
- points/lines/tiangles: elem data
- nverts: number of vertices
- pos: vertex positions
- norm/tang: vertex normals/tangents
- texcoord: vertex texcoord
- color: vertex color
- tangsp: tangent space for normal and bump mapping
- Returns:
- shape id
Function add_point_shape()
int add_point_shape(scene* scn, int npoints, const int* points, int nverts,
const ym::vec3f* pos, const ym::vec3f* norm,
const ym::vec2f* texcoord = nullptr, const ym::vec4f* color = nullptr,
const float* radius = nullptr);
Sets a shape in the scene.
- Parameters:
- scn: scene
- sid: shape id
- frame: local-to-world frame (x, y, z, o in column major order)
- mid: material id
- npoints/nlines/ntriangles: number of elements
- points/lines/tiangles: elem data
- nverts: number of vertices
- pos: vertex positions
- norm/tang: vertex normals/tangents
- texcoord: vertex texcoord
- color: vertex color
- radius: vertex radius
- Returns:
- shape id
Function add_line_shape()
int add_line_shape(scene* scn, int nlines, const ym::vec2i* lines, int nverts,
const ym::vec3f* pos, const ym::vec3f* tang,
const ym::vec2f* texcoord = nullptr, const ym::vec4f* color = nullptr,
const float* radius = nullptr);
Sets a shape in the scene.
- Parameters:
- scn: scene
- frame: local-to-world frame (x, y, z, o in column major order)
- mid: material id
- npoints/nlines/ntriangles: number of elements
- points/lines/tiangles: elem data
- nverts: number of vertices
- pos: vertex positions
- norm/tang: vertex normals/tangents
- texcoord: vertex texcoord
- color: vertex color
- radius: vertex radius
- Returns:
- shape id
Function add_instance()
int add_instance(scene* scn, const ym::frame3f& frame, int sid, int mid);
Adds an instance in the scene.
- Parameters:
- scn: scene
- iid: instance id
- frame: local-to-world frame (x, y, z, o in column major order)
- sid: shape id
- mid: material id
- Returns:
- instance id
Function specular_exponent_to_roughness()
float specular_exponent_to_roughness(float n);
Convert a Phong exponent to GGX/Phong roughness
Function specular_fresnel_from_ks()
void specular_fresnel_from_ks(
const ym::vec3f& ks, ym::vec3f& es, ym::vec3f& esk);
Estimates the fresnel coefficient es from ks at normal incidence
Struct intersect_point
struct intersect_point {
float dist = 0;
int iid = -1;
int sid = -1;
int eid = -1;
ym::vec3f euv = {0, 0, 0};
operator bool() const;
}
Ray-scene Intersection.
- Members:
- dist: ray distance
- iid: instance index
- sid: shape index
- eid: element distance
- euv: element baricentric coordinates
- operator bool(): check whether it was a hit
Typedef intersect_first_cb
using intersect_first_cb = std::function<intersect_point(const ym::ray3f& ray)>;
Ray-scene closest intersection callback.
- Parameters:
- ray: ray
- Return:
- intersection point
Typedef intersect_any_cb
using intersect_any_cb = std::function<bool(const ym::ray3f& ray)>;
Ray-scene intersection callback
- Parameters:
- ray: ray
- Return:
- whether we intersect or not
Function set_intersection_callbacks()
void set_intersection_callbacks(scene* scn, void* ctx,
intersect_first_cb intersect_first, intersect_any_cb intersect_any);
Sets the intersection callbacks
Function init_intersection()
void init_intersection(scene* scn);
Initialize acceleration structure.
- Parameters:
- scn: trace scene
Typedef logging_cb
using logging_cb = std::function<void(const char*)>;
Logging callback
Function set_logging_callbacks()
void set_logging_callbacks(
scene* scn, logging_cb log_info, logging_cb log_error);
Logger
Function init_lights()
void init_lights(scene* scn);
Initialize lighting.
- Parameters:
- scn: trace scene
Enum shader_type
enum struct shader_type {
pathtrace = 0,
eyelight,
direct,
direct_ao,
}
Type of rendering algorithm (shader)
- Values:
- pathtrace: pathtrace
- eyelight: eye hight for quick previews
- direct: direct illumination
- direct_ao: direct illumination with ambient occlusion
Enum rng_type
enum struct rng_type {
uniform = 0,
stratified,
cmjs,
}
Random number generator type
- Values:
- uniform: uniform random numbers
- stratified: stratified random numbers
- cmjs: correlated multi-jittered sampling
Enum filter_type
enum struct filter_type {
box = 1,
triangle = 2,
cubic = 3,
catmull_rom = 4,
mitchell = 5
}
Filter type
- Values:
- box: box filter
- triangle: hat filter
- cubic: cubic spline
- catmull_rom: Catmull-Rom spline
- mitchell: Mitchell-Netrevalli
Struct trace_params
struct trace_params {
int camera_id = 0;
int width = 0;
int height = 0;
int nsamples = 256;
shader_type stype = shader_type::pathtrace;
rng_type rtype = rng_type::stratified;
filter_type ftype = filter_type::box;
bool aux_buffers = false;
ym::vec3f amb = {0, 0, 0};
bool envmap_invisible = false;
int min_depth = 3;
int max_depth = 8;
float pixel_clamp = 10;
float ray_eps = 1e-4f;
bool parallel = true;
}
Rendering params
- Members:
- camera_id: camera id
- width: width
- height: height
- nsamples: number of samples
- stype: sampler type
- rtype: random number generation type
- ftype: filter type
- aux_buffers: compute auxiliary buffers
- amb: ambient lighting
- envmap_invisible: view environment map
- min_depth: minimum ray depth
- max_depth: maximum ray depth
- pixel_clamp: final pixel clamping
- ray_eps: ray intersection epsilon
- parallel: parallel execution
Function trace_block()
void trace_block(const scene* scn, ym::vec4f* img, int block_x, int block_y,
int block_width, int block_height, int samples_min, int samples_max,
const trace_params& params);
Renders a block of sample
Notes: It is safe to call the function in parallel on different blocks. But two threads should not access the same pixels at the same time. Also blocks with different samples should be called sequentially if accumulate is true.
- Parameters:
- scn: trace scene
- cid: camera id
- img: pixel data in RGBA format (width/height in params)
- nsamples: number of samples
- block_x, block_y: block corner
- block_width, block_height: block width and height
- samples_min, samples_max: sample block to render [sample_min, sample_max]; max values are excluded
Struct trace_state
struct trace_state;
State for progressive rendering and denoising
Function make_state()
trace_state* make_state();
Creates state
Function init_state()
void init_state(
trace_state* state, const scene* scn, const trace_params& params);
Initialize state
Function free_state()
void free_state(trace_state*& state);
Clear state
Function get_traced_image()
ym::image4f& get_traced_image(trace_state* state);
Grabs a reference to the image from the state
Function get_aux_buffers()
void get_aux_buffers(const trace_state* state, ym::image4f& norm,
ym::image4f& albedo, ym::image4f& depth);
Grabs the image from the state
Function get_cur_sample()
int get_cur_sample(const trace_state* state);
Gets the current sample number
Function trace_next_samples()
bool trace_next_samples(trace_state* state, int nsamples);
Trace the next nsamples samples.
Function trace_image()
inline ym::image4f trace_image(const scene* scn, const trace_params& params);
Trace the whole image
Function trace_async_start()
void trace_async_start(trace_state* state);
Starts an anyncrhounous renderer with a maximum of 256 samples.
Function trace_async_stop()
void trace_async_stop(trace_state* state);
Stop the asynchronous renderer.


In Ghanian culture when children are born they are given their first names in accordance with the day of the week they were born and their gender. Are you curious to know what you'll be called if you were born in Ghana? If yes please fill in the form below to generate your Akan


Title: HTML entry with well-formed paragraphs Date: 2019-06-28 15:12:07-07:00 Entry-ID: 545 UUID: 19e362d7-e9e7-5eaa-ab6f-0e18c9ae67e3
This is a well-formed paragraph. Here is a link.
This is also a well-formed paragraph.


This field is required
Minimum {{control.errors.minlength.requiredLength}} characters are required
Maximum {{control.errors.maxlength.requiredLength}} characters are required
{{control.errors.unique}}
{{control.errors.lessThen}}
{{control.errors.greaterThan}}
Email invalid
{{control.errors.mobile}}
{{control.errors.confirmPassword}}
Letter,number, dashes, and underscores only. Please try again without symbols
The Password is not the same. Please fix it.


EBay selling StubHub to viagogo for $4.05 billion
by The Associated PressEBay is selling StubHub to ticket seller viagogo for $4.05 billion in cash.
The transaction is part of a review that eBay undertook earlier this year following pressure from an activist investor. The San Jose, California-based company then said it was also reviewing options for its classified ads business.
EBay Inc. bought StubHub in 2007 for $310 million. Both StubHub and the classifieds business each brought in less than 10% of eBay's total revenue last year.
The addition of StubHub will allow viagogo to sell tickets in more than 70 countries and give buyers access to a wider selection of tickets.
Viagogo's founder and CEO Eric Baker is a StubHub co-founder. In a statement, Baker said it has been his longtime wish to unite the two companies.
The sale is targeted to close by the end of 2020's first quarter.
_____
This story has been corrected to show the transaction is worth $4.05 billion, not $4.5 billion.


--- layout: newsstory title: DRAB DRAW BY THE SEA match: Weymouth 0 Yeltz 0 ---
On the positive side - we got a point away from home, kept a clean sheet and stretched our unbeaten run to 4 games. On the other hand, we've still only won once away in the league.
The quality of the match reports has been excellent so far, so hopefully one of you brave souls who made the trip down there will file a match report telling us what actually happened.
It's a free Saturday next weekend so you can get all your Xmas pressies with your conscience clear, but before that we're away to Burton in the League Cup on Tuesday.


{% extends "base.html" %} {% block content %} {% if authorized %}
Administrative Actions
These actions can have dire consequences if abused. Please only use if you have been told by a producer!
Restart Nginx
Restart Nginx?
Are you sure you want to restart the streaming server?
No Yes


Pokefile
This site was built entirely for education purposes only
Simple project created with HTML5, CSS3, Stylus, AngularJS, MaterialDesign, MaterialDesignIcons.
Project
Based on this project
Pokémon
Pokémon images, names and information (c) 1995-2014 Nintendo/Game freak.
Images and content were taken from the following resources:
This software comes bundled with data extracted from the Pokémon series of video games. Some terminology from the Pokémon franchise is also necessarily used within the software itself. This is all the intellectual property of Nintendo, Creatures, inc., and GAME FREAK, inc. and is protected by various copyrights and trademarks. The author believes that the use of this intellectual property for a fan reference is covered by fair use and that the software is significantly impaired without said property included. Any use of this copyrighted property is at your own legal risk.
Code: The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyright (c) 2015 David Castillo


- To start a new game, follow the instructions in the message center in the middle of the page. When two people have signed on, the game will begin.
- Blank spaces representing the answer word will appear on the page.
- Use the letter buttons at the bottom of the page to guess what letters are part of the answer word.
- If you guess a letter correctly, the letter will show up in one of the blank spaces and your color progress bar will raise.
- If you answer incorrectly, your HANGMAN will start to be drawn.
- Keep an eye on your opponent's progress bar because if they figure out the word correctly first, they will win the game.
- The first person to guess the word correctly or the last person standing wins!
- If it seems like the page has crashed, press the "reset" button in the upper left corner.


---
layout: post
title: Hang a left at Europa
date: '2013-06-25T13:19:00.000-04:00'
author: Robert Sica
tags:
- whatif
- planets
modified_time: '2013-07-30T17:15:19.366-04:00'
blogger_id: tag:blogger.com,1999:blog-736339229338318027.post-6414534739767217923
blogger_orig_url: http://blog.purplecrowlidar.ca/2013/06/photographer-ron-miller-creates.html
---
Photographer Ron Miller creates incredible pictures of what it would look like if planets were closer
Agree with John Gruber, that would be one heckuva highway to cruise down.


arrow_back
BACK
people
Amanze Ogbonna
Title
Loading question ...
ANSWER QUESTION
No answers yet
Loading ...


General election 2019: Labour vows to end dental check-up charges
by Nick TriggleEveryone will be entitled to a "free teeth MOT" in England under a Labour government, the party says.
Labour is proposing to scrap band one dentistry charges, which cover a check up, a scale and polish, and any X-rays that may be needed.
It believes patients are put off going because of the fee - a check up costs £22.70 - with many ending up in A&E.
Dental leaders welcomed the move, but said there was a shortage of dentists that needed addressing too.
Shadow health secretary Jonathan Ashworth said charges were a real barrier to access services for some.
"With 135,000 patients presenting at A&E with dental problems every year, it's time we put prevention at the heart of our approach to health."
Labour leader Jeremy Corbyn added: "This is the first step towards making all dentistry services free of charge."
He told the BBC's Andrew Marr Show that free dental checks would "save money in the long-run" and it was "actually an investment for the future".
"If we don't have a dental check and then somewhere down the line we have a catastrophe, a disaster, massive pain, we have to go to A&E and that is then very expensive," he said.
Labour said the policy would cost £450m a year.
Health is devolved so the policy only covers England. Wales and Northern Ireland both charge for check ups, but Scotland does not.
How do the charges work?
There are three fee bands for treatment. They are:
- Band one (£22,70) - check up, scale and polish and any X-rays
- Band two (£62.10) - all the treatments in band one plus fillings, extractions and root canal treatment
- Band three (£269.30) - all treatments in band one and two plus crowns, dentures and bridges
People on low incomes, pregnant women and under 18s or under 19 and in full-time education are exempt from charges.
Nearly half of treatments delivered each year are provided free.
However, the exemption system has been criticised for being overly complex and has been blamed for people getting fined for wrongly claiming free dental care.
How many people are going without dental care?
Official NHS figures show about half of adults have not used an NHS dentist in the past two years and about four in 10 children for the past year.
But that does not mean that they are all going without care.
Some patients may feel they do not need to go, while large numbers pay to see dentists privately.
The figures also do not cover those who get care from specialist community teams, such as those with mental health problems, learning disabilities and some people in care homes.
No data is published on the actual number of people going without care when they need it.
Labour has pointed to figures suggesting one in five delays going because they cannot afford to see dentists, but that is from research a decade ago.
Will this policy solve the problem?
In theory, free checks should make a difference. The British Dental Association points to data from Scotland, which has had free check ups since 2006, that shows higher rates of NHS dentistry use.
BDA chair Mick Armstrong said the system of exemptions was complex so simplifying the system should encourage more people to come forward for check ups - although they still face the prospect of charges if they need any work done.
But he also said workforce problems needed to be addressed if access was going to improve significantly.
Research by the BDA has suggested three quarters of NHS dental surgeries have vacancies they struggle to fill.
"Any plans to boost access must go hand-in-hand with support for a service facing serious recruitment problems.
"NHS dentistry cannot be delivered without NHS dentists."


-
Cotton Rich Super Skinny Fit Jeans from eewdsfsafwefwefew
Size: 2-4 years | Qty: 2
-
Cotton Rich Super Skinny Fit Jeans from eewdsfsafwefwefew
Size: 2-4 years | Qty: 2
{{- partial "coupon.html" . -}}
{{- partial "sign-in.html" . -}}
{{- partial "shipping-details.html" . -}}
{{- partial "shipping-summary.html" . -}}
{{- partial "payment-details.html" . -}}


Wife secretly got a babysitter and took me out to @bamboosushi. What a great evening.
1/21/2011, 10:30:36 PM
Favs: 0
Retweets: 0
link--- layout: tweet ---
Wife secretly got a babysitter and took me out to @bamboosushi. What a great evening.
1/21/2011, 10:30:36 PM
Favs: 0
Retweets: 0
link


This class provides the basic mechanism for an application to specify Quality of Service attributes for a Subscriber.
More...
#include "SubscriberQos.hpp"
Inherits dds::core::EntityQos< org::eclipse::cyclonedds::sub::qos::SubscriberQosDelegate >.
This class provides the basic mechanism for an application to specify Quality of Service attributes for a Subscriber.
- Attributes
-
A QosPolicy can be set when the Subscriber is created or modified with the set qos operation. Both operations take the SubscriberQos object as a parameter. There may be cases where several policies are in conflict. Consistency checking is performed each time the policies are modified when they are being created and, in case they are already enabled, via the set qos operation.
Some QosPolicy have "immutable" semantics meaning that they can only be specified either at Subscriber creation time or prior to calling the enable operation on the Subscriber.
- See also
- DCPS_QoS
Definition at line 58 of file SubscriberQos.hpp.
◆ SubscriberQos() [1/2]
| dds::sub::qos::SubscriberQos::SubscriberQos |
( |
| ) |
|
|
inline |
◆ SubscriberQos() [2/2]
| dds::sub::qos::SubscriberQos::SubscriberQos |
( |
const SubscriberQos & |
qos | ) |
|
Create copied QoS type.
- Parameters
-
| qos | the QoS to copy policies from. |
◆ operator<<()
| EntityQos& dds::core::EntityQos::operator<< |
( |
const POLICY & |
p | ) |
|
|
inherited |
Generic function for setting a policy applicable to this QoS object. Available policies depend on the actual instantiation of the template class, which might be DomainParticipantQos, TopicQos, PublisherQos, etc.
- Parameters
-
| p | the policy to be set for this QoS instance. |
◆ operator>>()
| const EntityQos& dds::core::EntityQos::operator>> |
( |
POLICY & |
p | ) |
const |
|
inherited |
Generic function for obtaining the value of a specific policy belonging to this QoS instance.
- Returns
- policy
◆ policy() [1/3]
| POLICY& dds::core::EntityQos::policy |
( |
| ) |
|
|
inherited |
Generic function for obtaining the value of a specific policy belonging to this QoS instance.
- Returns
- policy
◆ policy() [2/3]
| const POLICY& dds::core::EntityQos::policy |
( |
| ) |
const |
|
inherited |
Generic function for obtaining the value of a specific policy belonging to this QoS instance.
- Returns
- policy
◆ policy() [3/3]
| EntityQos& dds::core::EntityQos::policy |
( |
const POLICY & |
p | ) |
|
|
inherited |
Generic function for setting a policy applicable to this QoS object. Available policies depend on the actual instantiation of the template class, which might be DomainParticipantQos, TopicQos, PublisherQos, etc.
- Parameters
-
| p | the policy to be set for this QoS instance. |
The documentation for this class was generated from the following file:


Why Court Sacked Four Kano Emirs Installed By Ganduje
by Olugbenga IgeThe installation of four additional Emirs in Kano State has been nullified by the state High Court, Concise News reports.
The presiding judge, Justice Usman Na’abba ruled that the creation of the Emirates and subsequent appointment of four new first-class Emirs did not follow due process.
Justice Na’bba also ruled that the State House of Assembly violated the provision of section 101 of the 1999 constitution which allows the assembly to make laws.
He then declared the creation null and void.
Governor Abdullahi Ganduje of Kano State had earlier in May assented the bill seeking the establishment of four additional first-class Emirates – Rano, Gaya, Karaya and Bichiin.
The governor assented the bill following its passage by the Kano State House of Assembly. He later in the month presented letters of appointment to the four new first-class Emirs during a ceremony held at the state capital.
Those presented with the letters of appointment include Aminu Ado Bayero, the son of Late Emir of Kano, Ado Bayero, as the Emir of Bichi; Ibrahim Abulkadir as the Emir of Gaya; Tafida Abubakar as the Emir Of Rano and Abubakar Ibrahim II as the Emir of Karaye.
Ganduje during the presentation said the creation of the four Emirates will make Kano traditional system more efficient.
The creation of the new Emirates was however met with controversy as four Kano State kingmakers filed a suit against Ganduje and the State Assembly.
The kingmakers who took the legal action are Madakin Kano, district head of Dawakintofa; Yusuf Nabahani, district head of Wudil; Abdullahi Sarki-Ibrahim, district head of Gabasawa; and Bello Abubakar, district head of Dambatta, Mukhtar Adnan.
It was learned that the creation of the new emirates was to reduce the power of Emir Sanusi who reportedly worked against the governor’s reelection.


boto v2.2.0
The 2.2.0 release of boto is now available on PyPI.
You can view a list of issues that have been closed in this release at
https://github.com/boto/boto/issues?milestone=5&state=closed.
You can get a comprehensive list of all commits made between the 2.0 release
and the 2.1.0 release at
https://github.com/boto/boto/compare/fa0d6a1e49c8468abbe2c99cdc9f5fd8fd19f8f8...26c8eb108873bf8ce1b9d96d642eea2beef78c77.
Some highlights of this release:
- Support for Amazon DynamoDB service.
- Support for S3 Object Lifecycle (Expiration).
- Allow anonymous request for S3.
- Support for creating Load Balancers in VPC.
- Support for multi-dimension metrics in CloudWatch.
- Support for Elastic Network Interfaces in EC2.
- Support for Amazon S3 Multi-Delete capability.
- Support for new AMIversion and overriding of parameters in EMR.
- Support for SendMessageBatch request in SQS.
- Support for DescribeInstanceStatus request in EC2.
- Many, many improvements and additions to API documentation and Tutorials.
Special thanks to Greg Taylor for all of the Sphinx cleanups and new docs.
There were 336 commits in this release from 40 different authors. The authors
are listed below, in no particular order:
- Garrett Holmstrom
- mLewisLogic
- Warren Turkal
- Nathan Binkert
- Scott Moser
- Jeremy Edberg
- najeira
- Marc Cohen
- Jim Browne
- Mitch Garnaat
- David Ormsbee
- Blake Maltby
- Thomas O’Dowd
- Victor Trac
- David Marin
- Greg Taylor
- rdodev
- Jonathan Sabo
- rdoci
- Mike Schwartz
- l33twolf
- Keith Fitzgerald
- Oleksandr Gituliar
- Jason Allum
- Ilya Volodarsky
- Rajesh
- Felipe Reyes
- Andy Grimm
- Seth Davis
- Dave King
- andy
- Chris Moyer
- ruben
- Spike Gronim
- Daniel Norberg
- Justin Riley
- Milan Cermak timtebeek
- unknown
- Yotam Gingold
- Brian Oldfield
We processed 21 pull requests for this release from 40 different contributors.
Here are the github user id’s for all of the pull request authors:
- milancermak
- jsabo
- gituliar
- rdodev
- marccohen
- tpodowd
- trun
- jallum
- binkert
- ormsbee
- timtebeek


No Jabber on iPhone
So I finally managed to get the toolchain for iPhone building - after re-installing XCode and then installing the occdtools (OCD?) tools from a different subversion revision I even got my apps to compile, not withstanding some random header madness and so on. I then went so far as to download and 'add' Jabber to ApolloIM to see if it would work.
Now it's been an embarassingly long time since I've done much but Java, but either this is extremely well put together code or I clearly missed something obvious or libpurple (an IM library) isn't compiled correctly. I say 'well put together' because adding jabber was trivial: Editing maybe 5 files (slight distinction between jabber and xmpp). Alternatively, I missed something obvious because it didn't work - running my re-compiled version of it from the command line on the iPhone (ha!), well google mail would fail while authenticating, but msn worked fine.
Which could mean something is wrong with libpurple. ref: This and this, from Erica Sadun, although there's a difference between going outside of somethings design and there being something wrong. But for the latter case the interview here suggests that everything is held together by gum and shoestrings... There's some ambiguity, but looking in various repositories it doesn't look like libpurple has been recompiled since September.
(MobileChat 2.0 (beta) is supposed to have gtalk/jabber as well, but ... the comments sound a lot like my experience).
Something I don't understand yet is, why is everything using purple? isn't it an IM library? (NM, my bad, purple != libPurple, thanks Erica!)
About this entry
You"re currently reading "No Jabber on iPhone," an entry on a crick in the net
- Published:
- 12.09.07 / 7pm
- Category:
- Circular File
Libpurple is not the same thing as the iPhone's purple apps. Libpurple was ported by core and is used in several applications including ApolloIM. Purple apps refer to SpringBoard's application-loading protocol.
Is GTalk the same as Jabber?? I have a Jabber account, but when I try to login to GTalk with Mobile Chat v2.0.0b it does not work. Also, even if I try to log in via the web on my computer, it obviously doens't recognize the username/pword.. Google Talk cannot be the same as xmpp/jabber. I use a jabber client called Spark and I can login fine.. Am I missing something here?


A heavily customized ESLint config and plugin for JavaScript following the Google JavaScript style guide.


₦1,200
3 items
⚫ Completed
3 days ago
₦1,200
3 items
⚫ Completed
8 hours ago
₦1,200
3 items
⚫ Declined
2 days ago
₦1,200
3 items
⚫ Approved
3 days ago


SHORTCUTS
EXPLORE
Rajpal Yadav <3
Stay hungry. Stay foolish.
Sapna Garg's birthday is today.
Anamika Jain's birthday is next week.
India to face Pakistan in Champions Trophy Final 2017 in London on 18th June.
Apple will be releasing its 10th iPhone Anniversary in September.
Amazon acquires Whole Food Market in biggest deal for 13.2bn USD
Once again the Yearly Friendsbook Data Shows change in trends.
Srikanth wins the Indonesian Open final. Winning on 4-3-4-6
India will face Ausralia in Hockey Semi-Finals on Sunday
UCL selection will soon take place in Marayem Arena, Spain for 26th Time.
Congress Man attacked outside the parliament. Culprit to appear in court on 22nd.
Brexit soon to take place affects neighbouring businesses imensly before.
Presidential elections in Russia to take place soon. But might as well affects the economy.
Donald Trump to elect new Finance commitee soon. As new Aligations are put on the existing.


{% extends "layout.html" %} {% block page_title %} Money Claims Prototype {% endblock %} {% block content %} {% include "includes/phase_banner_beta.html" %} You can't cancel the CCJ You didn’t pay the claim within 28 days of it being issued. This means you can't cancel it. You can instead apply to have it shown as paid or ‘satisfied’ on public records. The CCJ will be removed from the register after 6 years. {% include 'prototypes/prototype-aug-2019/includes/contact.html' %} {% endblock %}
You didn’t pay the claim within 28 days of it being issued. This means you can't cancel it.
You can instead apply to have it shown as paid or ‘satisfied’ on public records. The CCJ will be removed from the register after 6 years.


In the Year 2006, Under the visionary leadership of the then Principal Dr. Debabrata Chowdhury , and with the proper assistance of Prof. Bikash Chandra Pal, Prof.(Dr) Mainak Gupta & Prof. Angshutosh Khan, and with very few students , Electronics Department started its journey and emerged as one of the prime Department of Asutosh College.


GERMAN HIGH SCHOOL HISTORY TEXTBOOKS: HOW WELL DO THEY DEAL WITH THE RISE AND FALL OF THE THIRD REICH?
by William P. Yurochko
Dissertation submitted to the Faculty of the Virginia Polytechnic Institute and State University in partial fulfillment of the requirements for the degree of DOCTOR OF EDUCATION in
Curriculum and Instruction
APPROVED:
Daniel B. Fleming, Shairman
Normg/Jean Peters David M. Moore
, - Arnold H. Schuetz (Cognate) Catherine A. Brown
April, 1988
Blacksburg, Virginia


Key figures concerning Italian products in France
Italy’s rich culinary heritage is very appreciated in France.
It is the 5th supplier country for foodstuffs in France: €4.15 million (7.8% of the
French import market).
The three leading product categories are:
Sweet and bakery products,
Dairy products
Pasta.
+16% for sweet products +13% for dairy products +5.8% for pasta
Italy is the largest producer of organic products in the European Union.


Wikipedia page URL
Load data
Reset map
Load example page
Commonwealth
South America
Provinces of China
Council of Eur.
African Union
OPEC
NATO
BRICS
Country labels
Microstate labels
Save as SVG
Save as PNG
Path over:
Path out:
Path click:


🔧 Advanced: Report Dependency
DocFX Incremental Build Framework provides the flexiblity to register customized dependency type and report dependency. In this topic, we will go through how to do that.
Register Dependency Type
Dependency type
| Property | Type | Description |
|---|---|---|
| Name | string | name of the dependency type(it should be unique) |
| Phase | enum(Compile or Link ) |
the build phase that this type of dependency could have an effect on. |
| Transitivity | enum(None or SameType or All ) |
whether the dependency is transitive, transitive upon the dependencies with same type, or transitive upon any dependency. |
Reserved dependency types
Below table lists all reserved dependency types. When creating a customized dependency type, name shouldn't conflict with the reserved ones.
| Name | Phase | Transitivity | Description |
|---|---|---|---|
| include | Compile | All | file inclusion and code snippet |
| uid | Link | None | cross reference |
| file | Link | None | file link |
| overwrite | Link | All | overwrite files |
| bookmark | Link | None | file link with bookmark |
| metadata | Link | None | metadata related dependency |
| reference | Link | None | managed reference document's references |
Register a customized dependency type
Plugins are flexible to register customized dependency types by implementing @Microsoft.DocAsCode.Plugins.ISupportIncrementalBuildStep interface's method @Microsoft.DocAsCode.Plugins.ISupportIncrementalBuildStep.GetDependencyTypesToRegister. The method would be called by the framework at the very start of the whole build.
Sample code:
public IEnumerable<DependencyType> GetDependencyTypesToRegister() => new[]
{
new DependencyType()
{
Name = "ref",
Phase = BuildPhase.Link,
Transitivity = DependencyTransitivity.None,
}
};
Report Dependency item
DependencyItem model
| Property | Type | Description |
|---|---|---|
| From | DependencyItemSourceInfo | the depending one |
| To | DependencyItemSourceInfo | the dependent one |
| Type | string | the dependency type name |
DependencyItemSourceInfo model
| Property | Type | Description |
|---|---|---|
| sourceType | string | the type of the value. file and uid are reserved types |
| value | string | value |
How to report
@Microsoft.DocAsCode.Plugins.IHostService interface provides the methods to report directed/reversed dependency items.
If you want to report the dependency between an file and another file, you can use below method:
directed dependency: @Microsoft.DocAsCode.Plugins.IHostService.ReportDependencyTo(Microsoft.DocAsCode.Plugins.FileModel,System.String,System.String)
reversed dependency: @Microsoft.DocAsCode.Plugins.IHostService.ReportDependencyFrom(Microsoft.DocAsCode.Plugins.FileModel,System.String,System.String)
For example, i'd like to report a dependency: file ~/test.md
(filemodel is a
) depends on file ~/../include/token/md
, dependency type is include
,
i could call the method ReportDependencyTo(a, "~/../include/token.md", "include")
.
Plugins are only allowed to report a dependency during Compile
phase. However, some plugins might don't have enough info to resolve some dependency to file until the whole phase completes. Incremental build framework provides the flexiblity that plugins could report dependency between items that are not files and resolve them later.
directed dependency: @Microsoft.DocAsCode.Plugins.IHostService.ReportDependencyTo(Microsoft.DocAsCode.Plugins.FileModel,System.String,System.String,System.String)
reversed dependency: @Microsoft.DocAsCode.Plugins.IHostService.ReportDependencyFrom(Microsoft.DocAsCode.Plugins.FileModel,System.String,System.String,System.String)
report reference: @Microsoft.DocAsCode.Plugins.IHostService.ReportReference(Microsoft.DocAsCode.Plugins.FileModel,System.String,System.String)
A common usage is to report dependency between file and uid.
For example, i'd like to report a dependency: file ~/test.md
(filemodel is a
) depends on sentenceId @Testid(filemodel is b
), dependency type is link
,
i could call the method ReportDependencyTo(a, "Testid", "sentenceId", "link")
to report the dependency and ReportReference(b, "Testid", "sentenceId")
to report the mapping between sentenceId and file. This way, the framework would do the resolution work and resolve it to file-file dependency.


Demo - jquery-simple-datetimepicker
Inline
Append to Input-field
Append to Input-field (Inline)
In addition, this default date has specified by the input's value ("2012-01-01 10:00").
Avaiable options
About details for these options, please see: Wiki.
Current date ("current": "2012-3-4 12:30")
dateFormat ("dateFormat": "YY/MM/DD h:m")
locale ("locale": "ja")
Available locales:
- "en" : English (default)
- "ja" : Japanese
- "ru" : Russian - Thanks to: rdolgushin
- "br" : Brazil - Thanks to: Mauricio
- "cn" : Chinese - Thanks to: jasonslyvia
- "de" : German - Thanks to: rtakeda
- "sv" : Swedish - Thanks to: MacDknife
- "id" : Bahasa Indonesia - Thanks to: robzlabz
- "tr" : Turkish - Thanks to: myfell
- "es" : Spanish - Thanks to: maw
- "ko" : Korean - Thanks to: perhapsspy
- "pt" : Portuguese - Thanks to: adc-tcarvalho
- "nl" : Dutch (Naderlands) - Thanks to: Mondane
- "cz" : Czech - Thanks to: Jan Zatloukal
- "fr" : French - Thanks to: matll42
- "it" : Italian - Thanks to: Mauro Zuccato
Change the interval of minute ("minuteInterval": 15)
Avaiable value:
min: 5, max: 30. (default: 30 minute. it means interval of each 30 minute.)
Change the first day of the week ("firstDayOfWeek": 1)
Avaiable value:
min: 0 (sunday), max: 6 (satday), default: 0 (sunday).
Thanks to: concept1hundred.
Close when selected date & time ("closeOnSelected": true) with append to Input-field mode
It's will also useful for use with two input-fields.
-
Disable the automatic scroll of time-list ("timelistScroll": false)
Disable the fade animation ("animation": false)
Disable the calendar scroll with mouse wheel ("calendarMouseScroll": false)
Disable the Today button ("todayButton": false)
Date-only mode ("dateOnly": true)
Only allow future datetimes ("futureOnly": true)
Date Ranges (not compatible with 'inline:true' at this time)


Why is it that you can feel sad up to 240 times longer than you do feeling ashamed, surprised, irritated or even bored? It's because sadness often goes hand in hand with events of greater impact such as death or accidents. You need more time to mull over and cope with what happened to fully comprehend it, say Philippe Verduyn and Saskia Lavrijsen of the University of Leuven in Belgium. Their research, published in Springer's journal Motivation and Emotion, is the first to provide clear evidence to explain why some emotions last a longer time than others.
The Belgian researchers asked 233 high school students to recollect recent emotional episodes and report their duration. The participants also had to answer questions about the strategies they use to appraise and deal with these emotions.
Meaningful differences in duration were indeed found to exist between emotions. Out of a set of 27 emotions, sadness lasted the longest, whereas shame, surprise, fear, disgust, boredom, being touched, irritated or feeling relief were often over in a flash. Interestingly enough, boredom also counts among the shorter emotions experienced. Verduyn and Lavrijsen say that this means that even though time seems to pass slowly when one is bored, an episode of boredom typically doesn't last that long.
The researchers discovered that emotions that last a shorter time are typically elicited by events that have relatively low importance attached to them. On the other hand, long-lasting emotions tend to be caused by events that have strong implications for a person's major concerns. Verduyn says some of these implications may only become apparent over time, which then causes the emotion to be maintained or strengthened. The feeling therefore endures while a person rethinks the events and consequences over and over again.
Duration was found to be a dimension that can differentiate between otherwise very similar emotions. For instance, Verduyn and Lavrijsen found that guilt is an emotion that persists much longer than shame, while anxiety lingers longer than fear.
"Rumination is the central determinant of why some emotions last longer than others. Emotions associated with high levels of rumination will last longest," says Verduyn, explaining the role that such constant and repetitive thinking has on the experience of positive and negative emotions.
"Emotions of shorter duration are typically – but, of course, not always – elicited by events of relatively low importance. On the other hand, long-lasting emotions tend to be about something highly important," Lavrijsen explains further.


In the past, salvia had been a great meditative assistant and served to sustain a positive outlook on life. Ripping a couple hits off a bong usually resulted in the laughy, ethereal feeling. It wasnt a substitute for anything else, though.
After school, on a beautiful september afternoon in kansas, a friend had invited a large number of people over. I could not smoke any bud, barring a blood test in the next week, so I brought along a sack of salvia. My friend came with, bringing along a 4 chambered, large capacity bong. Sitting on a 2nd story deck, several gathered around the contraption and smoked. After watching them, slighty jealous, I pulled out the Salvia. A bowl was loaded to the brim and ready to be taken. I had never tried smoking it out of this before, and was anxious to see what happened.
I took my first hit, held it in, and before taking my next breath, exhaled, immediately milked the bong afterwards. The next hit came and went, and the too familiar 'weight' began pressing in on me. I went to take a third hit but before I even could put face near the pipe, I felt a loss of control. I dropped down to the ground, and slouched back against the wall. I could hear people asking if I was ok, but I had no concern for that and the sounds hit me and seemed to mute off into the distance.
My visual field blurred and large coloured dots began floating around. Rainbows fluttered up through the cracks in the decks slant pattern woodwork. There were people there with no faces, coming and going as if in another dimension. My thoughts raced and I realized mysteries so complex that nothing in reality compared to them. I forgot everything I came up with almost instantly though, yet I was aware that I couldn't remember them. I felt as if my soul unattached from my body, and I lay in a dream state. It was not so much a lucid dream, as a realm that the conscious is involved in the subconcious's doings and undoings. My body is merely a vessel, and my soul roamed freeeee! Time, hearing, taste, sight, all perceptions no longer meant anything.
Personally, I am not sure how or if I even could estimate how long I was in this alternate reality. When I returned to base, it had only been 3 minutes, according to the people around me. The afterglow of this drug is amazing. Truly an amazing and very often misinterpreted entheogen.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


Kindy provide a destination a destination port so that we can give you a price
Country
Bacon
Black Olives
Extra Cheese
Mushrooms
Pepperoni
Sausage
Port
Bacon
Black Olives
Extra Cheese
Mushrooms
Pepperoni
Sausage
Prices are al indictive until contract is signed


Elizabeth Katkin
Democrat
General Counsel, LDK Logistics, Inc.
Yale College, BA, 1989; Columbia University School of International and Public Affairs, Master of International Affairs, 1992; Columbia University School of Law, JD, 1995
80113
I have held fundraisers and participated in get out the vote activities for Democratic candidates at the state and federal level. In 2016, I donated to Hillary Clinton and was a member of the Clinton regional finance team. In 2020, I donated to Joe Biden and was a member of Lawyers for Biden and Women for Biden. I have donated to the campaigns of Michael Bennet, John Hickenlooper, Phil Weiser, Chris Hansen. I have also donated to Move On, Act Blue, and a number of out of state candidates, including Amy McGrath and Sara Gideon. I served as a volunteer election watcher in the 2020 election.
Colorado Ballet, Trustee (2012-present); Co-Chair of the Board of Trustees (2015-2019) Civico, Member since 2019, Governor's Fellowship (2019-2020) Cherry Hills Village Elementary PTCO, Treasurer (2016-2018) Lawyers for Good Government, volunteer lawyer (2016-present) Columbia University, School of Public and International Affairs, Member, Alumni Advisory Board (2011-2017) Food Bank of the Rockies, volunteer, 2020
While I have not had a formal role in advocacy work in Colorado, as an author of a nonfiction book, lawyer, and former fertility patient of many years, I participated in advocacy in conjunction with Colorado Fertility Associates and RESOLVE on behalf of the Colorado Family Building Act, which passed last year. Also, through my long-term service on the board, and particularly as Chair, of Colorado Ballet, I ha e advocated for the arts in general and for expanding both artistic and audience reach with respect to age, income and ethnic diversity.
I have had a longstanding interest in government and public service, and have always had a passion for justice. While my career path has not yet led me to work full time in public service, I have tried to contribute to civic life where I can through board service, pro bono legal work, and volunteering. I believe that ensuring that districts are drawn fairly and in such a way as to ensure that every individual is fairly represented is a fundamental aspect of democracy.
I have been a lawyer for nearly twenty-five years and I believe that the majority of my colleagues and clients would say that my greatest asset to them as a lawyer is my negotiating and mediating skills. I pursued corporate law rather than litigation because I do not like to fight, and I think that most conflict can be resolved by understanding the perspective and goals of the counterparty and trying to reach reasonable compromises. While I may hold firm views, I generally try to explain and persuade, rather than argue or steamroll. I have served as a moot court judge, and have experience with weighing facts and arguments and coming to decisions that my not align with my personal views, and I am confident in my ability to be fair and impartial. In addition, my role as a board chair enhanced my experience in navigating a large board comprised of trustees with a diversity of opinions and political views.
In my work as a lawyer both representing clients and as in-house general counsel, I am often called upon to analyze questions of law and or fact. Whether in the process of negotiating a deal, or figuring out a fair resolution when a deal has not gone as planned, I regularly face the challenge of analyzing a problem and presenting proposed solutions. I am very confident in my ability to both reason through and negotiate a fair compromise, even in situations where there is seemingly little common ground.
female


All Classes
AbstractHookQueue
AbstractHookRunner
HookRequest
InMemoryQueue
Publisher
SequentialHookRunner


After you have declared the options that the Zend\Console\Getopt object should recognize, and supply arguments from the command-line or an array, you can query the object to find out which options were specified by a user in a given command-line invocation of your program. The class implements magic methods so you can query for options by name.
The parsing of the data is deferred until the first query you make against the Zend\Console\Getopt object to find out if an option was given, the object performs its parsing. This allows you to use several method calls to configure the options, arguments, help strings, and configuration options before parsing takes place.
If the user gave any invalid options on the command-line, the parsing function throws a Zend\Console\Getopt\Exception. You should catch this exception in your application code. You can use the parse() method to force the object to parse the arguments. This is useful because you can invoke parse() in a try block. If it passes, you can be sure that the parsing won’t throw an exception again. The exception thrown has a custom method getUsageMessage(), which returns as a string the formatted set of usage messages for all declared options.
Catching Getopt Exceptions
1 2 3 4 5 6 7 | try {
$opts = new Zend\Console\Getopt('abp:');
$opts->parse();
} catch (Zend\Console\Getopt\Exception $e) {
echo $e->getUsageMessage();
exit;
}
|
Cases where parsing throws an exception include:
You can use the getOption() method to query the value of an option. If the option had a parameter, this method returns the value of the parameter. If the option had no parameter but the user did specify it on the command-line, the method returns TRUE. Otherwise the method returns NULL.
Using getOption()
1 2 3 | $opts = new Zend\Console\Getopt('abp:');
$b = $opts->getOption('b');
$p_parameter = $opts->getOption('p');
|
Alternatively, you can use the magic __get() function to retrieve the value of an option as if it were a class member variable. The __isset() magic method is also implemented.
Using __get() and __isset() Magic Methods
1 2 3 4 5 | $opts = new Zend\Console\Getopt('abp:');
if (isset($opts->b)) {
echo "I got the b option.\n";
}
$p_parameter = $opts->p; // null if not set
|
If your options are declared with aliases, you may use any of the aliases for an option in the methods above.
There are several methods to report the full set of options given by the user on the current command-line.
In all of the above dumping methods, the flag string is the first string in the corresponding list of aliases. For example, if the option aliases were declared like verbose|v, then the first string, verbose, is used as the canonical name of the option. The name of the option flag does not include any preceding dashes.
After option arguments and their parameters have been parsed from the command-line, there may be additional arguments remaining. You can query these arguments using the getRemainingArgs() method. This method returns an array of the strings that were not part of any options.
Using getRemainingArgs()
1 2 3 | $opts = new Zend\Console\Getopt('abp:');
$opts->setArguments(array('-p', 'p_parameter', 'filename'));
$args = $opts->getRemainingArgs(); // returns array('filename')
|
Zend\Console\Getopt supports the GNU convention that an argument consisting of a double-dash signifies the end of options. Any arguments following this signifier must be treated as non-option arguments. This is useful if you might have a non-option argument that begins with a dash. For example: “rm -- -filename-with-dash”.
The source code of this file is hosted on GitHub. Everyone can update and fix errors in this document with few clicks - no downloads needed.