<commit_before>/**
 * VIE - Vienna IKS Editables
 * (c) 2011 Henri Bergius, IKS Consortium
 */
(function() {
    // Export the VIE namespace for both CommonJS and the browser
    var VIE;
    if (typeof exports !== 'undefined') {
        VIE = exports;
    } else {
        VIE = this.VIE = {};
    }

    // Require underscore using CommonJS require if it isn't yet loaded
    var _ = this._;
    if (!_ && (typeof require !== 'undefined')) _ = require('underscore')._;
    if (!_) {
        throw 'VIE requires underscore.js to be available';
    }

    // Require Backbone using CommonJS require if it isn't yet loaded
    var Backbone = this.Backbone;
    if (!Backbone && (typeof require !== 'undefined')) Backbone = require('backbone');
    if (!Backbone) {
        throw 'VIE requires Backbone.js to be available';
    }

    // Require jQuery using CommonJS require if it isn't yet loaded
    var jQuery = this.jQuery;
    if (!jQuery && (typeof require !== 'undefined')) jQuery = require('jquery');
    if (!jQuery) {
        throw 'VIE requires jQuery to be available';
    }

    // Backbone Model for RDF entities
    VIE.RDFEntity = Backbone.Model.extend({
        namespaces: {},
        type: '',

        toJSONLD: function() {
            var instance = this;
            var instanceLD = {};

            if (typeof instance.id !== 'undefined') {
                instanceLD['@'] = '<' + instance.id + '>';
            } else {
                instanceLD['@'] = instance.cid.replace('c', '_:bnode');
            }

            if (instance.namespaces.length > 0) {
                instanceLD['#'] = instance.namespaces;
            }

            if (instance.type) {
                instanceLD.a = instance.type;
            }

            for (var property in instance.attributes) if(instance.attributes.hasOwnProperty(property)) { //  && typeof instance.attributes[property] != "function"
                if (["id"].indexOf(property) == -1)
                    instanceLD[property] = instance.attributes[property];
            }
            return instanceLD;
        }
    });

    // Backbone View for RDF entities represented in RDFa
    VIE.RDFaView = Backbone.View.extend({
        // Ensure view gets updated when properties of the entity change
        initialize: function() {
            _.bindAll(this, 'render');
            this.model.bind('change', this.render);
        },

        render: function() {
            VIE.RDFa.writeEntity(this.el, this.model.toJSONLD());
            return this;
        }
    });

    // Entity Manager keeps track of all RDFa entities loaded via VIE
    VIE.EntityManager = {
        Entities: {},
        allEntities: [],

        Types: {},

        getById: function(id) {
            if (typeof VIE.EntityManager.Entities[id] === 'undefined') {
                return null;
            }
            return VIE.EntityManager.Entities[id];
        },

        getByJSONLD: function(jsonld) {
            var entityInstance;
            var properties;

            properties = VIE.EntityManager._JSONtoProperties(jsonld);

            if (typeof jsonld['@'] !== 'undefined') {
                entityInstance = VIE.EntityManager.getById(jsonld['@']);
                if (entityInstance) {
                    entityInstance.set(properties);
                    return entityInstance;
                }
            }

            entityInstance = new VIE.RDFEntity(properties);

            if (typeof jsonld['#'] !== 'undefined') {
                entityInstance.namespaces = jsonld['#'];
            }

            if (typeof jsonld.a !== 'undefined') {
                entityInstance.type = jsonld.a;
            }

            if (typeof jsonld['@'] !== 'undefined') {
                entityInstance.id = jsonld['@'];
                VIE.EntityManager.Entities[entityInstance.id] = entityInstance;
            }

            VIE.EntityManager.allEntities.push(entityInstance);

            return entityInstance;
        },

        // Clean up JSON-LD so that it can be used as properties in a Backbone Model
        _JSONtoProperties: function(jsonld) {
            var properties;
            properties = jQuery.extend({}, jsonld);
            delete properties['@'];
            delete properties.a;
            delete properties['#'];
            return properties;
        }
    };

    // Mapping between RDFa and Backbone models
    VIE.RDFaEntities = {
        Views: [],

        // Create a Backbone model instance for a RDFa-marked element
        getInstance: function(element) {
            element = jQuery(element);
            var entityInstance;
            var viewInstance;
            var jsonld;

            jsonld = VIE.RDFa.readEntity(element);
            if (!jsonld) {
                return null;
            }

            entityInstance = VIE.EntityManager.getByJSONLD(jsonld);

            jQuery.each(VIE.RDFaEntities.Views, function() {
                // Check whether we already have this view instantiated for the element
                if (this.el.get(0) == element.get(0)) {
                    viewInstance = this;
                    return false;
                }
            });

            if (!viewInstance) {
                // Create a view for the RDFa
                viewInstance = new VIE.RDFaView({
                    model: entityInstance,
                    el: element,
                    tagName: element.get(0).nodeName
                });
                VIE.RDFaEntities.Views.push(viewInstance);
            }

            return entityInstance;
        },

        // Get a list of Backbone model instances for all RDFa-marked content in an element
        getInstances: function(element) {
            var entities = [];
            var entity;

            if (typeof element === 'undefined') {
                element = jQuery(document);

                // We're working with the full document scope, add the document itself as an entity
                jQuery(VIE.RDFa.subjectSelector, element).andSelf().each(function() {
                    entity = VIE.RDFaEntities.getInstance(this);
                    if (entity) {
                        entities.push(entity);
                    }
                });
            } else {
                jQuery(VIE.RDFa.subjectSelector, element).each(function() {
                    entity = VIE.RDFaEntities.getInstance(this);
                    if (entity) {
                        entities.push(entity);
                    }
                });
            }

            return entities;
        }
    },

    // RDFa reading and writing utilities
    VIE.RDFa = {
        // Resolved prefix->namespace pairs
        Namespaces: {},

        subjectSelector: '[about],[typeof],[src]',

        // Get a JSON-LD en
        readEntity: function(element) {
            var entity;
            var subject;
            var namespaces = {};
            var namespace;

            subject = VIE.RDFa.getSubject(element);

            // Read properties from element
            entity = VIE.RDFa._getElementProperties(subject, element, false);
            if (jQuery.isEmptyObject(entity)) {
                // No properties, skip creating entity
                return null;
            }

            // Resolve namespaces
            for (var propertyName in entity) {
                var propertyParts = propertyName.split(':');
                if (propertyParts.length === 1) {
                    // No namespace for element
                    continue;
                }
                namespace = VIE.RDFa._resolveNamespace(propertyParts[0], element);
                if (namespace) {
                    namespaces[propertyParts[0]] = namespace;
                }
            }
            if (!jQuery.isEmptyObject(namespaces)) {
                entity['#'] = namespaces;
            }

            // Read typeof from element
            entity.a = VIE.RDFa._getElementValue(element, 'typeof');

            if (typeof subject == 'string') {
                entity['@'] = subject;
            }
            return entity;
        },

        readEntities: function(element) {
            var entities = [];
            var entity;

            if (typeof element === 'undefined') {
                element = jQuery(document);

                // We're working with the full document scope, add the document itself as an entity
                jQuery(VIE.RDFa.subjectSelector, element).andSelf().each(function() {
                    entity = VIE.RDFa.readEntity(this);
                    if (entity) {
                        entities.push(entity);
                    }
                });
            } else {
                jQuery(VIE.RDFa.subjectSelector, element).each(function() {
                    entity = VIE.RDFa.readEntity(this);
                    if (entity) {
                        entities.push(entity);
                    }
                });
            }

            return entities;
        },

        writeEntity: function(element, jsonld) {
            VIE.RDFa.findElementProperties(VIE.RDFa.getSubject(element), element, true).each(function() {
                var propertyElement = jQuery(this);
                var propertyName = propertyElement.attr('property');

                if (typeof jsonld[propertyName] === 'undefined') {
                    // Entity doesn't contain this property
                    return true;
                }

                if (jsonld[propertyName] instanceof Array) {
                    // For now we don't deal with multivalued properties in Views
                    return true;
                }

                if (VIE.RDFa._readPropertyValue(propertyElement) !== jsonld[propertyName]) {
                    VIE.RDFa._writePropertyValue(propertyElement, jsonld[propertyName]);
                }
            });
            return this;
        },

        _readPropertyValue: function(element) {
            // Property has machine-readable content value
            var content = element.attr('content');
            if (content) {
                return content;
            }
            var resource = element.attr('resource');
            if (resource) {
                return '<' + resource + '>';
            }
            var href = element.attr('href');
            if (href) {
                return '<' + href + '>';
            }

            if (element.attr('rel')) {
                // Relation, we should look for identified child objects
                var value = [];
                jQuery(element).children(VIE.RDFa.subjectSelector).each(function() {
                    var subject = VIE.RDFa.getSubject(this);
                    if (typeof subject == 'string') {
                        value.push('<' + subject + '>');
                    }
                });
                return value;
            }

            // Property has inline value
            return element.html();
        },

        _writePropertyValue: function(element, value) {
            // Property has machine-readable content value
            var content = element.attr('content');
            if (content) {
                element.attr('content', value);
                return;
            }
            var resource = element.attr('resource');
            if (resource) {
                element.attr('resource', value);
            }

            // Property has inline value
            element.html(value);
        },

        getSubject: function(element) {
            if (typeof document !== 'undefined') {
                if (element === document) {
                    return document.baseURI;
                }
            }
            var subject;
            jQuery(element).closest(VIE.RDFa.subjectSelector).each(function() {
                if (jQuery(this).attr('about')) {
                    subject = jQuery(this).attr('about');
                    return true;
                }
                if (jQuery(this).attr('src')) {
                    subject = jQuery(this).attr('src');
                    return true;
                }
                if (jQuery(this).attr('typeof')) {
                    subject = this;
                }
            });

            return subject;
        },

        _resolveNamespace: function(prefix, element) {
            if (typeof VIE.RDFa.Namespaces[prefix] !== 'undefined') {
                return VIE.RDFa.Namespaces[prefix];
            }

            jQuery('[xmlns\\:' + prefix + ']').each(function() {
                VIE.RDFa.Namespaces[prefix] = jQuery(this).attr('xmlns:' + prefix);
            });

            return VIE.RDFa.Namespaces[prefix];
        },

        // Get the value of attribute from the element or from one of its children
        _getElementValue: function(element, propertyName) {
            element = jQuery(element);
            if (typeof element.attr(propertyName) !== 'undefined')
            {
                // Direct match with container
                return element.attr(propertyName);
            }
            return element.find('[' + propertyName + ']').attr(propertyName);
        },

        findElementProperties: function(subject, element, allowPropertiesInProperties) {
            return jQuery(element).find('[property],[rel]').add(jQuery(element).filter('[property],[rel]')).filter(function() {
                if (VIE.RDFa.getSubject(this) !== subject) {
                    // The property is under another entity, skip
                    return false;
                }

                if (!allowPropertiesInProperties) {
                    if (!jQuery(this).parents('[property]').length) {
                        return true;
                    }
                    // This property is under another property, skip
                    return false;
                }

                return true;
            });
        },

        _getElementProperties: function(subject, element, emptyValues) {
            var containerProperties = {};

            VIE.RDFa.findElementProperties(subject, element, true).each(function() {
                var propertyName;
                var propertyValue;
                var objectProperty = jQuery(this);

                propertyName = objectProperty.attr('property');
                if (!propertyName) {
                    propertyName = objectProperty.attr('rel');
                }

                propertyValue = VIE.RDFa._readPropertyValue(objectProperty);

                if (typeof containerProperties[propertyName] !== 'undefined') {
                    if (containerProperties[propertyName] instanceof Array) {
                        if (emptyValues) {
                            return;
                        }
                        containerProperties[propertyName].push(propertyValue);
                        return;
                    }
                    // Multivalued property, convert to Array
                    var previousValue = containerProperties[propertyName];
                    containerProperties[propertyName] = [];

                    if (emptyValues) {
                        return;
                    }

                    containerProperties[propertyName].push(previousValue);
                    containerProperties[propertyName].push(propertyValue);
                    return;
                }

                if (emptyValues) {
                    containerProperties[propertyName] = '';
                    return;
                }

                containerProperties[propertyName] = propertyValue;
            });

            return containerProperties;
        }
    };

    VIE.cleanup = function() {
        VIE.EntityManager.Entities = {};
        VIE.EntityManager.allEntities = [];
        VIE.EntityManager.Types = {};
        VIE.RDFaEntities.Views = [];
        VIE.RDFa.Namespaces = {};
    };

}).call(this);
<commit_msg>Clean up predicate finding<commit_after>/**
 * VIE - Vienna IKS Editables
 * (c) 2011 Henri Bergius, IKS Consortium
 */
