<commit_before>import gulp from 'gulp'
import exec from 'gulp-exec';
import moment from 'moment';
import * as path from 'path';
import { exec as execSimple } from 'child_process';
import { deleteFolderRecursive } from "./tasks/util.babel";
import { criteria } from "./tasks/criteria.babel";
import { developmentColumn } from "./tasks/developmentColumn.babel";
import yaml2json from "js-yaml";
import { existsSync, readFileSync, writeFileSync } from "fs";
import { Configuration } from "./model/model.module";

const argv = require('minimist')(process.argv.slice(2));
argv.dir = argv.dir || "";

const ucBaseRoot = __dirname.replace(path.join("lib", "gulp"), "");
const ucRoot = __dirname.replace(path.join(argv.dir, "lib", "gulp"), "");

const tmp = path.join(ucRoot, 'tmp');
const lib = path.join(ucBaseRoot, 'lib');

const paths = {
    json: path.join(tmp, 'data'),
    dist: path.join(ucRoot, 'dist'),
    data: path.join(ucRoot, 'data'),
    config: path.join(ucRoot, 'configuration'),
    mdToJson: path.join(lib, "md-to-json"),
    assets: path.join(ucBaseRoot, 'src/assets')
};

const names = {
    data: 'data.json',
    versionInformation: 'VersionInformation.ts',
    config: 'comparison.yml',
    defaultConfig: 'comparison-default.yml',
    autoConfig: 'comparison-auto-config.yml',
    configJson: 'comparison.json'
};

const files = {
    markdown: [
        path.join(paths.data, '*.md')
    ],
    json: [
        path.join(tmp, 'data', '*.json')
    ],
    config: path.join(paths.config, names.config),
    style: path.join(paths.config, 'style.css'),
    defaultConfig: path.join(paths.config, 'comparison-default.yml'),
    description: path.join(paths.config, 'description.md'),
    mdToJsonGradle: path.join(lib, 'md-to-json/build.gradle'),
    dataJson: path.join(paths.dist, names.data),
    autoConfig: path.join(paths.config, names.autoConfig),
    versionInformation: path.join(paths.assets, names.versionInformation),
    errorLog: path.join(tmp, 'error.log')
};

const globs = {
    markdown: path.join(paths.data, '/**/', '*.md'),
    config: path.join(paths.config, names.config),
    defaultConfig: path.join(paths.config, names.defaultConfig),
    description: path.join(paths.config, '/**/', 'description.md'),
    style: path.join(paths.config, '/**/', 'style.css'),
    bib: path.join(paths.data, '/**/', '*.bib'),
    csl: path.join(paths.data, '/**/', '*.csl')
};

// BUILD / UPDATE data files -------------------------------------<
function assets() {
    return gulp.src([files.description, files.style])
        .pipe(gulp.dest(paths.dist));
}

function config(done) {
    const userConfig = Configuration.load(yaml2json.safeLoad(readFileSync(files.config, "utf8")));
    const autoConfig = Configuration.load(yaml2json.safeLoad(readFileSync(files.autoConfig, "utf8")));
    userConfig.combine(autoConfig);
    writeFileSync(path.join(paths.dist, names.configJson), JSON.stringify(userConfig.json()), "utf8");
    done();
}

gulp.task('release', function () {
    const version = argv.tag;
    const date = moment().format("YYYY-MM-DD");
    if (typeof(version) === 'undefined' || version === null || version === 'undefined') {
        throw new Error('Undefined argument tag use: `npm run release -- --tag=x.x.x`');
    }
    return gulp.src(files.versionInformation)
        .pipe(gulp.dest(paths.assets))
        .pipe(exec('sed -i\'.bak\' "s/tag = \\".*\\"/tag = \\"v' + version + '\\"/g" ' + files.versionInformation))
        .pipe(exec('sed -i\'.bak\' "s/tagDate = \\".*\\"/tagDate = \\"' + date + '\\"/g" ' + files.versionInformation))
        .pipe(exec('sed -i\'.bak\' -E "s/(tagLink = \\".*)\\/v.*\\"/\\1\\/v' + version + '\\"/" ' + files.versionInformation));
});

function markdown(callback) {
    deleteFolderRecursive(paths.json);
    const command = path.join(paths.mdToJson, 'gradlew') + " -q -b "
        + files.mdToJsonGradle
        + " run --args=\""
        + "--input " + paths.data
        + " --output " + files.dataJson
        + " --tmp " + paths.json
        + " --children {item:{1:false}}"
        + " --plainChildren {item:{1:true},header:{3:true}}\"";
    console.log(command)
    execSimple(command,
        function (err, stdout, stderr) {
            if (!existsSync(tmp)) {
                fs.mkdirSync(tmp);
            }
            writeFileSync(files.errorLog, JSON.stringify(stderr), "utf8");
            console.log(stdout);
            console.log(stderr);
            callback(err);
        });
}

function changeCriteria(done) {
    criteria(paths, files, done);
}

function copyDist(done) {
    const rootDist = path.join(ucRoot, 'dist');
    const nodeModuleDist = path.join(ucBaseRoot, 'dist');
    if (rootDist === nodeModuleDist) {
        return done();
    } else {
        return gulp.src([path.join(nodeModuleDist, '**/*')]).pipe(gulp.dest(rootDist));
    }
}

gulp.task('development-column', function (done) {
    developmentColumn(files, done);
});
// --------------------------------------------------------------->

// DEFAULT task --------------------------------------------------<
gulp.task('default', gulp.series(copyDist, markdown, changeCriteria, 'development-column', assets, config));
// --------------------------------------------------------------->

// DEVELOPMENT tasks --------------------------------------------------<
gulp.task('update-data', function () {
    gulp.watch(globs.markdown, gulp.series('default'));
});

gulp.task('update-config', function () {
    gulp.watch([globs.config, globs.defaultConfig], gulp.series(changeCriteria, assets, config));
});

gulp.task('update-description', function () {
    gulp.watch(globs.description, gulp.series(changeCriteria, assets, config));
});

gulp.task('update-style', function () {
    gulp.watch(globs.style, assets);
});

gulp.task('update-citation', function () {
    gulp.watch([globs.csl, globs.bib], gulp.series(changeCriteria, assets, config));
});

gulp.task('update', gulp.parallel('update-data', 'update-config', 'update-description', 'update-citation', 'update-style'));

gulp.task('dev', gulp.series(copyDist, 'default', 'update'));
// --------------------------------------------------------------->
<commit_msg>Quick fix for base path<commit_after>import gulp from 'gulp'
import exec from 'gulp-exec';
import moment from 'moment';
import * as path from 'path';
import { exec as execSimple } from 'child_process';
import { deleteFolderRecursive } from "./tasks/util.babel";
import { criteria } from "./tasks/criteria.babel";
import { developmentColumn } from "./tasks/developmentColumn.babel";
import yaml2json from "js-yaml";
import { existsSync, readFileSync, writeFileSync } from "fs";
import { Configuration } from "./model/model.module";

const argv = require('minimist')(process.argv.slice(2));
argv.dir = argv.dir || "";

const ucBaseRoot = __dirname.replace(path.join("lib", "gulp"), "");

var ucRoot;
if (argv.dir === "") {
    ucRoot = ucBaseRoot;
} else {
    ucRoot = ucBaseRoot.replace(argv.dir + "/", "");
}

const tmp = path.join(ucRoot, 'tmp');
const lib = path.join(ucBaseRoot, 'lib');

const paths = {
    json: path.join(tmp, 'data'),
    dist: path.join(ucRoot, 'dist'),
    data: path.join(ucRoot, 'data'),
    config: path.join(ucRoot, 'configuration'),
    mdToJson: path.join(lib, "md-to-json"),
    assets: path.join(ucBaseRoot, 'src/assets')
};

const names = {
    data: 'data.json',
    versionInformation: 'VersionInformation.ts',
    config: 'comparison.yml',
    defaultConfig: 'comparison-default.yml',
    autoConfig: 'comparison-auto-config.yml',
    configJson: 'comparison.json'
};

const files = {
    markdown: [
        path.join(paths.data, '*.md')
    ],
    json: [
        path.join(tmp, 'data', '*.json')
    ],
    config: path.join(paths.config, names.config),
    style: path.join(paths.config, 'style.css'),
    defaultConfig: path.join(paths.config, 'comparison-default.yml'),
    description: path.join(paths.config, 'description.md'),
    mdToJsonGradle: path.join(lib, 'md-to-json/build.gradle'),
    dataJson: path.join(paths.dist, names.data),
    autoConfig: path.join(paths.config, names.autoConfig),
    versionInformation: path.join(paths.assets, names.versionInformation),
    errorLog: path.join(tmp, 'error.log')
};

const globs = {
    markdown: path.join(paths.data, '/**/', '*.md'),
    config: path.join(paths.config, names.config),
    defaultConfig: path.join(paths.config, names.defaultConfig),
    description: path.join(paths.config, '/**/', 'description.md'),
    style: path.join(paths.config, '/**/', 'style.css'),
    bib: path.join(paths.data, '/**/', '*.bib'),
    csl: path.join(paths.data, '/**/', '*.csl')
};

// BUILD / UPDATE data files -------------------------------------<
function assets() {
    return gulp.src([files.description, files.style])
        .pipe(gulp.dest(paths.dist));
}

function config(done) {
    const userConfig = Configuration.load(yaml2json.safeLoad(readFileSync(files.config, "utf8")));
    const autoConfig = Configuration.load(yaml2json.safeLoad(readFileSync(files.autoConfig, "utf8")));
    userConfig.combine(autoConfig);
    writeFileSync(path.join(paths.dist, names.configJson), JSON.stringify(userConfig.json()), "utf8");
    done();
}

gulp.task('release', function () {
    const version = argv.tag;
    const date = moment().format("YYYY-MM-DD");
    if (typeof(version) === 'undefined' || version === null || version === 'undefined') {
        throw new Error('Undefined argument tag use: `npm run release -- --tag=x.x.x`');
    }
    return gulp.src(files.versionInformation)
        .pipe(gulp.dest(paths.assets))
        .pipe(exec('sed -i\'.bak\' "s/tag = \\".*\\"/tag = \\"v' + version + '\\"/g" ' + files.versionInformation))
        .pipe(exec('sed -i\'.bak\' "s/tagDate = \\".*\\"/tagDate = \\"' + date + '\\"/g" ' + files.versionInformation))
        .pipe(exec('sed -i\'.bak\' -E "s/(tagLink = \\".*)\\/v.*\\"/\\1\\/v' + version + '\\"/" ' + files.versionInformation));
});

function markdown(callback) {
    deleteFolderRecursive(paths.json);
    const command = path.join(paths.mdToJson, 'gradlew') + " -q -b "
        + files.mdToJsonGradle
        + " run --args=\""
        + "--input " + paths.data
        + " --output " + files.dataJson
        + " --tmp " + paths.json
        + " --children {item:{1:false}}"
        + " --plainChildren {item:{1:true},header:{3:true}}\"";
    console.log(command)
    execSimple(command,
        function (err, stdout, stderr) {
            if (!existsSync(tmp)) {
                fs.mkdirSync(tmp);
            }
            writeFileSync(files.errorLog, JSON.stringify(stderr), "utf8");
            console.log(stdout);
            console.log(stderr);
            callback(err);
        });
}

function changeCriteria(done) {
    criteria(paths, files, done);
}

