'use strict';

const chai = require('chai'),
  expect = chai.expect,
  Support = require('../../support'),
  Sequelize = Support.Sequelize,
  Op = Sequelize.Op,
  dialect = Support.getTestDialect(),
  DataTypes = require('sequelize/lib/data-types'),
  sequelize = require('sequelize/lib/sequelize');

if (dialect.match(/^postgres/)) {
  describe('[POSTGRES Specific] DAO', () => {
    beforeEach(async function() {
      this.sequelize.options.quoteIdentifiers = true;
      this.User = this.sequelize.define('User', {
        username: DataTypes.STRING,
        email: { type: DataTypes.ARRAY(DataTypes.TEXT) },
        settings: DataTypes.HSTORE,
        document: { type: DataTypes.HSTORE, defaultValue: { default: "'value'" } },
        phones: DataTypes.ARRAY(DataTypes.HSTORE),
        emergency_contact: DataTypes.JSON,
        emergencyContact: DataTypes.JSON,
        friends: {
          type: DataTypes.ARRAY(DataTypes.JSON),
          defaultValue: []
        },
        magic_numbers: {
          type: DataTypes.ARRAY(DataTypes.INTEGER),
          defaultValue: []
        },
        course_period: DataTypes.RANGE(DataTypes.DATE),
        acceptable_marks: { type: DataTypes.RANGE(DataTypes.DECIMAL), defaultValue: [0.65, 1] },
        available_amount: DataTypes.RANGE,
        holidays: DataTypes.ARRAY(DataTypes.RANGE(DataTypes.DATE)),
        location: DataTypes.GEOMETRY()
      });
      await this.User.sync({ force: true });
    });

    afterEach(function() {
      this.sequelize.options.quoteIdentifiers = true;
    });

    it('should be able to search within an array', async function() {
      await this.User.findAll({
        where: {
          email: ['hello', 'world']
        },
        attributes: ['id', 'username', 'email', 'settings', 'document', 'phones', 'emergency_contact', 'friends'],
        logging(sql) {
          expect(sql).to.equal('Executing (default): SELECT "id", "username", "email", "settings", "document", "phones", "emergency_contact", "friends" FROM "Users" AS "User" WHERE "User"."email" = ARRAY[\'hello\',\'world\']::TEXT[];');
        }
      });
    });

    it('should be able to update a field with type ARRAY(JSON)', async function() {
      const userInstance = await this.User.create({
        username: 'bob',
        email: ['myemail@email.com'],
        friends: [{
          name: 'John Smith'
        }]
      });

      expect(userInstance.friends).to.have.length(1);
      expect(userInstance.friends[0].name).to.equal('John Smith');

      const obj = await userInstance.update({
        friends: [{
          name: 'John Smythe'
        }]
      });

      const friends = await obj['friends'];
      expect(friends).to.have.length(1);
      expect(friends[0].name).to.equal('John Smythe');
      await friends;
    });

    it('should be able to find a record while searching in an array', async function() {
      await this.User.bulkCreate([
        { username: 'bob', email: ['myemail@email.com'] },
        { username: 'tony', email: ['wrongemail@email.com'] }
      ]);

      const user = await this.User.findAll({ where: { email: ['myemail@email.com'] } });
      expect(user).to.be.instanceof(Array);
      expect(user).to.have.length(1);
      expect(user[0].username).to.equal('bob');
    });

    describe('json', () => {
      it('should be able to retrieve a row with ->> operator', async function() {
        await Promise.all([
          this.User.create({ username: 'swen', emergency_contact: { name: 'kate' } }),
          this.User.create({ username: 'anna', emergency_contact: { name: 'joe' } })]);

        const user = await this.User.findOne({ where: sequelize.json("emergency_contact->>'name'", 'kate'), attributes: ['username', 'emergency_contact'] });
        expect(user.emergency_contact.name).to.equal('kate');
      });

      it('should be able to query using the nested query language', async function() {
        await Promise.all([
          this.User.create({ username: 'swen', emergency_contact: { name: 'kate' } }),
          this.User.create({ username: 'anna', emergency_contact: { name: 'joe' } })]);

        const user = await this.User.findOne({
          where: sequelize.json({ emergency_contact: { name: 'kate' } })
        });

        expect(user.emergency_contact.name).to.equal('kate');
      });

      it('should be able to query using dot syntax', async function() {
        await Promise.all([
          this.User.create({ username: 'swen', emergency_contact: { name: 'kate' } }),
          this.User.create({ username: 'anna', emergency_contact: { name: 'joe' } })]);

        const user = await this.User.findOne({ where: sequelize.json('emergency_contact.name', 'joe') });
        expect(user.emergency_contact.name).to.equal('joe');
      });

      it('should be able to query using dot syntax with uppercase name', async function() {
        await Promise.all([
          this.User.create({ username: 'swen', emergencyContact: { name: 'kate' } }),
          this.User.create({ username: 'anna', emergencyContact: { name: 'joe' } })]);

        const user = await this.User.findOne({
          attributes: [[sequelize.json('emergencyContact.name'), 'contactName']],
          where: sequelize.json('emergencyContact.name', 'joe')
        });

        expect(user.get('contactName')).to.equal('joe');
      });

      it('should be able to store values that require JSON escaping', async function() {
        const text = "Multi-line '$string' needing \"escaping\" for $$ and $1 type values";

        const user0 = await this.User.create({ username: 'swen', emergency_contact: { value: text } });
        expect(user0.isNewRecord).to.equal(false);
        await this.User.findOne({ where: { username: 'swen' } });
        const user = await this.User.findOne({ where: sequelize.json('emergency_contact.value', text) });
        expect(user.username).to.equal('swen');
      });

      it('should be able to findOrCreate with values that require JSON escaping', async function() {
        const text = "Multi-line '$string' needing \"escaping\" for $$ and $1 type values";

        const user0 = await this.User.findOrCreate({ where: { username: 'swen' }, defaults: { emergency_contact: { value: text } } });
        expect(!user0.isNewRecord).to.equal(true);
        await this.User.findOne({ where: { username: 'swen' } });
        const user = await this.User.findOne({ where: sequelize.json('emergency_contact.value', text) });
        expect(user.username).to.equal('swen');
      });
    });

    describe('hstore', () => {
      it('should tell me that a column is hstore and not USER-DEFINED', async function() {
        const table = await this.sequelize.queryInterface.describeTable('Users');
        expect(table.settings.type).to.equal('HSTORE');
        expect(table.document.type).to.equal('HSTORE');
      });

      it('should NOT stringify hstore with insert', async function() {
        await this.User.create({
          username: 'bob',
          email: ['myemail@email.com'],
          settings: { mailing: false, push: 'facebook', frequency: 3 }
        }, {
          logging(sql) {
            const unexpected = '\'"mailing"=>"false","push"=>"facebook","frequency"=>"3"\',\'"default"=>"\'\'value\'\'"\'';
            expect(sql).not.to.include(unexpected);
          }
        });
      });

      it('should not rename hstore fields', async function() {
        const Equipment = this.sequelize.define('Equipment', {
          grapplingHook: {
            type: DataTypes.STRING,
            field: 'grappling_hook'
          },
          utilityBelt: {
            type: DataTypes.HSTORE
          }
        });

        await Equipment.sync({ force: true });

        await Equipment.findAll({
          where: {
            utilityBelt: {
              grapplingHook: true
            }
          },
          logging(sql) {
            expect(sql).to.contains(' WHERE "Equipment"."utilityBelt" = \'"grapplingHook"=>"true"\';');
          }
        });
      });

      it('should not rename json fields', async function() {
        const Equipment = this.sequelize.define('Equipment', {
          grapplingHook: {
            type: DataTypes.STRING,
            field: 'grappling_hook'
          },
          utilityBelt: {
            type: DataTypes.JSON
          }
        });

        await Equipment.sync({ force: true });

        await Equipment.findAll({
          where: {
            utilityBelt: {
              grapplingHook: true
            }
          },
          logging(sql) {
            expect(sql).to.contains(' WHERE CAST(("Equipment"."utilityBelt"#>>\'{grapplingHook}\') AS BOOLEAN) = true;');
          }
        });
      });

    });

    describe('range', () => {
      it('should tell me that a column is range and not USER-DEFINED', async function() {
        const table = await this.sequelize.queryInterface.describeTable('Users');
        expect(table.course_period.type).to.equal('TSTZRANGE');
        expect(table.available_amount.type).to.equal('INT4RANGE');
      });

    });

    describe('enums', () => {
      it('should be able to create enums with escape values', async function() {
        const User = this.sequelize.define('UserEnums', {
          mood: DataTypes.ENUM('happy', 'sad', '1970\'s')
        });

        await User.sync({ force: true });
      });

      it('should be able to ignore enum types that already exist', async function() {
        const User = this.sequelize.define('UserEnums', {
          mood: DataTypes.ENUM('happy', 'sad', 'meh')
        });

        await User.sync({ force: true });

        await User.sync();
      });

      it('should be able to create/drop enums multiple times', async function() {
        const User = this.sequelize.define('UserEnums', {
          mood: DataTypes.ENUM('happy', 'sad', 'meh')
        });

        await User.sync({ force: true });

        await User.sync({ force: true });
      });

      it('should be able to create/drop multiple enums multiple times', async function() {
        const DummyModel = this.sequelize.define('Dummy-pg', {
          username: DataTypes.STRING,
          theEnumOne: {
            type: DataTypes.ENUM,
            values: [
              'one',
              'two',
              'three'
            ]
          },
          theEnumTwo: {
            type: DataTypes.ENUM,
            values: [
              'four',
              'five',
              'six'
            ]
          }
        });

        await DummyModel.sync({ force: true });
        // now sync one more time:
        await DummyModel.sync({ force: true });
        // sync without dropping
        await DummyModel.sync();
      });

      it('should be able to create/drop multiple enums multiple times with field name (#7812)', async function() {
        const DummyModel = this.sequelize.define('Dummy-pg', {
          username: DataTypes.STRING,
          theEnumOne: {
            field: 'oh_my_this_enum_one',
            type: DataTypes.ENUM,
            values: [
              'one',
              'two',
              'three'
            ]
          },
          theEnumTwo: {
            field: 'oh_my_this_enum_two',
            type: DataTypes.ENUM,
            values: [
              'four',
              'five',
              'six'
            ]
          }
        });

        await DummyModel.sync({ force: true });
        // now sync one more time:
        await DummyModel.sync({ force: true });
        // sync without dropping
        await DummyModel.sync();
      });

      it('should be able to add values to enum types', async function() {
        let User = this.sequelize.define('UserEnums', {
          mood: DataTypes.ENUM('happy', 'sad', 'meh')
        });

        await User.sync({ force: true });
        User = this.sequelize.define('UserEnums', {
          mood: DataTypes.ENUM('neutral', 'happy', 'sad', 'ecstatic', 'meh', 'joyful')
        });

        await User.sync();
        const enums = await this.sequelize.getQueryInterface().pgListEnums(User.getTableName());
        expect(enums).to.have.length(1);
        expect(enums[0].enum_value).to.equal('{neutral,happy,sad,ecstatic,meh,joyful}');
      });

      it('should be able to add multiple values with different order', async function() {
        let User = this.sequelize.define('UserEnums', {
          priority: DataTypes.ENUM('1', '2', '6')
        });

        await User.sync({ force: true });
        User = this.sequelize.define('UserEnums', {
          priority: DataTypes.ENUM('0', '1', '2', '3', '4', '5', '6', '7')
        });

        await User.sync();
        const enums = await this.sequelize.getQueryInterface().pgListEnums(User.getTableName());
        expect(enums).to.have.length(1);
        expect(enums[0].enum_value).to.equal('{0,1,2,3,4,5,6,7}');
      });

      describe('ARRAY(ENUM)', () => {
        it('should be able to ignore enum types that already exist', async function() {
          const User = this.sequelize.define('UserEnums', {
            permissions: DataTypes.ARRAY(DataTypes.ENUM([
              'access',
              'write',
              'check',
              'delete'
            ]))
          });

          await User.sync({ force: true });

          await User.sync();
        });

        it('should be able to create/drop enums multiple times', async function() {
          const User = this.sequelize.define('UserEnums', {
            permissions: DataTypes.ARRAY(DataTypes.ENUM([
              'access',
              'write',
              'check',
              'delete'
            ]))
          });

          await User.sync({ force: true });

          await User.sync({ force: true });
        });

        it('should be able to add values to enum types', async function() {
          let User = this.sequelize.define('UserEnums', {
            permissions: DataTypes.ARRAY(DataTypes.ENUM([
              'access',
              'write',
              'check',
              'delete'
            ]))
          });

          await User.sync({ force: true });
          User = this.sequelize.define('UserEnums', {
            permissions: DataTypes.ARRAY(
              DataTypes.ENUM('view', 'access', 'edit', 'write', 'check', 'delete')
            )
          });

          await User.sync();
          const enums = await this.sequelize.getQueryInterface().pgListEnums(User.getTableName());
          expect(enums).to.have.length(1);
          expect(enums[0].enum_value).to.equal('{view,access,edit,write,check,delete}');
        });

        it('should be able to insert new record', async function() {
          const User = this.sequelize.define('UserEnums', {
            name: DataTypes.STRING,
            type: DataTypes.ENUM('A', 'B', 'C'),
            owners: DataTypes.ARRAY(DataTypes.STRING),
            permissions: DataTypes.ARRAY(DataTypes.ENUM([
              'access',
              'write',
              'check',
              'delete'
            ]))
          });

          await User.sync({ force: true });

          const user = await User.create({
            name: 'file.exe',
            type: 'C',
            owners: ['userA', 'userB'],
            permissions: ['access', 'write']
          });

          expect(user.name).to.equal('file.exe');
          expect(user.type).to.equal('C');
          expect(user.owners).to.deep.equal(['userA', 'userB']);
          expect(user.permissions).to.deep.equal(['access', 'write']);
        });

        it('should be able to insert a new record even with a redefined field name', async function() {
          const User = this.sequelize.define('UserEnums', {
            name: DataTypes.STRING,
            type: DataTypes.ENUM('A', 'B', 'C'),
            owners: DataTypes.ARRAY(DataTypes.STRING),
            specialPermissions: {
              type: DataTypes.ARRAY(DataTypes.ENUM([
                'access',
                'write',
                'check',
                'delete'
              ])),
              field: 'special_permissions'
            }
          });

          await User.sync({ force: true });

          const user = await User.bulkCreate([{
            name: 'file.exe',
            type: 'C',
            owners: ['userA', 'userB'],
            specialPermissions: ['access', 'write']
          }]);

          expect(user.length).to.equal(1);
        });

        it('should fail when trying to insert foreign element on ARRAY(ENUM)', async function() {
          const User = this.sequelize.define('UserEnums', {
            name: DataTypes.STRING,
            type: DataTypes.ENUM('A', 'B', 'C'),
            owners: DataTypes.ARRAY(DataTypes.STRING),
            permissions: DataTypes.ARRAY(DataTypes.ENUM([
              'access',
              'write',
              'check',
              'delete'
            ]))
          });

          await expect(User.sync({ force: true }).then(() => {
            return User.create({
              name: 'file.exe',
              type: 'C',
              owners: ['userA', 'userB'],
              permissions: ['cosmic_ray_disk_access']
            });
          })).to.be.rejectedWith(/invalid input value for enum "enum_UserEnums_permissions": "cosmic_ray_disk_access"/);
        });

        it('should be able to find records', async function() {
          const User = this.sequelize.define('UserEnums', {
            name: DataTypes.STRING,
            type: DataTypes.ENUM('A', 'B', 'C'),
            permissions: DataTypes.ARRAY(DataTypes.ENUM([
              'access',
              'write',
              'check',
              'delete'
            ]))
          });

          await User.sync({ force: true });

          await User.bulkCreate([{
            name: 'file1.exe',
            type: 'C',
            permissions: ['access', 'write']
          }, {
            name: 'file2.exe',
            type: 'A',
            permissions: ['access', 'check']
          }, {
            name: 'file3.exe',
            type: 'B',
            permissions: ['access', 'write', 'delete']
          }]);

          const users = await User.findAll({
            where: {
              type: {
                [Op.in]: ['A', 'C']
              },
              permissions: {
                [Op.contains]: ['write']
              }
            }
          });

          expect(users.length).to.equal(1);
          expect(users[0].name).to.equal('file1.exe');
          expect(users[0].type).to.equal('C');
          expect(users[0].permissions).to.deep.equal(['access', 'write']);
        });
      });
    });

    describe('integers', () => {
      describe('integer', () => {
        beforeEach(async function() {
          this.User = this.sequelize.define('User', {
            aNumber: DataTypes.INTEGER
          });

          await this.User.sync({ force: true });
        });

        it('positive', async function() {
          const User = this.User;

          const user = await User.create({ aNumber: 2147483647 });
          expect(user.aNumber).to.equal(2147483647);
          const _user = await User.findOne({ where: { aNumber: 2147483647 } });
          expect(_user.aNumber).to.equal(2147483647);
        });

        it('negative', async function() {
          const User = this.User;

          const user = await User.create({ aNumber: -2147483647 });
          expect(user.aNumber).to.equal(-2147483647);
          const _user = await User.findOne({ where: { aNumber: -2147483647 } });
          expect(_user.aNumber).to.equal(-2147483647);
        });
      });

      describe('bigint', () => {
        beforeEach(async function() {
          this.User = this.sequelize.define('User', {
            aNumber: DataTypes.BIGINT
          });

          await this.User.sync({ force: true });
        });

        it('positive', async function() {
          const User = this.User;

          const user = await User.create({ aNumber: '9223372036854775807' });
          expect(user.aNumber).to.equal('9223372036854775807');
          const _user = await User.findOne({ where: { aNumber: '9223372036854775807' } });
          expect(_user.aNumber).to.equal('9223372036854775807');
        });

        it('negative', async function() {
          const User = this.User;

          const user = await User.create({ aNumber: '-9223372036854775807' });
          expect(user.aNumber).to.equal('-9223372036854775807');
          const _user = await User.findOne({ where: { aNumber: '-9223372036854775807' } });
          expect(_user.aNumber).to.equal('-9223372036854775807');
        });
      });
    });

    describe('timestamps', () => {
      beforeEach(async function() {
        this.User = this.sequelize.define('User', {
          dates: DataTypes.ARRAY(DataTypes.DATE)
        });
        await this.User.sync({ force: true });
      });

      it('should use bind params instead of "TIMESTAMP WITH TIME ZONE"', async function() {
        await this.User.create({
          dates: []
        }, {
          logging(sql) {
            expect(sql).not.to.contain('TIMESTAMP WITH TIME ZONE');
            expect(sql).not.to.contain('DATETIME');
          }
        });
      });
    });

    describe('model', () => {
      it('create handles array correctly', async function() {
        const oldUser = await this.User
          .create({ username: 'user', email: ['foo@bar.com', 'bar@baz.com'] });

        expect(oldUser.email).to.contain.members(['foo@bar.com', 'bar@baz.com']);
      });

      it('should save hstore correctly', async function() {
        const newUser = await this.User.create({ username: 'user', email: ['foo@bar.com'], settings: { created: '"value"' } });
        // Check to see if the default value for an hstore field works
        expect(newUser.document).to.deep.equal({ default: "'value'" });
        expect(newUser.settings).to.deep.equal({ created: '"value"' });

        // Check to see if updating an hstore field works
        const oldUser = await newUser.update({ settings: { should: 'update', to: 'this', first: 'place' } });
        // Postgres always returns keys in alphabetical order (ascending)
        expect(oldUser.settings).to.deep.equal({ first: 'place', should: 'update', to: 'this' });
      });

      it('should save hstore array correctly', async function() {
        const User = this.User;

        await this.User.create({
          username: 'bob',
          email: ['myemail@email.com'],
          phones: [{ number: '123456789', type: 'mobile' }, { number: '987654321', type: 'landline' }, { number: '8675309', type: "Jenny's" }, { number: '5555554321', type: '"home\n"' }]
        });

        const user = await User.findByPk(1);
        expect(user.phones.length).to.equal(4);
        expect(user.phones[1].number).to.equal('987654321');
        expect(user.phones[2].type).to.equal("Jenny's");
        expect(user.phones[3].type).to.equal('"home\n"');
      });

      it('should bulkCreate with hstore property', async function() {
        const User = this.User;

        await this.User.bulkCreate([{
          username: 'bob',
          email: ['myemail@email.com'],
          settings: { mailing: true, push: 'facebook', frequency: 3 }
        }]);

        const user = await User.findByPk(1);
        expect(user.settings.mailing).to.equal('true');
      });

      it('should update hstore correctly', async function() {
        const newUser = await this.User.create({ username: 'user', email: ['foo@bar.com'], settings: { test: '"value"' } });
        // Check to see if the default value for an hstore field works
        expect(newUser.document).to.deep.equal({ default: "'value'" });
        expect(newUser.settings).to.deep.equal({ test: '"value"' });

        // Check to see if updating an hstore field works
        await this.User.update({ settings: { should: 'update', to: 'this', first: 'place' } }, { where: newUser.where() });
        await newUser.reload();
        // Postgres always returns keys in alphabetical order (ascending)
        expect(newUser.settings).to.deep.equal({ first: 'place', should: 'update', to: 'this' });
      });

      it('should update hstore correctly and return the affected rows', async function() {
        const oldUser = await this.User.create({ username: 'user', email: ['foo@bar.com'], settings: { test: '"value"' } });
        // Update the user and check that the returned object's fields have been parsed by the hstore library
        const [count, users] = await this.User.update({ settings: { should: 'update', to: 'this', first: 'place' } }, { where: oldUser.where(), returning: true });
        expect(count).to.equal(1);
        expect(users[0].settings).to.deep.equal({ should: 'update', to: 'this', first: 'place' });
      });

      it('should read hstore correctly', async function() {
        const data = { username: 'user', email: ['foo@bar.com'], settings: { test: '"value"' } };

        await this.User.create(data);
        const user = await this.User.findOne({ where: { username: 'user' } });
        // Check that the hstore fields are the same when retrieving the user
        expect(user.settings).to.deep.equal(data.settings);
      });

      it('should read an hstore array correctly', async function() {
        const data = { username: 'user', email: ['foo@bar.com'], phones: [{ number: '123456789', type: 'mobile' }, { number: '987654321', type: 'landline' }] };

        await this.User.create(data);
        // Check that the hstore fields are the same when retrieving the user
        const user = await this.User.findOne({ where: { username: 'user' } });
        expect(user.phones).to.deep.equal(data.phones);
      });

      it('should read hstore correctly from multiple rows', async function() {
        await this.User
          .create({ username: 'user1', email: ['foo@bar.com'], settings: { test: '"value"' } });

        await this.User.create({ username: 'user2', email: ['foo2@bar.com'], settings: { another: '"example"' } });
        // Check that the hstore fields are the same when retrieving the user
        const users = await this.User.findAll({ order: ['username'] });
        expect(users[0].settings).to.deep.equal({ test: '"value"' });
        expect(users[1].settings).to.deep.equal({ another: '"example"' });
      });

      it('should read hstore correctly from included models as well', async function() {
        const HstoreSubmodel = this.sequelize.define('hstoreSubmodel', {
          someValue: DataTypes.HSTORE
        });
        const submodelValue = { testing: '"hstore"' };

        this.User.hasMany(HstoreSubmodel);

        await this.sequelize
          .sync({ force: true });

        const user0 = await this.User.create({ username: 'user1' });
        const submodel = await HstoreSubmodel.create({ someValue: submodelValue });
        await user0.setHstoreSubmodels([submodel]);
        const user = await this.User.findOne({ where: { username: 'user1' }, include: [HstoreSubmodel] });
        expect(user.hasOwnProperty('hstoreSubmodels')).to.be.ok;
        expect(user.hstoreSubmodels.length).to.equal(1);
        expect(user.hstoreSubmodels[0].someValue).to.deep.equal(submodelValue);
      });

      it('should save range correctly', async function() {
        const period = [new Date(2015, 0, 1), new Date(2015, 11, 31)];
        const newUser = await this.User.create({ username: 'user', email: ['foo@bar.com'], course_period: period });
        // Check to see if the default value for a range field works

        expect(newUser.acceptable_marks.length).to.equal(2);
        expect(newUser.acceptable_marks[0].value).to.equal('0.65'); // lower bound
        expect(newUser.acceptable_marks[1].value).to.equal('1'); // upper bound
        expect(newUser.acceptable_marks[0].inclusive).to.deep.equal(true); // inclusive
        expect(newUser.acceptable_marks[1].inclusive).to.deep.equal(false); // exclusive
        expect(newUser.course_period[0].value instanceof Date).to.be.ok; // lower bound
        expect(newUser.course_period[1].value instanceof Date).to.be.ok; // upper bound
        expect(newUser.course_period[0].value).to.equalTime(period[0]); // lower bound
        expect(newUser.course_period[1].value).to.equalTime(period[1]); // upper bound
        expect(newUser.course_period[0].inclusive).to.deep.equal(true); // inclusive
        expect(newUser.course_period[1].inclusive).to.deep.equal(false); // exclusive

        // Check to see if updating a range field works
        await newUser.update({ acceptable_marks: [0.8, 0.9] });
        await newUser.reload(); // Ensure the acceptable_marks array is loaded with the complete range definition
        expect(newUser.acceptable_marks.length).to.equal(2);
        expect(newUser.acceptable_marks[0].value).to.equal('0.8'); // lower bound
        expect(newUser.acceptable_marks[1].value).to.equal('0.9'); // upper bound
      });

      it('should save range array correctly', async function() {
        const User = this.User;
        const holidays = [
          [new Date(2015, 3, 1), new Date(2015, 3, 15)],
          [new Date(2015, 8, 1), new Date(2015, 9, 15)]
        ];

        await User.create({
          username: 'bob',
          email: ['myemail@email.com'],
          holidays
        });

        const user = await User.findByPk(1);
        expect(user.holidays.length).to.equal(2);
        expect(user.holidays[0].length).to.equal(2);
        expect(user.holidays[0][0].value instanceof Date).to.be.ok;
        expect(user.holidays[0][1].value instanceof Date).to.be.ok;
        expect(user.holidays[0][0].value).to.equalTime(holidays[0][0]);
        expect(user.holidays[0][1].value).to.equalTime(holidays[0][1]);
        expect(user.holidays[1].length).to.equal(2);
        expect(user.holidays[1][0].value instanceof Date).to.be.ok;
        expect(user.holidays[1][1].value instanceof Date).to.be.ok;
        expect(user.holidays[1][0].value).to.equalTime(holidays[1][0]);
        expect(user.holidays[1][1].value).to.equalTime(holidays[1][1]);
      });

      it('should bulkCreate with range property', async function() {
        const User = this.User;
        const period = [new Date(2015, 0, 1), new Date(2015, 11, 31)];

        await User.bulkCreate([{
          username: 'bob',
          email: ['myemail@email.com'],
          course_period: period
        }]);

        const user = await User.findByPk(1);
        expect(user.course_period[0].value instanceof Date).to.be.ok;
        expect(user.course_period[1].value instanceof Date).to.be.ok;
        expect(user.course_period[0].value).to.equalTime(period[0]);  // lower bound
        expect(user.course_period[1].value).to.equalTime(period[1]);  // upper bound
        expect(user.course_period[0].inclusive).to.deep.equal(true);  // inclusive
        expect(user.course_period[1].inclusive).to.deep.equal(false); // exclusive
      });

      it('should update range correctly', async function() {
        const User = this.User;
        const period = [new Date(2015, 0, 1), new Date(2015, 11, 31)];

        const newUser = await User.create({ username: 'user', email: ['foo@bar.com'], course_period: period });
        // Check to see if the default value for a range field works
        expect(newUser.acceptable_marks.length).to.equal(2);
        expect(newUser.acceptable_marks[0].value).to.equal('0.65'); // lower bound
        expect(newUser.acceptable_marks[1].value).to.equal('1'); // upper bound
        expect(newUser.acceptable_marks[0].inclusive).to.deep.equal(true); // inclusive
        expect(newUser.acceptable_marks[1].inclusive).to.deep.equal(false); // exclusive
        expect(newUser.course_period[0].value instanceof Date).to.be.ok;
        expect(newUser.course_period[1].value instanceof Date).to.be.ok;
        expect(newUser.course_period[0].value).to.equalTime(period[0]); // lower bound
        expect(newUser.course_period[1].value).to.equalTime(period[1]); // upper bound
        expect(newUser.course_period[0].inclusive).to.deep.equal(true);  // inclusive
        expect(newUser.course_period[1].inclusive).to.deep.equal(false); // exclusive

        const period2 = [new Date(2015, 1, 1), new Date(2015, 10, 30)];

        // Check to see if updating a range field works
        await User.update({ course_period: period2 }, { where: newUser.where() });
        await newUser.reload();
        expect(newUser.course_period[0].value instanceof Date).to.be.ok;
        expect(newUser.course_period[1].value instanceof Date).to.be.ok;
        expect(newUser.course_period[0].value).to.equalTime(period2[0]); // lower bound
        expect(newUser.course_period[1].value).to.equalTime(period2[1]); // upper bound
        expect(newUser.course_period[0].inclusive).to.deep.equal(true);  // inclusive
        expect(newUser.course_period[1].inclusive).to.deep.equal(false); // exclusive
      });

      it('should update range correctly and return the affected rows', async function() {
        const User = this.User;
        const period = [new Date(2015, 1, 1), new Date(2015, 10, 30)];

        const oldUser = await User.create({
          username: 'user',
          email: ['foo@bar.com'],
          course_period: [new Date(2015, 0, 1), new Date(2015, 11, 31)]
        });

        // Update the user and check that the returned object's fields have been parsed by the range parser
        const [count, users] = await User.update({ course_period: period }, { where: oldUser.where(), returning: true });
        expect(count).to.equal(1);
        expect(users[0].course_period[0].value instanceof Date).to.be.ok;
        expect(users[0].course_period[1].value instanceof Date).to.be.ok;
        expect(users[0].course_period[0].value).to.equalTime(period[0]); // lower bound
        expect(users[0].course_period[1].value).to.equalTime(period[1]); // upper bound
        expect(users[0].course_period[0].inclusive).to.deep.equal(true);  // inclusive
        expect(users[0].course_period[1].inclusive).to.deep.equal(false); // exclusive
      });

      it('should read range correctly', async function() {
        const User = this.User;

        const course_period = [{ value: new Date(2015, 1, 1), inclusive: false }, { value: new Date(2015, 10, 30), inclusive: false }];

        const data = { username: 'user', email: ['foo@bar.com'], course_period };

        await User.create(data);
        const user = await User.findOne({ where: { username: 'user' } });
        // Check that the range fields are the same when retrieving the user
        expect(user.course_period).to.deep.equal(data.course_period);
      });

      it('should read range array correctly', async function() {
        const User = this.User;
        const holidays = [
          [{ value: new Date(2015, 3, 1, 10), inclusive: true }, { value: new Date(2015, 3, 15), inclusive: true }],
          [{ value: new Date(2015, 8, 1), inclusive: true }, { value: new Date(2015, 9, 15), inclusive: true }]
        ];
        const data = { username: 'user', email: ['foo@bar.com'], holidays };

        await User.create(data);
        // Check that the range fields are the same when retrieving the user
        const user = await User.findOne({ where: { username: 'user' } });
        expect(user.holidays).to.deep.equal(data.holidays);
      });

      it('should read range correctly from multiple rows', async function() {
        const User = this.User;
        const periods = [
          [new Date(2015, 0, 1), new Date(2015, 11, 31)],
          [new Date(2016, 0, 1), new Date(2016, 11, 31)]
        ];

        await User
          .create({ username: 'user1', email: ['foo@bar.com'], course_period: periods[0] });

        await User.create({ username: 'user2', email: ['foo2@bar.com'], course_period: periods[1] });
        // Check that the range fields are the same when retrieving the user
        const users = await User.findAll({ order: ['username'] });
        expect(users[0].course_period[0].value).to.equalTime(periods[0][0]); // lower bound
        expect(users[0].course_period[1].value).to.equalTime(periods[0][1]); // upper bound
        expect(users[0].course_period[0].inclusive).to.deep.equal(true); // inclusive
        expect(users[0].course_period[1].inclusive).to.deep.equal(false); // exclusive
        expect(users[1].course_period[0].value).to.equalTime(periods[1][0]); // lower bound
        expect(users[1].course_period[1].value).to.equalTime(periods[1][1]); // upper bound
        expect(users[1].course_period[0].inclusive).to.deep.equal(true); // inclusive
        expect(users[1].course_period[1].inclusive).to.deep.equal(false); // exclusive
      });

      it('should read range correctly from included models as well', async function() {
        const period = [new Date(2016, 0, 1), new Date(2016, 11, 31)];
        const HolidayDate = this.sequelize.define('holidayDate', {
          period: DataTypes.RANGE(DataTypes.DATE)
        });

        this.User.hasMany(HolidayDate);

        await this.sequelize
          .sync({ force: true });

        const user0 = await this.User
          .create({ username: 'user', email: ['foo@bar.com'] });

        const holidayDate = await HolidayDate.create({ period });
        await user0.setHolidayDates([holidayDate]);
        const user = await this.User.findOne({ where: { username: 'user' }, include: [HolidayDate] });
        expect(user.hasOwnProperty('holidayDates')).to.be.ok;
        expect(user.holidayDates.length).to.equal(1);
        expect(user.holidayDates[0].period.length).to.equal(2);
        expect(user.holidayDates[0].period[0].value).to.equalTime(period[0]);
        expect(user.holidayDates[0].period[1].value).to.equalTime(period[1]);
      });
    });

    it('should save geometry correctly', async function() {
      const point = { type: 'Point', coordinates: [39.807222, -76.984722] };
      const newUser = await this.User.create({ username: 'user', email: ['foo@bar.com'], location: point });
      expect(newUser.location).to.deep.eql(point);
    });

    it('should update geometry correctly', async function() {
      const User = this.User;
      const point1 = { type: 'Point', coordinates: [39.807222, -76.984722] };
      const point2 = { type: 'Point', coordinates: [39.828333, -77.232222] };
      const oldUser = await User.create({ username: 'user', email: ['foo@bar.com'], location: point1 });
      const [, updatedUsers] = await User.update({ location: point2 }, { where: { username: oldUser.username }, returning: true });
      expect(updatedUsers[0].location).to.deep.eql(point2);
    });

    it('should read geometry correctly', async function() {
      const User = this.User;
      const point = { type: 'Point', coordinates: [39.807222, -76.984722] };

      const user0 = await User.create({ username: 'user', email: ['foo@bar.com'], location: point });
      const user = await User.findOne({ where: { username: user0.username } });
      expect(user.location).to.deep.eql(point);
    });

    describe('[POSTGRES] Unquoted identifiers', () => {
      it('can insert and select', async function() {
        this.sequelize.options.quoteIdentifiers = false;
        this.sequelize.getQueryInterface().queryGenerator.options.quoteIdentifiers = false;

        this.User = this.sequelize.define('Userxs', {
          username: DataTypes.STRING,
          fullName: DataTypes.STRING // Note mixed case
        }, {
          quoteIdentifiers: false
        });

        await this.User.sync({ force: true });

        const user = await this.User
          .create({ username: 'user', fullName: 'John Smith' });

        // We can insert into a table with non-quoted identifiers
        expect(user.id).to.exist;
        expect(user.id).not.to.be.null;
        expect(user.username).to.equal('user');
        expect(user.fullName).to.equal('John Smith');

        // We can query by non-quoted identifiers
        const user2 = await this.User.findOne({
          where: { fullName: 'John Smith' }
        });

        // We can map values back to non-quoted identifiers
        expect(user2.id).to.equal(user.id);
        expect(user2.username).to.equal('user');
        expect(user2.fullName).to.equal('John Smith');

        // We can query and aggregate by non-quoted identifiers
        const count = await this.User
          .count({
            where: { fullName: 'John Smith' }
          });

        this.sequelize.options.quoteIndentifiers = true;
        this.sequelize.getQueryInterface().queryGenerator.options.quoteIdentifiers = true;
        this.sequelize.options.logging = false;
        expect(count).to.equal(1);
      });

      it('can select nested include', async function() {
        this.sequelize.options.quoteIdentifiers = false;
        this.sequelize.getQueryInterface().queryGenerator.options.quoteIdentifiers = false;
        this.Professor = this.sequelize.define('Professor', {
          fullName: DataTypes.STRING
        }, {
          quoteIdentifiers: false
        });
        this.Class = this.sequelize.define('Class', {
          name: DataTypes.STRING
        }, {
          quoteIdentifiers: false
        });
        this.Student = this.sequelize.define('Student', {
          fullName: DataTypes.STRING
        }, {
          quoteIdentifiers: false
        });
        this.ClassStudent = this.sequelize.define('ClassStudent', {
        }, {
          quoteIdentifiers: false,
          tableName: 'class_student'
        });
        this.Professor.hasMany(this.Class);
        this.Class.belongsTo(this.Professor);
        this.Class.belongsToMany(this.Student, { through: this.ClassStudent });
        this.Student.belongsToMany(this.Class, { through: this.ClassStudent });

        try {
          await this.Professor.sync({ force: true });
          await this.Student.sync({ force: true });
          await this.Class.sync({ force: true });
          await this.ClassStudent.sync({ force: true });

          await this.Professor.bulkCreate([
            {
              id: 1,
              fullName: 'Albus Dumbledore'
            },
            {
              id: 2,
              fullName: 'Severus Snape'
            }
          ]);

          await this.Class.bulkCreate([
            {
              id: 1,
              name: 'Transfiguration',
              ProfessorId: 1
            },
            {
              id: 2,
              name: 'Potions',
              ProfessorId: 2
            },
            {
              id: 3,
              name: 'Defence Against the Dark Arts',
              ProfessorId: 2
            }
          ]);

          await this.Student.bulkCreate([
            {
              id: 1,
              fullName: 'Harry Potter'
            },
            {
              id: 2,
              fullName: 'Ron Weasley'
            },
            {
              id: 3,
              fullName: 'Ginny Weasley'
            },
            {
              id: 4,
              fullName: 'Hermione Granger'
            }
          ]);

          await Promise.all([
            this.Student.findByPk(1)
              .then(Harry => {
                return Harry.setClasses([1, 2, 3]);
              }),
            this.Student.findByPk(2)
              .then(Ron => {
                return Ron.setClasses([1, 2]);
              }),
            this.Student.findByPk(3)
              .then(Ginny => {
                return Ginny.setClasses([2, 3]);
              }),
            this.Student.findByPk(4)
              .then(Hermione => {
                return Hermione.setClasses([1, 2, 3]);
              })
          ]);

          const professors = await this.Professor.findAll({
            include: [
              {
                model: this.Class,
                include: [
                  {
                    model: this.Student
                  }
                ]
              }
            ],
            order: [
              ['id'],
              [this.Class, 'id'],
              [this.Class, this.Student, 'id']
            ]
          });

          expect(professors.length).to.eql(2);
          expect(professors[0].fullName).to.eql('Albus Dumbledore');
          expect(professors[0].Classes.length).to.eql(1);
          expect(professors[0].Classes[0].Students.length).to.eql(3);
        } finally {
          this.sequelize.getQueryInterface().queryGenerator.options.quoteIdentifiers = true;
        }
      });
    });
  });
}