(function() {
    // Export the VIE namespace for both CommonJS and the browser
    var VIE;
    if (typeof exports !== 'undefined') {
        VIE = exports;
    } else {
        VIE = this.VIE = {};
    }

    // Require underscore using CommonJS require if it isn't yet loaded
    var _ = this._;
    if (!_ && (typeof require !== 'undefined')) _ = require('underscore')._;
    if (!_) {
        throw 'VIE requires underscore.js to be available';
    }

    // Require Backbone using CommonJS require if it isn't yet loaded
    var Backbone = this.Backbone;
    if (!Backbone && (typeof require !== 'undefined')) Backbone = require('backbone');
    if (!Backbone) {
        throw 'VIE requires Backbone.js to be available';
    }

    // Require jQuery using CommonJS require if it isn't yet loaded
    var jQuery = this.jQuery;
    if (!jQuery && (typeof require !== 'undefined')) jQuery = require('jquery');
    if (!jQuery) {
        throw 'VIE requires jQuery to be available';
    }

    // Backbone Model for RDF entities
    VIE.RDFEntity = Backbone.Model.extend({
        namespaces: {},
        type: '',

        toJSONLD: function() {
            var instance = this;
            var instanceLD = {};

            if (typeof instance.id !== 'undefined') {
                instanceLD['@'] = '<' + instance.id + '>';
            } else {
                instanceLD['@'] = instance.cid.replace('c', '_:bnode');
            }

            if (instance.namespaces.length > 0) {
                instanceLD['#'] = instance.namespaces;
            }

            if (instance.type) {
                instanceLD.a = instance.type;
            }

            for (var property in instance.attributes) if(instance.attributes.hasOwnProperty(property)) { //  && typeof instance.attributes[property] != "function"
                if (["id"].indexOf(property) == -1)
                    instanceLD[property] = instance.attributes[property];
            }
            return instanceLD;
        }
    });

    // Backbone View for RDF entities represented in RDFa
    VIE.RDFaView = Backbone.View.extend({
        // Ensure view gets updated when properties of the entity change
        initialize: function() {
            _.bindAll(this, 'render');
            this.model.bind('change', this.render);
        },

        render: function() {
            VIE.RDFa.writeEntity(this.el, this.model.toJSONLD());
            return this;
        }
    });

    // Entity Manager keeps track of all RDFa entities loaded via VIE
    VIE.EntityManager = {
        Entities: {},
        allEntities: [],

        Types: {},

        getById: function(id) {
            if (typeof VIE.EntityManager.Entities[id] === 'undefined') {
                return null;
            }
            return VIE.EntityManager.Entities[id];
        },

        getByJSONLD: function(jsonld) {
            var entityInstance;
            var properties;

            properties = VIE.EntityManager._JSONtoProperties(jsonld);

            if (typeof jsonld['@'] !== 'undefined') {
                entityInstance = VIE.EntityManager.getById(jsonld['@']);
                if (entityInstance) {
                    entityInstance.set(properties);
                    return entityInstance;
                }
            }

            entityInstance = new VIE.RDFEntity(properties);

            if (typeof jsonld['#'] !== 'undefined') {
                entityInstance.namespaces = jsonld['#'];
            }

            if (typeof jsonld.a !== 'undefined') {
                entityInstance.type = jsonld.a;
            }

            if (typeof jsonld['@'] !== 'undefined') {
                entityInstance.id = jsonld['@'];
                VIE.EntityManager.Entities[entityInstance.id] = entityInstance;
            }

            VIE.EntityManager.allEntities.push(entityInstance);

            return entityInstance;
        },

        // Clean up JSON-LD so that it can be used as properties in a Backbone Model
        _JSONtoProperties: function(jsonld) {
            var properties;
            properties = jQuery.extend({}, jsonld);
            delete properties['@'];
            delete properties.a;
            delete properties['#'];
            return properties;
        }
    };

    // Mapping between RDFa and Backbone models
    VIE.RDFaEntities = {
        Views: [],

        // Create a Backbone model instance for a RDFa-marked element
        getInstance: function(element) {
            element = jQuery(element);
            var entityInstance;
            var viewInstance;
            var jsonld;

            jsonld = VIE.RDFa.readEntity(element);
            if (!jsonld) {
                return null;
            }

            entityInstance = VIE.EntityManager.getByJSONLD(jsonld);

            jQuery.each(VIE.RDFaEntities.Views, function() {
                // Check whether we already have this view instantiated for the element
                if (this.el.get(0) == element.get(0)) {
                    viewInstance = this;
                    return false;
                }
            });

            if (!viewInstance) {
                // Create a view for the RDFa
                viewInstance = new VIE.RDFaView({
                    model: entityInstance,
                    el: element,
                    tagName: element.get(0).nodeName
                });
                VIE.RDFaEntities.Views.push(viewInstance);
            }

            return entityInstance;
        },

        // Get a list of Backbone model instances for all RDFa-marked content in an element
        getInstances: function(element) {
            var entities = [];
            var entity;

            if (typeof element === 'undefined') {
                // We're working with the full document scope
                element = jQuery(document);
            }

            jQuery(VIE.RDFa.subjectSelector, element).add(jQuery(element).filter(VIE.RDFa.subjectSelector)).each(function() {
                entity = VIE.RDFaEntities.getInstance(this);
                if (entity) {
                    entities.push(entity);
                }
            });

            return entities;
        }
    },

    // RDFa reading and writing utilities
    VIE.RDFa = {
        // Resolved prefix->namespace pairs
        Namespaces: {},

        subjectSelector: '[about],[typeof],[src]',
        predicateSelector: '[property],[rel]',

        // Get a JSON-LD en
        readEntity: function(element) {
            var entity;
            var subject;
            var namespaces = {};
            var namespace;

            subject = VIE.RDFa.getSubject(element);

            // Read properties from element
            entity = VIE.RDFa._getElementProperties(subject, element, false);
            if (jQuery.isEmptyObject(entity)) {
                // No properties, skip creating entity
                return null;
            }

            // Resolve namespaces
            for (var propertyName in entity) {
                var propertyParts = propertyName.split(':');
                if (propertyParts.length === 1) {
                    // No namespace for element
                    continue;
                }
                namespace = VIE.RDFa._resolveNamespace(propertyParts[0], element);
                if (namespace) {
                    namespaces[propertyParts[0]] = namespace;
                }
            }
            if (!jQuery.isEmptyObject(namespaces)) {
                entity['#'] = namespaces;
            }

            // Read typeof from element
            entity.a = VIE.RDFa._getElementValue(element, 'typeof');

            if (typeof subject == 'string') {
                entity['@'] = subject;
            }
            return entity;
        },

        readEntities: function(element) {
            var entities = [];
            var entity;

            if (typeof element === 'undefined') {
                // We're working with the full document scope
                element = jQuery(document);
            }

            jQuery(VIE.RDFa.subjectSelector, element).add(jQuery(element).filter(VIE.RDFa.subjectSelector)).each(function() {
                entity = VIE.RDFa.readEntity(this);
                if (entity) {
                    entities.push(entity);
                }
            });

            return entities;
        },

        writeEntity: function(element, jsonld) {
            VIE.RDFa.findElementProperties(VIE.RDFa.getSubject(element), element, true).each(function() {
                var propertyElement = jQuery(this);
                var propertyName = propertyElement.attr('property');

                if (typeof jsonld[propertyName] === 'undefined') {
                    // Entity doesn't contain this property
                    return true;
                }

                if (jsonld[propertyName] instanceof Array) {
                    // For now we don't deal with multivalued properties in Views
                    return true;
                }

                if (VIE.RDFa._readPropertyValue(propertyElement) !== jsonld[propertyName]) {
                    VIE.RDFa._writePropertyValue(propertyElement, jsonld[propertyName]);
                }
            });
            return this;
        },

        _readPropertyValue: function(element) {
            // Property has machine-readable content value
            var content = element.attr('content');
            if (content) {
                return content;
            }
            var resource = element.attr('resource');
            if (resource) {
                return '<' + resource + '>';
            }
            var href = element.attr('href');
            if (href) {
                return '<' + href + '>';
            }

            if (element.attr('rel')) {
                // Relation, we should look for identified child objects
                var value = [];
                jQuery(element).children(VIE.RDFa.subjectSelector).each(function() {
                    var subject = VIE.RDFa.getSubject(this);
                    if (typeof subject == 'string') {
                        value.push('<' + subject + '>');
                    }
                });
                return value;
            }

            // Property has inline value
            return element.html();
        },

        _writePropertyValue: function(element, value) {
            // Property has machine-readable content value
            var content = element.attr('content');
            if (content) {
                element.attr('content', value);
                return;
            }
            var resource = element.attr('resource');
            if (resource) {
                element.attr('resource', value);
            }

            // Property has inline value
            element.html(value);
        },

        getSubject: function(element) {
            if (typeof document !== 'undefined') {
                if (element === document) {
                    return document.baseURI;
                }
            }
            var subject;
            jQuery(element).closest(VIE.RDFa.subjectSelector).each(function() {
                if (jQuery(this).attr('about')) {
                    subject = jQuery(this).attr('about');
                    return true;
                }
                if (jQuery(this).attr('src')) {
                    subject = jQuery(this).attr('src');
                    return true;
                }
                if (jQuery(this).attr('typeof')) {
                    subject = this;
                }
            });

            return subject;
        },

        _resolveNamespace: function(prefix, element) {
            if (typeof VIE.RDFa.Namespaces[prefix] !== 'undefined') {
                return VIE.RDFa.Namespaces[prefix];
            }

            jQuery('[xmlns\\:' + prefix + ']').each(function() {
                VIE.RDFa.Namespaces[prefix] = jQuery(this).attr('xmlns:' + prefix);
            });

            return VIE.RDFa.Namespaces[prefix];
        },

        // Get the value of attribute from the element or from one of its children
        _getElementValue: function(element, propertyName) {
            element = jQuery(element);
            if (typeof element.attr(propertyName) !== 'undefined')
            {
                // Direct match with container
                return element.attr(propertyName);
            }
            return element.find('[' + propertyName + ']').attr(propertyName);
        },

        findElementProperties: function(subject, element, allowPropertiesInProperties) {
            return jQuery(element).find(VIE.RDFa.predicateSelector).add(jQuery(element).filter(VIE.RDFa.predicateSelector)).filter(function() {
                if (VIE.RDFa.getSubject(this) !== subject) {
                    // The property is under another entity, skip
                    return false;
                }

                if (!allowPropertiesInProperties) {
                    if (!jQuery(this).parents('[property]').length) {
                        return true;
                    }
                    // This property is under another property, skip
                    return false;
                }

                return true;
            });
        },

        _getElementProperties: function(subject, element, emptyValues) {
            var containerProperties = {};

            VIE.RDFa.findElementProperties(subject, element, true).each(function() {
                var propertyName;
                var propertyValue;
                var objectProperty = jQuery(this);

                propertyName = objectProperty.attr('property');
                if (!propertyName) {
                    propertyName = objectProperty.attr('rel');
                }

                propertyValue = VIE.RDFa._readPropertyValue(objectProperty);

                if (typeof containerProperties[propertyName] !== 'undefined') {
                    if (containerProperties[propertyName] instanceof Array) {
                        if (emptyValues) {
                            return;
                        }
                        containerProperties[propertyName].push(propertyValue);
                        return;
                    }
                    // Multivalued property, convert to Array
                    var previousValue = containerProperties[propertyName];
                    containerProperties[propertyName] = [];

                    if (emptyValues) {
                        return;
                    }

                    containerProperties[propertyName].push(previousValue);
                    containerProperties[propertyName].push(propertyValue);
                    return;
                }

                if (emptyValues) {
                    containerProperties[propertyName] = '';
                    return;
                }

                containerProperties[propertyName] = propertyValue;
            });

            return containerProperties;
        }
    };

    VIE.cleanup = function() {
        VIE.EntityManager.Entities = {};
        VIE.EntityManager.allEntities = [];
        VIE.EntityManager.Types = {};
        VIE.RDFaEntities.Views = [];
        VIE.RDFa.Namespaces = {};
    };

}).call(this);
<|endoftext|>