function copyDist(done) {
    const rootDist = path.join(ucRoot, 'dist');
    const nodeModuleDist = path.join(ucBaseRoot, 'dist');
    if (rootDist === nodeModuleDist) {
        return done();
    } else {
        return gulp.src([path.join(nodeModuleDist, '**/*')]).pipe(gulp.dest(rootDist));
    }
}

gulp.task('development-column', function (done) {
    developmentColumn(files, done);
});
// --------------------------------------------------------------->

// DEFAULT task --------------------------------------------------<
gulp.task('default', gulp.series(copyDist, markdown, changeCriteria, 'development-column', assets, config));
// --------------------------------------------------------------->

// DEVELOPMENT tasks --------------------------------------------------<
gulp.task('update-data', function () {
    gulp.watch(globs.markdown, gulp.series('default'));
});

gulp.task('update-config', function () {
    gulp.watch([globs.config, globs.defaultConfig], gulp.series(changeCriteria, assets, config));
});

gulp.task('update-description', function () {
    gulp.watch(globs.description, gulp.series(changeCriteria, assets, config));
});

gulp.task('update-style', function () {
    gulp.watch(globs.style, assets);
});

gulp.task('update-citation', function () {
    gulp.watch([globs.csl, globs.bib], gulp.series(changeCriteria, assets, config));
});

gulp.task('update', gulp.parallel('update-data', 'update-config', 'update-description', 'update-citation', 'update-style'));

gulp.task('dev', gulp.series(copyDist, 'default', 'update'));
// --------------------------------------------------------------->
<|endoftext|>


<commit_before>/* eslint-disable import/no-extraneous-dependencies */
import 'should';
import capitalize from 'lodash/capitalize';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import it from '.';

const capitalized = result => Observable.of(capitalize(result));

it('should capitalize {{given}}', test => test
    .givenEach(['hello', 'world'])
    .when(capitalized)
    .thenEach(
        (result, expected) => {
            result.length.should.be.exactly(5);
            result.should.be.exactly(expected);
        },
        ['Hello', 'World']
    )
);
<commit_msg>Changed indentation for readability.<commit_after>/* eslint-disable import/no-extraneous-dependencies */
import 'should';
import capitalize from 'lodash/capitalize';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import it from '.';

const capitalized = result => Observable.of(capitalize(result));

it('should capitalize {{given}}', test => test
    .givenEach(
        ['hello', 'world']
    )
    .when(capitalized)
    .thenEach(
        (result, expected) => {
            result.length.should.be.exactly(5);
            result.should.be.exactly(expected);
        },
        ['Hello', 'World']
    )
);
<|endoftext|>


<commit_before>/* @flow */

import PageParserTree from '.';
import LiveSet from 'live-set';
import type {TagTreeNode} from 'tag-tree';

global.MutationObserver = class {
  observe() {}
  disconnect() {}
};

global._log = '';

if (!document.documentElement) throw new Error();
document.documentElement.innerHTML = `

      one
      two

      three

          four

          five

blah

foo bar

FIRST

SECOND

reply to second

reply to you

THIRD

bar foo

thing

bar

`;

function qs(el: HTMLElement, selector: string): HTMLElement {
  const result = el.querySelector(selector);
  if (!result) throw new Error(`Selector failed to find element: ${selector}`);
  return result;
}

test('sync test', () => {
  const page = new PageParserTree(document, [
    {sources: [null], selectors: [
      'body',
      'nav',
      {$tag: 'topnav'}
    ]},
    {sources: ['topnav'], selectors: [
      'div',
      'a',
      {$tag: 'navLink'}
    ]},
    {sources: ['topnav'], selectors: [
      'div',
      {$map: el => el.querySelector('a[href="blah"]')},
      {$filter: el => el.textContent !== 'five'},
      {$tag: 'navBlahFourLink'}
    ]},
    {sources: [null], selectors: [
      'body',
      '.page-sidebar',
      'div',
      {$tag: 'sidebarItem'}
    ]},
    {sources: [null], selectors: [
      'body',
      '.page-outer',
      '.article-comments',
      {$tag: 'commentSection'}
    ]},
    {sources: ['commentSection', 'replySection'], selectors: [
      {$or: [
        [
          '.comment'
        ], [
          '.comment2',
          '.comment2-inner'
        ]
      ]},
      {$tag: 'comment', ownedBy: ['comment']}
    ]},
    {sources: ['comment'], selectors: [
      '.replies',
      {$tag: 'replySection', ownedBy: ['comment']}
    ]}
  ]);

  expect(Array.from(page.tree.getAllByTag('navBlahFourLink').values()).map(x => x.getValue().outerHTML))
    .toEqual([
      'four'
    ]);

  const allComments: LiveSet<TagTreeNode<HTMLElement>> = page.tree.getAllByTag('comment');
  expect(Array.from(allComments.values()).map(x=>qs(x.getValue(), '.body').textContent))
    .toEqual([
      'foo bar',
      'bar foo',
      'FIRST',
      'SECOND',
      'THIRD',
      'reply to second',
      'reply to you'
    ]);

  const topLevelComments: LiveSet<TagTreeNode<HTMLElement>> = page.tree.getOwnedByTag('comment');
  expect(Array.from(topLevelComments.values()).map(x=>qs(x.getValue(), '.body').textContent))
    .toEqual([
      'foo bar',
      'bar foo'
    ]);

  const foobarComments: LiveSet<TagTreeNode<HTMLElement>> = Array.from(topLevelComments.values())[0].getOwnedByTag('comment');

  expect(Array.from(foobarComments.values()).map(x=>qs(x.getValue(), '.body').textContent))
    .toEqual([
      'FIRST',
      'SECOND',
      'THIRD'
    ]);
});

describe('validation', () => {
  test('ownedBy non-existent tag', () => {
    expect(() => new PageParserTree(document, [
      {sources: [null], selectors: [
        'body',
        'a',
        {$tag: 'foo', ownedBy: ['bar']}
      ]}
    ])).toThrowError();
  });

  test('inconsistent definitions', () => {
    expect(() => new PageParserTree(document, [
      {sources: [null], selectors: [
        'body',
        {$tag: 'bar'},
        {$tag: 'foo', ownedBy: ['foo']},
        {$tag: 'foo', ownedBy: ['bar']},
      ]}
    ])).toThrowError();

    expect(() => new PageParserTree(document, [
      {sources: [null], selectors: [
        'body',
        {$tag: 'bar'},
        {$tag: 'foo', ownedBy: ['foo', 'bar']},
        {$tag: 'foo', ownedBy: ['bar']},
      ]}
    ])).toThrowError();

    expect(() => new PageParserTree(document, [
      {sources: [null], selectors: [
        'body',
        {$tag: 'bar'},
        {$tag: 'foo'},
        {$tag: 'foo', ownedBy: ['bar']},
      ]}
    ])).toThrowError();

    expect(() => new PageParserTree(document, [
      {sources: [null], selectors: [
        'body',
        {$tag: 'bar'},
        {$tag: 'foo', ownedBy: ['bar']},
        {$tag: 'foo'},
      ]}
    ])).toThrowError();
  });

  test('consistent redefinition', () => {
    expect(() => new PageParserTree(document, [
      {sources: [null], selectors: [
        'body',
        {$tag: 'bar'},
        {$tag: 'foo', ownedBy: ['bar']},
        {$tag: 'foo', ownedBy: ['bar']},
      ]}
    ])).not.toThrowError();
  });
});
<commit_msg>Test element removal.<commit_after>/* @flow */

import PageParserTree from '.';
import LiveSet from 'live-set';
import type {TagTreeNode} from 'tag-tree';
import EventEmitter from 'events';
import delay from 'pdelay';

const emitters = new WeakMap();
function ev(el: Element): EventEmitter {
  let emitter = emitters.get(el);
  if (!emitter) {
    emitter = new EventEmitter();
    emitters.set(el, emitter);
  }
  return emitter;
}

global.MutationObserver = class {
  _elements = [];
  _cb: Function;
  constructor(cb) {
    this._cb = cb;
  }
  _listener = mutations => {
    this._cb(mutations);
  };
  observe(element) {
    this._elements.push(element);
    ev(element).on('mutate', this._listener);
  }
  disconnect() {
    this._elements.forEach(el => ev(el).removeListener('mutate', this._listener));
  }
};

if (!document.documentElement) throw new Error();
document.documentElement.innerHTML = `

      one
      two

      three

          four

          five

blah

foo bar

FIRST

SECOND

reply to second

reply to you

THIRD

bar foo

thing

bar

`;

function qs(el: HTMLElement, selector: string): HTMLElement {
  const result = el.querySelector(selector);
  if (!result) throw new Error(`Selector failed to find element: ${selector}`);
  return result;
}

test('sync test', async () => {
  const page = new PageParserTree(document, [
    {sources: [null], selectors: [
      'body',
      'nav',
      {$tag: 'topnav'}
    ]},
    {sources: ['topnav'], selectors: [
      'div',
      'a',
      {$tag: 'navLink'}
    ]},
    {sources: ['topnav'], selectors: [
      'div',
      {$map: el => el.querySelector('a[href="blah"]')},
      {$filter: el => el.textContent !== 'five'},
      {$tag: 'navBlahFourLink'}
    ]},
    {sources: [null], selectors: [
      'body',
      '.page-sidebar',
      'div',
      {$tag: 'sidebarItem'}
    ]},
    {sources: [null], selectors: [
      'body',
      '.page-outer',
      '.article-comments',
      {$tag: 'commentSection'}
    ]},
    {sources: ['commentSection', 'replySection'], selectors: [
      {$or: [
        [
          '.comment'
        ], [
          '.comment2',
          '.comment2-inner'
        ]
      ]},
      {$tag: 'comment', ownedBy: ['comment']}
    ]},
    {sources: ['comment'], selectors: [
      '.replies',
      {$tag: 'replySection', ownedBy: ['comment']}
    ]}
  ]);

  expect(Array.from(page.tree.getAllByTag('navBlahFourLink').values()).map(x => x.getValue().outerHTML))
    .toEqual([
      'four'
    ]);

  const allComments: LiveSet<TagTreeNode<HTMLElement>> = page.tree.getAllByTag('comment');
  expect(Array.from(allComments.values()).map(x=>qs(x.getValue(), '.body').textContent))
    .toEqual([
      'foo bar',
      'bar foo',
      'FIRST',
      'SECOND',
      'THIRD',
      'reply to second',
      'reply to you'
    ]);

  const topLevelComments: LiveSet<TagTreeNode<HTMLElement>> = page.tree.getOwnedByTag('comment');
  expect(Array.from(topLevelComments.values()).map(x=>qs(x.getValue(), '.body').textContent))
    .toEqual([
      'foo bar',
      'bar foo'
    ]);

  const foobarComment: TagTreeNode<HTMLElement> = Array.from(topLevelComments.values())[0];
  const foobarComments: LiveSet<TagTreeNode<HTMLElement>> = foobarComment.getOwnedByTag('comment');

  expect(Array.from(foobarComments.values()).map(x=>qs(x.getValue(), '.body').textContent))
    .toEqual([
      'FIRST',
      'SECOND',
      'THIRD'
    ]);

  {
    const foobarCommentParentElement: any = foobarComment.getValue().parentElement;
    foobarComment.getValue().remove();
    ev(foobarCommentParentElement).emit('mutate', [{
      addedNodes: [],
      removedNodes: [foobarComment.getValue()]
    }]);
  }

  await delay(0);

  expect(Array.from(topLevelComments.values()).map(x=>qs(x.getValue(), '.body').textContent))
    .toEqual([
      'bar foo'
    ]);

  expect(Array.from(foobarComments.values()).map(x=>qs(x.getValue(), '.body').textContent))
    .toEqual([
    ]);
});