/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * 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.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 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.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define */

define(function (require, exports, module) {

    "use strict";

    // Code that needs to display user strings should call require("strings") to load
    // src/strings.js. This file will dynamically load strings.js for the specified brackets.locale.
    //
    // See the README.md file in this folder for information on how to add a new translation for
    // another language or locale.
    //
    // TODO: dynamically populate the local prefix list below?
    module.exports = {
        root: true,
        "cs": true,
        "de": true,
        "fi": true,
        "fr": true,
        "nb": true,
        "es": true,
        "it": true,
        "pl": true,
        "pt-br": true,
        "pt-pt": true,
        "ja": true,
        "tr": true,
        "ru": true,
        "sv": true,
        "zh-cn": true,
        "hu" : true
    };
});


combined-stream

# combined-stream

A stream that emits multiple other streams one after another.

## Installation

``` bash
npm install combined-stream
```

## Usage

Here is a simple example that shows how you can use combined-stream to combine
two files into one:

``` javascript
var CombinedStream = require('combined-stream');
var fs = require('fs');

var combinedStream = CombinedStream.create();
combinedStream.append(fs.createReadStream('file1.txt'));
combinedStream.append(fs.createReadStream('file2.txt'));

combinedStream.pipe(fs.createWriteStream('combined.txt'));
```

