<commit_before>import React from 'react';
import {setObjProperty, getObjProperty} from './utils';

export function createFormValidator(message, isValidFunction) {
    return {
        message : message,
        validatorFunction : isValidFunction,
        setRequired : false
    };
}

export function createIsRequiredFormValidator(message) {
    message = message || 'Pole jest wymagane';
    let validator = createFormValidator(message, function(value) {
        return ! (value == null || value == undefined || value.trim().length == 0);
    });
    validator.setRequired = true;
    return validator;
}

export function createMinLengthFormValidator(minLength, message) {
    message = message || 'Mimimalna długość to ' + minLength;
    let validator = createFormValidator(message, function(value) {
        return ! (value == null || value == undefined || value.trim().length < minLength);
    });
    validator.setRequired = true;
    return validator;
}

export function createMaxLengthFormValidator(maxLength, message) {
    message = message || 'Maksymalna długość to ' + maxLength;
    let validator = createFormValidator(message, function(value) {
        return (value == null || value == undefined || value.trim().length < maxLength);
    });
    return validator;
}

export function createEqLengthFormValidator(eqLength, message) {
    message = message || 'Wymagana długość to ' + eqLength;
    let validator = createFormValidator(message, function(value) {
        return (value == null || value == undefined || value.trim().length == eqLength);
    });
    return validator;
}

export function createRegexLengthFormValidator(regex, message) {
    if (typeof regex === 'string') {
        regex = new RegExp(regex, "i");
    }
    message = message || 'Niewłaściwy format (' + regex + ')';
    let validator = createFormValidator(message, function(value) {
        if (value == undefined || value == null) {
            return true;
        }
        return regex.test(value);
    });
    return validator;
}

export class Input extends React.Component {
    static contextTypes = {
        wizard : React.PropTypes.object
    };

    static propTypes = {
        type : React.PropTypes.string.isRequired, // input type
        name : React.PropTypes.string.isRequired, // field name
        label : React.PropTypes.string.isRequired, // label
        required : React.PropTypes.bool, // if field is required
        instantValidation : React.PropTypes.bool, // if validate onChange event
        inputId : React.PropTypes.string, // id for an input otherwise autogenerated
        placeholder : React.PropTypes.string, // input placeholder
        validators : React.PropTypes.arrayOf(React.PropTypes.object), // validators
        className : React.PropTypes.string
    };

    static defaultProps = {
        required : false,
        validators : [],
        className: ""
    };

    constructor(props) {
        super();
        this.props = props;
        let required = props.required;
        props.validators.forEach((validator) => {
            if (validator.setRequired) {
                required = true;
            }
        });
        this.validators = props.validators.slice();
        this.state = { error : null, label : props.label, required : required };
        this.inputId = props.inputId || 'form-input-' + props.name;
        if (this.validators.length == 0 && props.required) {
            this.validators.push(createIsRequiredFormValidator());
        }
        this.handleChange = this.handleChange.bind(this);
        this.validate = this.validate.bind(this);
        this.value = this.value.bind(this);
        this.orgOnChange = this.props.onChange;
    }

    componentWillMount() {
        // register field in form
        this.context.wizard.formInputs.push(this);
        //prepare props for input
        this.inputProps = Object.assign({}, this.props, {onChange:this.handleChange, id:this.inputId, value:this.context.wizard.data[this.props.name]});
        delete this.inputProps.data; // clear it
        delete this.inputProps.validators; // clear it
        delete this.inputProps.required; // clear it
        delete this.inputProps.options; // clear it
        delete this.inputProps.instantValidation; // clear it
        delete this.inputProps.defaultValue; // clear it
        delete this.inputProps.outerClassName;
        this.inputProps.className = 'form-control' + (this.props.className ?  ' ' + this.props.className : '') + ' form-wizard-input form-wizard-input-' + this.props.type;
    }

    componentWillUnmount() {
        // TODO unregister from wizard
    }

    validate() {
        let value = getObjProperty(this.context.wizard.data, this.props.name);
        for(let i=0; i<this.validators.length; i++) {
            let validator = this.validators[i];
            let isValid = validator.validatorFunction(value);
            if (! isValid) {
               this.setState({error : validator.message});
               return false;
            }
        }
        this.setState({error : null});
        return true;
    }

    value(newValue) {
        const name = this.props.name;
        const data = this.context.wizard.data;
        const old = getObjProperty(data, name);
        if (newValue != undefined) { // set new value
            const nv = newValue == '' ? null : newValue;
            if (nv != old) {
                setObjProperty(data, name, nv);
                let instantValidation = this.props.instantValidation;
                if (instantValidation == undefined) {
                    instantValidation = this.context.wizard.props.instantValidation;
                }
                if (instantValidation) {
                    this.validate();
                }
                this.forceUpdate();
            }
        }
        return old;
    }

    handleChange(event) {
        let ep;
        if (event.target) {
            const val = event.target.value;
            this.value(val == undefined ? null : val);
            ep = event;
        }
        if (this.orgOnChange) {
            this.orgOnChange(ep);
        }
    }

    render() {
        const name = this.props.name;
        let type = this.props.type == undefined ? undefined : this.props.type.toLowerCase();
        return (
                <div className={` ${this.props.outerClassName}   `}>
                    <div className={`form-group ${this.props.className} ${this.state.error != null ? 'has-error' : ''}`}>
                        {this.state.label}
                        {(() => {
                            if (this.state.required) {
                                return ();
                            }
                        })()}
                        {(() => {
                            let dv = this.value();
                            if (dv == null) {
                                dv = '';
                            }
                            if (this.props.options != undefined) { // select
                                if (type != undefined && type != 'select' && type !='nice-select') {
                                    throw 'Cannot use options with type "' + type +'"';
                                }
                                if (type == 'nice-select') {
                                    const opts = [{value:'', label:'Wybierz', name:name}];
                                    const isArr = Array.isArray(this.props.options);
                                    for(let key in this.props.options) {
                                        const sval = this.props.options[key];
                                        opts.push({value:isArr ? sval : key, label:sval, name:name});
                                    }
                                    return (<Select
                                        name={this.props.name}
                                        value={dv}
                                        options={opts}
                                        onChange={this.handleChange}
                                        required={this.state.required}
                                    />);
                                } else {
                                    let opts = [];
                                    opts.push((<option key="" value=""></option>));
                                    let isa = Array.isArray(this.props.options);
                                    for (let key in this.props.options) {
                                        let val = this.props.options[key];
                                        let rk = isa ? val : key;
                                        opts.push((<option label={val} value={rk} key={rk}>{val}</option>));
                                    }
                                    return (<select {...this.inputProps} value={dv}>{opts}</select>);
                                }
                            }
                            type = type || 'text';
                            if (type == 'textarea') {
                                return (<textarea {...this.inputProps} value={dv}/>);
                            } else {
                                return (<input type={type} {...this.inputProps} value={dv}/>);
                            }
                        })()}
                        {(() => {
                            if (this.state.error != null) {
                                return (
                                    {this.state.error}
                                );
                            }
                        })()}

        );
    }
}

export class Form extends React.Component {
    static childContextTypes = {
        wizard : React.PropTypes.object
    };

    static propTypes = {
        data : React.PropTypes.object,   // where to save or get values
        instantValidation : React.PropTypes.bool,   // parameter to pass to Input(s)
        onValidationError : React.PropTypes.func,   // callback func(event, form)
        onSubmit : React.PropTypes.func             // callback func(event, form)
    };

    static defaultProps = {
        instantValidation : false,
        data : {}
    };

    constructor(props) {
        super();
        this.props = props;
        this.data = props.data;
        this.formInputs = [];
        this.state = { };
        this.handleOnSubmit = this.handleOnSubmit.bind(this);
    }

    getChildContext() {
        const self = this;
        return {
            wizard: self
        };
    }

    handleOnSubmit(event) {
        event.preventDefault();
        console.debug("Submit (Form)", event, this.data);
        // validation
        let ret = true;
        this.formInputs.forEach((fin) => {
            if (! fin.validate()) {
                ret = false;
            }
        });
        if (ret) {
            if (this.props.onSubmit) {
                this.props.onSubmit(event, this);
            }
        } else {
            if (this.props.onValidationError) {
                this.props.onValidationError(event, this);
            }
        }
    }

    render() {
        return (<form {...this.props} onSubmit={this.handleOnSubmit}>
            {this.props.children}
        </form>);
    }

}
<commit_msg>cleanup<commit_after>import React from 'react';
import {setObjProperty, getObjProperty} from './utils';

export function createFormValidator(message, isValidFunction) {
    return {
        message : message,
        validatorFunction : isValidFunction,
        setRequired : false
    };
}

export function createIsRequiredFormValidator(message) {
    message = message || 'Pole jest wymagane';
    let validator = createFormValidator(message, function(value) {
        return ! (value == null || value == undefined || value.trim().length == 0);
    });
    validator.setRequired = true;
    return validator;
}

export function createMinLengthFormValidator(minLength, message) {
    message = message || 'Mimimalna długość to ' + minLength;
    let validator = createFormValidator(message, function(value) {
        return ! (value == null || value == undefined || value.trim().length < minLength);
    });
    validator.setRequired = true;
    return validator;
}

export function createMaxLengthFormValidator(maxLength, message) {
    message = message || 'Maksymalna długość to ' + maxLength;
    let validator = createFormValidator(message, function(value) {
        return (value == null || value == undefined || value.trim().length < maxLength);
    });
    return validator;
}

export function createEqLengthFormValidator(eqLength, message) {
    message = message || 'Wymagana długość to ' + eqLength;
    let validator = createFormValidator(message, function(value) {
        return (value == null || value == undefined || value.trim().length == eqLength);
    });
    return validator;
}

export function createRegexLengthFormValidator(regex, message) {
    if (typeof regex === 'string') {
        regex = new RegExp(regex, "i");
    }
    message = message || 'Niewłaściwy format (' + regex + ')';
    let validator = createFormValidator(message, function(value) {
        if (value == undefined || value == null) {
            return true;
        }
        return regex.test(value);
    });
    return validator;
}

export class Input extends React.Component {
    static contextTypes = {
        wizard : React.PropTypes.object
    };

    static propTypes = {
        type : React.PropTypes.string.isRequired, // input type
        name : React.PropTypes.string.isRequired, // field name
        label : React.PropTypes.string.isRequired, // label
        required : React.PropTypes.bool, // if field is required
        instantValidation : React.PropTypes.bool, // if validate onChange event
        inputId : React.PropTypes.string, // id for an input otherwise autogenerated
        placeholder : React.PropTypes.string, // input placeholder
        validators : React.PropTypes.arrayOf(React.PropTypes.object), // validators
        className : React.PropTypes.string
    };

    static defaultProps = {
        required : false,
        validators : [],
        className: ""
    };