describe('validation', () => {
  test('ownedBy non-existent tag', () => {
    expect(() => new PageParserTree(document, [
      {sources: [null], selectors: [
        'body',
        'a',
        {$tag: 'foo', ownedBy: ['bar']}
      ]}
    ])).toThrowError();
  });

  test('inconsistent definitions', () => {
    expect(() => new PageParserTree(document, [
      {sources: [null], selectors: [
        'body',
        {$tag: 'bar'},
        {$tag: 'foo', ownedBy: ['foo']},
        {$tag: 'foo', ownedBy: ['bar']},
      ]}
    ])).toThrowError();

    expect(() => new PageParserTree(document, [
      {sources: [null], selectors: [
        'body',
        {$tag: 'bar'},
        {$tag: 'foo', ownedBy: ['foo', 'bar']},
        {$tag: 'foo', ownedBy: ['bar']},
      ]}
    ])).toThrowError();

    expect(() => new PageParserTree(document, [
      {sources: [null], selectors: [
        'body',
        {$tag: 'bar'},
        {$tag: 'foo'},
        {$tag: 'foo', ownedBy: ['bar']},
      ]}
    ])).toThrowError();

    expect(() => new PageParserTree(document, [
      {sources: [null], selectors: [
        'body',
        {$tag: 'bar'},
        {$tag: 'foo', ownedBy: ['bar']},
        {$tag: 'foo'},
      ]}
    ])).toThrowError();
  });

  test('consistent redefinition', () => {
    expect(() => new PageParserTree(document, [
      {sources: [null], selectors: [
        'body',
        {$tag: 'bar'},
        {$tag: 'foo', ownedBy: ['bar']},
        {$tag: 'foo', ownedBy: ['bar']},
      ]}
    ])).not.toThrowError();
  });
});
<|endoftext|>


<commit_before>module.exports = /#(?:boobs?|milf|naked|porno?|idgaf)|(?:fetish|booty|nsfw|cock|sugarMeDaddy\.com)/i;
<commit_msg>added another filter in regex.<commit_after>module.exports = /#(?:boobs?|milf|naked|porno?|idgaf|sugarDaddy)|(?:fetish|booty|nsfw|cock|sugarMeDaddy\.com)/i;
<|endoftext|>


<commit_before>/**
 * @fileoverview YouTube Media Controller - Wrapper for YouTube Media API
 */

/**
 * YouTube Media Controller - Wrapper for YouTube Media API
 * @param {videojs.Player|Object} player
 * @param {Object=} options
 * @param {Function=} ready
 * @constructor
 */
videojs.Youtube = videojs.MediaTechController.extend({
  init: function(player, options, ready){
    videojs.MediaTechController.call(this, player, options, ready);

    this.player_ = player;
    this.player_el_ = document.getElementById(this.player_.id());

    // Regex that parse the video ID for any YouTube URL
    var regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
    var match = options.source.src.match(regExp);

    if (match && match[2].length == 11){
      this.videoId = match[2];

      // Show the YouTube poster only if we don't use YouTube poster (otherwise the controls pop, it's not nice)
      if (!this.player_.options().ytcontrols){
        this.player_.poster('http://img.youtube.com/vi/' + this.videoId + '/0.jpg');

        // Cover the entire iframe to have the same poster than YouTube
        // Doesn't exist right away because the DOM hasn't created it
        var self = this;
        setTimeout(function(){ self.player_.posterImage.el().style.backgroundSize = 'cover'; }, 50);
      }
    }

    this.id_ = this.player_.id() + '_youtube_api';

    this.el_ = videojs.Component.prototype.createEl('iframe', {
      id: this.id_,
      className: 'vjs-tech',
      scrolling: 'no',
      marginWidth: 0,
      marginHeight: 0,
      frameBorder: 0,
      webkitAllowFullScreen: '',
      mozallowfullscreen: '',
      allowFullScreen: ''
    });

    this.player_el_.insertBefore(this.el_, this.player_el_.firstChild);

    var params = {
      enablejsapi: 1,
      iv_load_policy: 3,
      playerapiid: this.id(),
      disablekb: 1,
      controls: (this.player_.options().ytcontrols)?1:0,
      showinfo: 0,
      modestbranding: 1,
      rel: 0,
      autoplay: (this.player_.options().autoplay)?1:0,
      loop: (this.player_.options().loop)?1:0
    };

    // If we are not on a server, don't specify the origin (it will crash)
    if (window.location.protocol != 'file:') {
      params.origin = window.location.origin;
    }

    this.el_.src = 'http://www.youtube.com/embed/' + this.videoId + '?' + videojs.Youtube.makeQueryString(params);

    if (this.player_.options().ytcontrols){
      // Hide the big play button when using YouTube controls
      // Doesn't exist right away because the DOM hasn't created it
      var self = this;
      setTimeout(function(){ self.player_.bigPlayButton.hide(); }, 50);
    }

    if (videojs.Youtube.apiReady){
      this.loadYoutube();
    } else {
      // Add to the queue because the YouTube API is not ready
      videojs.Youtube.loadingQueue.push(this);

      // Load the YouTube API if it is the first YouTube video
      if(!videojs.Youtube.apiLoading){
        var tag = document.createElement('script');
        tag.src = 'http://www.youtube.com/iframe_api';
        var firstScriptTag = document.getElementsByTagName('script')[0];
        firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
        videojs.Youtube.apiLoading = true;
      }
    }
  }
});

videojs.Youtube.prototype.dispose = function(){
  this.ytplayer.destroy();
  videojs.MediaTechController.prototype.dispose.call(this);
};

videojs.Youtube.prototype.play = function(){
  if (this.isReady_){
    this.ytplayer.playVideo();
  } else {
    // We will play it when the API will be ready
    this.playOnReady = true;

    if (!this.player_.options.ytcontrols) {
      // Keep the big play button until it plays for real
      this.player_.bigPlayButton.show();
    }
  }
};

videojs.Youtube.prototype.pause = function(){ this.ytplayer.pauseVideo(); };
videojs.Youtube.prototype.paused = function(){
  return this.lastState !== YT.PlayerState.PLAYING &&
         this.lastState !== YT.PlayerState.BUFFERING;
};

videojs.Youtube.prototype.currentTime = function(){ return this.ytplayer.getCurrentTime(); };

videojs.Youtube.prototype.setCurrentTime = function(seconds){
  this.ytplayer.seekTo(seconds, true);
  this.player_.trigger('timeupdate');
};

videojs.Youtube.prototype.duration = function(){ return this.ytplayer.getDuration(); };
videojs.Youtube.prototype.buffered = function(){
  var loadedBytes = this.ytplayer.getVideoBytesLoaded();
  var totalBytes = this.ytplayer.getVideoBytesTotal();
  if (!loadedBytes || !totalBytes) return 0;

  var duration = this.ytplayer.getDuration();
  var secondsBuffered = (loadedBytes / totalBytes) * duration;
  var secondsOffset = (this.ytplayer.getVideoStartBytes() / totalBytes) * duration;
  return videojs.createTimeRange(secondsOffset, secondsOffset + secondsBuffered);
};

videojs.Youtube.prototype.volume = function() {
  if (isNaN(this.volumeVal)) {
    this.volumeVal = this.ytplayer.getVolume() / 100.0;
  }

  return this.volumeVal;
};

videojs.Youtube.prototype.setVolume = function(percentAsDecimal){
  if (percentAsDecimal && percentAsDecimal != this.volumeVal) {
    this.ytplayer.setVolume(percentAsDecimal * 100.0);
    this.volumeVal = percentAsDecimal;
    this.player_.trigger('volumechange');
  }
};

videojs.Youtube.prototype.muted = function() { return this.ytplayer.isMuted(); };
videojs.Youtube.prototype.setMuted = function(muted) {
  if (muted) {
    this.ytplayer.mute();
  } else {
    this.ytplayer.unMute();
  }

  var self = this;
  setTimeout(function() { self.player_.trigger('volumechange'); }, 50);
};

videojs.Youtube.prototype.onReady = function(){
  this.isReady_ = true;
  this.player_.trigger('techready');

  // Hide the poster when ready because YouTube has it's own
  this.player_.posterImage.hide();
  this.triggerReady();
  this.player_.trigger('durationchange');

  // Play right away if we clicked before ready
  if (this.playOnReady){
    this.player_.bigPlayButton.hide();
    this.ytplayer.playVideo();
  }

  if (!this.player_.options().controls || this.player_.options().ytcontrols){
    // Hide the VideoJS controls
    this.player_.controlBar.hide();
  }
};

videojs.Youtube.prototype.onStateChange = function(state){
  if (state != this.lastState){
    switch(state){
      case -1:
        this.player_.trigger('durationchange');
        break;

      case YT.PlayerState.ENDED:
        this.player_.trigger('ended');

        if (!this.player_.options().ytcontrols){
          this.player_.bigPlayButton.show();
        }
        break;

      case YT.PlayerState.PLAYING:
        this.player_.trigger('timeupdate');
        this.player_.trigger('durationchange');
        this.player_.trigger('playing');
        this.player_.trigger('play');
        break;

      case YT.PlayerState.PAUSED:
        this.player_.trigger('pause');
        break;

      case YT.PlayerState.BUFFERING:
        this.player_.trigger('timeupdate');
        this.player_.trigger('waiting');

        // Hide the waiting spinner since YouTube has its own
        this.player_.loadingSpinner.hide();
        break;

      case YT.PlayerState.CUED:
        break;
    }

    this.lastState = state;
  }
};

videojs.Youtube.prototype.onPlaybackQualityChange = function(quality){
  switch(quality){
    case 'medium':
      this.player_.videoWidth = 480;
      this.player_.videoHeight = 360;
      break;

    case 'large':
      this.player_.videoWidth = 640;
      this.player_.videoHeight = 480;
      break;

    case 'hd720':
      this.player_.videoWidth = 960;
      this.player_.videoHeight = 720;
      break;

    case 'hd1080':
      this.player_.videoWidth = 1440;
      this.player_.videoHeight = 1080;
      break;

    case 'highres':
      this.player_.videoWidth = 1920;
      this.player_.videoHeight = 1080;
      break;

    case 'small':
      this.player_.videoWidth = 320;
      this.player_.videoHeight = 240;
      break;

    default:
      this.player_.videoWidth = 0;
      this.player_.videoHeight = 0;
      break;
  }

  this.player_.trigger('ratechange');
};

videojs.Youtube.prototype.onError = function(error){
  this.player_.error = error;
  this.player_.trigger('error');
};

videojs.Youtube.isSupported = function(){
  return true;
};

videojs.Youtube.canPlaySource = function(srcObj){
  return (srcObj.type == 'video/youtube');
};

// All videos created before YouTube API is loaded
videojs.Youtube.loadingQueue = [];

// Create the YouTube player
videojs.Youtube.prototype.loadYoutube = function(){
  this.ytplayer = new YT.Player(this.id_, {
    events: {
      onReady: function(e) { e.target.vjsTech.onReady(); },
      onStateChange: function(e) { e.target.vjsTech.onStateChange(e.data); },
      onPlaybackQualityChange: function(e){ e.target.vjsTech.onPlaybackQualityChange(e.data); },
      onError: function(e){ e.target.vjsTech.onError(e.data); }
    }
  });

  this.ytplayer.vjsTech = this;
};