<commit_before>
jQuery(document).ready(function() {
	// clear the title from the front page search box
	// or set title if box is empty
    var setTitle = function(event) {
		var title = "/^(FundFind).*?$/";
		if (jQuery('.frontin').val() == "") {
			jQuery('.frontin').val(title);
		} else if (jQuery(this).val() == title) {
            jQuery(this).val("");
        }
    }
    jQuery('.frontin').focus(setTitle);
	jQuery('.frontin').blur(setTitle);
});

<commit_msg>whitespace<commit_after>jQuery(document).ready(function() {
	// clear the title from the front page search box
	// or set title if box is empty
    var setTitle = function(event) {
		var title = "/^(FundFind).*?$/";
		if (jQuery('.frontin').val() == "") {
			jQuery('.frontin').val(title);
		} else if (jQuery(this).val() == title) {
            jQuery(this).val("");
        }
    }
    jQuery('.frontin').focus(setTitle);
	jQuery('.frontin').blur(setTitle);
});

<|endoftext|>


<commit_before>var chai = require('chai');
var chaiHttp = require('chai-http');
var server = require('../app');
var should = chai.should();
// var expect  = chai.expect;
// var request = require("request");

chai.use(chaiHttp);

describe("Date-a-Dog Server Rest API Tests", function() {
  describe("Should return user profile for test user on /api/loginTest", function() {
    var res;
    chai.request(server)
    .post('/api/loginTest')
    .end(function(error, response){
      res = response;
      done();
    });
    it('Response is OK', function() {
      res.should.have.status(200);
    });

    it('Response is a valid JSON', function() {
      res.should.be.json;
      res.body.should.be.a('object');
    });

    // Check id
    it('id is correct', function() {
      res.body.should.have.property('id');
      res.body.id.should.equal(119889308491710);
    });

    // Check email
    it('email is correct', function() {
      res.body.should.have.property('email');
      res.body.email.should.equal('dateadog@gmail.com');
    });

    // Check fname
    it('fname is correct', function() {
      res.body.should.have.property('fname');
      res.body.fname.should.equal('Sally');
    });

    // Check lname
    it('lname is correct', function() {
      res.body.should.have.property('lname');
      res.body.lname.should.equal('Smith');
    });

    // Check street
    it('street is correct', function() {
      res.body.should.have.property('street');
      res.body.street.should.equal('Paul G. Allen Center for Computer Science & Engineering (Cse)');
    });

    // Check city
    it('city is correct', function() {
      res.body.should.have.property('city');
      res.body.city.should.equal('Seattle');
    });

    // Check state
    it('state is correct', function() {
      res.body.should.have.property('state');
      res.body.state.should.equal('WA');
    });

    // Check zip
    it('zip is correct', function() {
      res.body.should.have.property('zip');
      res.body.zip.should.equal('98195');
    });

    // Check phone
    it('phone is correct', function() {
      res.body.should.have.property('phone');
      res.body.phone.should.equal('(206) 543-1695');
    });

    // Check shelterid
    it('fname is correct', function() {
      res.body.should.have.property('shelterid');
      res.body.shelterid.should.equal('WA214');
    });
  });
});
<commit_msg>Update #5 to attempt at verbose implementation of login test<commit_after>var chai = require('chai');
var chaiHttp = require('chai-http');
var server = require('../app');
var should = chai.should();
// var expect  = chai.expect;
// var request = require("request");

chai.use(chaiHttp);