While the example above works great, it will pause all source streams until
they are needed. If you don't want that to happen, you can set `pauseStreams`
to `false`:

``` javascript
var CombinedStream = require('combined-stream');
var fs = require('fs');

var combinedStream = CombinedStream.create({pauseStreams: false});
combinedStream.append(fs.createReadStream('file1.txt'));
combinedStream.append(fs.createReadStream('file2.txt'));

combinedStream.pipe(fs.createWriteStream('combined.txt'));
```

However, what if you don't have all the source streams yet, or you don't want
to allocate the resources (file descriptors, memory, etc.) for them right away?
Well, in that case you can simply provide a callback that supplies the stream
by calling a `next()` function:

``` javascript
var CombinedStream = require('combined-stream');
var fs = require('fs');

var combinedStream = CombinedStream.create();
combinedStream.append(function(next) {
  next(fs.createReadStream('file1.txt'));
});
combinedStream.append(function(next) {
  next(fs.createReadStream('file2.txt'));
});

combinedStream.pipe(fs.createWriteStream('combined.txt'));
```

## API

### CombinedStream.create([options])

Returns a new combined stream object. Available options are:

* `maxDataSize`
* `pauseStreams`

The effect of those options is described below.

### combinedStream.pauseStreams = true

Whether to apply back pressure to the underlaying streams. If set to `false`,
the underlaying streams will never be paused. If set to `true`, the
underlaying streams will be paused right after being appended, as well as when
`delayedStream.pipe()` wants to throttle.