videojs.Youtube.makeQueryString = function(args){
  var array = [];
  for (var key in args){
    if (args.hasOwnProperty(key)){
      array.push(encodeURIComponent(key) + '=' + encodeURIComponent(args[key]));
    }
  }

  return array.join('&');
};

// Called when YouTube API is ready to be used
window.onYouTubeIframeAPIReady = function(){

  var yt;
  while ((yt = videojs.Youtube.loadingQueue.shift())){
    yt.loadYoutube();
  }
  videojs.Youtube.loadingQueue = [];
  videojs.Youtube.apiReady = true;
}

// TODO: Use advanced optimization
// Export for advanced closure compiler

/*goog.exportProperty(videojs, 'Youtube', videojs.Youtube);
goog.exportProperty(videojs.Youtube, 'Events', videojs.Youtube.Events);
goog.exportProperty(videojs.Youtube, 'isSupported', videojs.Youtube.isSupported);
goog.exportProperty(videojs.Youtube, 'canPlaySource', videojs.Youtube.canPlaySource);

goog.exportProperty(videojs.Youtube.prototype, 'setCurrentTime', videojs.Youtube.prototype.setCurrentTime);
goog.exportProperty(videojs.Youtube.prototype, 'setVolume', videojs.Youtube.prototype.setVolume);
goog.exportProperty(videojs.Youtube.prototype, 'setMuted', videojs.Youtube.prototype.setMuted);
goog.exportProperty(videojs.Youtube.prototype, 'setPreload', videojs.Youtube.prototype.setPreload);
goog.exportProperty(videojs.Youtube.prototype, 'setAutoplay', videojs.Youtube.prototype.setAutoplay);
goog.exportProperty(videojs.Youtube.prototype, 'setLoop', videojs.Youtube.prototype.setLoop);*/
<commit_msg>No advanced closure compiler (not worth it)<commit_after>/**
 * @fileoverview YouTube Media Controller - Wrapper for YouTube Media API
 */

/**
 * YouTube Media Controller - Wrapper for YouTube Media API
 * @param {videojs.Player|Object} player
 * @param {Object=} options
 * @param {Function=} ready
 * @constructor
 */
videojs.Youtube = videojs.MediaTechController.extend({
  init: function(player, options, ready){
    videojs.MediaTechController.call(this, player, options, ready);

    this.player_ = player;
    this.player_el_ = document.getElementById(this.player_.id());

    // Regex that parse the video ID for any YouTube URL
    var regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
    var match = options.source.src.match(regExp);

    if (match && match[2].length == 11){
      this.videoId = match[2];

      // Show the YouTube poster only if we don't use YouTube poster (otherwise the controls pop, it's not nice)
      if (!this.player_.options().ytcontrols){
        this.player_.poster('http://img.youtube.com/vi/' + this.videoId + '/0.jpg');

        // Cover the entire iframe to have the same poster than YouTube
        // Doesn't exist right away because the DOM hasn't created it
        var self = this;
        setTimeout(function(){ self.player_.posterImage.el().style.backgroundSize = 'cover'; }, 50);
      }
    }

    this.id_ = this.player_.id() + '_youtube_api';

    this.el_ = videojs.Component.prototype.createEl('iframe', {
      id: this.id_,
      className: 'vjs-tech',
      scrolling: 'no',
      marginWidth: 0,
      marginHeight: 0,
      frameBorder: 0,
      webkitAllowFullScreen: '',
      mozallowfullscreen: '',
      allowFullScreen: ''
    });

    this.player_el_.insertBefore(this.el_, this.player_el_.firstChild);

    var params = {
      enablejsapi: 1,
      iv_load_policy: 3,
      playerapiid: this.id(),
      disablekb: 1,
      controls: (this.player_.options().ytcontrols)?1:0,
      showinfo: 0,
      modestbranding: 1,
      rel: 0,
      autoplay: (this.player_.options().autoplay)?1:0,
      loop: (this.player_.options().loop)?1:0
    };

    // If we are not on a server, don't specify the origin (it will crash)
    if (window.location.protocol != 'file:') {
      params.origin = window.location.origin;
    }

    this.el_.src = 'http://www.youtube.com/embed/' + this.videoId + '?' + videojs.Youtube.makeQueryString(params);

    if (this.player_.options().ytcontrols){
      // Hide the big play button when using YouTube controls
      // Doesn't exist right away because the DOM hasn't created it
      var self = this;
      setTimeout(function(){ self.player_.bigPlayButton.hide(); }, 50);
    }

    if (videojs.Youtube.apiReady){
      this.loadYoutube();
    } else {
      // Add to the queue because the YouTube API is not ready
      videojs.Youtube.loadingQueue.push(this);

      // Load the YouTube API if it is the first YouTube video
      if(!videojs.Youtube.apiLoading){
        var tag = document.createElement('script');
        tag.src = 'http://www.youtube.com/iframe_api';
        var firstScriptTag = document.getElementsByTagName('script')[0];
        firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
        videojs.Youtube.apiLoading = true;
      }
    }
  }
});

videojs.Youtube.prototype.dispose = function(){
  this.ytplayer.destroy();
  videojs.MediaTechController.prototype.dispose.call(this);
};

videojs.Youtube.prototype.play = function(){
  if (this.isReady_){
    this.ytplayer.playVideo();
  } else {
    // We will play it when the API will be ready
    this.playOnReady = true;

    if (!this.player_.options.ytcontrols) {
      // Keep the big play button until it plays for real
      this.player_.bigPlayButton.show();
    }
  }
};

videojs.Youtube.prototype.pause = function(){ this.ytplayer.pauseVideo(); };
videojs.Youtube.prototype.paused = function(){
  return this.lastState !== YT.PlayerState.PLAYING &&
         this.lastState !== YT.PlayerState.BUFFERING;
};

videojs.Youtube.prototype.currentTime = function(){ return this.ytplayer.getCurrentTime(); };

videojs.Youtube.prototype.setCurrentTime = function(seconds){
  this.ytplayer.seekTo(seconds, true);
  this.player_.trigger('timeupdate');
};

videojs.Youtube.prototype.duration = function(){ return this.ytplayer.getDuration(); };
videojs.Youtube.prototype.buffered = function(){
  var loadedBytes = this.ytplayer.getVideoBytesLoaded();
  var totalBytes = this.ytplayer.getVideoBytesTotal();
  if (!loadedBytes || !totalBytes) return 0;

  var duration = this.ytplayer.getDuration();
  var secondsBuffered = (loadedBytes / totalBytes) * duration;
  var secondsOffset = (this.ytplayer.getVideoStartBytes() / totalBytes) * duration;
  return videojs.createTimeRange(secondsOffset, secondsOffset + secondsBuffered);
};

videojs.Youtube.prototype.volume = function() {
  if (isNaN(this.volumeVal)) {
    this.volumeVal = this.ytplayer.getVolume() / 100.0;
  }

  return this.volumeVal;
};

videojs.Youtube.prototype.setVolume = function(percentAsDecimal){
  if (percentAsDecimal && percentAsDecimal != this.volumeVal) {
    this.ytplayer.setVolume(percentAsDecimal * 100.0);
    this.volumeVal = percentAsDecimal;
    this.player_.trigger('volumechange');
  }
};

videojs.Youtube.prototype.muted = function() { return this.ytplayer.isMuted(); };
videojs.Youtube.prototype.setMuted = function(muted) {
  if (muted) {
    this.ytplayer.mute();
  } else {
    this.ytplayer.unMute();
  }

  var self = this;
  setTimeout(function() { self.player_.trigger('volumechange'); }, 50);
};

videojs.Youtube.prototype.onReady = function(){
  this.isReady_ = true;
  this.player_.trigger('techready');

  // Hide the poster when ready because YouTube has it's own
  this.player_.posterImage.hide();
  this.triggerReady();
  this.player_.trigger('durationchange');

  // Play right away if we clicked before ready
  if (this.playOnReady){
    this.player_.bigPlayButton.hide();
    this.ytplayer.playVideo();
  }

  if (!this.player_.options().controls || this.player_.options().ytcontrols){
    // Hide the VideoJS controls
    this.player_.controlBar.hide();
  }
};

videojs.Youtube.prototype.onStateChange = function(state){
  if (state != this.lastState){
    switch(state){
      case -1:
        this.player_.trigger('durationchange');
        break;

      case YT.PlayerState.ENDED:
        this.player_.trigger('ended');

        if (!this.player_.options().ytcontrols){
          this.player_.bigPlayButton.show();
        }
        break;

      case YT.PlayerState.PLAYING:
        this.player_.trigger('timeupdate');
        this.player_.trigger('durationchange');
        this.player_.trigger('playing');
        this.player_.trigger('play');
        break;

      case YT.PlayerState.PAUSED:
        this.player_.trigger('pause');
        break;

      case YT.PlayerState.BUFFERING:
        this.player_.trigger('timeupdate');
        this.player_.trigger('waiting');

        // Hide the waiting spinner since YouTube has its own
        this.player_.loadingSpinner.hide();
        break;

      case YT.PlayerState.CUED:
        break;
    }

    this.lastState = state;
  }
};

videojs.Youtube.prototype.onPlaybackQualityChange = function(quality){
  switch(quality){
    case 'medium':
      this.player_.videoWidth = 480;
      this.player_.videoHeight = 360;
      break;

    case 'large':
      this.player_.videoWidth = 640;
      this.player_.videoHeight = 480;
      break;

    case 'hd720':
      this.player_.videoWidth = 960;
      this.player_.videoHeight = 720;
      break;

    case 'hd1080':
      this.player_.videoWidth = 1440;
      this.player_.videoHeight = 1080;
      break;

    case 'highres':
      this.player_.videoWidth = 1920;
      this.player_.videoHeight = 1080;
      break;

    case 'small':
      this.player_.videoWidth = 320;
      this.player_.videoHeight = 240;
      break;

    default:
      this.player_.videoWidth = 0;
      this.player_.videoHeight = 0;
      break;
  }

  this.player_.trigger('ratechange');
};

videojs.Youtube.prototype.onError = function(error){
  this.player_.error = error;
  this.player_.trigger('error');
};

videojs.Youtube.isSupported = function(){
  return true;
};

videojs.Youtube.canPlaySource = function(srcObj){
  return (srcObj.type == 'video/youtube');
};

// All videos created before YouTube API is loaded
videojs.Youtube.loadingQueue = [];

// Create the YouTube player
videojs.Youtube.prototype.loadYoutube = function(){
  this.ytplayer = new YT.Player(this.id_, {
    events: {
      onReady: function(e) { e.target.vjsTech.onReady(); },
      onStateChange: function(e) { e.target.vjsTech.onStateChange(e.data); },
      onPlaybackQualityChange: function(e){ e.target.vjsTech.onPlaybackQualityChange(e.data); },
      onError: function(e){ e.target.vjsTech.onError(e.data); }
    }
  });

  this.ytplayer.vjsTech = this;
};

videojs.Youtube.makeQueryString = function(args){
  var array = [];
  for (var key in args){
    if (args.hasOwnProperty(key)){
      array.push(encodeURIComponent(key) + '=' + encodeURIComponent(args[key]));
    }
  }

  return array.join('&');
};