describe("Date-a-Dog Server Rest API Tests", function() {
  describe("Should return user profile for test user on /api/loginTest", function() {
    var res;
    chai.request(server)
    .post('/api/loginTest')
    .end(function(err, res){
      it('Response is OK', function() {
        res.should.have.status(200);
      });

      it('Response is a valid JSON', function() {
        res.should.be.json;
        res.body.should.be.a('object');
      });

      // Check id
      it('id is correct', function() {
        res.body.should.have.property('id');
        res.body.id.should.equal(119889308491710);
      });

      // Check email
      it('email is correct', function() {
        res.body.should.have.property('email');
        res.body.email.should.equal('dateadog@gmail.com');
      });

      // Check fname
      it('fname is correct', function() {
        res.body.should.have.property('fname');
        res.body.fname.should.equal('Sally');
      });

      // Check lname
      it('lname is correct', function() {
        res.body.should.have.property('lname');
        res.body.lname.should.equal('Smith');
      });

      // Check street
      it('street is correct', function() {
        res.body.should.have.property('street');
        res.body.street.should.equal('Paul G. Allen Center for Computer Science & Engineering (Cse)');
      });

      // Check city
      it('city is correct', function() {
        res.body.should.have.property('city');
        res.body.city.should.equal('Seattle');
      });

      // Check state
      it('state is correct', function() {
        res.body.should.have.property('state');
        res.body.state.should.equal('WA');
      });

      // Check zip
      it('zip is correct', function() {
        res.body.should.have.property('zip');
        res.body.zip.should.equal('98195');
      });

      // Check phone
      it('phone is correct', function() {
        res.body.should.have.property('phone');
        res.body.phone.should.equal('(206) 543-1695');
      });

      // Check shelterid
      it('fname is correct', function() {
        res.body.should.have.property('shelterid');
        res.body.shelterid.should.equal('WA214');
      });
      done();
    });
  });
});
<|endoftext|>


<commit_before>/*globals window, document*/

var Backbone = require('backbone'),
    Features = require('lib/features'),
    $        = require('jquery'),
    _        = require('underscore'),
    Hours    = require('models/hours'),
    gmaps    = require('google-maps');

var aggregateOpenHours = function(facility) {
  var mergedHours = Hours.merge.apply(
    Hours,
    facility.services.map(function(service) {
      return Hours.fromData(service.openHours);
    })
  );

  return mergedHours.humanizeCondensed();
};

var DetailView = Backbone.View.extend({
  template: require('templates/detail'),

  events: {
    "render.done":             'setMap',
    "click .inset-directions": 'launchDirections',
    "click .inset-gmap":       'launchDirections'
  },

  render: function() {
    var facility = this.model;
    var $mapdiv =  this.$('#detail-gmap');

    facility.openHours = aggregateOpenHours(facility);

    this.$el.html(this.template({
      facility: facility,
      isMobile: Features.isMobile(),
      navButtons: [
      {'class': 'left', id: 'backNav-button', text: 'Back'}
      ]
    }));
    _.defer( function( view ){ view.setMap();}, this );
    this.$('#backNav-button').click(function(){
      require('routers/router').instance.back();
    });

    return this;
  },

  launchDirections: function() {
    var urlBase = Features.isMobile() ? "comgooglemaps://?daddr=" : 'https://maps.google.com?daddr=',
        dAddr = encodeURIComponent(this.model.address +
                                   "@" +
                                   this.model.location.latitude +
                                   "," +
                                   this.model.location.longitude),
        url = urlBase + dAddr;

    if (Features.isMobile()) {
      document.location = url;
    } else {
      window.open(url, '_blank');
    }
    return false;
  },

  setMap: function(){
    if(this.$('#detail-gmap')) {
      var location = new gmaps.LatLng(this.model.location.latitude,
                                      this.model.location.longitude);
      var mapOptions = {
            center: location,
            zoom: 15,
            mapTypeId: gmaps.MapTypeId.ROADMAP,
            mapTypeControl: false,
            scrollwheel: false,
            navigationControl: false,
            draggable: false,
            streetViewControl: false,
            zoomControl: false
          };
      var map = new gmaps.Map(this.$('#detail-gmap')[0], mapOptions);

      new gmaps.Marker({map: map,
                        position: location,
                        draggable: false});
      }
      this.layout();
  },

  layout: function(){
    $.each(this.$('.desco'), function() {
      if ($(this).text().length > 52) {
        $(this).text($(this).text().substr(0,52)+"...");
      }
    });

    this.$('.prevrow').last().remove();

  }

});

module.exports = DetailView;
<commit_msg>detail view: some cleanup<commit_after>/*globals window, document*/

var Backbone = require('backbone'),
    Features = require('lib/features'),
    $        = require('jquery'),
    _        = require('underscore'),
    Hours    = require('models/hours'),
    gmaps    = require('google-maps');

var aggregateOpenHours = function(facility) {
  var mergedHours = Hours.merge.apply(
    Hours,
    facility.services.map(function(service) {
      return Hours.fromData(service.openHours);
    })
  );

  return mergedHours.humanizeCondensed();
};

var DetailView = Backbone.View.extend({
  template: require('templates/detail'),

  events: {
    'render.done':             'setMap',
    'click .inset-directions': 'launchDirections',
    'click .inset-gmap':       'launchDirections'
  },

  render: function() {
    var facility = this.model,
        $mapdiv =  this.$('#detail-gmap');

    facility.openHours = aggregateOpenHours(facility);

    this.$el.html(this.template({
      facility: facility,
      isMobile: Features.isMobile(),
      navButtons: [
      {'class': 'left', id: 'backNav-button', text: 'Back'}
      ]
    }));
    _.defer( function( view ){ view.setMap();}, this );
    this.$('#backNav-button').click(function(){
      require('routers/router').instance.back();
    });

    return this;
  },

  launchDirections: function() {
    var urlBase = Features.isMobile() ? "comgooglemaps://?daddr=" : 'https://maps.google.com?daddr=',
        dAddr = encodeURIComponent(this.model.address +
                                   "@" +
                                   this.model.location.latitude +
                                   "," +
                                   this.model.location.longitude),
        url = urlBase + dAddr;

    if (Features.isMobile()) {
      document.location = url;
    } else {
      window.open(url, '_blank');
    }
    return false;
  },

  setMap: function(){
    if(this.$('#detail-gmap')) {
      var location = new gmaps.LatLng(this.model.location.latitude,
                                      this.model.location.longitude);
      var mapOptions = {
            center: location,
            zoom: 15,
            mapTypeId: gmaps.MapTypeId.ROADMAP,
            mapTypeControl: false,
            scrollwheel: false,
            navigationControl: false,
            draggable: false,
            streetViewControl: false,
            zoomControl: false
          };
      var map = new gmaps.Map(this.$('#detail-gmap')[0], mapOptions);

      new gmaps.Marker({map: map,
                        position: location,
                        draggable: false});
      }
  }
});

module.exports = DetailView;
<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import LocalizedStrings from 'react-native-localization';

export const pageInfoStrings = new LocalizedStrings({
  gb: {
    address: 'Address',
    code: 'Code',
    comment: 'Comment',
    confirm_date: 'Confirm Date',
    customer: 'Customer',
    entered_by: 'Entered By',
    entry_date: 'Entry Date',
    months_stock_required: 'Months Stock',
    stocktake_name: 'Stocktake Name',
    supplier: 'Supplier',
    their_ref: 'Their Ref',
  },
  fr: {
    address: 'Addresse',
    code: 'Code',
    comment: 'Commentaire',
    confirm_date: 'Date de confirmation',
    customer: 'Client',
    entered_by: 'Entrée par',
    entry_date: "Date d'entrée",
    months_stock_required: 'Mois de stock',
    stocktake_name: "Nom du relevé d'inventaire",
    supplier: 'Fournisseur',
    their_ref: 'Leur référence',
  },
  gil: {
    // TODO: add - stocktake_name
    address: 'Am tabo',
    code: 'Code',
    comment: 'Comment',
    confirm_date: 'Confirm Date',
    customer: 'Kiriniki ke aoraki',
    entered_by: 'Entered By',
    entry_date: 'Entry Date',
    months_stock_required: 'Iraua te Namakaina?',
    supplier: 'Kambana n oota, Pharmacy ke HC',
    their_ref: 'Ana Ref',
  },
  tl: {
    // TODO: add - stocktake_name
    address: 'Enderesu',
    code: 'Kódigu',
    comment: 'komentáriu',
    confirm_date: 'Data Konfirmadu',
    customer: 'Kliente',
    entered_by: 'Naran Hatama\nDadus',
    entry_date: 'Data Hatama',
    months_stock_required: 'Pedido ba fulan',
    supplier: 'Distribuidor',
    their_ref: 'Referensia',
  },
  la: {
    address: 'ທີ່ຢູ່',
    code: 'ລະຫັດ',
    comment: 'ຄໍາເຫັນ',
    confirm_date: 'ຢືນຢັນ ວັນທີ',
    customer: 'ລາຍຊື່ຜູ້ຮັບສິນຄ້າ',
    entered_by: 'ປ້ອນຂໍ້ມູນໂດຍ',
    entry_date: 'ວັນທີປ້ອນ',
    months_stock_required: 'ສິນຄ້າພາຍໃນເດືອນ',
    stocktake_name: 'ຊື່ຂອງໃບກວດກາສິນຄ້າໃນສາງ',
    supplier: 'ຜູ້ສະໜອງ',
    their_ref: 'ຂໍ້ມູນອ້າງອີງ',
  },
});

export default pageInfoStrings;
<commit_msg>Add pageInfoStrings<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

/**
 * TODO: by_batch
 */

import LocalizedStrings from 'react-native-localization';