    constructor(props) {
        super();
        this.props = props;
        let required = props.required;
        props.validators.forEach((validator) => {
            if (validator.setRequired) {
                required = true;
            }
        });
        this.validators = props.validators.slice();
        this.state = { error : null, label : props.label, required : required };
        this.inputId = props.inputId || 'form-input-' + props.name;
        if (this.validators.length == 0 && props.required) {
            this.validators.push(createIsRequiredFormValidator());
        }
        this.handleChange = this.handleChange.bind(this);
        this.validate = this.validate.bind(this);
        this.value = this.value.bind(this);
        this.orgOnChange = this.props.onChange;
    }

    componentWillMount() {
        // register field in form
        this.context.wizard.formInputs.push(this);
        //prepare props for input
        this.inputProps = Object.assign({}, this.props, {onChange:this.handleChange, id:this.inputId, value:this.context.wizard.data[this.props.name]});
        delete this.inputProps.data; // clear it
        delete this.inputProps.validators; // clear it
        delete this.inputProps.required; // clear it
        delete this.inputProps.options; // clear it
        delete this.inputProps.instantValidation; // clear it
        delete this.inputProps.defaultValue; // clear it
        delete this.inputProps.outerClassName;
        this.inputProps.className = 'form-control' + (this.props.className ?  ' ' + this.props.className : '') + ' form-wizard-input form-wizard-input-' + this.props.type;
    }

    componentWillUnmount() {
        // TODO unregister from wizard
    }

    validate() {
        let value = getObjProperty(this.context.wizard.data, this.props.name);
        for(let i=0; i<this.validators.length; i++) {
            let validator = this.validators[i];
            let isValid = validator.validatorFunction(value);
            if (! isValid) {
               this.setState({error : validator.message});
               return false;
            }
        }
        this.setState({error : null});
        return true;
    }

    value(newValue) {
        const name = this.props.name;
        const data = this.context.wizard.data;
        const old = getObjProperty(data, name);
        if (newValue != undefined) { // set new value
            const nv = newValue == '' ? null : newValue;
            if (nv != old) {
                setObjProperty(data, name, nv);
                let instantValidation = this.props.instantValidation;
                if (instantValidation == undefined) {
                    instantValidation = this.context.wizard.props.instantValidation;
                }
                if (instantValidation) {
                    this.validate();
                }
                this.forceUpdate();
            }
        }
        return old;
    }

    handleChange(event) {
        const val = event.target.value;
        this.value(val == undefined ? null : val);
        if (this.orgOnChange) {
            this.orgOnChange(ep);
        }
    }

    render() {
        const name = this.props.name;
        let type = this.props.type == undefined ? undefined : this.props.type.toLowerCase();
        return (
                <div className={` ${this.props.outerClassName}   `}>
                    <div className={`form-group ${this.props.className} ${this.state.error != null ? 'has-error' : ''}`}>
                        {this.state.label}
                        {(() => {
                            if (this.state.required) {
                                return ();
                            }
                        })()}
                        {(() => {
                            let dv = this.value();
                            if (dv == null) {
                                dv = '';
                            }
                            if (this.props.options != undefined) { // select
                                if (type != undefined && type != 'select' && type !='nice-select') {
                                    throw 'Cannot use options with type "' + type +'"';
                                }
                                if (type == 'nice-select') {
                                    const opts = [{value:'', label:'Wybierz', name:name}];
                                    const isArr = Array.isArray(this.props.options);
                                    for(let key in this.props.options) {
                                        const sval = this.props.options[key];
                                        opts.push({value:isArr ? sval : key, label:sval, name:name});
                                    }
                                    return (<Select
                                        name={this.props.name}
                                        value={dv}
                                        options={opts}
                                        onChange={this.handleChange}
                                        required={this.state.required}
                                    />);
                                } else {
                                    let opts = [];
                                    opts.push((<option key="" value=""></option>));
                                    let isa = Array.isArray(this.props.options);
                                    for (let key in this.props.options) {
                                        let val = this.props.options[key];
                                        let rk = isa ? val : key;
                                        opts.push((<option label={val} value={rk} key={rk}>{val}</option>));
                                    }
                                    return (<select {...this.inputProps} value={dv}>{opts}</select>);
                                }
                            }
                            type = type || 'text';
                            if (type == 'textarea') {
                                return (<textarea {...this.inputProps} value={dv}/>);
                            } else {
                                return (<input type={type} {...this.inputProps} value={dv}/>);
                            }
                        })()}
                        {(() => {
                            if (this.state.error != null) {
                                return (
                                    {this.state.error}
                                );
                            }
                        })()}

        );
    }
}

export class Form extends React.Component {
    static childContextTypes = {
        wizard : React.PropTypes.object
    };

    static propTypes = {
        data : React.PropTypes.object,   // where to save or get values
        instantValidation : React.PropTypes.bool,   // parameter to pass to Input(s)
        onValidationError : React.PropTypes.func,   // callback func(event, form)
        onSubmit : React.PropTypes.func             // callback func(event, form)
    };

    static defaultProps = {
        instantValidation : false,
        data : {}
    };

    constructor(props) {
        super();
        this.props = props;
        this.data = props.data;
        this.formInputs = [];
        this.state = { };
        this.handleOnSubmit = this.handleOnSubmit.bind(this);
    }

    getChildContext() {
        const self = this;
        return {
            wizard: self
        };
    }

    handleOnSubmit(event) {
        event.preventDefault();
        console.debug("Submit (Form)", event, this.data);
        // validation
        let ret = true;
        this.formInputs.forEach((fin) => {
            if (! fin.validate()) {
                ret = false;
            }
        });
        if (ret) {
            if (this.props.onSubmit) {
                this.props.onSubmit(event, this);
            }
        } else {
            if (this.props.onValidationError) {
                this.props.onValidationError(event, this);
            }
        }
    }

    render() {
        return (<form {...this.props} onSubmit={this.handleOnSubmit}>
            {this.props.children}
        </form>);
    }

}
<|endoftext|>


<commit_before>var GUIElement = function(parent, pubSub) {
    this.x = 0;
    this.y = 0;

    this.width = 0;
    this.height = 0;
    this.pubSub = pubSub;

    this.parent = parent;
    this.children = [];
};

GUIElement.prototype.render = function() {

    this.pubSub.emit("Render");
};

GUIElement.prototype.update = function() {

    this.pubSub.emit("Update");
};

GUIElement.prototype.addChild = function(child) {
    var index = this.children.indexOf(child);

    if(index < 0) {
        if(child.parent != this) {
            child.parent = this;
            child.pubSub.emit("ParentAdded", {parent : this});
        }

        this.children.push(child);
        this.pubSub.emit("ChildAdded", {child : child});
        return true;
    }

    return false;
};

GUIElement.prototype.removeChild = function(child) {
    var index = this.children.indexOf(child);
    if(index >= 0) {
        if(child.parent == this) {
            child.parent = undefined;
            child.pubSub.emit("ParentRemoved", {parent : this});
        }

        this.children.splice(index, 1);
        this.pubSub.emit("ChildRemoved", {child:child});
        return true;
    }

    return false;
};

GUIElement.prototype.hasChild = function(child) {
    return this.children.indexOf(child) >= 0;
};

var createGUIElement = function() {

};<commit_msg>childByName getter and monitoring variables<commit_after>var GUIElement = function(parent, pubSub, name) {
    this.name = name;

    this.active = true;
    this.visible = true;

    // all variables prefixed with *last* are monitoring variables
    // and should not be changed manually
    this.lastActive = this.active;
    this.lastVisible = this.visible;

    this.selected = false;
    this.mouseOver = false;

    this.lastSelected = this.selected;
    this.lastMouseOver = this.mouseOver;

    this.x = 0;
    this.y = 0;

    this.lastX = this.x;
    this.lastY = this.y;

    this.width = 0;
    this.height = 0;

    this.lastWidth = this.width;
    this.lastHeight = this.height;

    this.pubSub = pubSub;

    this.parent = parent;
    this.children = [];
};

GUIElement.prototype.render = function() {
    if(!active) return;

    if(!visible) {
        // TODO render grayscale?
        return;
    }

    this.pubSub.emit("Render");
};

GUIElement.prototype.update = function() {
    if(!active) return;

    this.monitorState();
    this.pubSub.emit("Update");
};

GUIElement.prototype.addChild = function(child) {
    var index = this.children.indexOf(child);

    if(index < 0) {
        if(child.parent != this) {
            child.parent = this;
            child.pubSub.emit("ParentAdded", {parent : this});
        }

        this.children.push(child);
        this.pubSub.emit("ChildAdded", {child : child});
        return true;
    }

    return false;
};

GUIElement.prototype.removeChild = function(child) {
    var index = this.children.indexOf(child);
    if(index >= 0) {
        if(child.parent == this) {
            child.parent = undefined;
            child.pubSub.emit("ParentRemoved", {parent : this});
        }

        this.children.splice(index, 1);
        this.pubSub.emit("ChildRemoved", {child:child});
        return true;
    }

    return false;
};

GUIElement.prototype.hasChild = function(child) {
    return this.children.indexOf(child) >= 0;
};

GUIElement.prototype.getChildByName = function(name) {
    for(var i = 0; i < this.children.length; ++i) {
        if(this.children[i].name === name) {
            return this.children[i];
        }
    }

    return undefined;
};

GUIElement.property.monitorState = function() {

};

var createGUIElement = function() {

};<|endoftext|>


<commit_before>// node dependencies
var Sequelize = require('sequelize');
var dbConfig = require('./dbPassword');

// create database connection
var db = new Sequelize('hackifieds', 'root', dbConfig.password, {
  host: 'localhost',
  dialect: 'mysql',

  pool: {
    max: 5,
    min: 0,
    idle: 10000
  }
});

// User model
var User = db.define('User', {
  userId: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
  username: { type: Sequelize.STRING(100), allowNull: true },
  firstName: { type: Sequelize.STRING(100), allowNull: true },
  lastName: { type: Sequelize.STRING(100), allowNull: true },
  email: { type: Sequelize.STRING(100), allowNull: true },
  profilePic: { type: Sequelize.STRING(100), allowNull: true },
  phone: Sequelize.STRING(100),
  school: { type: Sequelize.STRING(100), allowNull: true },
  cohort: { type: Sequelize.STRING(100), allowNull: true }
});