// Called when YouTube API is ready to be used
window.onYouTubeIframeAPIReady = function(){

  var yt;
  while ((yt = videojs.Youtube.loadingQueue.shift())){
    yt.loadYoutube();
  }
  videojs.Youtube.loadingQueue = [];
  videojs.Youtube.apiReady = true;
}

<|endoftext|>


<commit_before>import 'hyperagent/config' as c;
import 'hyperagent/ajax' as ajax;
import Properties from 'hyperagent/properties';

function Resource(args) {
  if (args === Object(args)) {
    this._options = args;
  } else {
    this._options = { url: args };
  }

  // Create empty attributes by default.
  this.props = Properties({});
  this.embedded = {};
  this.links = {};

  this.loaded = false;
}

Resource.factory = function (cls) {
  return function (object, options) {
    return new cls(object, options);
  }
};

Resource.prototype.fetch = function fetch() {
  // Pick only AJAX-relevant options.
  var options = c._.pick(this._options, 'jsonp', 'headers', 'username',
      'password', 'url');

  return ajax(options).then(function _ajaxThen(response) {
    this._parse(response);
    this.loaded = true;

    // Return the agent back.
    return this;
  }.bind(this));
};

Resource.prototype.url = function url() {
  return this._options.url;
};

/**
 * Parses a response string.
 */
Resource.prototype._parse = function _parse(response) {
  var object = JSON.parse(response);
  this._load(object);
};

Resource.prototype._load = function _load(object) {
  this.props = new Properties(object);

  // HAL actually defines this as OPTIONAL
  if (object._links) {
    this.links = new LazyResource(this, object._links, {
      factory: Resource.factory(LinkResource)
    });

    // Don't access through this.links to avoid triggering recursions
    if (object._links.self) {
      this._navigateUrl(object._links.self.href);
    }
  }

  if (object._embedded) {
    this.embedded = new LazyResource(this, object._embedded, {
      factory: Resource.factory(EmbeddedResource)
    });
  }
};

/**
 * Updates the internal URL to the new, relative change. This is not an
 * idempotent function.
 */
Resource.prototype._navigateUrl = function _navigateUrl(value) {
  if (!value) {
    throw new Error('Expected absolute or relative URL, but got: ' + value);
  }

  var uri = new URI(value);
  if (uri.is('absolute')) {
    // Replace the current url if it's absolute
    this._options.url = uri.normalize().toString();
  } else if (value[0] === '/') {
    this._options.url = (new URI(this._options.url))
      .resource(value).normalize().toString();
  } else {
    // TODO: Handle relative changes
    this._options.url = new URI([this._options.url, value].join('/'))
      .normalize().toString();
  }
};

/**
 * Wrap a resource inside a lazy container that loads all properties of the
 * given `object` on access in a Resource.
 *
 * Arguments:
 *  - parentResource: the resource this one depends is created from
 *    extract a custom URL value.
 *  - object: the object to wrap
 *  - options: optional options
 *    - transform: A function applied to the resource once accessed, receives
 *      the new resource and the source object as parameters and is expected to
 *      return the resource.
 */
function LazyResource(parentResource, object, options) {
  this._parent = parentResource;
  this._options = _.defaults(options || {}, {
    factory: function (object, options) {
      var resource = new Resource(options);
      resource._load(object);

      return resource;
    }
  });

  // Set _parent and _options to not be enumerable, to allow easy looping over
  // all entries.
  Object.defineProperties(this, {
    _parent: {
      enumerable: false
    },
    _options: {
      enumerable: false
    }
  })

  _.each(object, function (obj, key) {
    if (Array.isArray(obj)) {
      this._setLazyArray(key, obj);
    } else {
      this._setLazyObject(key, obj);
    }
  }.bind(this));
}

LazyResource.prototype._setLazyObject = function _setLazy(key, object) {
  // Define a lazy getter for the resource.
  Object.defineProperty(this, key, {
    enumerable: true,
    get: this._makeGetter(object)
  });
};

LazyResource.prototype._setLazyArray = function _setLazy(key, array) {
  // Define a lazy getter for the resource that contains the array.
  Object.defineProperty(this, key, {
    enumerable: true,
    get: function () {
      return array.map(function (object) {
        return this._makeGetter(object)();
      }.bind(this));
    }
  });
};

LazyResource.prototype._makeGetter = function _makeGetter(object) {
  var parent = this._parent;
  var options = this._options;

  return function () {
      return new options.factory(object, _.clone(parent._options));
  }.bind(this);
};

function EmbeddedResource(object, options) {
  // Inherit from Resource
  Resource.call(this, options);

  this._load(object);

  // Embedded resources are alsways considered as loaded.
  this.loaded = true;
}

_.extend(EmbeddedResource.prototype, Resource.prototype);

function LinkResource(object, options) {
  // Inherit from Resource
  Resource.call(this, options);

  // The href is OPTIONAL, even for links.
  if (object.href) {
    this._navigateUrl(object.href);
  } else {
    console.warn('Link object did not provide an `href`: ', object);
  }

  this._load(object);
}

_.extend(LinkResource.prototype, Resource.prototype);

export { Resource, LazyResource };
<commit_msg>WIP: Templated Links<commit_after>import 'hyperagent/config' as c;
import 'hyperagent/ajax' as ajax;
import Properties from 'hyperagent/properties';

function Resource(args) {
  if (args === Object(args)) {
    this._options = args;
  } else {
    this._options = { url: args };
  }

  // Create empty attributes by default.
  this.props = Properties({});
  this.embedded = {};
  this.links = {};

  this.loaded = false;
}

Resource.factory = function (cls) {
  return function (object, options) {
    return new cls(object, options);
  }
};

Resource.prototype.fetch = function fetch() {
  // Pick only AJAX-relevant options.
  var options = c._.pick(this._options, 'jsonp', 'headers', 'username',
      'password', 'url');

  return ajax(options).then(function _ajaxThen(response) {
    this._parse(response);
    this.loaded = true;

    // Return the agent back.
    return this;
  }.bind(this));
};

Resource.prototype.url = function url() {
  return this._options.url;
};

/**
 * Parses a response string.
 */
Resource.prototype._parse = function _parse(response) {
  var object = JSON.parse(response);
  this._load(object);
};

Resource.prototype._load = function _load(object) {
  this.props = new Properties(object);

  // HAL actually defines this as OPTIONAL
  if (object._links) {
    this.links = new LazyResource(this, object._links, {
      factory: Resource.factory(LinkResource)
    });

    // Don't access through this.links to avoid triggering recursions
    if (object._links.self) {
      this._navigateUrl(object._links.self.href);
    }
  }

  if (object._embedded) {
    this.embedded = new LazyResource(this, object._embedded, {
      factory: Resource.factory(EmbeddedResource)
    });
  }
};

/**
 * Updates the internal URL to the new, relative change. This is not an
 * idempotent function.
 */
Resource.prototype._navigateUrl = function _navigateUrl(value) {
  if (!value) {
    throw new Error('Expected absolute or relative URL, but got: ' + value);
  }

  var uri = new URI(value);
  if (uri.is('absolute')) {
    // Replace the current url if it's absolute
    this._options.url = uri.normalize().toString();
  } else if (value[0] === '/') {
    this._options.url = (new URI(this._options.url))
      .resource(value).normalize().toString();
  } else {
    // TODO: Handle relative changes
    this._options.url = new URI([this._options.url, value].join('/'))
      .normalize().toString();
  }
};

/**
 * Wrap a resource inside a lazy container that loads all properties of the
 * given `object` on access in a Resource.
 *
 * Arguments:
 *  - parentResource: the resource this one depends is created from
 *    extract a custom URL value.
 *  - object: the object to wrap
 *  - options: optional options
 *    - factory: A function taking a the object and the options to wrap inside a
 *      Resource.
 */
function LazyResource(parentResource, object, options) {
  this._parent = parentResource;
  this._options = _.defaults(options || {}, {
    factory: function (object, options) {
      var resource = new Resource(options);
      resource._load(object);

      return resource;
    }
  });

  // Set _parent and _options to not be enumerable, to allow easy looping over
  // all entries.
  Object.defineProperties(this, {
    _parent: {
      enumerable: false
    },
    _options: {
      enumerable: false
    }
  })

  _.each(object, function (obj, key) {
    if (Array.isArray(obj)) {
      this._setLazyArray(key, obj);
    } else {
      this._setLazyObject(key, obj);
    }
  }.bind(this));
}

LazyResource.prototype._setLazyObject = function _setLazy(key, object) {
  // Define a lazy getter for the resource.
  Object.defineProperty(this, key, {
    enumerable: true,
    get: this._makeGetter(object)
  });
};

LazyResource.prototype._setLazyArray = function _setLazy(key, array) {
  // Define a lazy getter for the resource that contains the array.
  Object.defineProperty(this, key, {
    enumerable: true,
    get: function () {
      return array.map(function (object) {
        return this._makeGetter(object)();
      }.bind(this));
    }
  });
};

LazyResource.prototype._makeGetter = function _makeGetter(object) {
  var parent = this._parent;
  var options = this._options;

  return function () {
      return new options.factory(object, _.clone(parent._options));
  }.bind(this);
};

function EmbeddedResource(object, options) {
  // Inherit from Resource
  Resource.call(this, options);

  this._load(object);

  // Embedded resources are alsways considered as loaded.
  this.loaded = true;
}

_.extend(EmbeddedResource.prototype, Resource.prototype);

function LinkResource(object, options, params) {
  // Inherit from Resource
  Resource.call(this, options);

  var href = object.href;

  if (object.templated && !params) {
    console.warn('Creating a templated link without params. ' +
        'Use Resource.link() instead!');
  }

  // The href is OPTIONAL, even for links.
  if (href) {
    this._navigateUrl(href);
  } else {
    console.warn('Link object did not provide an `href`: ', object);
  }

  this._load(object);
}

_.extend(LinkResource.prototype, Resource.prototype);

export { Resource, LazyResource };
<|endoftext|>


<commit_before>'use strict'

var deepEqual = require('deep-equal')
var filter = require('../../common/array/filter')
var find = require('../../common/array/find')

var arrayBuffer = require('array-buffer')
var toBuffer = arrayBuffer.toBuffer

var errors = require('../../common/errors')
var BadRequestError = errors.BadRequestError

var keys = require('../../common/keys')
var primaryKey = keys.primary
var typeKey = keys.type
var isArrayKey = keys.isArray

// For complex types.
var matchCheck = [
  [ Date, function (a, b) { return a.getTime() === b.getTime() } ],
  [ Buffer, function (a, b) { return a.equals(toBuffer(b)) } ],
  [ Object, function (a, b) { return deepEqual(a, b, { strict: true }) } ]
]

// For comparing sort order.
var comparisons = [
  [ Number, function (a, b) { return a - b } ],
  [ String, function (a, b) { return a < b ? -1 : a > b ? 1 : 0 } ],
  [ Boolean, function (a, b) { return a === b ? 0 : a ? 1 : -1 } ],
  [ Date, function (a, b) { return a.getTime() - b.getTime() } ],
  [ Buffer, Buffer.compare ],

  // There is no comparison here that makes sense.
  [ Object, function (a, b) {
    return Object.keys(a).length - Object.keys(b).length
  } ]
]

// Browser-safe ID generation.
exports.generateId = function () {
  return ('00000000' + Math.floor(Math.random() * Math.pow(2, 32))
    .toString(16)).slice(-8)
}