### combinedStream.maxDataSize = 2 * 1024 * 1024

The maximum amount of bytes (or characters) to buffer for all source streams.
If this value is exceeded, `combinedStream` emits an `'error'` event.

### combinedStream.dataSize = 0

The amount of bytes (or characters) currently buffered by `combinedStream`.

### combinedStream.append(stream)

Appends the given `stream` to the combinedStream object. If `pauseStreams` is
set to `true, this stream will also be paused right away.

`streams` can also be a function that takes one parameter called `next`. `next`
is a function that must be invoked in order to provide the `next` stream, see
example above.

Regardless of how the `stream` is appended, combined-stream always attaches an
`'error'` listener to it, so you don't have to do that manually.

Special case: `stream` can also be a String or Buffer.

### combinedStream.write(data)

You should not call this, `combinedStream` takes care of piping the appended
streams into itself for you.

### combinedStream.resume()

Causes `combinedStream` to start drain the streams it manages. The function is
idempotent, and also emits a `'resume'` event each time which usually goes to
the stream that is currently being drained.

### combinedStream.pause();

If `combinedStream.pauseStreams` is set to `false`, this does nothing.
Otherwise a `'pause'` event is emitted, this goes to the stream that is
currently being drained, so you can use it to apply back pressure.

### combinedStream.end();

Sets `combinedStream.writable` to false, emits an `'end'` event, and removes
all streams from the queue.

### combinedStream.destroy();

Same as `combinedStream.end()`, except it emits a `'close'` event instead of
`'end'`.

## License

combined-stream is licensed under the MIT license.


#testId {
	background-color:#06F
}

.testClass {
	color:#900
}


var binary = require('../');
var test = require('tap').test;

test('not enough buf', function (t) {
    t.plan(3);

    var vars = binary(new Buffer([1,2,3,4]))
        .word8('a')
        .buffer('b', 10)
        .word8('c')
        .vars
    ;

    t.same(vars.a, 1);
    t.equal(vars.b.toString(), new Buffer([2,3,4]).toString());
    t.strictEqual(vars.c, null);
});


"fi": true,
"fr": true,
"nb": true,
"es": true,
"it": true,


[![build status](https://secure.travis-ci.org/jprichardson/node-fs-extra.png)](http://travis-ci.org/jprichardson/node-fs-extra)

Node.js: fs-extra
=================

This module adds a few extra file system methods that aren't included in the native `fs` module. It is a drop in replacement for `fs`.

Why?
----

I got tired of including `mkdirp`, `rimraf`, and `cp -r` in most of my projects.

Installation
------------

    npm install fs-extra

Usage
-----

```javascript
var fs = require('fs-extra');
```

Methods
-------

**NOTE:** You can still use the native Node.js methods. They are copied over to `fs-extra`.

### copy(src, dest, callback)

Copy a file or directory. The directory can have contents. Like `cp -r`. There isn't a synchronous version implemented yet.

Sync: (none)

Examples:

```javascript
var fs = require('fs-extra');