export const pageInfoStrings = new LocalizedStrings({
  gb: {
    address: 'Address',
    code: 'Code',
    comment: 'Comment',
    confirm_date: 'Confirm Date',
    customer: 'Customer',
    entered_by: 'Entered By',
    entry_date: 'Entry Date',
    months_stock_required: 'Months Stock',
    stocktake_name: 'Stocktake Name',
    supplier: 'Supplier',
    their_ref: 'Their Ref',
    by_batch: 'By batch',
  },
  fr: {
    address: 'Addresse',
    code: 'Code',
    comment: 'Commentaire',
    confirm_date: 'Date de confirmation',
    customer: 'Client',
    entered_by: 'Entrée par',
    entry_date: "Date d'entrée",
    months_stock_required: 'Mois de stock',
    stocktake_name: "Nom du relevé d'inventaire",
    supplier: 'Fournisseur',
    their_ref: 'Leur référence',
    by_batch: 'By batch',
  },
  gil: {
    // TODO: add - stocktake_name
    address: 'Am tabo',
    code: 'Code',
    comment: 'Comment',
    confirm_date: 'Confirm Date',
    customer: 'Kiriniki ke aoraki',
    entered_by: 'Entered By',
    entry_date: 'Entry Date',
    months_stock_required: 'Iraua te Namakaina?',
    supplier: 'Kambana n oota, Pharmacy ke HC',
    their_ref: 'Ana Ref',
    by_batch: 'By batch',
  },
  tl: {
    // TODO: add - stocktake_name
    address: 'Enderesu',
    code: 'Kódigu',
    comment: 'komentáriu',
    confirm_date: 'Data Konfirmadu',
    customer: 'Kliente',
    entered_by: 'Naran Hatama\nDadus',
    entry_date: 'Data Hatama',
    months_stock_required: 'Pedido ba fulan',
    supplier: 'Distribuidor',
    their_ref: 'Referensia',
    by_batch: 'By batch',
  },
  la: {
    address: 'ທີ່ຢູ່',
    code: 'ລະຫັດ',
    comment: 'ຄໍາເຫັນ',
    confirm_date: 'ຢືນຢັນ ວັນທີ',
    customer: 'ລາຍຊື່ຜູ້ຮັບສິນຄ້າ',
    entered_by: 'ປ້ອນຂໍ້ມູນໂດຍ',
    entry_date: 'ວັນທີປ້ອນ',
    months_stock_required: 'ສິນຄ້າພາຍໃນເດືອນ',
    stocktake_name: 'ຊື່ຂອງໃບກວດກາສິນຄ້າໃນສາງ',
    supplier: 'ຜູ້ສະໜອງ',
    their_ref: 'ຂໍ້ມູນອ້າງອີງ',
    by_batch: 'By batch',
  },
});

export default pageInfoStrings;
<|endoftext|>


<commit_before>/**
 * Represents a Bert object. That is to say, it is the JavaScript representation
 * of an Erlang native type.
 *
 * Although the encoder could perform "clever" conversions, like a regular
 * JavaScript array to an Erlang list type, it doesn't. The reason being that
 * an array could be a tuple or a list, or even an Erlang string! And strings
 * can be strings or binaries or atoms. Don't even get me started on numbers.
 * Forcing explicit typing like this causes less errors during encoding.
 */
var BertObj = function(type, value) {this.type  = type; this.value = value;};

/**
 * The "BertClass" object is used to create a Bert object that can encode and
 * decode data using Erlang's external term format. It is a binary format, and
 * so the decoder expects inputs to be either strings, with each character being
 * one byte of data, or an array, with each element being one byte of data. The
 * encoding process will generate an array of byte data given a BertObj object.
 */
var BertClass = function() {
    /**
     * I know you thought I was going to leave you hanging with that awful to
     * use BertObj, but fear not, I have helper functions to the rescue!
     */
    this.Int = function(value) {return new BertObj("int", value);};

    this.Float = function(value) {return new BertObj("float", value);};

    this.Atom = function(value) {return new BertObj("atom", value);};

    this.String = function(value) {return new BertObj("string", value);};

    this.Binary = function(value) {return new BertObj("binary", value);};

    this.Tuple = function(value) {
        if (!(value instanceof Array)) {
            throw "Must use an array to create tuples."
        }
        return new BertObj("tuple", value);
    };

    this.List = function(value) {
        if (!(value instanceof Array)) {
            throw "Must use an array to create lists."
        }
        return new BertObj("list", value);
    };

    // Most of these tokens map to a function for encoding/decoding.
    // This is subset of allowed tokens in the Erlang external term format.
    this.TOKENS = {
        131: "start",
        70:  "new_float",
        77:  "bitstring",
        97:  "small_int",
        98:  "int",
        99:  "float",
        100: "atom",
        102: "port",
        103: "pid",
        104: "small_tuple",
        105: "tuple",
        106: "nil",
        107: "string",
        108: "list",
        109: "binary",
        110: "small_big",
        111: "big",
        115: "small_atom",
        116: "map",
        118: "atom_utf8",
        119: "small_atom_utf8"
    };

    // Yup. Magic numbers.
    this.four_byte_max_number = 134217727;

    // Get the next "token" based on the data type.
    this.next_token = function(data) {
        if (typeof(data) == "string") {
            return [data.charCodeAt(0), data.substring(1)];
        }
        else {
            return [data[0], data.slice(1)];
        }
    };

    // Splits the data in two, where the first part of the split is `length`
    // long and the second part are all remaining elements after that.
    this.split = function(data, length) {
        if (length == null) { length = 1; }
        if (typeof(data) == "string") {
            return [data.substring(0, length), data.substring(length)];
        }
        else {
            return [data.slice(0, length), data.slice(length)];
        }
    }

    // Decode a string or array into a JavaScript object.
    this.decode = function(data) {
        var parts = this.next_token(data);
        if (this.TOKENS[parts[0]] != "start") {
            throw "Data must begin with an appropriate start token, actually starts with " + parts[0];
        }
        var result = this.decode_data(parts[1]);
        return result[0].value;
    };

    this.decode_data = function(data) {
        var parts = this.next_token(data);
        var token = parts[0], data = parts[1];
        var type, result;
        var type = this.TOKENS[token];
        var result = this["decode_" + type](data);
        return this.handle_result(type, result);
    };

    this.handle_result = function(type, result) {
        return [new BertObj(type, result[0]), result[1]];
    };

    this.decode_small_int = function(data) {
        return this.decode_int(data, 1);
    };

    this.decode_int = function(data, byteLength) {
        if (byteLength == null) { byteLength = 4; }
        var parts = this.split(data, byteLength);
        var size = 0, offset = 0;
        for (var i = 0; i < byteLength; i++) {
            offset = (byteLength - i - 1) * 8;
            size += data[i] << offset;
        }
        return [size, parts[1]];
    };

    this.decode_float = function(data) {
        var float = this.decode_string(data, 31);
        return [parseFloat(float[0]), float[1]];
    };

    this.decode_atom = function(data) {
        return this.decode_string(data, 2);
    };

    this.decode_port = function(data) {
        var atom = this.decode_data(data);
        var id = this.decode_int(atom[1], 4);
        var creation = this.decode_int(id[1], 1);
        return [atom[0] + "<" + id[0] + ">", creation[1]];
    };

    this.decode_pid = function(data) {
        var atom = this.decode_data(data);
        var id = this.decode_int(atom[1], 4);
        var serial = this.decode_int(id[1], 4);
        var creation = this.decode_int(serial[1], 1);
        return [atom[0] + "<" + id[0] + ">", creation[1]];
    };

    this.decode_small_tuple = function(data) {
        return this.decode_tuple(data, 1);
    };

    this.decode_tuple = function(data, byteLength) {
        if (byteLength == null) { byteLength = 4; }
        var parts = this.decode_int(data, byteLength);
        var arity = parts[0];
        var elements = parts[1];
        var tuple = [];
        for (var i = 0; i < arity; i++) {
            parts = this.decode_data(elements);
            tuple.push(parts[0].value);
            elements = parts[1];
        }
        return [tuple, elements];
    };

    this.decode_nil = function(data) {
        return [[], data];
    };

    this.decode_string = function(data, byteLength) {
        if (byteLength == null) { byteLength = 2; }
        var parts = this.decode_int(data, byteLength);
        var length = parts[0];
        parts = this.split(parts[1], length);
        var atom = "";
        for (var i = 0; i < length; i++) {
            atom += String.fromCharCode(parts[0][i]);
        }
        return [atom, parts[1]];
    };

    this.decode_list = function(data) {
        var parts = this.decode_int(data, 4);
        var length = parts[0];
        var elements = parts[1];
        var arr = [];
        for (var i = 0; i < length; i++) {
            parts = this.decode_data(elements);
            arr.push(parts[0].value);
            elements = parts[1];
        }
        var removenil = this.decode_data(elements);
        if (removenil[0].type != "nil") {
            throw "Lists parsed by this tool are expected to end properly, with a nil terminator."
        }
        return [arr, removenil[1]];
    };

    this.decode_binary = function(data) {
        return this.decode_string(data, 4);
    };

    this.decode_small_big = function(data) {
        return this.decode_big(data, 1);
    };

    this.decode_big = function(data, byteLength) {
        if (byteLength == null) { byteLength = 4; }
        var arity = this.decode_int(data, byteLength);
        var length = arity[0];
        var sign = this.decode_int(arity[1], 1);
        var parts = this.split(sign[1], length);
        var elements = parts[0];
        var num = 0;
        for (var i = 0; i < length; i++) {
            num += elements[i] * Math.pow(256, i);
        }
        if (sign[0] != 0) { num * -1; }
        return [num, parts[1]];
    };

    this.decode_small_atom = function(data) {
        return this.decode_string(data, 1);
    };

    this.decode_map = function(data) {
        var parts = this.decode_int(data, 4);
        var arity = parts[0];
        var pairs = parts[1];
        var map = {};
        var result, key, value;
        for (var i = 0; i < arity; i++) {
            result = this.decode_data(pairs);
            key = result[0].value;
            result = this.decode_data(result[1]);
            value = result[0].value;
            map[key] = value;
            pairs = result[1];
        }
        return [map, pairs];
    };

    this.decode_atom_utf8 = function(data) {
        return this.decode_atom(data);
    };

    this.decode_small_atom_utf8 = function(data) {
        return this.decode_small_atom(data);
    };

    // Encode a BertObj into an array of byte data.
    this.encode = function(obj) {
        if (!(obj instanceof BertObj)) {
            throw "Can only encode BertObj data structures.";
        }
        var buffer = [131];
        return this.encode_data(obj, buffer);
    };

    this.encode_data = function(obj, buffer) {
        return this["encode_" + obj.type](obj.value, buffer)
    };

    this.encode_num = function(num, byteLength, buffer) {
        var value = 0;
        for (var offset = (byteLength - 1) * 8; offset >= 0; offset -= 8) {
            value = num >> offset;
            buffer.push(value);
            num = num - (value << offset);
        }
        return buffer;
    };

    this.encode_int = function(data, buffer) {
        if (data > this.four_byte_max_number) {
            throw "Can only encode integers up to " + this.four_byte_max_number;
        }
        return this.encode_num(data, 4, buffer);
    };

    this.encode_atom = function(data, buffer) {
        var length = data.length;
        if (length >= 256) {
            throw "Atoms may only be up to 255 bytes.";
        }
        buffer.push(100);
        buffer.push(0);
        buffer.push(length);
        this.encode_string_to_buffer(data, buffer);
        return buffer;
    };

    this.encode_tuple = function(data, buffer) {
        var length = data.length, bytes = 0;
        if (length > this.four_byte_max_number) {
            throw "Your list is too long. Seriously, way too long.";
        }
        else if (length < 256) {
            buffer.push(104);
            bytes = 1;
        }
        else {
            buffer.push(105);
            bytes = 4;
        }
        this.encode_num(length, bytes, buffer);
        for (var i = 0; i < length; i++) {
            this.encode_data(data[i], buffer);
        }
        return buffer;
    };

    this.encode_binary = function(data, buffer) {
        if (data.length > this.four_byte_max_number) {
            throw "Your binary string is too long. Seriously, way too long."
        }
        buffer.push(109);
        this.encode_num(data.length, 4, buffer);
        return this.encode_string_to_buffer(data, buffer);
    };

    this.encode_string_to_buffer = function(str, buffer) {
        for (var i = 0; i < str.length; i++) {
            buffer.push(str.charCodeAt(i));
        }
        return buffer;
    };
};