// Category model
var Category = db.define('Category', {
  'categoryId': {type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
  'categoryName': {type: Sequelize.STRING(25), allowNull: false}
});

// Listing model
var Listing = db.define('Listing', {
  listingId: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
  title: { type: Sequelize.STRING(100), allowNull: false },
  description: { type: Sequelize.TEXT, allowNull: false },
  location: { type: Sequelize.STRING(100), allowNull: false },
  price: { type: Sequelize.DECIMAL(10, 2) },
  startDate: { type: Sequelize.DATE, defaultValue: Sequelize.NOW },
  endDate: { type: Sequelize.DATE },
  roomtype: { type: Sequelize.STRING(100) },
  distance: { type: Sequelize.STRING(100) },
  duration: { type: Sequelize.STRING(100) },
});

// Image model
var Image = db.define('Image', {
  imageId: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
  path: { type: Sequelize.TEXT, allowNull: false }
});

// define foreign key relationships
User.hasMany(Listing, { foreignKey: { name: 'userId', allowNull: false } });
Listing.belongsTo(User, { foreignKey: { name: 'userId', allowNull: false } });
Category.hasMany(Listing, { foreignKey: { name: 'categoryId', allowNull: false } });
Listing.belongsTo(Category, { foreignKey: { name: 'categoryId', allowNull: false } });
Listing.hasMany(Image, { foreignKey: { name: 'listingId', allowNull: false } });
Image.belongsTo(Listing, { foreignKey: { name: 'listingId', allowNull: false } });

// Sync database
User.sync()
  .then( function () {
    console.log( 'Created (or fetched existing) Users table.' );
  })
  .catch( function (err) {
    console.log( 'Unable to create/fetch Users table: ' + err );
  });

Category.sync()
  .then( function () {
    console.log( 'Created (or fetched existing) Categories table.' );
  })
  .catch( function (err) {
    console.log( 'Unable to create/fetch Categories table: ' + err );
  });

Listing.sync()
  .then( function () {
    console.log( 'Created (or fetched existing) Listings table.' );
  })
  .catch( function (err) {
    console.log( 'Unable to create/fetch Listings table: ' + err );
  });

Image.sync()
  .then( function () {
    console.log( 'Created (or fetched existing) Images table.' );
  })
  .catch( function (err) {
    console.log( 'Unable to create/fetch Images table: ' + err );
  });

db.sync()
// db.sync( { force: true } ) // use this line instead of above to overwrite with new schemas
  .then( function () {
    console.log( 'Connection to hackifieds database opened' );
  })
  .catch( function (err) {
    console.log( 'Error opening hackifieds database: ' + err );
  });

exports.User = User;
exports.Category = Category;
exports.Listing = Listing;
exports.Image = Image;

<commit_msg>Make a form<commit_after>// node dependencies
var Sequelize = require('sequelize');
var dbConfig = require('./dbPassword');

// create database connection
var db = new Sequelize('hackifieds', 'root', dbConfig.password, {
  host: 'localhost',
  dialect: 'mysql',

  pool: {
    max: 5,
    min: 0,
    idle: 10000
  }
});

// User model
var User = db.define('User', {
  userId: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
  username: { type: Sequelize.STRING(100), allowNull: true },
  firstName: { type: Sequelize.STRING(100), allowNull: true },
  lastName: { type: Sequelize.STRING(100), allowNull: true },
  email: { type: Sequelize.STRING(100), allowNull: true },
  profilePic: { type: Sequelize.STRING(100), allowNull: true },
  phone: Sequelize.STRING(100),
  school: { type: Sequelize.STRING(100), allowNull: true },
  cohort: { type: Sequelize.STRING(100), allowNull: true }
});

// Category model
var Category = db.define('Category', {
  'categoryId': {type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
  'categoryName': {type: Sequelize.STRING(25), allowNull: false}
});

// Listing model
var Listing = db.define('Listing', {
  listingId: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
  title: { type: Sequelize.STRING(100), allowNull: false },
  description: { type: Sequelize.TEXT, allowNull: false },
  location: { type: Sequelize.STRING(100), allowNull: false },
  price: { type: Sequelize.DECIMAL(10, 2) },
  startDate: { type: Sequelize.DATE, defaultValue: Sequelize.NOW },
  endDate: { type: Sequelize.DATE },
  contactNum: { type: Sequelize.STRING(100) },
  roomtype: { type: Sequelize.STRING(100) },
  distance: { type: Sequelize.STRING(100) },
  duration: { type: Sequelize.STRING(100) },
});

// Image model
var Image = db.define('Image', {
  imageId: { type: Sequelize.INTEGER, primaryKey: true, autoIncrement: true },
  path: { type: Sequelize.TEXT, allowNull: false }
});

// define foreign key relationships
User.hasMany(Listing, { foreignKey: { name: 'userId', allowNull: false } });
Listing.belongsTo(User, { foreignKey: { name: 'userId', allowNull: false } });
Category.hasMany(Listing, { foreignKey: { name: 'categoryId', allowNull: false } });
Listing.belongsTo(Category, { foreignKey: { name: 'categoryId', allowNull: false } });
Listing.hasMany(Image, { foreignKey: { name: 'listingId', allowNull: false } });
Image.belongsTo(Listing, { foreignKey: { name: 'listingId', allowNull: false } });

// Sync database
User.sync()
  .then( function () {
    console.log( 'Created (or fetched existing) Users table.' );
  })
  .catch( function (err) {
    console.log( 'Unable to create/fetch Users table: ' + err );
  });

Category.sync()
  .then( function () {
    console.log( 'Created (or fetched existing) Categories table.' );
  })
  .catch( function (err) {
    console.log( 'Unable to create/fetch Categories table: ' + err );
  });

Listing.sync()
  .then( function () {
    console.log( 'Created (or fetched existing) Listings table.' );
  })
  .catch( function (err) {
    console.log( 'Unable to create/fetch Listings table: ' + err );
  });

Image.sync()
  .then( function () {
    console.log( 'Created (or fetched existing) Images table.' );
  })
  .catch( function (err) {
    console.log( 'Unable to create/fetch Images table: ' + err );
  });

db.sync()
// db.sync( { force: true } ) // use this line instead of above to overwrite with new schemas
  .then( function () {
    console.log( 'Connection to hackifieds database opened' );
  })
  .catch( function (err) {
    console.log( 'Error opening hackifieds database: ' + err );
  });

exports.User = User;
exports.Category = Category;
exports.Listing = Listing;
exports.Image = Image;

<|endoftext|>


<commit_before>/**
 * Created by Ryan Whitley, Daniel Duarte, and Nicholas Hallahan
 *    on 6/03/14.
 */
var Util = require('./MVTUtil');
var StaticLabel = require('./StaticLabel/StaticLabel.js');

module.exports = MVTFeature;

function MVTFeature(mvtLayer, vtf, ctx, id, style) {
  if (!vtf) return null;

  // Apply all of the properties of vtf to this object.
  for (var key in vtf) {
    // Ignore private fields.
    if (key.charAt(0) !== '_') {
      this[key] = vtf[key];
    }
  }

  this.mvtLayer = mvtLayer;
  this.mvtSource = mvtLayer.mvtSource;
  this.map = mvtLayer.mvtSource.map;

  this.id = id;

  this.layerLink = this.mvtSource.layerLink;
  this.toggleEnabled = true;
  this.selected = false;

  // how much we divide the coordinate from the vector tile
  this.divisor = vtf.extent / ctx.tileSize;
  this.extent = vtf.extent;
  this.tileSize = ctx.tileSize;

  //An object to store the paths and contexts for this feature
  this.tiles = {};

  this.style = style;

  //Add to the collection
  this.addTileFeature(vtf, ctx);

  this.map.on('zoomend', this.removeLabel, this);
  var self = this;
  mvtLayer.on('remove', function() {
    self.map.off('zoomend', self.removeLabel, self);
  });

  if (style && style.dynamicLabel && typeof style.dynamicLabel === 'function') {
    this.dynamicLabel = this.mvtSource.dynamicLabel.createFeature(this);
  }

  ajax(this);
}

function ajax(self) {
  var style = self.style;
  if (style && style.ajaxSource && typeof style.ajaxSource === 'function') {
    var ajaxEndpoint = style.ajaxSource(self);
    if (ajaxEndpoint) {
      Util.getJSON(ajaxEndpoint, function(error, response, body) {
        if (error) {
          throw ['ajaxSource AJAX Error', error];
        } else {
          ajaxCallback(self, response);
          return true;
        }
      });
    }
  }
  return false;
}

function ajaxCallback(self, response) {
  self.ajaxData = response;

  /**
   * You can attach a callback function to a feature in your app
   * that will get called whenever new ajaxData comes in. This
   * can be used to update UI that looks at data from within a feature.
   *
   * setStyle may possibly have a style with a different ajaxData source,
   * and you would potentially get new contextual data for your feature.
   *
   * TODO: This needs to be documented.
   */
  if (typeof self.ajaxDataReceived === 'function') {
    self.ajaxDataReceived(self, response);
  }

  self._setStyle(self.mvtLayer.style);
  redrawTiles(self);
}

MVTFeature.prototype._setStyle = function(styleFn) {
  this.style = styleFn(this, this.ajaxData);

  // The label gets removed, and the (re)draw,
  // that is initiated by the MVTLayer creates a new label.
  this.removeLabel();
};

MVTFeature.prototype.setStyle = function(styleFn) {
  this.ajaxData = null;
  this.style = styleFn(this, null);
  var hasAjaxSource = ajax(this);
  if (!hasAjaxSource) {
    // The label gets removed, and the (re)draw,
    // that is initiated by the MVTLayer creates a new label.
    this.removeLabel();
  }
};

MVTFeature.prototype.draw = function(canvasID) {
  //Get the info from the tiles list
  var tileInfo =  this.tiles[canvasID];

  var vtf = tileInfo.vtf;
  var ctx = tileInfo.ctx;

  //Get the actual canvas from the parent layer's _tiles object.
  var xy = canvasID.split(":").slice(1, 3).join(":");
  ctx.canvas = this.mvtLayer._tiles[xy];

//  This could be used to directly compute the style function from the layer on every draw.
//  This is much less efficient...
//  this.style = this.mvtLayer.style(this);

  if (this.selected) {
    var style = this.style.selected || this.style;
  } else {
    var style = this.style;
  }

  switch (vtf.type) {
    case 1: //Point
      this._drawPoint(ctx, vtf.coordinates, style);
      if (!this.staticLabel && typeof this.style.staticLabel === 'function') {
        if (this.style.ajaxSource && !this.ajaxData) {
          break;
        }
        this._drawStaticLabel(ctx, vtf.coordinates, style);
      }
      break;

    case 2: //LineString
      this._drawLineString(ctx, vtf.coordinates, style);
      break;

    case 3: //Polygon
      this._drawPolygon(ctx, vtf.coordinates, style);
      break;

    default:
      throw new Error('Unmanaged type: ' + vtf.type);
  }

};

MVTFeature.prototype.getPathsForTile = function(canvasID) {
  //Get the info from the parts list
  return this.tiles[canvasID].paths;
};

MVTFeature.prototype.addTileFeature = function(vtf, ctx) {
  //Store the important items in the tiles list

  //We only want to store info for tiles for the current map zoom.  If it is tile info for another zoom level, ignore it
  //Also, if there are existing tiles in the list for other zoom levels, expunge them.
  var zoom = this.map.getZoom();

  if(ctx.zoom != zoom) return;

  this.clearTileFeatures(zoom); //TODO: This iterates thru all tiles every time a new tile is added.  Figure out a better way to do this.

  this.tiles[ctx.id] = {
    ctx: ctx,
    vtf: vtf,
    paths: []
  };

};

/**
 * Clear the inner list of tile features if they don't match the given zoom.
 *
 * @param zoom
 */
MVTFeature.prototype.clearTileFeatures = function(zoom) {
  //If stored tiles exist for other zoom levels, expunge them from the list.
  for (var key in this.tiles) {
     if(key.split(":")[0] != zoom) delete this.tiles[key];
  }
};

/**
 * Redraws all of the tiles associated with a feature. Useful for
 * style change and toggling.
 *
 * @param self
 */
function redrawTiles(self) {
  //Redraw the whole tile, not just this vtf
  var tiles = self.tiles;
  var mvtLayer = self.mvtLayer;

  for (var id in tiles) {
    var tileZoom = parseInt(id.split(':')[0]);
    var mapZoom = self.map.getZoom();
    if (tileZoom === mapZoom) {
      //Redraw the tile
      mvtLayer.redrawTile(id);
    }
  }
}

MVTFeature.prototype.toggle = function() {
  if (this.selected) {
    this.deselect();
  } else {
    this.select();
  }
};

MVTFeature.prototype.select = function() {
  this.selected = true;
  this.mvtSource.featureSelected(this);
  redrawTiles(this);
  var linkedFeature = this.linkedFeature();
  if (linkedFeature && linkedFeature.staticLabel && !linkedFeature.staticLabel.selected) {
    linkedFeature.staticLabel.select();
  }
};

MVTFeature.prototype.deselect = function() {
  this.selected = false;
  this.mvtSource.featureDeselected(this);
  redrawTiles(this);
  var linkedFeature = this.linkedFeature();
  if (linkedFeature && linkedFeature.staticLabel && linkedFeature.staticLabel.selected) {
    linkedFeature.staticLabel.deselect();
  }
};

MVTFeature.prototype.on = function(eventType, callback) {
  this._eventHandlers[eventType] = callback;
};

MVTFeature.prototype._drawPoint = function(ctx, coordsArray, style) {
  if (!style) return;
  if (!ctx || !ctx.canvas) return;

  var tile = this.tiles[ctx.id];

  //Get radius
  var radius = 1;
  if (typeof style.radius === 'function') {
    radius = style.radius(ctx.zoom); //Allows for scale dependent rednering
  }
  else{
    radius = style.radius;
  }

  var p = this._tilePoint(coordsArray[0][0]);
  var c = ctx.canvas;
  var ctx2d;
  try{
    ctx2d = c.getContext('2d');
  }
  catch(e){
    console.log("_drawPoint error: " + e);
    return;
  }

  ctx2d.beginPath();
  ctx2d.fillStyle = style.color;
  ctx2d.arc(p.x, p.y, radius, 0, Math.PI * 2);
  ctx2d.closePath();
  ctx2d.fill();

  if(style.lineWidth && style.strokeStyle){
    ctx2d.lineWidth = style.lineWidth;
    ctx2d.strokeStyle = style.strokeStyle;
    ctx2d.stroke();
  }

  ctx2d.restore();
  tile.paths.push([p]);
};

MVTFeature.prototype._drawLineString = function(ctx, coordsArray, style) {
  if (!style) return;
  if (!ctx || !ctx.canvas) return;

  var ctx2d = ctx.canvas.getContext('2d');
  ctx2d.strokeStyle = style.color;
  ctx2d.lineWidth = style.size;
  ctx2d.beginPath();

  var projCoords = [];
  var tile = this.tiles[ctx.id];

  for (var gidx in coordsArray) {
    var coords = coordsArray[gidx];

    for (i = 0; i < coords.length; i++) {
      var method = (i === 0 ? 'move' : 'line') + 'To';
      var proj = this._tilePoint(coords[i]);
      projCoords.push(proj);
      ctx2d[method](proj.x, proj.y);
    }
  }

  ctx2d.stroke();
  ctx2d.restore();

  tile.paths.push(projCoords);
};

MVTFeature.prototype._drawPolygon = function(ctx, coordsArray, style) {
  if (!style) return;
  if (!ctx || !ctx.canvas) return;

  var ctx2d = ctx.canvas.getContext('2d');
  var outline = style.outline;

  // color may be defined via function to make choropleth work right
  if (typeof style.color === 'function') {
    ctx2d.fillStyle = style.color(ctx2d);
  } else {
    ctx2d.fillStyle = style.color;
  }

  if (outline) {
    ctx2d.strokeStyle = outline.color;
    ctx2d.lineWidth = outline.size;
  }
  ctx2d.beginPath();

  var projCoords = [];
  var tile = this.tiles[ctx.id];

  var featureLabel = this.dynamicLabel;
  if (featureLabel) {
    featureLabel.addTilePolys(ctx, coordsArray);
  }

  for (var gidx = 0, len = coordsArray.length; gidx < len; gidx++) {
    var coords = coordsArray[gidx];

    for (var i = 0; i < coords.length; i++) {
      var coord = coords[i];
      var method = (i === 0 ? 'move' : 'line') + 'To';
      var proj = this._tilePoint(coords[i]);
      projCoords.push(proj);
      ctx2d[method](proj.x, proj.y);
    }
  }

  ctx2d.closePath();
  ctx2d.fill();
  if (outline) {
    ctx2d.stroke();
  }

  tile.paths.push(projCoords);

};

MVTFeature.prototype._drawStaticLabel = function(ctx, coordsArray, style) {
  if (!style) return;
  if (!ctx) return;

  // If the corresponding layer is not on the map,
  // we dont want to put on a label.
  if (!this.mvtLayer._map) return;

  var vecPt = this._tilePoint(coordsArray[0][0]);

  // We're making a standard Leaflet Marker for this label.
  var p = this._project(vecPt, ctx.tile.x, ctx.tile.y, this.extent, this.tileSize); //vectile pt to merc pt
  var mercPt = L.point(p.x, p.y); // make into leaflet obj
  var latLng = this.map.unproject(mercPt); // merc pt to latlng

  this.staticLabel = new StaticLabel(this, ctx, latLng, style);
  this.mvtLayer.featureWithLabelAdded(this);
};

MVTFeature.prototype.removeLabel = function() {
  if (!this.staticLabel) return;
  this.staticLabel.remove();
  this.staticLabel = null;
};

/**
 * Projects a vector tile point to the Spherical Mercator pixel space for a given zoom level.
 *
 * @param vecPt
 * @param tileX
 * @param tileY
 * @param extent
 * @param tileSize
 */
MVTFeature.prototype._project = function(vecPt, tileX, tileY, extent, tileSize) {
  var xOffset = tileX * tileSize;
  var yOffset = tileY * tileSize;
  return {
    x: Math.floor(vecPt.x + xOffset),
    y: Math.floor(vecPt.y + yOffset)
  };
};

/**
 * Takes a coordinate from a vector tile and turns it into a Leaflet Point.
 *
 * @param ctx
 * @param coords
 * @returns {eGeomType.Point}
 * @private
 */
MVTFeature.prototype._tilePoint = function(coords) {
  return new L.Point(coords.x / this.divisor, coords.y / this.divisor);
};

MVTFeature.prototype.linkedFeature = function() {
  var linkedLayer = this.mvtLayer.linkedLayer();
  if(linkedLayer){
    var linkedFeature = linkedLayer.features[this.id];
    return linkedFeature;
  }else{
    return null;
  }
};

<commit_msg>Clear map feature tiles on zoomend.<commit_after>/**
 * Created by Ryan Whitley, Daniel Duarte, and Nicholas Hallahan
 *    on 6/03/14.
 */
var Util = require('./MVTUtil');
var StaticLabel = require('./StaticLabel/StaticLabel.js');

module.exports = MVTFeature;

function MVTFeature(mvtLayer, vtf, ctx, id, style) {
  if (!vtf) return null;

  // Apply all of the properties of vtf to this object.
  for (var key in vtf) {
    // Ignore private fields.
    if (key.charAt(0) !== '_') {
      this[key] = vtf[key];
    }
  }

  this.mvtLayer = mvtLayer;
  this.mvtSource = mvtLayer.mvtSource;
  this.map = mvtLayer.mvtSource.map;

  this.id = id;

  this.layerLink = this.mvtSource.layerLink;
  this.toggleEnabled = true;
  this.selected = false;

  // how much we divide the coordinate from the vector tile
  this.divisor = vtf.extent / ctx.tileSize;
  this.extent = vtf.extent;
  this.tileSize = ctx.tileSize;

  //An object to store the paths and contexts for this feature
  this.tiles = {};

  this.style = style;

  //Add to the collection
  this.addTileFeature(vtf, ctx);

  this.map.on('zoomend', this._zoomend, this);
  var self = this;
  mvtLayer.on('remove', function() {
    self.map.off('zoomend', self._zoomend, self);
  });

  if (style && style.dynamicLabel && typeof style.dynamicLabel === 'function') {
    this.dynamicLabel = this.mvtSource.dynamicLabel.createFeature(this);
  }

  ajax(this);
}

function ajax(self) {
  var style = self.style;
  if (style && style.ajaxSource && typeof style.ajaxSource === 'function') {
    var ajaxEndpoint = style.ajaxSource(self);
    if (ajaxEndpoint) {
      Util.getJSON(ajaxEndpoint, function(error, response, body) {
        if (error) {
          throw ['ajaxSource AJAX Error', error];
        } else {
          ajaxCallback(self, response);
          return true;
        }
      });
    }
  }
  return false;
}

function ajaxCallback(self, response) {
  self.ajaxData = response;

  /**
   * You can attach a callback function to a feature in your app
   * that will get called whenever new ajaxData comes in. This
   * can be used to update UI that looks at data from within a feature.
   *
   * setStyle may possibly have a style with a different ajaxData source,
   * and you would potentially get new contextual data for your feature.
   *
   * TODO: This needs to be documented.
   */
  if (typeof self.ajaxDataReceived === 'function') {
    self.ajaxDataReceived(self, response);
  }

  self._setStyle(self.mvtLayer.style);
  redrawTiles(self);
}

MVTFeature.prototype._setStyle = function(styleFn) {
  this.style = styleFn(this, this.ajaxData);

  // The label gets removed, and the (re)draw,
  // that is initiated by the MVTLayer creates a new label.
  this.removeLabel();
};

MVTFeature.prototype.setStyle = function(styleFn) {
  this.ajaxData = null;
  this.style = styleFn(this, null);
  var hasAjaxSource = ajax(this);
  if (!hasAjaxSource) {
    // The label gets removed, and the (re)draw,
    // that is initiated by the MVTLayer creates a new label.
    this.removeLabel();
  }
};

MVTFeature.prototype.draw = function(canvasID) {
  //Get the info from the tiles list
  var tileInfo =  this.tiles[canvasID];

  var vtf = tileInfo.vtf;
  var ctx = tileInfo.ctx;

  //Get the actual canvas from the parent layer's _tiles object.
  var xy = canvasID.split(":").slice(1, 3).join(":");
  ctx.canvas = this.mvtLayer._tiles[xy];

//  This could be used to directly compute the style function from the layer on every draw.
//  This is much less efficient...
//  this.style = this.mvtLayer.style(this);

  if (this.selected) {
    var style = this.style.selected || this.style;
  } else {
    var style = this.style;
  }

  switch (vtf.type) {
    case 1: //Point
      this._drawPoint(ctx, vtf.coordinates, style);
      if (!this.staticLabel && typeof this.style.staticLabel === 'function') {
        if (this.style.ajaxSource && !this.ajaxData) {
          break;
        }
        this._drawStaticLabel(ctx, vtf.coordinates, style);
      }
      break;

    case 2: //LineString
      this._drawLineString(ctx, vtf.coordinates, style);
      break;

    case 3: //Polygon
      this._drawPolygon(ctx, vtf.coordinates, style);
      break;

    default:
      throw new Error('Unmanaged type: ' + vtf.type);
  }

};

MVTFeature.prototype.getPathsForTile = function(canvasID) {
  //Get the info from the parts list
  return this.tiles[canvasID].paths;
};

MVTFeature.prototype.addTileFeature = function(vtf, ctx) {
  //Store the important items in the tiles list

  //We only want to store info for tiles for the current map zoom.  If it is tile info for another zoom level, ignore it
  //Also, if there are existing tiles in the list for other zoom levels, expunge them.
  var zoom = this.map.getZoom();

  if(ctx.zoom != zoom) return;

  this.tiles[ctx.id] = {
    ctx: ctx,
    vtf: vtf,
    paths: []
  };

};

/**
 * Clear the inner list of tile features if they don't match the given zoom.
 *
 * @param zoom
 */
MVTFeature.prototype.clearTileFeatures = function(zoom) {
  //If stored tiles exist for other zoom levels, expunge them from the list.
  for (var key in this.tiles) {
     if(key.split(":")[0] != zoom) delete this.tiles[key];
  }
};

/**
 * Redraws all of the tiles associated with a feature. Useful for
 * style change and toggling.
 *
 * @param self
 */
function redrawTiles(self) {
  //Redraw the whole tile, not just this vtf
  var tiles = self.tiles;
  var mvtLayer = self.mvtLayer;

  for (var id in tiles) {
    var tileZoom = parseInt(id.split(':')[0]);
    var mapZoom = self.map.getZoom();
    if (tileZoom === mapZoom) {
      //Redraw the tile
      mvtLayer.redrawTile(id);
    }
  }
}

MVTFeature.prototype.toggle = function() {
  if (this.selected) {
    this.deselect();
  } else {
    this.select();
  }
};

MVTFeature.prototype.select = function() {
  this.selected = true;
  this.mvtSource.featureSelected(this);
  redrawTiles(this);
  var linkedFeature = this.linkedFeature();
  if (linkedFeature && linkedFeature.staticLabel && !linkedFeature.staticLabel.selected) {
    linkedFeature.staticLabel.select();
  }
};

MVTFeature.prototype.deselect = function() {
  this.selected = false;
  this.mvtSource.featureDeselected(this);
  redrawTiles(this);
  var linkedFeature = this.linkedFeature();
  if (linkedFeature && linkedFeature.staticLabel && linkedFeature.staticLabel.selected) {
    linkedFeature.staticLabel.deselect();
  }
};

MVTFeature.prototype.on = function(eventType, callback) {
  this._eventHandlers[eventType] = callback;
};

MVTFeature.prototype._drawPoint = function(ctx, coordsArray, style) {
  if (!style) return;
  if (!ctx || !ctx.canvas) return;

  var tile = this.tiles[ctx.id];

  //Get radius
  var radius = 1;
  if (typeof style.radius === 'function') {
    radius = style.radius(ctx.zoom); //Allows for scale dependent rednering
  }
  else{
    radius = style.radius;
  }

  var p = this._tilePoint(coordsArray[0][0]);
  var c = ctx.canvas;
  var ctx2d;
  try{
    ctx2d = c.getContext('2d');
  }
  catch(e){
    console.log("_drawPoint error: " + e);
    return;
  }

  ctx2d.beginPath();
  ctx2d.fillStyle = style.color;
  ctx2d.arc(p.x, p.y, radius, 0, Math.PI * 2);
  ctx2d.closePath();
  ctx2d.fill();

  if(style.lineWidth && style.strokeStyle){
    ctx2d.lineWidth = style.lineWidth;
    ctx2d.strokeStyle = style.strokeStyle;
    ctx2d.stroke();
  }

  ctx2d.restore();
  tile.paths.push([p]);
};

MVTFeature.prototype._drawLineString = function(ctx, coordsArray, style) {
  if (!style) return;
  if (!ctx || !ctx.canvas) return;

  var ctx2d = ctx.canvas.getContext('2d');
  ctx2d.strokeStyle = style.color;
  ctx2d.lineWidth = style.size;
  ctx2d.beginPath();

  var projCoords = [];
  var tile = this.tiles[ctx.id];

  for (var gidx in coordsArray) {
    var coords = coordsArray[gidx];

    for (i = 0; i < coords.length; i++) {
      var method = (i === 0 ? 'move' : 'line') + 'To';
      var proj = this._tilePoint(coords[i]);
      projCoords.push(proj);
      ctx2d[method](proj.x, proj.y);
    }
  }

  ctx2d.stroke();
  ctx2d.restore();

  tile.paths.push(projCoords);
};

MVTFeature.prototype._drawPolygon = function(ctx, coordsArray, style) {
  if (!style) return;
  if (!ctx || !ctx.canvas) return;

  var ctx2d = ctx.canvas.getContext('2d');
  var outline = style.outline;

  // color may be defined via function to make choropleth work right
  if (typeof style.color === 'function') {
    ctx2d.fillStyle = style.color(ctx2d);
  } else {
    ctx2d.fillStyle = style.color;
  }

  if (outline) {
    ctx2d.strokeStyle = outline.color;
    ctx2d.lineWidth = outline.size;
  }
  ctx2d.beginPath();

  var projCoords = [];
  var tile = this.tiles[ctx.id];

  var featureLabel = this.dynamicLabel;
  if (featureLabel) {
    featureLabel.addTilePolys(ctx, coordsArray);
  }

  for (var gidx = 0, len = coordsArray.length; gidx < len; gidx++) {
    var coords = coordsArray[gidx];

    for (var i = 0; i < coords.length; i++) {
      var coord = coords[i];
      var method = (i === 0 ? 'move' : 'line') + 'To';
      var proj = this._tilePoint(coords[i]);
      projCoords.push(proj);
      ctx2d[method](proj.x, proj.y);
    }
  }

  ctx2d.closePath();
  ctx2d.fill();
  if (outline) {
    ctx2d.stroke();
  }

  tile.paths.push(projCoords);

};

MVTFeature.prototype._drawStaticLabel = function(ctx, coordsArray, style) {
  if (!style) return;
  if (!ctx) return;

  // If the corresponding layer is not on the map,
  // we dont want to put on a label.
  if (!this.mvtLayer._map) return;

  var vecPt = this._tilePoint(coordsArray[0][0]);

  // We're making a standard Leaflet Marker for this label.
  var p = this._project(vecPt, ctx.tile.x, ctx.tile.y, this.extent, this.tileSize); //vectile pt to merc pt
  var mercPt = L.point(p.x, p.y); // make into leaflet obj
  var latLng = this.map.unproject(mercPt); // merc pt to latlng

  this.staticLabel = new StaticLabel(this, ctx, latLng, style);
  this.mvtLayer.featureWithLabelAdded(this);
};

MVTFeature.prototype.removeLabel = function() {
  if (!this.staticLabel) return;
  this.staticLabel.remove();
  this.staticLabel = null;
};

MVTFeature.prototype._zoomend = function() {
  this.removeLabel();
  this.clearTileFeatures(this.map.getZoom());
};

/**
 * Projects a vector tile point to the Spherical Mercator pixel space for a given zoom level.
 *
 * @param vecPt
 * @param tileX
 * @param tileY
 * @param extent
 * @param tileSize
 */
MVTFeature.prototype._project = function(vecPt, tileX, tileY, extent, tileSize) {
  var xOffset = tileX * tileSize;
  var yOffset = tileY * tileSize;
  return {
    x: Math.floor(vecPt.x + xOffset),
    y: Math.floor(vecPt.y + yOffset)
  };
};

/**
 * Takes a coordinate from a vector tile and turns it into a Leaflet Point.
 *
 * @param ctx
 * @param coords
 * @returns {eGeomType.Point}
 * @private
 */
MVTFeature.prototype._tilePoint = function(coords) {
  return new L.Point(coords.x / this.divisor, coords.y / this.divisor);
};

MVTFeature.prototype.linkedFeature = function() {
  var linkedLayer = this.mvtLayer.linkedLayer();
  if(linkedLayer){
    var linkedFeature = linkedLayer.features[this.id];
    return linkedFeature;
  }else{
    return null;
  }
};

<|endoftext|>


<commit_before>const FileCollection = require('laravel-mix/src/FileCollection');
const File = require('laravel-mix/src/File');
const Task = require('laravel-mix/src/tasks/Task');
const PugSeeder = require('./PugSeeder');

const notifier = require('node-notifier');
const glob = require('glob');
const path = require('path');
const pug  = require('pug');
const fs   = require('fs');

class MixPugTask extends Task {

    /**
     * Run the pug compiler.
     */
    run() {

        let {files, dest, options} = this.data;

        if (!options) {
            options = {
                seeds: null,
                locals: {},
                pug: null
            };
        }

        // Set destination folder
        this.dest = dest;

        // Set pug options
        this.pugOptions = options.pug;

        // Setup template seeder
        this.seedPath = options.seeds;
        this.locals = options.locals;

        this.seeder = this.createSeeder();

        // Prepare Template Files
        this.templates = files;

        // We'll be watching for changes on all pug files
        // in case a layout, mixin or partial changes and
        // all seed files included.
        this.files = new FileCollection(
            glob.sync('**/*.pug', {ignore: 'node_modules/**/*'}).concat(
                this.seeder.files
            )
        );

        // Preprare destination assets
        this.assets = files.map(asset => this.prepareAssets(asset));

        this.compile();
    }

    /**
     * Compiles a collection of Pug templates.
     *
     */
    compile() {

        this.templates.forEach((template, index) => this.compileTemplate(template, index));

        return this;
    }

    /**
     * Compiles a single pug template
     *
     * @param {string} src Path to the pug source file
     * @param {number} index
     */
    compileTemplate(src, index) {
        let file = new File(src);
        let output = this.assets[index];

        try {

            let template = pug.compileFile(file.path(), this.pugOptions);

            let html = template(
                this.seeder.locals
            );

            fs.writeFileSync(output.path(), html);

            this.onSuccess();

        } catch (e) {
            this.onFail(e.name + ': ' + e.message);
        }
    }

    /**
     * Updates seeder with changed data files
     *
     */
    createSeeder() {
        return new PugSeeder(this.seedPath)
            .extend(this.locals);
    }

    /**
     * Recompile on change when using watch
     *
     * @param {string} updatedFile
     */
    onChange(updatedFile) {
        this.seeder = this.createSeeder();
        this.compile();
    }

    /**
     * Handle successful compilation.
     *
     * @param {string} output
     */
    onSuccess(output) {
        if (Config.notifications.onSuccess) {
            notifier.notify({
                title: 'Laravel Mix',
                message: 'Pug Compilation Successful',
                contentImage: 'node_modules/laravel-mix-pug/src/logo.png'
            });
        }
    }

    /**
     * Handle failed compilation.
     *
     * @param {string} output
     */
    onFail(output) {
        console.log("\n");
        console.log('Pug Compilation Failed!');
        console.log();
        console.log(output);

        if (Mix.isUsing('notifications')) {
            notifier.notify({
                title: 'Laravel Mix',
                subtitle: 'Pug Compilation Failed',
                message: output,
                contentImage: 'node_modules/laravel-mix-pug/src/logo.png'
            });
        }
    }

    prepareAssets(src) {
        let file = new File(src);
        let output = path.join(this.dest, file.nameWithoutExtension() + '.html');
        let asset = new File(output);

        Mix.addAsset(asset);

        return asset;
    }

}

module.exports = MixPugTask;
<commit_msg>Added possibility to change the output extension file and to remove part of the source path.<commit_after>const FileCollection = require('laravel-mix/src/FileCollection');
const File = require('laravel-mix/src/File');
const Task = require('laravel-mix/src/tasks/Task');
const PugSeeder = require('./PugSeeder');

const notifier = require('node-notifier');
const glob = require('glob');
const path = require('path');
const pug  = require('pug');
const fs   = require('fs');

class MixPugTask extends Task {

    /**
     * Run the pug compiler.
     */
    run() {

        let {files, dest, options} = this.data;

        if (!options) {
            options = {
                seeds: null,
                locals: {},
                pug: null,
                ext: '.html',
                excludePath: null
            };
        }

        // Set destination folder
        this.dest = dest;

        // Set pug options
        this.pugOptions = options.pug;

        // Setup template seeder
        this.seedPath = options.seeds;
        this.locals = options.locals || {};
        this.extension = options.ext || '.html';
        this.excludePath = options.excludePath || null;

        this.seeder = this.createSeeder();

        // Prepare Template Files
        this.templates = files;

        // We'll be watching for changes on all pug files
        // in case a layout, mixin or partial changes and
        // all seed files included.
        this.files = new FileCollection(
            glob.sync('**/*.pug', {ignore: 'node_modules/**/*'}).concat(
                this.seeder.files
            )
        );

        // Preprare destination assets
        this.assets = files.map(asset => this.prepareAssets(asset));

        this.compile();
    }

    /**
     * Compiles a collection of Pug templates.
     *
     */
    compile() {

        this.templates.forEach((template, index) => this.compileTemplate(template, index));

        return this;
    }

    /**
     * Compiles a single pug template
     *
     * @param {string} src Path to the pug source file
     * @param {number} index
     */
    compileTemplate(src, index) {
        let file = new File(src);
        let output = this.assets[index];

        try {

            let template = pug.compileFile(file.path(), this.pugOptions);

            let html = template(
                this.seeder.locals
            );

            fs.writeFileSync(output.path(), html);

            this.onSuccess();

        } catch (e) {
            this.onFail(e.name + ': ' + e.message);
        }
    }

    /**
     * Updates seeder with changed data files
     *
     */
    createSeeder() {
        return new PugSeeder(this.seedPath)
            .extend(this.locals);
    }

    /**
     * Recompile on change when using watch
     *
     * @param {string} updatedFile
     */
    onChange(updatedFile) {
        this.seeder = this.createSeeder();
        this.compile();
    }

    /**
     * Handle successful compilation.
     *
     * @param {string} output
     */
    onSuccess(output) {
        if (Config.notifications.onSuccess) {
            notifier.notify({
                title: 'Laravel Mix',
                message: 'Pug Compilation Successful',
                contentImage: 'node_modules/laravel-mix-pug/src/logo.png'
            });
        }
    }

    /**
     * Handle failed compilation.
     *
     * @param {string} output
     */
    onFail(output) {
        console.log("\n");
        console.log('Pug Compilation Failed!');
        console.log();
        console.log(output);

        if (Mix.isUsing('notifications')) {
            notifier.notify({
                title: 'Laravel Mix',
                subtitle: 'Pug Compilation Failed',
                message: output,
                contentImage: 'node_modules/laravel-mix-pug/src/logo.png'
            });
        }
    }

    relativePathFromSource(filePath, excludePath) {
         excludePath = excludePath || 'resources/assets/pug';
         return filePath.split(excludePath).pop();
    }

    prepareAssets(src) {
        let file = new File(src);
        let pathFromBase = this.relativePathFromSource(file.base(), this.excludePath);
        let baseDir = path.join(this.dest, pathFromBase);

        if (!File.exists(baseDir)) {
            new File(baseDir).makeDirectories();
        }

        let output = path.join(baseDir, file.nameWithoutExtension() + this.extension);
        let asset = new File(output);

        Mix.addAsset(asset);

        return asset;
    }

}

module.exports = MixPugTask;
<|endoftext|>


<commit_before>"use strict";

const events  = require('events');
const _       = require('underscore');
const Promise = require('bluebird');
const glob    = require('glob');

const Plugin  = require('./Plugin.js');

class PluginHost extends events.EventEmitter {

	constructor(core) {
		super();

		this._core = core;
		this._loadedPlugins = new Map();
	}

	unloadAll() {
		let plugins = [];
		this._loadedPlugins.forEach(plugin => plugins.push(this.unload(plugin)));
		return Promise.all(plugins);
	}

	unload(plugin) {
		if(plugin.getInstance())
			return plugin.getInstance().destroy();

		return Promise.reject("plugin not loaded");
	}

	loadAll() {
		this.unloadAll();

		let plugins = this._findPlugins();

		return Promise.map(plugins, plugin => {
			return Plugin.load(plugin).then(loaded => this.load(loaded));
		});
	}

	load(plugin) {
		['log', 'info', 'warn', 'error', 'dir', 'trace'].forEach(type => {
			let eventName = `console.${type}`;
			plugin.on(`console.${type}`, args => this._core.log("Plugin/" + plugin.getName(), args, type));
		});

		this._loadedPlugins.set(plugin.getName(), plugin);

		return plugin.initialise();
	}

	_findPlugins() {
		let plugins = [];

		// STEP 1: Find any local plugins - these override everything
		plugins = plugins.concat(glob.sync(this._core.settings.dataPath + '/*/package.json'));

		// STEP 2: Find any node_modules that belong in our ecosystem
		plugins = plugins.concat(glob.sync('node_modules/shadowbot-plugin-*/package.json'));

		// STEP 3: Find any built-in plugins
		plugins = plugins.concat(glob.sync('plugins/*/package.json'));

		return plugins;
	}

}

module.exports = PluginHost;
<commit_msg>Lower priority plugins are now silently rejected.<commit_after>"use strict";

const events  = require('events');
const _       = require('underscore');
const Promise = require('bluebird');
const glob    = require('glob');

const Plugin  = require('./Plugin');

class PluginHost extends events.EventEmitter {

	constructor(core) {
		super();

		this._core = core;
		this._loadedPlugins = new Map();
	}

	unloadAll() {
		let plugins = [];
		this._loadedPlugins.forEach(plugin => plugins.push(this.unload(plugin)));
		return Promise.all(plugins);
	}

	unload(plugin) {
		if(plugin.getInstance())
			return plugin.getInstance().destroy();

		return Promise.reject("plugin not loaded");
	}

	loadAll() {
		this.unloadAll();

		let plugins = this._findPlugins();

		return Promise.map(plugins, plugin => {
			return Plugin.load(plugin).then(loaded => this.load(loaded));
		});
	}

	load(plugin) {
		['log', 'info', 'warn', 'error', 'dir', 'trace'].forEach(type => {
			let eventName = `console.${type}`;
			plugin.on(`console.${type}`, args => this._core.log("Plugin/" + plugin.getName(), args, type));
		});

		if(this._loadedPlugins.has(plugin.getName()))
			return Promise.resolve();

		this._loadedPlugins.set(plugin.getName(), plugin);

		return plugin.initialise();
	}

	_findPlugins() {
		let plugins = [];

		// STEP 1: Find any local plugins - these override everything
		plugins = plugins.concat(glob.sync(this._core.settings.dataPath + '/*/package.json'));

		// STEP 2: Find any node_modules that belong in our ecosystem
		plugins = plugins.concat(glob.sync('node_modules/shadowbot-plugin-*/package.json'));

		// STEP 3: Find any built-in plugins
		plugins = plugins.concat(glob.sync('plugins/*/package.json'));

		return plugins;
	}

}

module.exports = PluginHost;
<|endoftext|>


<commit_before>function PostReporter( request, reply ) {
  console.log(request);
  return reply({
    color: 'green',
    message: 'Request recived',
    notify: false,
    message_format: 'text',
  })
}

module.exports = PostReporter;
<commit_msg>Debug payload<commit_after>function PostReporter( request, reply ) {
  console.log(request.payload);
  return reply({
    color: 'green',
    message: 'Request recived',
    notify: false,
    message_format: 'text',
  })
}

module.exports = PostReporter;
<|endoftext|>


<commit_before>define(function(require) {

    'use strict';

    var Node = require('./Node');
    var glenum = require('./core/glenum');
    var glinfo = require('./core/glinfo');
    var DynamicGeometry = require('./DynamicGeometry');

    // Cache
    var prevDrawID = 0;
    var prevDrawIndicesBuffer = null;
    var prevDrawIsUseFace = true;

    var currentDrawID;

    var RenderInfo = function() {
        this.faceNumber = 0;
        this.vertexNumber = 0;
        this.drawCallNumber = 0;
    };

    function VertexArrayObject(
        availableAttributes,
        availableAttributeSymbols,
        indicesBuffer
    ) {
        this.availableAttributes = availableAttributes;
        this.availableAttributeSymbols = availableAttributeSymbols;
        this.indicesBuffer = indicesBuffer;

        this.vao = null;
    }
    /**
     * @constructor qtek.Renderable
     * @extends qtek.Node
     */
    var Renderable = Node.derive(
    /** @lends qtek.Renderable# */
    {
        /**
         * @type {qtek.Material}
         */
        material: null,

        /**
         * @type {qtek.Geometry}
         */
        geometry: null,

        /**
         * @type {number}
         */
        mode: glenum.TRIANGLES,

        _drawCache: null,

        _renderInfo: null
    }, function() {
        this._drawCache = {};
        this._renderInfo = new RenderInfo();
    },
    /** @lends qtek.Renderable.prototype */
    {

        /**
         * Used when mode is LINES, LINE_STRIP or LINE_LOOP
         * @type {number}
         */
        lineWidth: 1,

        /**
         * @type {boolean}
         */
        culling: true,
        /**
         * @type {number}
         */
        cullFace: glenum.BACK,
        /**
         * @type {number}
         */
        frontFace: glenum.CCW,

        /**
         * Software frustum culling
         * @type {boolean}
         */
        frustumCulling: true,
        /**
         * @type {boolean}
         */
        receiveShadow: true,
        /**
         * @type {boolean}
         */
        castShadow: true,
        /**
         * @type {boolean}
         */
        ignorePicking: false,

        /**
         * @return {boolean}
         */
        isRenderable: function() {
            return this.geometry && this.material && this.material.shader && this.visible;
        },

        /**
         * @param  {WebGLRenderingContext} _gl
         * @param  {qtek.Material} [globalMaterial]
         * @return {Object}
         */
        render: function(_gl, globalMaterial) {
            var material = globalMaterial || this.material;
            var shader = material.shader;
            var geometry = this.geometry;

            var glDrawMode = this.mode;

            var nVertex = geometry.getVertexNumber();
            var isUseFace = geometry.isUseFace();

            var uintExt = glinfo.getExtension(_gl, 'OES_element_index_uint');
            var useUintExt = uintExt && nVertex > 0xffff;
            var indicesType = useUintExt ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT;

            var vaoExt = glinfo.getExtension(_gl, 'OES_vertex_array_object');

            var isStatic = !geometry.dynamic;

            var renderInfo = this._renderInfo;
            renderInfo.vertexNumber = nVertex;
            renderInfo.faceNumber = 0;
            renderInfo.drawCallNumber = 0;
            // Draw each chunk
            var drawHashChanged = false;
            // Hash with shader id in case previous material has less attributes than next material
            currentDrawID = _gl.__GLID__ + '-' + geometry.__GUID__ + '-' + shader.__GUID__;

            if (currentDrawID !== prevDrawID) {
                drawHashChanged = true;
            } else {
                // The cache will be invalid in the following cases
                // 1. Geometry is splitted to multiple chunks
                // 2. VAO is enabled and is binded to null after render
                // 3. Geometry needs update
                if (
                    ((geometry instanceof DynamicGeometry) && (nVertex > 0xffff && !uintExt) && isUseFace)
                 || (vaoExt && isStatic)
                 || geometry._cache.isDirty()
                ) {
                    drawHashChanged = true;
                }
            }
            prevDrawID = currentDrawID;

            if (!drawHashChanged) {
                // Direct draw
                if (prevDrawIsUseFace) {
                    _gl.drawElements(glDrawMode, prevDrawIndicesBuffer.count, indicesType, 0);
                    renderInfo.faceNumber = prevDrawIndicesBuffer.count / 3;
                }
                else {
                    // FIXME Use vertex number in buffer
                    // getVertexNumber may get the wrong value when geometry forget to mark dirty after update
                    _gl.drawArrays(glDrawMode, 0, nVertex);
                }
                renderInfo.drawCallNumber = 1;
            } else {
                // Use the cache of static geometry
                var vaoList = this._drawCache[currentDrawID];
                if (!vaoList) {
                    var chunks = geometry.getBufferChunks(_gl);
                    if (!chunks) {  // Empty mesh
                        return;
                    }
                    vaoList = [];
                    for (var c = 0; c < chunks.length; c++) {
                        var chunk = chunks[c];
                        var attributeBuffers = chunk.attributeBuffers;
                        var indicesBuffer = chunk.indicesBuffer;

                        var availableAttributes = [];
                        var availableAttributeSymbols = [];
                        for (var a = 0; a < attributeBuffers.length; a++) {
                            var attributeBufferInfo = attributeBuffers[a];
                            var name = attributeBufferInfo.name;
                            var semantic = attributeBufferInfo.semantic;
                            var symbol;
                            if (semantic) {
                                var semanticInfo = shader.attribSemantics[semantic];
                                symbol = semanticInfo && semanticInfo.symbol;
                            } else {
                                symbol = name;
                            }
                            if (symbol && shader.attributeTemplates[symbol]) {
                                availableAttributes.push(attributeBufferInfo);
                                availableAttributeSymbols.push(symbol);
                            }
                        }

                        var vao = new VertexArrayObject(
                            availableAttributes,
                            availableAttributeSymbols,
                            indicesBuffer
                        );
                        vaoList.push(vao);
                    }
                    if (isStatic) {
                        this._drawCache[currentDrawID] = vaoList;
                    }
                }

                for (var i = 0; i < vaoList.length; i++) {
                    var vao = vaoList[i];
                    var needsBindAttributes = true;

                    // Create vertex object array cost a lot
                    // So we don't use it on the dynamic object
                    if (vaoExt && isStatic) {
                        // Use vertex array object
                        // http://blog.tojicode.com/2012/10/oesvertexarrayobject-extension.html
                        if (vao.vao == null) {
                            vao.vao = vaoExt.createVertexArrayOES();
                        } else {
                            needsBindAttributes = false;
                        }
                        vaoExt.bindVertexArrayOES(vao.vao);
                    }

                    var availableAttributes = vao.availableAttributes;
                    var indicesBuffer = vao.indicesBuffer;

                    if (needsBindAttributes) {
                        var locationList = shader.enableAttributes(_gl, vao.availableAttributeSymbols, (vaoExt && isStatic && vao.vao));
                        // Setting attributes;
                        for (var a = 0; a < availableAttributes.length; a++) {
                            var location = locationList[a];
                            if (location === -1) {
                                continue;
                            }
                            var attributeBufferInfo = availableAttributes[a];
                            var buffer = attributeBufferInfo.buffer;
                            var size = attributeBufferInfo.size;
                            var glType;
                            switch (attributeBufferInfo.type) {
                                case 'float':
                                    glType = _gl.FLOAT;
                                    break;
                                case 'byte':
                                    glType = _gl.BYTE;
                                    break;
                                case 'ubyte':
                                    glType = _gl.UNSIGNED_BYTE;
                                    break;
                                case 'short':
                                    glType = _gl.SHORT;
                                    break;
                                case 'ushort':
                                    glType = _gl.UNSIGNED_SHORT;
                                    break;
                                default:
                                    glType = _gl.FLOAT;
                                    break;
                            }

                            _gl.bindBuffer(_gl.ARRAY_BUFFER, buffer);
                            _gl.vertexAttribPointer(location, size, glType, false, 0, 0);
                        }
                    }
                    if (
                        glDrawMode == glenum.LINES ||
                        glDrawMode == glenum.LINE_STRIP ||
                        glDrawMode == glenum.LINE_LOOP
                    ) {
                        _gl.lineWidth(this.lineWidth);
                    }

                    prevDrawIndicesBuffer = indicesBuffer;
                    prevDrawIsUseFace = geometry.isUseFace();
                    //Do drawing
                    if (prevDrawIsUseFace) {
                        if (needsBindAttributes) {
                            _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, indicesBuffer.buffer);
                        }
                        _gl.drawElements(glDrawMode, indicesBuffer.count, indicesType, 0);
                        renderInfo.faceNumber += indicesBuffer.count / 3;
                    } else {
                        _gl.drawArrays(glDrawMode, 0, nVertex);
                    }

                    if (vaoExt && isStatic) {
                        vaoExt.bindVertexArrayOES(null);
                    }

                    renderInfo.drawCallNumber++;
                }
            }

            return renderInfo;
        },

        /**
         * Clone a new renderable
         * @method
         * @return {qtek.Renderable}
         */
        clone: (function() {
            var properties = [
                'castShadow', 'receiveShadow',
                'mode', 'culling', 'cullFace', 'frontFace',
                'frustumCulling'
            ];
            return function() {
                var renderable = Node.prototype.clone.call(this);

                renderable.geometry = this.geometry;
                renderable.material = this.material;

                for (var i = 0; i < properties.length; i++) {
                    var name = properties[i];
                    // Try not to overwrite the prototype property
                    if (renderable[name] !== this[name]) {
                        renderable[name] = this[name];
                    }
                }

                return renderable;
            };
        })()
    });

    Renderable.beforeFrame = function() {
        prevDrawID = 0;
    };

    // Enums
    Renderable.POINTS = glenum.POINTS;
    Renderable.LINES = glenum.LINES;
    Renderable.LINE_LOOP = glenum.LINE_LOOP;
    Renderable.LINE_STRIP = glenum.LINE_STRIP;
    Renderable.TRIANGLES = glenum.TRIANGLES;
    Renderable.TRIANGLE_STRIP = glenum.TRIANGLE_STRIP;
    Renderable.TRIANGLE_FAN = glenum.TRIANGLE_FAN;

    Renderable.BACK = glenum.BACK;
    Renderable.FRONT = glenum.FRONT;
    Renderable.FRONT_AND_BACK = glenum.FRONT_AND_BACK;
    Renderable.CW = glenum.CW;
    Renderable.CCW = glenum.CCW;

    Renderable.RenderInfo = RenderInfo;

    return Renderable;
});<commit_msg>isRenderable remove shader validation<commit_after>define(function(require) {

    'use strict';

    var Node = require('./Node');
    var glenum = require('./core/glenum');
    var glinfo = require('./core/glinfo');
    var DynamicGeometry = require('./DynamicGeometry');

    // Cache
    var prevDrawID = 0;
    var prevDrawIndicesBuffer = null;
    var prevDrawIsUseFace = true;

    var currentDrawID;

    var RenderInfo = function() {
        this.faceNumber = 0;
        this.vertexNumber = 0;
        this.drawCallNumber = 0;
    };

    function VertexArrayObject(
        availableAttributes,
        availableAttributeSymbols,
        indicesBuffer
    ) {
        this.availableAttributes = availableAttributes;
        this.availableAttributeSymbols = availableAttributeSymbols;
        this.indicesBuffer = indicesBuffer;

        this.vao = null;
    }
    /**
     * @constructor qtek.Renderable
     * @extends qtek.Node
     */
    var Renderable = Node.derive(
    /** @lends qtek.Renderable# */
    {
        /**
         * @type {qtek.Material}
         */
        material: null,

        /**
         * @type {qtek.Geometry}
         */
        geometry: null,

        /**
         * @type {number}
         */
        mode: glenum.TRIANGLES,

        _drawCache: null,

        _renderInfo: null
    }, function() {
        this._drawCache = {};
        this._renderInfo = new RenderInfo();
    },
    /** @lends qtek.Renderable.prototype */
    {

        /**
         * Used when mode is LINES, LINE_STRIP or LINE_LOOP
         * @type {number}
         */
        lineWidth: 1,

        /**
         * @type {boolean}
         */
        culling: true,
        /**
         * @type {number}
         */
        cullFace: glenum.BACK,
        /**
         * @type {number}
         */
        frontFace: glenum.CCW,

        /**
         * Software frustum culling
         * @type {boolean}
         */
        frustumCulling: true,
        /**
         * @type {boolean}
         */
        receiveShadow: true,
        /**
         * @type {boolean}
         */
        castShadow: true,
        /**
         * @type {boolean}
         */
        ignorePicking: false,

        /**
         * @return {boolean}
         */
        isRenderable: function() {
            return this.geometry && this.material && this.visible;
        },

        /**
         * @param  {WebGLRenderingContext} _gl
         * @param  {qtek.Material} [globalMaterial]
         * @return {Object}
         */
        render: function(_gl, globalMaterial) {
            var material = globalMaterial || this.material;
            var shader = material.shader;
            var geometry = this.geometry;

            var glDrawMode = this.mode;

            var nVertex = geometry.getVertexNumber();
            var isUseFace = geometry.isUseFace();

            var uintExt = glinfo.getExtension(_gl, 'OES_element_index_uint');
            var useUintExt = uintExt && nVertex > 0xffff;
            var indicesType = useUintExt ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT;

            var vaoExt = glinfo.getExtension(_gl, 'OES_vertex_array_object');

            var isStatic = !geometry.dynamic;

            var renderInfo = this._renderInfo;
            renderInfo.vertexNumber = nVertex;
            renderInfo.faceNumber = 0;
            renderInfo.drawCallNumber = 0;
            // Draw each chunk
            var drawHashChanged = false;
            // Hash with shader id in case previous material has less attributes than next material
            currentDrawID = _gl.__GLID__ + '-' + geometry.__GUID__ + '-' + shader.__GUID__;

            if (currentDrawID !== prevDrawID) {
                drawHashChanged = true;
            } else {
                // The cache will be invalid in the following cases
                // 1. Geometry is splitted to multiple chunks
                // 2. VAO is enabled and is binded to null after render
                // 3. Geometry needs update
                if (
                    ((geometry instanceof DynamicGeometry) && (nVertex > 0xffff && !uintExt) && isUseFace)
                 || (vaoExt && isStatic)
                 || geometry._cache.isDirty()
                ) {
                    drawHashChanged = true;
                }
            }
            prevDrawID = currentDrawID;

            if (!drawHashChanged) {
                // Direct draw
                if (prevDrawIsUseFace) {
                    _gl.drawElements(glDrawMode, prevDrawIndicesBuffer.count, indicesType, 0);
                    renderInfo.faceNumber = prevDrawIndicesBuffer.count / 3;
                }
                else {
                    // FIXME Use vertex number in buffer
                    // getVertexNumber may get the wrong value when geometry forget to mark dirty after update
                    _gl.drawArrays(glDrawMode, 0, nVertex);
                }
                renderInfo.drawCallNumber = 1;
            } else {
                // Use the cache of static geometry
                var vaoList = this._drawCache[currentDrawID];
                if (!vaoList) {
                    var chunks = geometry.getBufferChunks(_gl);
                    if (!chunks) {  // Empty mesh
                        return;
                    }
                    vaoList = [];
                    for (var c = 0; c < chunks.length; c++) {
                        var chunk = chunks[c];
                        var attributeBuffers = chunk.attributeBuffers;
                        var indicesBuffer = chunk.indicesBuffer;

                        var availableAttributes = [];
                        var availableAttributeSymbols = [];
                        for (var a = 0; a < attributeBuffers.length; a++) {
                            var attributeBufferInfo = attributeBuffers[a];
                            var name = attributeBufferInfo.name;
                            var semantic = attributeBufferInfo.semantic;
                            var symbol;
                            if (semantic) {
                                var semanticInfo = shader.attribSemantics[semantic];
                                symbol = semanticInfo && semanticInfo.symbol;
                            } else {
                                symbol = name;
                            }
                            if (symbol && shader.attributeTemplates[symbol]) {
                                availableAttributes.push(attributeBufferInfo);
                                availableAttributeSymbols.push(symbol);
                            }
                        }

                        var vao = new VertexArrayObject(
                            availableAttributes,
                            availableAttributeSymbols,
                            indicesBuffer
                        );
                        vaoList.push(vao);
                    }
                    if (isStatic) {
                        this._drawCache[currentDrawID] = vaoList;
                    }
                }

                for (var i = 0; i < vaoList.length; i++) {
                    var vao = vaoList[i];
                    var needsBindAttributes = true;

                    // Create vertex object array cost a lot
                    // So we don't use it on the dynamic object
                    if (vaoExt && isStatic) {
                        // Use vertex array object
                        // http://blog.tojicode.com/2012/10/oesvertexarrayobject-extension.html
                        if (vao.vao == null) {
                            vao.vao = vaoExt.createVertexArrayOES();
                        } else {
                            needsBindAttributes = false;
                        }
                        vaoExt.bindVertexArrayOES(vao.vao);
                    }

                    var availableAttributes = vao.availableAttributes;
                    var indicesBuffer = vao.indicesBuffer;

                    if (needsBindAttributes) {
                        var locationList = shader.enableAttributes(_gl, vao.availableAttributeSymbols, (vaoExt && isStatic && vao.vao));
                        // Setting attributes;
                        for (var a = 0; a < availableAttributes.length; a++) {
                            var location = locationList[a];
                            if (location === -1) {
                                continue;
                            }
                            var attributeBufferInfo = availableAttributes[a];
                            var buffer = attributeBufferInfo.buffer;
                            var size = attributeBufferInfo.size;
                            var glType;
                            switch (attributeBufferInfo.type) {
                                case 'float':
                                    glType = _gl.FLOAT;
                                    break;
                                case 'byte':
                                    glType = _gl.BYTE;
                                    break;
                                case 'ubyte':
                                    glType = _gl.UNSIGNED_BYTE;
                                    break;
                                case 'short':
                                    glType = _gl.SHORT;
                                    break;
                                case 'ushort':
                                    glType = _gl.UNSIGNED_SHORT;
                                    break;
                                default:
                                    glType = _gl.FLOAT;
                                    break;
                            }

                            _gl.bindBuffer(_gl.ARRAY_BUFFER, buffer);
                            _gl.vertexAttribPointer(location, size, glType, false, 0, 0);
                        }
                    }
                    if (
                        glDrawMode == glenum.LINES ||
                        glDrawMode == glenum.LINE_STRIP ||
                        glDrawMode == glenum.LINE_LOOP
                    ) {
                        _gl.lineWidth(this.lineWidth);
                    }

                    prevDrawIndicesBuffer = indicesBuffer;
                    prevDrawIsUseFace = geometry.isUseFace();
                    //Do drawing
                    if (prevDrawIsUseFace) {
                        if (needsBindAttributes) {
                            _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, indicesBuffer.buffer);
                        }
                        _gl.drawElements(glDrawMode, indicesBuffer.count, indicesType, 0);
                        renderInfo.faceNumber += indicesBuffer.count / 3;
                    } else {
                        _gl.drawArrays(glDrawMode, 0, nVertex);
                    }

                    if (vaoExt && isStatic) {
                        vaoExt.bindVertexArrayOES(null);
                    }

                    renderInfo.drawCallNumber++;
                }
            }

            return renderInfo;
        },

        /**
         * Clone a new renderable
         * @method
         * @return {qtek.Renderable}
         */
        clone: (function() {
            var properties = [
                'castShadow', 'receiveShadow',
                'mode', 'culling', 'cullFace', 'frontFace',
                'frustumCulling'
            ];
            return function() {
                var renderable = Node.prototype.clone.call(this);

                renderable.geometry = this.geometry;
                renderable.material = this.material;

                for (var i = 0; i < properties.length; i++) {
                    var name = properties[i];
                    // Try not to overwrite the prototype property
                    if (renderable[name] !== this[name]) {
                        renderable[name] = this[name];
                    }
                }

                return renderable;
            };
        })()
    });

    Renderable.beforeFrame = function() {
        prevDrawID = 0;
    };

    // Enums
    Renderable.POINTS = glenum.POINTS;
    Renderable.LINES = glenum.LINES;
    Renderable.LINE_LOOP = glenum.LINE_LOOP;
    Renderable.LINE_STRIP = glenum.LINE_STRIP;
    Renderable.TRIANGLES = glenum.TRIANGLES;
    Renderable.TRIANGLE_STRIP = glenum.TRIANGLE_STRIP;
    Renderable.TRIANGLE_FAN = glenum.TRIANGLE_FAN;

    Renderable.BACK = glenum.BACK;
    Renderable.FRONT = glenum.FRONT;
    Renderable.FRONT_AND_BACK = glenum.FRONT_AND_BACK;
    Renderable.CW = glenum.CW;
    Renderable.CCW = glenum.CCW;

    Renderable.RenderInfo = RenderInfo;

    return Renderable;
});<|endoftext|>