fs.copy('/tmp/myfile', '/tmp/mynewfile', function(err){
  if (err) {
    console.error(err);
  }
  else {
    console.log("success!")
  }
}); //copies file

fs.copy('/tmp/mydir', '/tmp/mynewdir', function(err){
  if (err) {
    console.error(err);
  }
  else {
    console.log("success!")
  }
}); //copies directory, even if it has subdirectories or files
```

### createFile(file, callback)

Creates a file. If the file that is requested to be created is in directories that do not exist, these directories are created. If the file already exists, it is **NOT MODIFIED**.

Sync: `createFileSync()`

Example:

```javascript
var fs = require('fs-extra')
  , file = '/tmp/this/path/does/not/exist/file.txt'

fs.createFile(file, function(err) {
  console.log(err); //null

  //file has now been created, including the directory it is to be placed in
})
```

### exists() / existsSync()

These methods are actually from `path` in v0.6. But in Node v0.8 they are moved from `path` to `fs`. So you can use this module to help make your modules v0.6 and v0.8 compatible.

### mkdirs(dir, callback)

Creates a directory. If the parent hierarchy doesn't exist, it's created. Like `mkdir -p`.

Alias: `mkdirp()`

Sync: `mkdirsSync()` / `mkdirpSync()`

Examples:

```javascript
var fs = require('fs-extra');

fs.mkdirs('/tmp/some/long/path/that/prob/doesnt/exist', function(err){
  if (err) {
    console.error(err);
  }
  else {
    console.log("success!")
  }
});

fs.mkdirsSync('/tmp/another/path');
```

### outputFile(file, data, callback)

Almost the same as `writeFile`, except that if the directory does not exist, it's created.

Sync: `outputFileSync()`

Example:

```javascript
var fs = require('fs-extra')
  , file = '/tmp/this/path/does/not/exist/file.txt'

fs.outputFile(file, 'hello!' function(err) {
  console.log(err); //null

  fs.readFile(file, 'utf8', function(err, data) {
    console.log(data); //hello!
  })
})
```

### readJson(file, callback)

Reads a JSON file and then parses it into an object.

Alias: `readJSON()`

Sync: `readJsonSync()`, `readJSONSync()`

Example:

```javascript
var fs = require('fs-extra');

fs.readJson('./package.json', function(err, packageObj) {
  console.log(packageObj.version); //0.1.3
});
```

### remove(dir, callback)

Removes a file or directory. The directory can have contents. Like `rm -rf`.

Alias: `delete()`

Sync: `removeSync()` / `deleteSync()`

Examples:

```javascript
var fs = require('fs-extra');

fs.remove('/tmp/myfile', function(err){
  if (err) {
    console.error(err);
  }
  else {
    console.log("success!")
  }
});