// Enjoy.
var Bert = new BertClass();
<commit_msg>Fix syntax errors<commit_after>/**
 * Represents a Bert object. That is to say, it is the JavaScript representation
 * of an Erlang native type.
 *
 * Although the encoder could perform "clever" conversions, like a regular
 * JavaScript array to an Erlang list type, it doesn't. The reason being that
 * an array could be a tuple or a list, or even an Erlang string! And strings
 * can be strings or binaries or atoms. Don't even get me started on numbers.
 * Forcing explicit typing like this causes less errors during encoding.
 */
var BertObj = function(type, value) {this.type  = type; this.value = value;};

/**
 * The "BertClass" object is used to create a Bert object that can encode and
 * decode data using Erlang's external term format. It is a binary format, and
 * so the decoder expects inputs to be either strings, with each character being
 * one byte of data, or an array, with each element being one byte of data. The
 * encoding process will generate an array of byte data given a BertObj object.
 */
var BertClass = function() {
    /**
     * I know you thought I was going to leave you hanging with that awful to
     * use BertObj, but fear not, I have helper functions to the rescue!
     */
    this.Int = function(value) {return new BertObj("int", value);};

    this.Float = function(value) {return new BertObj("float", value);};

    this.Atom = function(value) {return new BertObj("atom", value);};

    this.String = function(value) {return new BertObj("string", value);};

    this.Binary = function(value) {return new BertObj("binary", value);};

    this.Tuple = function(value) {
        if (!(value instanceof Array)) {
            throw "Must use an array to create tuples."
        }
        return new BertObj("tuple", value);
    };

    this.List = function(value) {
        if (!(value instanceof Array)) {
            throw "Must use an array to create lists."
        }
        return new BertObj("list", value);
    };

    // Most of these tokens map to a function for encoding/decoding.
    // This is subset of allowed tokens in the Erlang external term format.
    this.TOKENS = {
        131: "start",
        70:  "new_float",
        77:  "bitstring",
        97:  "small_int",
        98:  "int",
        99:  "float",
        100: "atom",
        102: "port",
        103: "pid",
        104: "small_tuple",
        105: "tuple",
        106: "nil",
        107: "string",
        108: "list",
        109: "binary",
        110: "small_big",
        111: "big",
        115: "small_atom",
        116: "map",
        118: "atom_utf8",
        119: "small_atom_utf8"
    };

    // Yup. Magic numbers.
    this.four_byte_max_number = 134217727;

    // Get the next "token" based on the data type.
    this.next_token = function(data) {
        if (typeof(data) == "string") {
            return [data.charCodeAt(0), data.substring(1)];
        }
        else {
            return [data[0], data.slice(1)];
        }
    };

    // Splits the data in two, where the first part of the split is `length`
    // long and the second part are all remaining elements after that.
    this.split = function(data, length) {
        if (length == null) { length = 1; }
        if (typeof(data) == "string") {
            return [data.substring(0, length), data.substring(length)];
        }
        else {
            return [data.slice(0, length), data.slice(length)];
        }
    };

    // Decode a string or array into a JavaScript object.
    this.decode = function(data) {
        var parts = this.next_token(data);
        if (this.TOKENS[parts[0]] != "start") {
            throw "Data must begin with an appropriate start token, actually starts with " + parts[0];
        }
        var result = this.decode_data(parts[1]);
        return result[0].value;
    };

    this.decode_data = function(data) {
        var parts = this.next_token(data);
        var token = parts[0], data = parts[1];
        var type, result;
        var type = this.TOKENS[token];
        var result = this["decode_" + type](data);
        return this.handle_result(type, result);
    };

    this.handle_result = function(type, result) {
        return [new BertObj(type, result[0]), result[1]];
    };

    this.decode_small_int = function(data) {
        return this.decode_int(data, 1);
    };

    this.decode_int = function(data, byteLength) {
        if (byteLength == null) { byteLength = 4; }
        var parts = this.split(data, byteLength);
        var size = 0, offset = 0;
        for (var i = 0; i < byteLength; i++) {
            offset = (byteLength - i - 1) * 8;
            size += data[i] << offset;
        }
        return [size, parts[1]];
    };

    this.decode_float = function(data) {
        var float = this.decode_string(data, 31);
        return [parseFloat(float[0]), float[1]];
    };

    this.decode_atom = function(data) {
        return this.decode_string(data, 2);
    };

    this.decode_port = function(data) {
        var atom = this.decode_data(data);
        var id = this.decode_int(atom[1], 4);
        var creation = this.decode_int(id[1], 1);
        return [atom[0] + "<" + id[0] + ">", creation[1]];
    };

    this.decode_pid = function(data) {
        var atom = this.decode_data(data);
        var id = this.decode_int(atom[1], 4);
        var serial = this.decode_int(id[1], 4);
        var creation = this.decode_int(serial[1], 1);
        return [atom[0] + "<" + id[0] + ">", creation[1]];
    };

    this.decode_small_tuple = function(data) {
        return this.decode_tuple(data, 1);
    };

    this.decode_tuple = function(data, byteLength) {
        if (byteLength == null) { byteLength = 4; }
        var parts = this.decode_int(data, byteLength);
        var arity = parts[0];
        var elements = parts[1];
        var tuple = [];
        for (var i = 0; i < arity; i++) {
            parts = this.decode_data(elements);
            tuple.push(parts[0].value);
            elements = parts[1];
        }
        return [tuple, elements];
    };

    this.decode_nil = function(data) {
        return [[], data];
    };

    this.decode_string = function(data, byteLength) {
        if (byteLength == null) { byteLength = 2; }
        var parts = this.decode_int(data, byteLength);
        var length = parts[0];
        parts = this.split(parts[1], length);
        var atom = "";
        for (var i = 0; i < length; i++) {
            atom += String.fromCharCode(parts[0][i]);
        }
        return [atom, parts[1]];
    };

    this.decode_list = function(data) {
        var parts = this.decode_int(data, 4);
        var length = parts[0];
        var elements = parts[1];
        var arr = [];
        for (var i = 0; i < length; i++) {
            parts = this.decode_data(elements);
            arr.push(parts[0].value);
            elements = parts[1];
        }
        var removenil = this.decode_data(elements);
        if (removenil[0].type != "nil") {
            throw "Lists parsed by this tool are expected to end properly, with a nil terminator.";
        }
        return [arr, removenil[1]];
    };

    this.decode_binary = function(data) {
        return this.decode_string(data, 4);
    };

    this.decode_small_big = function(data) {
        return this.decode_big(data, 1);
    };

    this.decode_big = function(data, byteLength) {
        if (byteLength == null) { byteLength = 4; }
        var arity = this.decode_int(data, byteLength);
        var length = arity[0];
        var sign = this.decode_int(arity[1], 1);
        var parts = this.split(sign[1], length);
        var elements = parts[0];
        var num = 0;
        for (var i = 0; i < length; i++) {
            num += elements[i] * Math.pow(256, i);
        }
        if (sign[0] != 0) { num *= -1; }
        return [num, parts[1]];
    };

    this.decode_small_atom = function(data) {
        return this.decode_string(data, 1);
    };

    this.decode_map = function(data) {
        var parts = this.decode_int(data, 4);
        var arity = parts[0];
        var pairs = parts[1];
        var map = {};
        var result, key, value;
        for (var i = 0; i < arity; i++) {
            result = this.decode_data(pairs);
            key = result[0].value;
            result = this.decode_data(result[1]);
            value = result[0].value;
            map[key] = value;
            pairs = result[1];
        }
        return [map, pairs];
    };

    this.decode_atom_utf8 = function(data) {
        return this.decode_atom(data);
    };

    this.decode_small_atom_utf8 = function(data) {
        return this.decode_small_atom(data);
    };

    // Encode a BertObj into an array of byte data.
    this.encode = function(obj) {
        if (!(obj instanceof BertObj)) {
            throw "Can only encode BertObj data structures.";
        }
        var buffer = [131];
        return this.encode_data(obj, buffer);
    };

    this.encode_data = function(obj, buffer) {
        return this["encode_" + obj.type](obj.value, buffer);
    };

    this.encode_num = function(num, byteLength, buffer) {
        var value = 0;
        for (var offset = (byteLength - 1) * 8; offset >= 0; offset -= 8) {
            value = num >> offset;
            buffer.push(value);
            num = num - (value << offset);
        }
        return buffer;
    };

    this.encode_int = function(data, buffer) {
        if (data > this.four_byte_max_number) {
            throw "Can only encode integers up to " + this.four_byte_max_number;
        }
        return this.encode_num(data, 4, buffer);
    };

    this.encode_atom = function(data, buffer) {
        var length = data.length;
        if (length >= 256) {
            throw "Atoms may only be up to 255 bytes.";
        }
        buffer.push(100);
        buffer.push(0);
        buffer.push(length);
        this.encode_string_to_buffer(data, buffer);
        return buffer;
    };

    this.encode_tuple = function(data, buffer) {
        var length = data.length, bytes = 0;
        if (length > this.four_byte_max_number) {
            throw "Your list is too long. Seriously, way too long.";
        }
        else if (length < 256) {
            buffer.push(104);
            bytes = 1;
        }
        else {
            buffer.push(105);
            bytes = 4;
        }
        this.encode_num(length, bytes, buffer);
        for (var i = 0; i < length; i++) {
            this.encode_data(data[i], buffer);
        }
        return buffer;
    };

    this.encode_binary = function(data, buffer) {
        if (data.length > this.four_byte_max_number) {
            throw "Your binary string is too long. Seriously, way too long.";
        }
        buffer.push(109);
        this.encode_num(data.length, 4, buffer);
        return this.encode_string_to_buffer(data, buffer);
    };

    this.encode_string_to_buffer = function(str, buffer) {
        for (var i = 0; i < str.length; i++) {
            buffer.push(str.charCodeAt(i));
        }
        return buffer;
    };
};