exports.applyOptions = function (count, fields, records, options) {
  var i, j, record, field, recordFields, isInclude, isExclude

  if (!options) options = {}

  if ('match' in options) {
    records = filter(records, matchByField(fields, options.match))
    count = records.length
  }

  if ('fields' in options) {
    isInclude = !find(Object.keys(options.fields),
      function (field) { return !options.fields[field] })
    isExclude = !find(Object.keys(options.fields),
      function (field) { return options.fields[field] })

    if (!isInclude && !isExclude)
      throw new BadRequestError('Fields format is invalid.')

    for (i = records.length; i--;) {
      record = records[i]
      recordFields = Object.keys(record)
      for (j = recordFields.length; j--;) {
        field = recordFields[j]
        if (field === primaryKey) continue
        if ((isInclude && !(field in options.fields)) ||
          (isExclude && field in options.fields))
          delete record[field]
      }
    }
  }

  if ('sort' in options)
    records = records.sort(compare(fields, options.sort))

  if ('limit' in options || 'offset' in options)
    records = records.slice(options.offset,
      options.offset && options.limit ?
      options.offset + options.limit : options.limit)

  records.count = count

  return records
}

function check (type, a, b) {
  var matcher
  if (b === null) return a === null
  matcher = find(matchCheck, function (pair) {
    return pair[0] === type
  })
  return matcher ? matcher[1](a, b) : a === b
}

function checkValue (fieldDefinition, a) {
  return function (b) {
    return fieldDefinition[isArrayKey] ?
      find(a, function (a) {
        return check(fieldDefinition[typeKey], b, a)
      }) : check(fieldDefinition[typeKey], b, a)
  }
}

function matchByField (fields, match) {
  var keys = Object.keys(match)
  var i, field, matches

  return function (record) {
    for (i = keys.length; i--;) {
      field = keys[i]
      matches = match[field]
      if (!Array.isArray(match[field])) matches = [ matches ]
      if (!find(matches, checkValue(fields[field], record[field])))
        return false
    }

    return true
  }
}

function findKey (key) {
  return function (pair) {
    return pair[0] === key
  }
}

function compare (fields, sort) {
  var keys = Object.keys(sort)
  var i, j, field, a, b, isAscending,
    fieldDefinition, fieldIsArray, fieldType, result

  return function (x, y) {
    for (i = 0, j = keys.length; i < j; i++) {
      field = keys[i]
      a = x[field]
      b = y[field]
      isAscending = sort[field]
      fieldDefinition = fields[field]
      fieldIsArray = fieldDefinition[isArrayKey]
      fieldType = fieldDefinition[typeKey]

      if (a === null) return isAscending ? -1 : 1
      if (b === null) return isAscending ? 1 : -1

      result = 0

      if (fieldIsArray) result = a.length - b.length
      else if (fieldType)
        result = find(comparisons, findKey(fieldType))[1](a, b)

      if (result === 0) continue

      return isAscending ? result : -result
    }

    return 0
  }
}
<commit_msg>fix issue when matchByField is attempting to match boolean false<commit_after>'use strict'

var deepEqual = require('deep-equal')
var filter = require('../../common/array/filter')
var find = require('../../common/array/find')

var arrayBuffer = require('array-buffer')
var toBuffer = arrayBuffer.toBuffer

var errors = require('../../common/errors')
var BadRequestError = errors.BadRequestError

var keys = require('../../common/keys')
var primaryKey = keys.primary
var typeKey = keys.type
var isArrayKey = keys.isArray

// For complex types.
var matchCheck = [
  [ Date, function (a, b) { return a.getTime() === b.getTime() } ],
  [ Buffer, function (a, b) { return a.equals(toBuffer(b)) } ],
  [ Object, function (a, b) { return deepEqual(a, b, { strict: true }) } ]
]

// For comparing sort order.
var comparisons = [
  [ Number, function (a, b) { return a - b } ],
  [ String, function (a, b) { return a < b ? -1 : a > b ? 1 : 0 } ],
  [ Boolean, function (a, b) { return a === b ? 0 : a ? 1 : -1 } ],
  [ Date, function (a, b) { return a.getTime() - b.getTime() } ],
  [ Buffer, Buffer.compare ],

  // There is no comparison here that makes sense.
  [ Object, function (a, b) {
    return Object.keys(a).length - Object.keys(b).length
  } ]
]

// Browser-safe ID generation.
exports.generateId = function () {
  return ('00000000' + Math.floor(Math.random() * Math.pow(2, 32))
    .toString(16)).slice(-8)
}

exports.applyOptions = function (count, fields, records, options) {
  var i, j, record, field, recordFields, isInclude, isExclude

  if (!options) options = {}

  if ('match' in options) {
    records = filter(records, matchByField(fields, options.match))
    count = records.length
  }

  if ('fields' in options) {
    isInclude = !find(Object.keys(options.fields),
      function (field) { return !options.fields[field] })
    isExclude = !find(Object.keys(options.fields),
      function (field) { return options.fields[field] })

    if (!isInclude && !isExclude)
      throw new BadRequestError('Fields format is invalid.')

    for (i = records.length; i--;) {
      record = records[i]
      recordFields = Object.keys(record)
      for (j = recordFields.length; j--;) {
        field = recordFields[j]
        if (field === primaryKey) continue
        if ((isInclude && !(field in options.fields)) ||
          (isExclude && field in options.fields))
          delete record[field]
      }
    }
  }

  if ('sort' in options)
    records = records.sort(compare(fields, options.sort))

  if ('limit' in options || 'offset' in options)
    records = records.slice(options.offset,
      options.offset && options.limit ?
      options.offset + options.limit : options.limit)

  records.count = count

  return records
}

function check (type, a, b) {
  var matcher
  if (b === null) return a === null
  matcher = find(matchCheck, function (pair) {
    return pair[0] === type
  })
  return matcher ? matcher[1](a, b) : a === b
}

function checkValue (fieldDefinition, a) {
  return function (b) {
    return fieldDefinition[isArrayKey] ?
      find(a, function (a) {
        return check(fieldDefinition[typeKey], b, a)
      }) : check(fieldDefinition[typeKey], b, a)
  }
}

function matchByField (fields, match) {
  var keys = Object.keys(match)
  var i, field, matches

  return function (record) {
    for (i = keys.length; i--;) {
      field = keys[i]
      matches = match[field]
      if (!Array.isArray(match[field])) matches = [ matches ]
      if (undefined === find(matches, checkValue(fields[field], record[field])))
        return false
    }

    return true
  }
}

function findKey (key) {
  return function (pair) {
    return pair[0] === key
  }
}

function compare (fields, sort) {
  var keys = Object.keys(sort)
  var i, j, field, a, b, isAscending,
    fieldDefinition, fieldIsArray, fieldType, result

  return function (x, y) {
    for (i = 0, j = keys.length; i < j; i++) {
      field = keys[i]
      a = x[field]
      b = y[field]
      isAscending = sort[field]
      fieldDefinition = fields[field]
      fieldIsArray = fieldDefinition[isArrayKey]
      fieldType = fieldDefinition[typeKey]

      if (a === null) return isAscending ? -1 : 1
      if (b === null) return isAscending ? 1 : -1

      result = 0

      if (fieldIsArray) result = a.length - b.length
      else if (fieldType)
        result = find(comparisons, findKey(fieldType))[1](a, b)

      if (result === 0) continue

      return isAscending ? result : -result
    }

    return 0
  }
}
<|endoftext|>


<commit_before>var sys           = require('sys'),
    http          = require('http'),
    url           = require('url'),
    HtmlToDom     = require('./htmltodom').HtmlToDom,
    domToHtml     = require('./domtohtml').domToHtml,
    htmlencoding  = require('./htmlencoding'),
    HTMLEncode    = htmlencoding.HTMLEncode,
    HTMLDecode    = htmlencoding.HTMLDecode,
    _console      = {
      log: console.log,
      info: console.info,
      warn: console.warn,
      error: console.error
    };

exports.windowAugmentation = function(dom, options) {
  options = options || {};
  var window  = exports.createWindow(dom, options),
      setupDoc = (typeof options.document === 'undefined');

  if (setupDoc) {
    browser = browserAugmentation(dom, options),
    options.document = new (browser.Document)();
  }

  window.document = options.document;

  if (options.document.childNodes.length === 0) {
    window.document.appendChild(
        window.document.createElement("html")
    );
    var head = window.document.createElement('head');
    window.document.documentElement.appendChild(head);
    head.appendChild(
        window.document.createElement('title')
    );
    window.document.documentElement.appendChild(
      window.document.createElement('body')
    );
  }

  if (!window.document.addEventListener) {
      window.document.addEventListener = function() {};
  }

  window.console = _console;
  window.document.compareDocumentPosition = function() {};
  window.document.documentElement.style = {};
  window.document.documentElement.hasAttribute = true;

  window.XMLHttpRequest = function() {};

  return window;
}

exports.createWindow = function(dom, options) {
    options = options || {};
    var document,
        window = {
          get document() { return document },
          set document(doc) {
            document = doc;
            if (document) {
              document.defaultView  = window;
              document.parentWindow = window;
            }
          },
          setTimeout: setTimeout,
          setInterval: setInterval,
          clearInterval: clearInterval,
          clearTimeout: clearTimeout,
          name: 'nodejs',
          innerWidth: 1024,
          innerHeight: 768,
          length: 1,
          outerWidth: 1024,
          outerHeight: 768,
          pageXOffset: 0,
          pageYOffset: 0,
          screenX: 0,
          screenY: 0,
          screenLeft: 0,
          screenTop: 0,
          scrollX: 0,
          scrollY: 0,
          scrollTop: 0,
          scrollLeft: 0
        };

    window.frames = [window];
    window.contentWindow = window;

    window.getComputedStyle = function(node) {
    var s = node.style,
          cs = {};

      for (var n in s) {
          cs[n] = s[n];
      }
      cs.__proto__ = {
          getPropertyValue: function(name) {
              return node.style[name];
          }
      };
      return cs;
    };

    window.addEventListener = function() {
      dom.Node.prototype.addEventListener.apply(window, arguments);
    };

    window.alert = function () {};
    window.blur = function () {};
    window.close = function () {};
    window.confirm = function () {};
    window.createPopup = function () {};
    window.focus = function () {};
    window.moveBy = function () {};
    window.moveTo = function () {};
    window.open = function () {};
    window.print = function () {};
    window.prompt = function () {};
    window.resizeBy = function () {};
    window.resizeTo = function () {};
    window.scroll = function () {};
    window.scrollBy = function () {};
    window.scrollTo = function () {};

    // Author: Swizec
    // some scripts expect a proper window.location; try parsing it from options.url
    if (options.url) {
  var host = options.url.split("://", 2)[1].split("/", 1)[0];
  window.location = { href: options.url,
          hash: (options.url.indexOf('#') > -1) ? "#"+options.url.split("#", 2)[1] : '',
          host: host,
          hostname: host.split(":", 2)[0],
          pathname: (function () {
        var path = options.url.split("://", 2)[1].split("/", 2)[1];
        return (path) ? path.split('#', 2)[0] : '';
          })(),
          port: (host.split(":", 2)[1]) ? host.split(":", 2)[1] : 80,
          protocol: options.url.split("://", 2)[0]+":",
          search: (options.url.indexOf('?') > -1) ? "?"+options.url.split("?", 2)[1] : '',
          // TODO: find a way to actually implement these
          reload: function () {},
          replace: function () {}
        }
    }else {
  window.location = { href: __filename };
    }

    window.navigator = {
      userAgent: 'Node.js (' + process.platform + '; U; rv:' + process.version + ')',
      appName: 'Node.js jsDom',
      platform: process.platform,
      appVersion: process.version
    };

    window.window = window;
    window.self   = window;

    window.close = function() {
        var len = document._nodes.length, i, el;
        for (i = 0; i < len; i++) {
            el = document._nodes[i];
            document._nodes[i] = null;
            if (el.parentNode) {
                el.parentNode.removeChild(el);
            }
        }
        delete document._attributes._parentNode;
        delete document._ownerDocument;
        delete document._children[0]._parentNode;
        delete document._children[0]._ownerDocument;
        delete document.defaultView;
        delete document.contentWindow;
        delete document.contentDocument;
        delete document.parentWindow;
        delete document._documentElement;

        delete window.self;
        delete window.window;
        delete window.contentWindow;
        delete window.document;
        len = window.frames.length;
        for (i = 0; i < len; i++) {
            if (window !== window.frames[i]) {
                window.frames[i].close();
            }
            delete window.frames[i];
        }
    };

    return window;
};