<commit_before>import Component from 'substance/ui/Component'
import isArray from 'substance/util/isArray'
import isPlainObject from 'substance/util/isPlainObject'

class ResultItem extends Component {

  shouldRerender() {
    return false
  }

  render($$) {
    var test = this.props.test
    var result = this.props.result
    var el = $$('div').addClass('sc-test-result')

    var header = $$('div')
    if (!test._skip) {
      if (result.ok) {
        header.append($$('span').addClass('se-status sm-ok').append("\u2713"))
      } else {
        header.append($$('span').addClass('se-status sm-not-ok').append("\u26A0"))
      }
    }
    header.append($$('span').addClass('se-description').append(String(result.name)))
    el.append(header)

    if (!test._skip && !result.ok && (result.expected || result.actual) ) {
      let diffEl = $$('div').addClass('se-diff')
      let expectedEl = $$('div').addClass('se-expected')
        .append('Expected:')
        .append($$('pre').append(_toString(result.expected)))
      let actualEl = $$('div').addClass('se-actual')
        .append('Actual:')
        .append($$('pre').append(_toString(result.actual)))
      diffEl.append(expectedEl, actualEl)
      el.append(diffEl)
    }

    return el
  }
}

function _toString(obj) {
  if (isArray(obj) || isPlainObject(obj)) {
    return JSON.stringify(obj)
  } else {
    return String(obj)
  }
}