// Enjoy.
var Bert = new BertClass();
<|endoftext|>


<commit_before>var http = require('http');
var https = require('https');
var URL = require('url');
var Path = require('path');
var ContentDisposition = require('content-disposition');
var BufferList = require('bl');
var moment = require('moment');
var MediaTyper = require('media-typer');
var Dom = require('whacko');
var Exif = require('exiftool');
var debug = require('debug')('url-inspector');
var OEmbedProviders = require('oembed-providers-unofficial');

module.exports = inspector;

var inspectors = {
	embed: [inspectEmbed, Infinity],
	image: [inspectMedia, 30000],
	audio: [inspectMedia, 30000],
	video: [inspectMedia, 100000],
	link: [inspectHTML, 8000],
	file: [inspectFile, 100],
	archive: [inspectArchive, 0]
};

function inspector(url, opts, cb) {
	url = encodeURI(url);
	var obj = {
		url: url
	};
	var urlObj = URL.parse(url);
	urlObj.headers = {
		"User-Agent": "Mozilla/5.0"
	};
	debug("test url", url);

	var oEmbedUrl = supportsOEmbed(urlObj);
	if (oEmbedUrl) {
		debug("oembed candidate");
		urlObj = URL.parse(oEmbedUrl);
		obj.type = "embed";
		obj.mime = "text/html";
	}
	request(urlObj, obj, function(err, tags) {
		if (obj) {
			normalize(obj);
			if (!obj.site) obj.site = urlObj.domain;
			if (opts.all && tags) obj.all = tags;
		}
		cb(err, obj);
	});
}

function supportsOEmbed(urlObj, cb) {
	var endpoint;
	var url = urlObj.href;
	var provider = OEmbedProviders.find(function(provider) {
		endpoint = provider.endpoints.find(function(point) {
			if (!point.schemes) return false;
			return !!point.schemes.find(function(scheme) {
				return new RegExp("^" + scheme.replace("*", ".*") + "$").test(url);
			});
		});
		return !!endpoint;
	});
	if (!provider) return false;
	// request oembed endpoint
	return endpoint.url + "?format=json&url=" + encodeURIComponent(url);
}

function request(urlObj, obj, cb) {
	debug("request url", urlObj.href);
	var req = (/^https:?$/.test(urlObj.protocol) ? https : http).request(urlObj, function(res) {
		var status = res.statusCode;
		debug("got response status %d", status);
		if (status < 200 || status >= 400) return cb(status);
		if (status >= 300 && status < 400 && res.headers.location) {
			var redirObj = URL.parse(res.headers.location);
			redirObj.redirects = (urlObj.redirects || 0) + 1;
			if (redirObj.redirects >= 5) return cb("Too many http redirects");
			return request(redirObj, obj, cb);
		}
		var mimeObj = MediaTyper.parse(res.headers['content-type']);
		if (obj.type == "embed") {
			obj.mime = "text/html";
			obj.type = "embed";
		} else {
			obj.mime = MediaTyper.format(mimeObj);
			obj.type = mime2type(mimeObj);
			obj.size = res.headers['content-length'];
			var pathname;
			var disposition = res.headers['content-disposition'];
			if (disposition) {
				disposition = ContentDisposition.parse(disposition);
				if (disposition && disposition.params.file) {
					pathname = URL.parse(disposition.params.file).pathname;
				}
			}
			if (!pathname) pathname = urlObj.pathname;
			var file = Path.basename(pathname);
			var fileext = Path.extname(file);
			if (!obj.ext) {
				obj.ext = fileext.substring(1);
			}
			obj.name = Path.basename(file, fileext);
		}

		debug("(mime, type, length) is (%s, %s, %d)", obj.mime, obj.type, obj.size);
		var fun = inspectors[obj.type];
		(function(next) {
			if (fun[1]) buffer(req, res, fun[1], next);
			else next();
		})(function(err, buf) {
			if (err) console.error(err);
			fun[0](obj, buf, function(err, tags) {
				if (err) console.error(err);
				cb(null, obj, tags);
			});
		});
	}).on('error', function(err) {
		return cb(err);
	});
	req.end();
}

function normalize(obj) {
	Object.keys(obj).forEach(function(key) {
		if (obj[key] == "" || obj[key] == null) delete obj[key];
	});
	if (obj.ext) obj.ext = obj.ext.toLowerCase();
}

function mime2type(obj) {
	var type = 'file';
	if (obj.subtype == "html") {
		type = 'link';
	} else if (['image', 'audio', 'video'].indexOf(obj.type) >= 0) {
		type = obj.type;
	} else if (['css', 'json', 'xml', 'plain'].indexOf(obj.subtype) >= 0) {
		type = 'file';
	} else if (obj.subtype == 'svg') {
		type = 'image';
	} else if (['x-xz', 'x-gtar', 'x-gtar-compressed',
	'x-tar', 'gzip', 'zip'].indexOf(obj.subtype) >= 0) {
		type = 'archive';
	}
	return type;
}

function buffer(req, res, length, cb) {
	var bl = new BufferList();
	res.on('data', function(buf) {
		bl.append(buf);
		if (bl.length >= length) {
			debug("got %d bytes, aborting", bl.length);
			req.abort();
		}
	});
	res.on('end', function(buf) {
		if (buf) bl.append(buf);
		debug("response ended, got %d bytes", bl.length);
		cb(null, bl.slice());
	});
	res.resume();

}

function importTags(tags, obj, map) {
	var val, tag, key, prev;
	if (!map) {
		// no map means all keys are already good
		map = {};
		for (key in tags) map[key] = key;
	}
	for (tag in map) {
		val = tags[tag];
		if (val === undefined) continue;
		delete tags[tag];
		key = map[tag];
		prev = obj[key];
		obj[key] = val;
	}
}

function importMeta(dom, map, obj) {
	var key, val;
	for (key in map) {
		val = dom('meta[name="' + map[key] + '"]').attr('content');
		if (val != null && val != "") obj[key] = val;
	}
}

function secondsToDuration(num) {
	var duration = moment.duration(parseInt(num), 'seconds');
	return moment(duration._data).format('HH:mm:ss');
}

function inspectMedia(obj, buf, cb) {
	Exif.metadata(buf, function(err, tags) {
		if (err) return cb(err);
		debug("exiftool got", tags);
		if (tags && tags.error) return cb(tags.error);
		if (!tags) return cb();
		importTags(tags, obj, {
			imageWidth: 'width',
			imageHeight: 'height',
			duration: 'duration',
			mimeType: 'mime',
			extension: 'ext',
			title: 'title',
			album: 'album',
			objectName: 'title'
		});
		if (tags.audioBitrate && !tags.duration) {
			var rate = parseInt(tags.audioBitrate) * 1000 / 8;
			obj.duration = secondsToDuration(obj.size / rate);
		}
		// copy to be able to serialize to JSON
		cb(null, Object.assign({}, tags));
	});
}

function inspectHTML(obj, buf, cb) {
	var dom = Dom.load(buf);
	var oembed = dom('link[type="application/json+oembed"]').attr('href');
	if (oembed) {
		obj.type = "embed";
		return request(URL.parse(oembed), obj, cb);
	}
	importTags({
		title: dom('title, h1').first().text(),
		icon: dom('link[rel="icon"],link[rel="shortcut icon"]').first().attr('href')
	}, obj);
	var oldType = obj.type;
	delete obj.type;
	importMeta(dom, {
		title: "og:title",
		thumbnail: "og:image",
		url: "og:url",
		type: "og:type",
		site: "og:site_name"
	}, obj);
	var ogType = obj.type;
	if (ogType) {
		if (ogType.startsWith('video')) obj.type = 'video';
		else if (ogType.startsWith('music')) obj.type = 'audio';
		else obj.type = 'link';
	} else {
		obj.type = oldType;
	}
	importMeta(dom, {
		title: "twitter:title",
		thumbnail: "twitter:image",
		url: "twitter:url",
		site: "twitter:site"
	}, obj);
	if (dom('meta[name="twitter:card"]').attr('content') == 'photo') obj.type = 'image';
	cb();
}