fs.removeSync('/home/jprichardson'); //I just deleted my entire HOME directory.
```

### writeJson(file, object, callback)

Writes an object to a JSON file.

Alias: `writeJSON()`

Sync: `writeJsonSync()`, `writeJSONSync()`

Example:

```javascript
var fs = require('fs-extra');
fs.writeJson('./package.json', {name: 'fs-extra'}, function(err){
  console.log(err);
});
```

Roadmap
-------

This contains items that I'm considering doing. I'd love community feedback.

* File system walker. I really like this one: https://github.com/daaku/nodejs-walker
* File/directory tree watcher. There are quite a few.
* Method to move files.
* Copy sync.
* Thinking about moving `rimraf`, `ncp`, and `mkdirps` code into this library. I'd like fs-extra to be a stable library that module authors
can depend upon. A bunch of other dependencies kinda sucks for modules/libraries.
* Change documentation to use the `fse` prefix instead of `fs`. This may encourage people to start using `fse` as a prefix and hence make their code clearer that they're not using the native `fs`. I'm very undecided on this one since `fs-extra` is a drop in replacement for the native `fs`.

Naming
------

I put a lot of thought into the naming of these function. Inspired by @coolaj86's request. So he deserves much of the credit for raising the issue. See discussion(s) here:

* https://github.com/jprichardson/node-fs-extra/issues/2
* https://github.com/flatiron/utile/issues/11
* https://github.com/ryanmcgrath/wrench-js/issues/29
* https://github.com/substack/node-mkdirp/issues/17

First, I believe that in as many cases as possible, the [Node.js naming schemes](http://nodejs.org/api/fs.html) should be chosen. However, there are problems with the Node.js own naming schemes.

For example, `fs.readFile()` and `fs.readdir()`: the **F** is capitalized in *File* and the **d** is not capitalized in *dir*. Perhaps a bit pedantic, but they should still be consistent. Also, Node.js has chosen a lot of POSIX naming schemes, which I believe is great. See: `fs.mkdir()`, `fs.rmdir()`, `fs.chown()`, etc.

We have a dilemma though. How do you consistently name methods that perform the following POSIX commands: `cp`, `cp -r`, `mkdir -p`, and `rm -rf`?

My perspective: when in doubt, err on the side of simplicity. Consider that for a moment. A directory is just a hierarchical grouping of directories and files. So when you want to copy it or remove it, in most cases you'll want to copy or remove all of its contents. When you want to create a directory, if the directory that it's suppose to be contained in does not exist, then in most cases you'll want to create that too.

So, if you want to remove a file or a directory regardless of whether it has contents, just call `fs.remove(path)` or its alias `fs.delete(path)`. If you want to copy a file or a directory whether it has contents, just call `fs.copy(source, destination)`. If you want to create a directory regardless of whether its parent directories exist, just call `fs.mkdirs(path)` or `fs.mkdirp(path)`.

Author
------

`node-fs-extra` was written by [JP Richardson][aboutjp]. You should follow him on Twitter [@jprichardson][twitter]. Also read his coding blog [Procbits][procbits]. If you write software with others, you should checkout [Gitpilot][gitpilot] to make collaboration with Git simple.

License
-------

Licensed under MIT

Copyright (c) 2011-2013 JP Richardson

[1]: http://nodejs.org/docs/latest/api/fs.html

[jsonfile]: https://github.com/jprichardson/node-jsonfile

[aboutjp]: http://about.me/jprichardson
[twitter]: http://twitter.com/jprichardson
[procbits]: http://procbits.com
[gitpilot]: http://gitpilot.com


var testutil = require('testutil')
  , fs = require('../')
  , path = require('path')

var TEST_DIR = '';

describe('fs-extra', function () {
  beforeEach(function() {
    TEST_DIR = testutil.createTestDir('fs-extra')
  })

  describe('+ outputFile', function() {
    describe('> when the file and directory does not exist', function() {
      it('should create the file', function(done) {
        var file = path.join(TEST_DIR, Math.random() + 't-ne', Math.random() + '.txt');
        F (fs.existsSync(file));
        fs.outputFile(file, 'hi jp', function(err) {
          F (err);
          T (fs.existsSync(file));
          EQ (fs.readFileSync(file, 'utf8'), 'hi jp')
          done();
        })
      })
    })

    describe('> when the file does exist', function() {
      it('should still modify the file', function(done) {
        var file = path.join(TEST_DIR, Math.random() + 't-e', Math.random() + '.txt');
        fs.mkdirsSync(path.dirname(file))
        fs.writeFileSync(file, 'hello world');
        fs.outputFile(file, 'hello jp', function(err) {
          if (err) return done(err)
          EQ (fs.readFileSync(file, 'utf8'), 'hello jp')
          done();
        })
      })
    })
  })

  describe('+ outputFileSync', function() {
    describe('> when the file and directory does not exist', function() {
      it('should create the file', function() {
        var file = path.join(TEST_DIR, Math.random() + 'ts-ne', Math.random() + '.txt');
        F (fs.existsSync(file));
        fs.outputFileSync(file, 'hello man');
        T (fs.existsSync(file));
        EQ (fs.readFileSync(file, 'utf8'), 'hello man')
      })
    })

    describe('> when the file does exist', function() {
      it('should still modify the file', function() {
        var file = path.join(TEST_DIR, Math.random() + 'ts-e', Math.random() + '.txt');
        fs.mkdirsSync(path.dirname(file))
        fs.writeFileSync(file, 'hello world');
        fs.outputFileSync(file, 'hello man');
        EQ (fs.readFileSync(file, 'utf8'), 'hello man')
      })
    })
  })

})


/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * 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.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 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.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define */

define({
    // Relative to the samples folder
    "GETTING_STARTED"   : "it/Primi passi"
});


"it": true,
"pl": true,
"pt-br": true,
"pt-pt": true,

/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * 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.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 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.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define */

define(function (require, exports, module) {

    "use strict";

    // Registry for languages that have specific per-language URLs or file paths that we use
    // elsewhere in Brackets.
    //
    // TODO: dynamically populate the local prefix list below?
    module.exports = {
        root: true,
        "de": true,
        "fr": true,
        "es": true,
        "ru": true,
        "sv": true
    };
});


var mkdirp = require('../');
var path = require('path');
var fs = require('fs');
var test = require('tap').test;

test('return value', function (t) {
    t.plan(2);
    var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
    var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
    var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16);

    var file = '/tmp/' + [x,y,z].join('/');

    // should return the first dir created.
    // By this point, it would be profoundly surprising if /tmp didn't
    // already exist, since every other test makes things in there.
    // Note that this will throw on failure, which will fail the test.
    var made = mkdirp.sync(file);
    t.equal(made, '/tmp/' + x);

    // making the same file again should have no effect.
    made = mkdirp.sync(file);
    t.equal(made, null);
});


/*!
 * jQuery UI Effects Scale @VERSION
 *
 * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Scale
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.effect.puff = function( o, done ) {
	var elem = $( this ),
		mode = $.effects.setMode( elem, o.mode || "hide" ),
		hide = mode === "hide",
		percent = parseInt( o.percent, 10 ) || 150,
		factor = percent / 100,
		original = {
			height: elem.height(),
			width: elem.width()
		};

	$.extend( o, {
		effect: "scale",
		queue: false,
		fade: true,
		mode: mode,
		complete: done,
		percent: hide ? percent : 100,
		from: hide ?
			original :
			{
				height: original.height * factor,
				width: original.width * factor
			}
	});

	elem.effect( o );
};

$.effects.effect.scale = function( o, done ) {

	// Create element
	var el = $( this ),
		options = $.extend( true, {}, o ),
		mode = $.effects.setMode( el, o.mode || "effect" ),
		percent = parseInt( o.percent, 10 ) ||
			( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
		direction = o.direction || "both",
		origin = o.origin,
		original = {
			height: el.height(),
			width: el.width(),
			outerHeight: el.outerHeight(),
			outerWidth: el.outerWidth()
		},
		factor = {
			y: direction !== "horizontal" ? (percent / 100) : 1,
			x: direction !== "vertical" ? (percent / 100) : 1
		};

	// We are going to pass this effect to the size effect:
	options.effect = "size";
	options.queue = false;
	options.complete = done;

	// Set default origin and restore for show/hide
	if ( mode !== "effect" ) {
		options.origin = origin || ["middle","center"];
		options.restore = true;
	}

	options.from = o.from || ( mode === "show" ? { height: 0, width: 0 } : original );
	options.to = {
		height: original.height * factor.y,
		width: original.width * factor.x,
		outerHeight: original.outerHeight * factor.y,
		outerWidth: original.outerWidth * factor.x
	};

	// Fade option to support puff
	if ( options.fade ) {
		if ( mode === "show" ) {
			options.from.opacity = 0;
			options.to.opacity = 1;
		}
		if ( mode === "hide" ) {
			options.from.opacity = 1;
			options.to.opacity = 0;
		}
	}

	// Animate
	el.effect( options );

};

$.effects.effect.size = function( o, done ) {

	// Create element
	var el = $( this ),
		props = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],

		// Always restore
		props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],

		// Copy for children
		props2 = [ "width", "height", "overflow" ],
		cProps = [ "fontSize" ],
		vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
		hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],

		// Set options
		mode = $.effects.setMode( el, o.mode || "effect" ),
		restore = o.restore || mode !== "effect",
		scale = o.scale || "both",
		origin = o.origin || [ "middle", "center" ],
		original, baseline, factor,
		position = el.css( "position" );

	if ( mode === "show" ) {
		el.show();
	}
	original = {
		height: el.height(),
		width: el.width(),
		outerHeight: el.outerHeight(),
		outerWidth: el.outerWidth()
	};

	el.from = o.from || original;
	el.to = o.to || original;

	// Set scaling factor
	factor = {
		from: {
			y: el.from.height / original.height,
			x: el.from.width / original.width
		},
		to: {
			y: el.to.height / original.height,
			x: el.to.width / original.width
		}
	};

	// Scale the css box
	if ( scale === "box" || scale === "both" ) {

		// Vertical props scaling
		if ( factor.from.y !== factor.to.y ) {
			props = props.concat( vProps );
			el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
			el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
		}

		// Horizontal props scaling
		if ( factor.from.x !== factor.to.x ) {
			props = props.concat( hProps );
			el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
			el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
		}
	}

	// Scale the content
	if ( scale === "content" || scale === "both" ) {

		// Vertical props scaling
		if ( factor.from.y !== factor.to.y ) {
			props = props.concat( cProps );
			el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
			el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
		}
	}

	$.effects.save( el, restore ? props : props1 );
	el.show();
	$.effects.createWrapper( el );
	el.css( "overflow", "hidden" ).css( el.from );

	// Adjust
	if (origin) { // Calculate baseline shifts
		baseline = $.effects.getBaseline( origin, original );
		el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
		el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
		el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
		el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
	}
	el.css( el.from ); // set top & left

	// Animate
	if ( scale === "content" || scale === "both" ) { // Scale the children

		// Add margins/font-size
		vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
		hProps = hProps.concat([ "marginLeft", "marginRight" ]);
		props2 = props.concat(vProps).concat(hProps);

		el.find( "*[width]" ).each( function(){
			var child = $( this ),
				c_original = {
					height: child.height(),
					width: child.width()
				};
			if (restore) {
				$.effects.save(child, props2);
			}

			child.from = {
				height: c_original.height * factor.from.y,
				width: c_original.width * factor.from.x
			};
			child.to = {
				height: c_original.height * factor.to.y,
				width: c_original.width * factor.to.x
			};

			// Vertical props scaling
			if ( factor.from.y !== factor.to.y ) {
				child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
				child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
			}

			// Horizontal props scaling
			if ( factor.from.x !== factor.to.x ) {
				child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
				child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
			}

			// Animate children
			child.css( child.from );
			child.animate( child.to, o.duration, o.easing, function() {

				// Restore children
				if ( restore ) {
					$.effects.restore( child, props2 );
				}
			});
		});
	}

	// Animate
	el.animate( el.to, {
		queue: false,
		duration: o.duration,
		easing: o.easing,
		complete: function() {
			if ( el.to.opacity === 0 ) {
				el.css( "opacity", el.from.opacity );
			}
			if( mode === "hide" ) {
				el.hide();
			}
			$.effects.restore( el, restore ? props : props1 );
			if ( !restore ) {

				// we need to calculate our new positioning based on the scaling
				if ( position === "static" ) {
					el.css({
						position: "relative",
						top: el.to.top,
						left: el.to.left
					});
				} else {
					$.each([ "top", "left" ], function( idx, pos ) {
						el.css( pos, function( _, str ) {
							var val = parseInt( str, 10 ),
								toRef = idx ? el.to.left : el.to.top;

							// if original was "auto", recalculate the new value from wrapper
							if ( str === "auto" ) {
								return toRef + "px";
							}

							return val + toRef + "px";
						});
					});
				}
			}

			$.effects.removeWrapper( el );
			done();
		}
	});

};

})(jQuery);


/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * 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.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 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.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, $ */

/**
 * PreferenceStorage defines an interface for persisting preference data as
 * name/value pairs for a module or plugin.
 */
define(function (require, exports, module) {
    "use strict";

    var PreferencesManager = require("preferences/PreferencesManager"),
        CollectionUtils    = require("utils/CollectionUtils");

    /**
     * @private
     * Validate JSON keys and values.
     */
    function _validateJSONPair(key, value) {
        if (typeof key === "string") {
            // validate temporary JSON
            var temp = {},
                error = null;
            temp[key] = value;

            try {
                temp = JSON.parse(JSON.stringify(temp));
            } catch (err) {
                error = err;
            }

            // set value to JSON storage if no errors occurred
            if (!error && (temp[key] !== undefined)) {
                return true;
            } else {
                console.error("Value '" + value + "' for key '" + key + "' must be a valid JSON value");
                return false;
            }
        } else {
            console.error("Preference key '" + key + "' must be a string");
            return false;
        }
    }

    /**
     * @private
     * Save to persistent storage.
     */
    function _commit() {
        PreferencesManager.savePreferences();
    }

    /**
     * Creates a new PreferenceStorage object.
     * @param {!string} clientID Unique identifier for PreferencesManager to
     *  associate this PreferenceStorage data with.
     * @param {!object} json JSON object to persist preference data.
     */
    function PreferenceStorage(clientID, json) {
        this._clientID = clientID;
        this._json = json;
    }

    /**
     * Unique clientID for this PreferenceStorage object.
     * @return {!string} clientID
     */
    PreferenceStorage.prototype.getClientID = function () {
        return this._clientID;
    };

    /**
     * Removes a preference from this PreferenceStorage object.
     * @param {!string} key A unique identifier
     */
    PreferenceStorage.prototype.remove = function (key) {
        // remove value from JSON storage
        delete this._json[key];
        _commit();
    };

    /**
     * Assigns a value for a key. Overwrites existing value if present.
     * @param {!string} key A unique identifier
     * @param {object} value A valid JSON value
     */
    PreferenceStorage.prototype.setValue = function (key, value) {
        if (_validateJSONPair(key, value)) {
            this._json[key] = value;
            _commit();
        }
    };

    /**
     * Retreive the value associated with the specified key.
     * @param {!string} key Key name to lookup.
     * @return {object} Returns the value for the key or undefined.
     */
    PreferenceStorage.prototype.getValue = function (key) {
        return this._json[key];
    };

    /**
     * Return all name-value pairs as a single JSON object.
     * @return {!object} JSON object containing name/value pairs for all keys
     *  in this PreferenceStorage object.
     */
    PreferenceStorage.prototype.getAllValues = function () {
        return JSON.parse(JSON.stringify(this._json));
    };

    /**
     * Writes name-value pairs from a JSON object as preference properties.
     * Invalid JSON values report an error and all changes are discarded.
     *
     * @param {!object} obj A JSON object with zero or more preference properties to write.
     * @param {boolean} append Defaults to false. When true, properties in the JSON object
     *  overwrite and/or append to the existing set of preference properties. When false,
     *  all existing preferences are deleted before writing new properties from the JSON object.
     */
    PreferenceStorage.prototype.setAllValues = function (obj, append) {
        var self = this,
            error = null;

        // validate all name/value pairs before committing
        CollectionUtils.some(obj, function (value, key) {
            try {
                _validateJSONPair(key, value);
            } catch (err) {
                // fail fast
                error = err;
                return true;
            }
        });

        // skip changes if any error is detected
        if (error) {
            console.error(error);
            return;
        }

        // delete all exiting properties if not appending
        if (!append) {
            CollectionUtils.forEach(this._json, function (value, key) {
                delete self._json[key];
            });
        }

        // copy properties from incoming JSON object
        CollectionUtils.forEach(obj, function (value, key) {
            self._json[key] = value;
        });

        _commit();
    };

    exports.PreferenceStorage = PreferenceStorage;
});


"pl": true,
"pt-br": true,
"pt-pt": true,
"ja": true,
"tr": true,
"ru": true,
"sv": true,

keep keep keep replace replace keep keep


/*!
 * jQuery UI Effects Drop @VERSION
 *
 * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Effects/Drop
 *
 * Depends:
 *	jquery.effects.core.js
 */
(function( $, undefined ) {

$.effects.effect.drop = function( o, done ) {

	var el = $( this ),
		props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
		mode = $.effects.setMode( el, o.mode || "hide" ),
		show = mode === "show",
		direction = o.direction || "left",
		ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
		motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
		animation = {
			opacity: show ? 1 : 0
		},
		distance;

	// Adjust
	$.effects.save( el, props );
	el.show();
	$.effects.createWrapper( el );

	distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]({ margin: true }) / 2;

	if ( show ) {
		el
			.css( "opacity", 0 )
			.css( ref, motion === "pos" ? -distance : distance );
	}

	// Animation
	animation[ ref ] = ( show ?
		( motion === "pos" ? "+=" : "-=" ) :
		( motion === "pos" ? "-=" : "+=" ) ) +
		distance;

	// Animate
	el.animate( animation, {
		queue: false,
		duration: o.duration,
		easing: o.easing,
		complete: function() {
			if ( mode === "hide" ) {
				el.hide();
			}
			$.effects.restore( el, props );
			$.effects.removeWrapper( el );
			done();
		}
	});
};

})(jQuery);


<!DOCTYPE HTML>

  <meta charset="utf-8">
  <title>Untitled Document</title>

A paragraph with no closing tag

h1<wbr>tag that auto closes the preceding p tag

first item

second item
 with a line break

3rd item

      Name
      Address
      Phone

      Name
      Address
      Phone

      Name

Address

      Phone

  <form name="form1" method="post" action="http://somesite.com/prog/adduser">
	<input type="button" name="prev" id="prev" value="<Prev">
	<input type="button" name="next" id="next" value="Next>">

	Select your magic number:
	<select name="select" id="select">
      <option value="1">item1
      <option value="2">item2</option>
      <option value="3">item3
	</select>
  </form>

selected color

 SOME FOOTNOTE

unclosed p

heading

 this text should be directly inside body because the p was closed by the h1


"ru": true,
"sv": true,
"zh-cn": true,
"hu" : true
};
});


<!DOCTYPE html>

	<meta charset="utf-8">
	<title>jQuery UI Tabs - Default functionality</title>
	<link rel="stylesheet" href="../../themes/base/jquery.ui.all.css">

	<link rel="stylesheet" href="../demos.css">

Nunc tincidunt

Proin dolor

Aenean lacinia

Proin elit arcu, rutrum commodo, vehicula tempus, commodo a, risus. Curabitur nec arcu. Donec sollicitudin mi sit amet mauris. Nam elementum quam ullamcorper ante. Etiam aliquet massa et lorem. Mauris dapibus lacus auctor risus. Aenean tempor ullamcorper leo. Vivamus sed magna quis ligula eleifend adipiscing. Duis orci. Aliquam sodales tortor vitae ipsum. Aliquam nulla. Duis aliquam molestie erat. Ut et mauris vel pede varius sollicitudin. Sed ut dolor nec orci tincidunt interdum. Phasellus ipsum. Nunc tristique tempus lectus.

Morbi tincidunt, dui sit amet facilisis feugiat, odio metus gravida ante, ut pharetra massa metus id nunc. Duis scelerisque molestie turpis. Sed fringilla, massa eget luctus malesuada, metus eros molestie lectus, ut tempus eros massa ut dolor. Aenean aliquet fringilla sem. Suspendisse sed ligula in ligula suscipit aliquam. Praesent in eros vestibulum mi adipiscing adipiscing. Morbi facilisis. Curabitur ornare consequat nunc. Aenean vel metus. Ut posuere viverra nulla. Aliquam erat volutpat. Pellentesque convallis. Maecenas feugiat, tellus pellentesque pretium posuere, felis lorem euismod felis, eu ornare leo nisi vel felis. Mauris consectetur tortor et purus.

Mauris eleifend est et turpis. Duis id erat. Suspendisse potenti. Aliquam vulputate, pede vel vehicula accumsan, mi neque rutrum erat, eu congue orci lorem eget lorem. Vestibulum non ante. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce sodales. Quisque eu urna vel enim commodo pellentesque. Praesent eu risus hendrerit ligula tempus pretium. Curabitur lorem enim, pretium nec, feugiat nec, luctus a, lacus.

Duis cursus. Maecenas ligula eros, blandit nec, pharetra at, semper at, magna. Nullam ac lacus. Nulla facilisi. Praesent viverra justo vitae neque. Praesent blandit adipiscing velit. Suspendisse potenti. Donec mattis, pede vel pharetra blandit, magna ligula faucibus eros, id euismod lacus dolor eget odio. Nam scelerisque. Donec non libero sed nulla mattis commodo. Ut sagittis. Donec nisi lectus, feugiat porttitor, tempor ac, tempor vitae, pede. Aenean vehicula velit eu tellus interdum rutrum. Maecenas commodo. Pellentesque nec elit. Fusce in lacus. Vivamus a libero vitae lectus hendrerit hendrerit.

Click tabs to swap between content that is broken into logical sections.


/*
 * datepicker_events.js
 */
(function($) {

module("datepicker: events");

var selectedThis = null,
selectedDate = null,
selectedInst = null;

function callback(date, inst) {
	selectedThis = this;
	selectedDate = date;
	selectedInst = inst;
}

function callback2(year, month, inst) {
	selectedThis = this;
	selectedDate = year + '/' + month;
	selectedInst = inst;
}

test('events', function() {
	var dateStr, newMonthYear, inp2,
		inp = init('#inp', {onSelect: callback}),
	date = new Date();
	// onSelect
	inp.val('').datepicker('show').
		simulate('keydown', {keyCode: $.ui.keyCode.ENTER});
	equal(selectedThis, inp[0], 'Callback selected this');
	equal(selectedInst, $.data(inp[0], PROP_NAME), 'Callback selected inst');
	equal(selectedDate, $.datepicker.formatDate('mm/dd/yy', date),
		'Callback selected date');
	inp.val('').datepicker('show').
		simulate('keydown', {ctrlKey: true, keyCode: $.ui.keyCode.DOWN}).
		simulate('keydown', {keyCode: $.ui.keyCode.ENTER});
	date.setDate(date.getDate() + 7);
	equal(selectedDate, $.datepicker.formatDate('mm/dd/yy', date),
		'Callback selected date - ctrl+down');
	inp.val('').datepicker('show').
		simulate('keydown', {keyCode: $.ui.keyCode.ESCAPE});
	equal(selectedDate, $.datepicker.formatDate('mm/dd/yy', date),
		'Callback selected date - esc');
    dateStr = '02/04/2008';
    inp.val(dateStr).datepicker('show').
        simulate('keydown', {keyCode: $.ui.keyCode.ENTER});
    equal(dateStr, selectedDate,
        'onSelect is called after enter keydown');
	// onChangeMonthYear
	inp.datepicker('option', {onChangeMonthYear: callback2, onSelect: null}).
		val('').datepicker('show');
	newMonthYear = function(date) {
		return date.getFullYear() + '/' + (date.getMonth() + 1);
	};
	date = new Date();
	date.setDate(1);
	inp.simulate('keydown', {keyCode: $.ui.keyCode.PAGE_UP});
	date.setMonth(date.getMonth() - 1);
	equal(selectedThis, inp[0], 'Callback change month/year this');
	equal(selectedInst, $.data(inp[0], PROP_NAME), 'Callback change month/year inst');
	equal(selectedDate, newMonthYear(date),
		'Callback change month/year date - pgup');
	inp.simulate('keydown', {keyCode: $.ui.keyCode.PAGE_DOWN});
	date.setMonth(date.getMonth() + 1);
	equal(selectedDate, newMonthYear(date),
		'Callback change month/year date - pgdn');
	inp.simulate('keydown', {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP});
	date.setFullYear(date.getFullYear() - 1);
	equal(selectedDate, newMonthYear(date),
		'Callback change month/year date - ctrl+pgup');
	inp.simulate('keydown', {ctrlKey: true, keyCode: $.ui.keyCode.HOME});
	date.setFullYear(date.getFullYear() + 1);
	equal(selectedDate, newMonthYear(date),
		'Callback change month/year date - ctrl+home');
	inp.simulate('keydown', {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN});
	date.setFullYear(date.getFullYear() + 1);
	equal(selectedDate, newMonthYear(date),
		'Callback change month/year date - ctrl+pgdn');
	inp.datepicker('setDate', new Date(2007, 1 - 1, 26));
	equal(selectedDate, '2007/1', 'Callback change month/year date - setDate');
	selectedDate = null;
	inp.datepicker('setDate', new Date(2007, 1 - 1, 12));
	ok(selectedDate == null, 'Callback change month/year date - setDate no change');
	// onChangeMonthYear step by 2
	inp.datepicker('option', {stepMonths: 2}).
		datepicker('hide').val('').datepicker('show').
		simulate('keydown', {keyCode: $.ui.keyCode.PAGE_UP});
	date.setMonth(date.getMonth() - 14);
	equal(selectedDate, newMonthYear(date),
		'Callback change month/year by 2 date - pgup');
	inp.simulate('keydown', {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_UP});
	date.setMonth(date.getMonth() - 12);
	equal(selectedDate, newMonthYear(date),
		'Callback change month/year by 2 date - ctrl+pgup');
	inp.simulate('keydown', {keyCode: $.ui.keyCode.PAGE_DOWN});
	date.setMonth(date.getMonth() + 2);
	equal(selectedDate, newMonthYear(date),
		'Callback change month/year by 2 date - pgdn');
	inp.simulate('keydown', {ctrlKey: true, keyCode: $.ui.keyCode.PAGE_DOWN});
	date.setMonth(date.getMonth() + 12);
	equal(selectedDate, newMonthYear(date),
		'Callback change month/year by 2 date - ctrl+pgdn');
	// onClose
	inp.datepicker('option', {onClose: callback, onChangeMonthYear: null, stepMonths: 1}).
		val('').datepicker('show').
		simulate('keydown', {keyCode: $.ui.keyCode.ESCAPE});
	equal(selectedThis, inp[0], 'Callback close this');
	equal(selectedInst, $.data(inp[0], PROP_NAME), 'Callback close inst');
	equal(selectedDate, '', 'Callback close date - esc');
	inp.val('').datepicker('show').
		simulate('keydown', {keyCode: $.ui.keyCode.ENTER});
	equal(selectedDate, $.datepicker.formatDate('mm/dd/yy', new Date()),
		'Callback close date - enter');
	inp.val('02/04/2008').datepicker('show').
		simulate('keydown', {keyCode: $.ui.keyCode.ESCAPE});
	equal(selectedDate, '02/04/2008', 'Callback close date - preset');
	inp.val('02/04/2008').datepicker('show').
		simulate('keydown', {ctrlKey: true, keyCode: $.ui.keyCode.END});
	equal(selectedDate, '', 'Callback close date - ctrl+end');

	inp2 = init('#inp2');
	inp2.datepicker().datepicker('option', {onClose: callback}).datepicker('show');
	inp.datepicker('show');
	equal(selectedThis, inp2[0], 'Callback close this');
});

})(jQuery);


var expect = require("expect.js"),
    vm = require("vm"),
    __get__ = require("../lib/__get__.js"),

    expectReferenceError = expectError(ReferenceError),
    expectTypeError = expectError(TypeError);

function expectError(ErrConstructor) {
    return function expectReferenceError(err) {
        expect(err.constructor.name).to.be(ErrConstructor.name);
    };
}

describe("__get__", function () {
    var moduleFake;

    beforeEach(function () {
        moduleFake = {
            __filename: "some/file.js",
            myNumber: 0,
            myObj: {}
        };

        vm.runInNewContext(
            "__get__ = " + __get__.toString() + "; " +
            "setNumber = function (value) { myNumber = value; }; " +
            "setObj = function (value) { myObj = value; }; ",
            moduleFake,
            __filename
        );
    });
    it("should return the initial value", function () {
        expect(moduleFake.__get__("myNumber")).to.be(0);
        expect(moduleFake.__get__("myObj")).to.eql({});
    });
    it("should return the changed value of the number", function () {
        var newObj = { hello: "hello" };

        moduleFake.setNumber(2);
        moduleFake.setObj(newObj);
        expect(moduleFake.__get__("myNumber")).to.be(2);
        expect(moduleFake.__get__("myObj")).to.be(newObj);
    });
    it("should throw a ReferenceError when getting not existing vars", function () {
        expect(function () {
            moduleFake.__get__("blabla");
        }).to.throwException(expectReferenceError);
    });
    it("should throw a TypeError when passing misfitting params", function () {
        expect(function () {
            moduleFake.__get__();
        }).to.throwException(expectTypeError);
        expect(function () {
            moduleFake.__get__(undefined);
        }).to.throwException(expectTypeError);
        expect(function () {
            moduleFake.__get__(null);
        }).to.throwException(expectTypeError);
        expect(function () {
            moduleFake.__get__(true);
        }).to.throwException(expectTypeError);
        expect(function () {
            moduleFake.__get__(2);
        }).to.throwException(expectTypeError);
        expect(function () {
            moduleFake.__get__("");
        }).to.throwException(expectTypeError);
        expect(function () {
            moduleFake.__get__([]);
        }).to.throwException(expectTypeError);
        expect(function () {
            moduleFake.__get__({});
        }).to.throwException(expectTypeError);
        expect(function () {
            moduleFake.__get__(function () {});
        }).to.throwException(expectTypeError);
    });
});


// TODO: dynamically populate the local prefix list below?

keep keep keep keep add keep keep keep keep


REPORTER = dot

test:
	@NODE_ENV=test ./node_modules/.bin/mocha --recursive --reporter $(REPORTER) --ignore-leaks --timeout 3000

test-cov:
	@NODE_ENV=test ./node_modules/.bin/mocha --require blanket --recursive --ignore-leaks --timeout 3000 -R travis-cov

test-cov-html:
	@NODE_ENV=test ./node_modules/.bin/mocha --require blanket --recursive --ignore-leaks --timeout 3000 -R html-cov > coverage.html

.PHONY: test test-cov test-cov-html


<!DOCTYPE html>

		<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
		<title>jQuery UI Example Page</title>
		<link type="text/css" href="css/smoothness/jquery-ui-1.8.16.custom.css" rel="stylesheet" />

Welcome to jQuery UI!

This page demonstrates the widgets you downloaded using the theme you selected in the download builder. We've included and linked to minified versions of jQuery, your personalized copy of jQuery UI (js/jquery-ui-1.8.16.custom.min.js), and css/smoothness/jquery-ui-1.8.16.custom.css which imports the entire jQuery UI CSS Framework. You can choose to link a subset of the CSS Framework depending on your needs.

You've downloaded components and a theme that are compatible with jQuery 1.3+. Please make sure you are using jQuery 1.3+ in your production environment.

YOUR COMPONENTS:

Accordion

First

Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet.

Second

Phasellus mattis tincidunt nibh.

Third

Nam dui erat, auctor a, dignissim quis.

Autocomplete

			<input id="autocomplete" style="z-index: 100; position: relative" title="type "a"" />

Button

		<button id="button">A button element</button>
		<form style="margin-top: 1em;">

				<input type="radio" id="radio1" name="radio" />Choice 1
				<input type="radio" id="radio2" name="radio" checked="checked" />Choice 2
				<input type="radio" id="radio3" name="radio" />Choice 3

		</form>

Tabs

First

Second

Third

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Phasellus mattis tincidunt nibh. Cras orci urna, blandit id, pretium vel, aliquet ornare, felis. Maecenas scelerisque sem non nisl. Fusce sed lorem in enim dictum bibendum.

Nam dui erat, auctor a, dignissim quis, sollicitudin eu, felis. Pellentesque nisi urna, interdum eget, sagittis et, consequat vestibulum, lacus. Mauris porttitor ullamcorper augue.

Dialog

Open Dialog

Overlay and Shadow Classes (not currently used in UI widgets)

Lorem ipsum dolor sit amet,  Nulla nec tortor. Donec id elit quis purus consectetur consequat.

Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id, sem. Morbi in orci.

Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur consequat.

Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante. Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque quam.

Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi. Aliquam ante.

Suspendisse scelerisque dui nec velit. Duis augue augue, gravida euismod, vulputate ac, facilisis id, sem. Morbi in orci. Nulla purus lacus, pulvinar vel, malesuada ac, mattis nec, quam. Nam molestie scelerisque quam. Nullam feugiat cursus lacus.orem ipsum dolor sit amet, consectetur adipiscing elit. Donec libero risus, commodo vitae, pharetra mollis, posuere eu, pede. Nulla nec tortor. Donec id elit quis purus consectetur consequat. Nam congue semper tellus. Sed erat dolor, dapibus sit amet, venenatis ornare, ultrices ut, nisi.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Framework Icons (content color preview)

Slider

Datepicker

Progressbar

Highlight / Error

				Hey! Sample ui-state-highlight style.

				Alert: Sample ui-state-error style.