export default ResultItem
<commit_msg>Render a diff.<commit_after>import { substanceGlobals, Component, isArray, isPlainObject } from 'substance'
import DMP from '../vendor/google-diff-match-patch/dmp'

substanceGlobals.DEBUG_RENDERING = false

class ResultItem extends Component {

  constructor(...args) {
    super(...args)

    this.dmp = new DMP()
  }

  shouldRerender() {
    return false
  }

  render($$) {
    var test = this.props.test
    var result = this.props.result
    var el = $$('div').addClass('sc-test-result')

    var header = $$('div')
    if (!test._skip) {
      if (result.ok) {
        header.append($$('span').addClass('se-status sm-ok').append("\u2713"))
      } else {
        header.append($$('span').addClass('se-status sm-not-ok').append("\u26A0"))
      }
    }
    header.append($$('span').addClass('se-description').append(String(result.name)))
    el.append(header)

    if (!test._skip && !result.ok && (result.expected || result.actual) ) {
      let expStr = _toString(result.expected)
      let actStr = _toString(result.actual)
      if (expStr !== actStr) {
        el.append(this._renderPatch($$, expStr, actStr))
      }
      let diffEl = $$('div').addClass('se-diff')
      diffEl.append(
        $$('div').addClass('se-expected')
        .append('Expected:')
        .append(
          $$('pre').append(_toString(result.expected))
        )
      )
      diffEl.append(
        $$('div').addClass('se-actual')
        .append('Actual:')
        .append(
          $$('pre').append(_toString(result.actual))
        )
      )
      el.append(diffEl)
    }

    return el
  }

  _renderPatch($$, act, exp) {
    const dmp = this.dmp
    let d = dmp.diff_main(act, exp);
    let html = dmp.diff_prettyHtml(d);
    return $$('div').addClass('se-patch').html(html)
  }
}

function _toString(obj) {
  if (isArray(obj) || isPlainObject(obj)) {
    return JSON.stringify(obj)
  } else {
    return String(obj)
  }
}

export default ResultItem
<|endoftext|>