function inspectEmbed(obj, buf, cb) {
	var tags = JSON.parse(buf.toString());
	importTags(tags, obj, {
		type: 'type',
		title: 'title',
		thumbnail_url: 'thumbnail',
		width: 'width',
		height: 'height',
		html: 'html',
		url: 'url',
		provider_name: 'site'
	});
	if (obj.type == "photo") obj.type = "image";
	else if (obj.type == "rich") obj.type = "embed";
	cb(null, tags);
}

function inspectFile(obj, buf, cb) {
	obj.sample = buf.toString().replace(/\s+/g, ' ').substring(0, 30);
	cb();
}

function inspectArchive(obj, buf, cb) {
	cb();
}

function inspectLink(obj, buf, cb) {
	cb();
}

<commit_msg>Set name to basename from path<commit_after>var http = require('http');
var https = require('https');
var URL = require('url');
var Path = require('path');
var ContentDisposition = require('content-disposition');
var BufferList = require('bl');
var moment = require('moment');
var MediaTyper = require('media-typer');
var Dom = require('whacko');
var Exif = require('exiftool');
var debug = require('debug')('url-inspector');
var OEmbedProviders = require('oembed-providers-unofficial');

module.exports = inspector;

var inspectors = {
	embed: [inspectEmbed, Infinity],
	image: [inspectMedia, 30000],
	audio: [inspectMedia, 30000],
	video: [inspectMedia, 100000],
	link: [inspectHTML, 8000],
	file: [inspectFile, 100],
	archive: [inspectArchive, 0]
};

function inspector(url, opts, cb) {
	url = encodeURI(url);
	var obj = {
		url: url
	};
	var urlObj = URL.parse(url);
	urlObj.headers = {
		"User-Agent": "Mozilla/5.0"
	};
	debug("test url", url);

	var oEmbedUrl = supportsOEmbed(urlObj);
	if (oEmbedUrl) {
		debug("oembed candidate");
		urlObj = URL.parse(oEmbedUrl);
		obj.type = "embed";
		obj.mime = "text/html";
	}
	request(urlObj, obj, function(err, tags) {
		if (obj) {
			normalize(obj);
			if (!obj.site) obj.site = urlObj.domain;
			if (opts.all && tags) obj.all = tags;
		}
		cb(err, obj);
	});
}

function supportsOEmbed(urlObj, cb) {
	var endpoint;
	var url = urlObj.href;
	var provider = OEmbedProviders.find(function(provider) {
		endpoint = provider.endpoints.find(function(point) {
			if (!point.schemes) return false;
			return !!point.schemes.find(function(scheme) {
				return new RegExp("^" + scheme.replace("*", ".*") + "$").test(url);
			});
		});
		return !!endpoint;
	});
	if (!provider) return false;
	// request oembed endpoint
	return endpoint.url + "?format=json&url=" + encodeURIComponent(url);
}

function request(urlObj, obj, cb) {
	debug("request url", urlObj.href);
	var req = (/^https:?$/.test(urlObj.protocol) ? https : http).request(urlObj, function(res) {
		var status = res.statusCode;
		debug("got response status %d", status);
		if (status < 200 || status >= 400) return cb(status);
		if (status >= 300 && status < 400 && res.headers.location) {
			var redirObj = URL.parse(res.headers.location);
			redirObj.redirects = (urlObj.redirects || 0) + 1;
			if (redirObj.redirects >= 5) return cb("Too many http redirects");
			return request(redirObj, obj, cb);
		}
		var mimeObj = MediaTyper.parse(res.headers['content-type']);
		if (obj.type == "embed") {
			obj.mime = "text/html";
			obj.type = "embed";
		} else {
			obj.mime = MediaTyper.format(mimeObj);
			obj.type = mime2type(mimeObj);
			obj.size = parseInt(res.headers['content-length']);
		}
		var disposition = res.headers['content-disposition'];
		if (disposition) {
			disposition = ContentDisposition.parse(disposition);
			if (disposition && disposition.params.file) {
				urlObj = URL.parse(disposition.params.file);
			}
		}
		obj.name = Path.basename(urlObj.path);

		debug("(mime, type, length) is (%s, %s, %d)", obj.mime, obj.type, obj.size);
		var fun = inspectors[obj.type];
		(function(next) {
			if (fun[1]) buffer(req, res, fun[1], next);
			else next();
		})(function(err, buf) {
			if (err) console.error(err);
			fun[0](obj, buf, function(err, tags) {
				if (err) console.error(err);
				cb(null, obj, tags);
			});
		});
	}).on('error', function(err) {
		return cb(err);
	});
	req.end();
}

function normalize(obj) {
	Object.keys(obj).forEach(function(key) {
		if (obj[key] == "" || obj[key] == null) delete obj[key];
	});
	if (obj.ext) obj.ext = obj.ext.toLowerCase();
}

function mime2type(obj) {
	var type = 'file';
	if (obj.subtype == "html") {
		type = 'link';
	} else if (['image', 'audio', 'video'].indexOf(obj.type) >= 0) {
		type = obj.type;
	} else if (['css', 'json', 'xml', 'plain'].indexOf(obj.subtype) >= 0) {
		type = 'file';
	} else if (obj.subtype == 'svg') {
		type = 'image';
	} else if (['x-xz', 'x-gtar', 'x-gtar-compressed',
	'x-tar', 'gzip', 'zip'].indexOf(obj.subtype) >= 0) {
		type = 'archive';
	}
	return type;
}

function buffer(req, res, length, cb) {
	var bl = new BufferList();
	res.on('data', function(buf) {
		bl.append(buf);
		if (bl.length >= length) {
			debug("got %d bytes, aborting", bl.length);
			req.abort();
		}
	});
	res.on('end', function(buf) {
		if (buf) bl.append(buf);
		debug("response ended, got %d bytes", bl.length);
		cb(null, bl.slice());
	});
	res.resume();

}

function importTags(tags, obj, map) {
	var val, tag, key, prev;
	if (!map) {
		// no map means all keys are already good
		map = {};
		for (key in tags) map[key] = key;
	}
	for (tag in map) {
		val = tags[tag];
		if (val === undefined) continue;
		delete tags[tag];
		key = map[tag];
		prev = obj[key];
		obj[key] = val;
	}
}

function importMeta(dom, map, obj) {
	var key, val;
	for (key in map) {
		val = dom('meta[name="' + map[key] + '"]').attr('content');
		if (val != null && val != "") obj[key] = val;
	}
}

function secondsToDuration(num) {
	var duration = moment.duration(parseInt(num), 'seconds');
	return moment(duration._data).format('HH:mm:ss');
}

function inspectMedia(obj, buf, cb) {
	Exif.metadata(buf, function(err, tags) {
		if (err) return cb(err);
		debug("exiftool got", tags);
		if (tags && tags.error) return cb(tags.error);
		if (!tags) return cb();
		importTags(tags, obj, {
			imageWidth: 'width',
			imageHeight: 'height',
			duration: 'duration',
			mimeType: 'mime',
			extension: 'ext',
			title: 'title',
			album: 'album',
			objectName: 'title'
		});
		if (tags.audioBitrate && !tags.duration) {
			var rate = parseInt(tags.audioBitrate) * 1000 / 8;
			obj.duration = secondsToDuration(obj.size / rate);
		}
		// copy to be able to serialize to JSON
		cb(null, Object.assign({}, tags));
	});
}

function inspectHTML(obj, buf, cb) {
	var dom = Dom.load(buf);
	var oembed = dom('link[type="application/json+oembed"]').attr('href');
	if (oembed) {
		obj.type = "embed";
		return request(URL.parse(oembed), obj, cb);
	}
	importTags({
		title: dom('title, h1').first().text(),
		icon: dom('link[rel="icon"],link[rel="shortcut icon"]').first().attr('href')
	}, obj);
	var oldType = obj.type;
	delete obj.type;
	importMeta(dom, {
		title: "og:title",
		thumbnail: "og:image",
		url: "og:url",
		type: "og:type",
		site: "og:site_name"
	}, obj);
	var ogType = obj.type;
	if (ogType) {
		if (ogType.startsWith('video')) obj.type = 'video';
		else if (ogType.startsWith('music')) obj.type = 'audio';
		else obj.type = 'link';
	} else {
		obj.type = oldType;
	}
	importMeta(dom, {
		title: "twitter:title",
		thumbnail: "twitter:image",
		url: "twitter:url",
		site: "twitter:site"
	}, obj);
	if (dom('meta[name="twitter:card"]').attr('content') == 'photo') obj.type = 'image';
	cb();
}

function inspectEmbed(obj, buf, cb) {
	var tags = JSON.parse(buf.toString());
	importTags(tags, obj, {
		type: 'type',
		title: 'title',
		thumbnail_url: 'thumbnail',
		width: 'width',
		height: 'height',
		html: 'html',
		url: 'url',
		provider_name: 'site'
	});
	if (obj.type == "photo") obj.type = "image";
	else if (obj.type == "rich") obj.type = "embed";
	cb(null, tags);
}

function inspectFile(obj, buf, cb) {
	obj.sample = buf.toString().replace(/\s+/g, ' ').substring(0, 30);
	cb();
}

function inspectArchive(obj, buf, cb) {
	cb();
}

function inspectLink(obj, buf, cb) {
	cb();
}

<|endoftext|>