var htmlparser = null; //Caching for HTMLParser require. HUGE performace boost.
/**
* 5000 iterations
* Without cache: ~1800+ms
* With cache: ~80ms
*/

var browserAugmentation = exports.browserAugmentation = function(dom, options) {

  if(!options) options = {};

  // set up html parser - use a provided one or try and load from library

  var htmltodom;

  if(options.parser) {
    htmltodom = new HtmlToDom(options.parser);
  } else {
    try {
      if (!htmlparser) {//Only require once
          htmlparser = require('htmlparser');
      }
      htmltodom = new HtmlToDom(htmlparser);
    } catch(e) {
     try {
        htmlparser = require('node-htmlparser/lib/node-htmlparser');
        htmltodom = new HtmlToDom(htmlparser);
      } catch(e) {
        htmltodom = new HtmlToDom();
      }
    }
  }

  /***************************************
  * Browser Augmentation                 *
  ***************************************/

  if (!dom.Node.prototype.__proto__.addEventListener) {
      dom.Node.prototype.addEventListener = function(){};
  }

  dom.Element.prototype.getElementsByClassName = function(className) {

    function filterByClassName(child) {
      if (!child) {
        return false;
      }

      if (child.nodeType &&
          child.nodeType === dom.Node.prototype.ENTITY_REFERENCE_NODE)
      {
        child = child._entity;
      }

      var classString = child.className;
      if (classString) {
        var s = classString.split(" ");
        for (var i=0; i<s.length; i++) {
          if (s[i] === className) {
            return true;
          }
        }
      }
      return false;
    }

    var disableLiveLists = this.ownerDocument &&
        this.ownerDocument.implementation &&
        this.ownerDocument.implementation.hasFeature("DisableLiveLists");

      return new dom.NodeList(dom.mapper(this, filterByClassName), !disableLiveLists);
  };

    dom.Document.prototype.__defineSetter__("title",function(value) {
        this.getElementsByTagName('title')[0].innerHTML = value;
        return value;
    });

    dom.Document.prototype.__defineGetter__("title",function() {
  // Swizec - sometimes there is no title
  var elements = this.getElementsByTagName('title');
  return (elements.length > 0) ? elements[0].innerHTML : '';
    });

  dom.Element.prototype.__defineGetter__('sourceIndex', function() {
    /*
    * According to QuirksMode:
    * Get the sourceIndex of element x. This is also the index number for
    * the element in the document.getElementsByTagName('*') array.
    * http://www.quirksmode.org/dom/w3c_core.html#t77
    */
    var items = this.ownerDocument.getElementsByTagName('*'),
        len = items.length;

    for (var i = 0; i < len; i++) {
        if (items[i] === this) {
            return i;
        }
    }
  });

  dom.Document.prototype.__defineGetter__('outerHTML', function() {
    var html = domToHtml(this.documentElement);
    if (this.doctype) {
        html = this.doctype.toString() + '\n' + html;
    }
    return html;
  });

  dom.Element.prototype.__defineGetter__('outerHTML', function() {
    return domToHtml(this);
  });

  dom.Element.prototype.__defineGetter__('innerHTML', function() {
    return domToHtml(this.childNodes, true);
  });
  dom.Element.prototype.__defineSetter__('doctype', function() {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
  });
  dom.Element.prototype.__defineGetter__('doctype', function() {
    var r = null;
    if (this.nodeName == '#document') {
        if (this._doctype) {
         r = this._doctype;
        }
    }
    return r;
  });

   dom.Element.prototype.__defineSetter__('innerHTML', function(html) {
    //Check for lib first

    if (html === null) {
        return null;
    }

    //Clear the children first:
    for (var i = this.childNodes.length-1; i >= 0; i--) {
        if (this.childNodes[i].parentNode) {
            this.childNodes[i].parentNode.removeChild(this.childNodes[i]);
        }
    }
    if (this.nodeName === '#document') {
        parseDocType(this, html);
    }
    var nodes = htmltodom.appendHtmlToElement(html, this);
    return html;
});

var DOC_HTML5 = /<!doctype html>/is,
    DOC_TYPE = /<!DOCTYPE (\w.*)">/is;

var parseDocType = function(doc, html) {
    var publicID = '',
        systemID = '',
        fullDT = '',
        name = 'HTML',
        set = true,
        html5DT = html.match(DOC_HTML5),
        dt = html.match(DOC_TYPE);

    //Default, No doctype === null
    doc._doctype = null;

    if (html5DT && html5DT[0]) { //Handle the HTML shorty doctype
        fullDT = html5DT[0];

    } else if (dt && dt[1]) { //Parse the doctype
        fullDT = dt[0];
        dt = dt[1].split(' "');
        var _id1 = dt.pop().replace(/"/g, ''),
            _id2 = dt.pop().replace(/"/g, '');

        if (_id1.indexOf('-//') !== -1) {
            publicID = _id1;
        }
        if (_id2.indexOf('-//') !== -1) {
            publicID = _id2;
        }
        if (_id1.indexOf('://') !== -1) {
            systemID = _id1;
        }
        if (_id2.indexOf('://') !== -1) {
            systemID = _id2;
        }
        if (dt.length) {
            dt = dt[0].split(' ');
            name = dt[0].toUpperCase();
        }
    } else {
        //No DocType found
        return;
    }
    doc._doctype = new dom.DOMImplementation().createDocumentType(name, publicID, systemID);
    doc._doctype._ownerDocument = doc;
    doc._doctype._fullDT = fullDT;
    doc._doctype.toString = function() {
        return this._fullDT;
    };
}

  dom.Document.prototype.__defineGetter__("body", function() {
    return this.getElementsByTagName("body").item(0);
  });

  dom.Document.prototype.__defineGetter__("head", function() {
    return this.getElementsByTagName("head").item(0);
  });

  // Author: Swizec
  // styleSheets is an interface to all of the css on a page
  // some scripts like readability.js expect this to exist
  dom.Document.prototype.__defineGetter__("styleSheets", function () {
    var styles = new Array(),
        nodes1 = this.getElementsByTagName("style"),
        nodes2 = (this.head) ? this.head.getElementsByTagName("link") : [],
        node;

    function StyleSheet(node) {
      this.cssText = node.textContent;
      this.disabled = false;
      this.href = (node.attributes['href']) ? node.attributes['href'] : '';
      this.media = (node.attributes['media']) ? node.attributes['media'] : 'screen';
      this.title = node.attributes['title'];
      this.type = node.attributes['type'];
    }

    for (var i=0; i < nodes1.length; i++ ) {
      node = nodes1.item(i);
      styles.push(new StyleSheet(node));
    }

    for (var i=0; i< nodes2.length; i++ ) {
      node = nodes2.item(i);
      if (node.attributes['rel'] == 'stylesheet') {
        styles.push(new StyleSheet(node));
      }
    }

    return styles;
  });

  dom.Document.prototype.console = _console;

    dom.Element.prototype.__defineGetter__('nodeName', function(val) {
        return this._nodeName.toUpperCase();
    });

    dom.Element.prototype.__defineGetter__('tagName', function(val) {
      var t = this._tagName.toUpperCase();
      //Document should not return a tagName
      if (this.nodeName === '#document') {
          t = null;
      }
      return t;
    });

    dom.Element.prototype.scrollTop = 0;
    dom.Element.prototype.scrollLeft = 0;

    dom.Element.prototype.__defineGetter__('text', function() {
        if (this.attributes.getNamedItem('value')) {
            return this.value;
        } else {
            return this.innerHTML;
        }
    });

    dom.Element.prototype.__defineGetter__('textContent', function() {
        var stripHTML = /<\S[^><]*>/g;
        var out = this.innerHTML;
        //Remove all the HTML
        out = out.replace(stripHTML, '');
        //Now decode the encoded text content
        out = HTMLDecode(out);
        return out;
    });
    dom.Element.prototype.__defineSetter__('textContent', function(txt) {
        //Un encode all the entities
        txt = HTMLEncode(txt);
        //Set the content
        this.innerHTML = txt;
        return txt;
    });

  return dom;
}
<commit_msg>Added window.dispatchEvent<commit_after>var sys           = require('sys'),
    http          = require('http'),
    url           = require('url'),
    HtmlToDom     = require('./htmltodom').HtmlToDom,
    domToHtml     = require('./domtohtml').domToHtml,
    htmlencoding  = require('./htmlencoding'),
    HTMLEncode    = htmlencoding.HTMLEncode,
    HTMLDecode    = htmlencoding.HTMLDecode,
    _console      = {
      log: console.log,
      info: console.info,
      warn: console.warn,
      error: console.error
    };

exports.windowAugmentation = function(dom, options) {
  options = options || {};
  var window  = exports.createWindow(dom, options),
      setupDoc = (typeof options.document === 'undefined');

  if (setupDoc) {
    browser = browserAugmentation(dom, options),
    options.document = new (browser.Document)();
  }

  window.document = options.document;

  if (options.document.childNodes.length === 0) {
    window.document.appendChild(
        window.document.createElement("html")
    );
    var head = window.document.createElement('head');
    window.document.documentElement.appendChild(head);
    head.appendChild(
        window.document.createElement('title')
    );
    window.document.documentElement.appendChild(
      window.document.createElement('body')
    );
  }

  if (!window.document.addEventListener) {
      window.document.addEventListener = function() {};
  }

  window.console = _console;
  window.document.compareDocumentPosition = function() {};
  window.document.documentElement.style = {};
  window.document.documentElement.hasAttribute = true;

  window.XMLHttpRequest = function() {};

  return window;
}

exports.createWindow = function(dom, options) {
    options = options || {};
    var document,
        window = {
          get document() { return document },
          set document(doc) {
            document = doc;
            if (document) {
              document.defaultView  = window;
              document.parentWindow = window;
            }
          },
          setTimeout: setTimeout,
          setInterval: setInterval,
          clearInterval: clearInterval,
          clearTimeout: clearTimeout,
          name: 'nodejs',
          innerWidth: 1024,
          innerHeight: 768,
          length: 1,
          outerWidth: 1024,
          outerHeight: 768,
          pageXOffset: 0,
          pageYOffset: 0,
          screenX: 0,
          screenY: 0,
          screenLeft: 0,
          screenTop: 0,
          scrollX: 0,
          scrollY: 0,
          scrollTop: 0,
          scrollLeft: 0
        };

    window.frames = [window];
    window.contentWindow = window;

    window.getComputedStyle = function(node) {
    var s = node.style,
          cs = {};

      for (var n in s) {
          cs[n] = s[n];
      }
      cs.__proto__ = {
          getPropertyValue: function(name) {
              return node.style[name];
          }
      };
      return cs;
    };

    window.addEventListener = function() {
      dom.Node.prototype.addEventListener.apply(window, arguments);
    };

    window.dispatchEvent = function() {
      dom.Node.prototype.dispatchEvent.apply(window, arguments);
    };

    window.alert = function () {};
    window.blur = function () {};
    window.close = function () {};
    window.confirm = function () {};
    window.createPopup = function () {};
    window.focus = function () {};
    window.moveBy = function () {};
    window.moveTo = function () {};
    window.open = function () {};
    window.print = function () {};
    window.prompt = function () {};
    window.resizeBy = function () {};
    window.resizeTo = function () {};
    window.scroll = function () {};
    window.scrollBy = function () {};
    window.scrollTo = function () {};

    // Author: Swizec
    // some scripts expect a proper window.location; try parsing it from options.url
    if (options.url) {
  var host = options.url.split("://", 2)[1].split("/", 1)[0];
  window.location = { href: options.url,
          hash: (options.url.indexOf('#') > -1) ? "#"+options.url.split("#", 2)[1] : '',
          host: host,
          hostname: host.split(":", 2)[0],
          pathname: (function () {
        var path = options.url.split("://", 2)[1].split("/", 2)[1];
        return (path) ? path.split('#', 2)[0] : '';
          })(),
          port: (host.split(":", 2)[1]) ? host.split(":", 2)[1] : 80,
          protocol: options.url.split("://", 2)[0]+":",
          search: (options.url.indexOf('?') > -1) ? "?"+options.url.split("?", 2)[1] : '',
          // TODO: find a way to actually implement these
          reload: function () {},
          replace: function () {}
        }
    }else {
  window.location = { href: __filename };
    }

    window.navigator = {
      userAgent: 'Node.js (' + process.platform + '; U; rv:' + process.version + ')',
      appName: 'Node.js jsDom',
      platform: process.platform,
      appVersion: process.version
    };

    window.window = window;
    window.self   = window;

    window.close = function() {
        var len = document._nodes.length, i, el;
        for (i = 0; i < len; i++) {
            el = document._nodes[i];
            document._nodes[i] = null;
            if (el.parentNode) {
                el.parentNode.removeChild(el);
            }
        }
        delete document._attributes._parentNode;
        delete document._ownerDocument;
        delete document._children[0]._parentNode;
        delete document._children[0]._ownerDocument;
        delete document.defaultView;
        delete document.contentWindow;
        delete document.contentDocument;
        delete document.parentWindow;
        delete document._documentElement;

        delete window.self;
        delete window.window;
        delete window.contentWindow;
        delete window.document;
        len = window.frames.length;
        for (i = 0; i < len; i++) {
            if (window !== window.frames[i]) {
                window.frames[i].close();
            }
            delete window.frames[i];
        }
    };

    return window;
};

var htmlparser = null; //Caching for HTMLParser require. HUGE performace boost.
/**
* 5000 iterations
* Without cache: ~1800+ms
* With cache: ~80ms
*/

var browserAugmentation = exports.browserAugmentation = function(dom, options) {

  if(!options) options = {};

  // set up html parser - use a provided one or try and load from library

  var htmltodom;

  if(options.parser) {
    htmltodom = new HtmlToDom(options.parser);
  } else {
    try {
      if (!htmlparser) {//Only require once
          htmlparser = require('htmlparser');
      }
      htmltodom = new HtmlToDom(htmlparser);
    } catch(e) {
     try {
        htmlparser = require('node-htmlparser/lib/node-htmlparser');
        htmltodom = new HtmlToDom(htmlparser);
      } catch(e) {
        htmltodom = new HtmlToDom();
      }
    }
  }

  /***************************************
  * Browser Augmentation                 *
  ***************************************/

  if (!dom.Node.prototype.__proto__.addEventListener) {
      dom.Node.prototype.addEventListener = function(){};
  }

  dom.Element.prototype.getElementsByClassName = function(className) {

    function filterByClassName(child) {
      if (!child) {
        return false;
      }

      if (child.nodeType &&
          child.nodeType === dom.Node.prototype.ENTITY_REFERENCE_NODE)
      {
        child = child._entity;
      }

      var classString = child.className;
      if (classString) {
        var s = classString.split(" ");
        for (var i=0; i<s.length; i++) {
          if (s[i] === className) {
            return true;
          }
        }
      }
      return false;
    }

    var disableLiveLists = this.ownerDocument &&
        this.ownerDocument.implementation &&
        this.ownerDocument.implementation.hasFeature("DisableLiveLists");

      return new dom.NodeList(dom.mapper(this, filterByClassName), !disableLiveLists);
  };

    dom.Document.prototype.__defineSetter__("title",function(value) {
        this.getElementsByTagName('title')[0].innerHTML = value;
        return value;
    });

    dom.Document.prototype.__defineGetter__("title",function() {
  // Swizec - sometimes there is no title
  var elements = this.getElementsByTagName('title');
  return (elements.length > 0) ? elements[0].innerHTML : '';
    });

  dom.Element.prototype.__defineGetter__('sourceIndex', function() {
    /*
    * According to QuirksMode:
    * Get the sourceIndex of element x. This is also the index number for
    * the element in the document.getElementsByTagName('*') array.
    * http://www.quirksmode.org/dom/w3c_core.html#t77
    */
    var items = this.ownerDocument.getElementsByTagName('*'),
        len = items.length;

    for (var i = 0; i < len; i++) {
        if (items[i] === this) {
            return i;
        }
    }
  });

  dom.Document.prototype.__defineGetter__('outerHTML', function() {
    var html = domToHtml(this.documentElement);
    if (this.doctype) {
        html = this.doctype.toString() + '\n' + html;
    }
    return html;
  });

  dom.Element.prototype.__defineGetter__('outerHTML', function() {
    return domToHtml(this);
  });

  dom.Element.prototype.__defineGetter__('innerHTML', function() {
    return domToHtml(this.childNodes, true);
  });
  dom.Element.prototype.__defineSetter__('doctype', function() {
      throw new core.DOMException(NO_MODIFICATION_ALLOWED_ERR);
  });
  dom.Element.prototype.__defineGetter__('doctype', function() {
    var r = null;
    if (this.nodeName == '#document') {
        if (this._doctype) {
         r = this._doctype;
        }
    }
    return r;
  });

   dom.Element.prototype.__defineSetter__('innerHTML', function(html) {
    //Check for lib first

    if (html === null) {
        return null;
    }

    //Clear the children first:
    for (var i = this.childNodes.length-1; i >= 0; i--) {
        if (this.childNodes[i].parentNode) {
            this.childNodes[i].parentNode.removeChild(this.childNodes[i]);
        }
    }
    if (this.nodeName === '#document') {
        parseDocType(this, html);
    }
    var nodes = htmltodom.appendHtmlToElement(html, this);
    return html;
});

var DOC_HTML5 = /<!doctype html>/is,
    DOC_TYPE = /<!DOCTYPE (\w.*)">/is;

var parseDocType = function(doc, html) {
    var publicID = '',
        systemID = '',
        fullDT = '',
        name = 'HTML',
        set = true,
        html5DT = html.match(DOC_HTML5),
        dt = html.match(DOC_TYPE);

    //Default, No doctype === null
    doc._doctype = null;

    if (html5DT && html5DT[0]) { //Handle the HTML shorty doctype
        fullDT = html5DT[0];

    } else if (dt && dt[1]) { //Parse the doctype
        fullDT = dt[0];
        dt = dt[1].split(' "');
        var _id1 = dt.pop().replace(/"/g, ''),
            _id2 = dt.pop().replace(/"/g, '');

        if (_id1.indexOf('-//') !== -1) {
            publicID = _id1;
        }
        if (_id2.indexOf('-//') !== -1) {
            publicID = _id2;
        }
        if (_id1.indexOf('://') !== -1) {
            systemID = _id1;
        }
        if (_id2.indexOf('://') !== -1) {
            systemID = _id2;
        }
        if (dt.length) {
            dt = dt[0].split(' ');
            name = dt[0].toUpperCase();
        }
    } else {
        //No DocType found
        return;
    }
    doc._doctype = new dom.DOMImplementation().createDocumentType(name, publicID, systemID);
    doc._doctype._ownerDocument = doc;
    doc._doctype._fullDT = fullDT;
    doc._doctype.toString = function() {
        return this._fullDT;
    };
}

  dom.Document.prototype.__defineGetter__("body", function() {
    return this.getElementsByTagName("body").item(0);
  });

  dom.Document.prototype.__defineGetter__("head", function() {
    return this.getElementsByTagName("head").item(0);
  });

  // Author: Swizec
  // styleSheets is an interface to all of the css on a page
  // some scripts like readability.js expect this to exist
  dom.Document.prototype.__defineGetter__("styleSheets", function () {
    var styles = new Array(),
        nodes1 = this.getElementsByTagName("style"),
        nodes2 = (this.head) ? this.head.getElementsByTagName("link") : [],
        node;

    function StyleSheet(node) {
      this.cssText = node.textContent;
      this.disabled = false;
      this.href = (node.attributes['href']) ? node.attributes['href'] : '';
      this.media = (node.attributes['media']) ? node.attributes['media'] : 'screen';
      this.title = node.attributes['title'];
      this.type = node.attributes['type'];
    }

    for (var i=0; i < nodes1.length; i++ ) {
      node = nodes1.item(i);
      styles.push(new StyleSheet(node));
    }

    for (var i=0; i< nodes2.length; i++ ) {
      node = nodes2.item(i);
      if (node.attributes['rel'] == 'stylesheet') {
        styles.push(new StyleSheet(node));
      }
    }

    return styles;
  });

  dom.Document.prototype.console = _console;

    dom.Element.prototype.__defineGetter__('nodeName', function(val) {
        return this._nodeName.toUpperCase();
    });

    dom.Element.prototype.__defineGetter__('tagName', function(val) {
      var t = this._tagName.toUpperCase();
      //Document should not return a tagName
      if (this.nodeName === '#document') {
          t = null;
      }
      return t;
    });

    dom.Element.prototype.scrollTop = 0;
    dom.Element.prototype.scrollLeft = 0;

    dom.Element.prototype.__defineGetter__('text', function() {
        if (this.attributes.getNamedItem('value')) {
            return this.value;
        } else {
            return this.innerHTML;
        }
    });

    dom.Element.prototype.__defineGetter__('textContent', function() {
        var stripHTML = /<\S[^><]*>/g;
        var out = this.innerHTML;
        //Remove all the HTML
        out = out.replace(stripHTML, '');
        //Now decode the encoded text content
        out = HTMLDecode(out);
        return out;
    });
    dom.Element.prototype.__defineSetter__('textContent', function(txt) {
        //Un encode all the entities
        txt = HTMLEncode(txt);
        //Set the content
        this.innerHTML = txt;
        return txt;
    });

  return dom;
}
<|endoftext|>