<commit_before>
define([
    'flight/lib/component',
    'flight/lib/registry',
    'data',
    'tpl!./list',
    'tpl!./item',
    'tpl!util/alert',
    'util/video/scrubber',
    'util/vertex/formatters',
    'util/popovers/withVertexScrollingPositionUpdates',
    'util/jquery.withinScrollable',
    'util/jquery.ui.draggable.multiselect'
], function(
    defineComponent,
    registry,
    appData,
    template,
    vertexTemplate,
    alertTemplate,
    VideoScrubber,
    F,
    withPositionUpdates) {
    'use strict';

    return defineComponent(List, withPositionUpdates);

    function List() {

        this.defaultAttrs({
            itemSelector: '.vertex-item',
            infiniteScrolling: false
        });

        this.stateForVertex = function(vertex) {
            var inWorkspace = appData.inWorkspace(vertex);
            return {
                inGraph: inWorkspace,
                inMap: inWorkspace && !!(
                        vertex.properties.geoLocation ||
                        (vertex.location || (vertex.locations && vertex.locations.length)) ||
                        (vertex.properties.latitude && vertex.properties.longitude)
                )
            };
        };

        this.vertexIdToClassName = function(id) {
            var className = this.classNameLookup[id] = (this.classNameLookup[id] || ('vId' + (++this.classNameIndex)));
            return className;
        };

        this.classNameMapForVertices = function(vertices) {
            var self = this,
                classNamesForVertex = {};

            vertices.forEach(function(v) {

                var className = self.vertexIdToClassName(v.id),
                    classes = [className],
                    vertexState = self.stateForVertex(v);

                if (vertexState.inGraph) classes.push('graph-displayed');
                if (vertexState.inMap) classes.push('map-displayed');

                classes.push('has_preview');

                classNamesForVertex[v.id] = classes.join(' ');
            });

            return classNamesForVertex;
        };

        this.after('initialize', function() {
            var self = this;

            this.classNameIndex = 0;
            this.classNameLookup = {};

            this.$node
                .addClass('vertex-list')
                .html(template({
                    vertices: this.attr.vertices,
                    infiniteScrolling: this.attr.infiniteScrolling && this.attr.total !== this.attr.vertices.length,
                    classNamesForVertex: this.classNameMapForVertices(this.attr.vertices),
                    F: F
                }));

            this.attachEvents();

            this.loadVisibleResultPreviews = _.debounce(this.loadVisibleResultPreviews.bind(this), 1000);
            this.loadVisibleResultPreviews();

            this.triggerInfiniteScrollRequest = _.debounce(this.triggerInfiniteScrollRequest.bind(this), 1000);
            this.triggerInfiniteScrollRequest();

            this.setupDraggables();

            this.onObjectsSelected(null, { edges: [], vertices: appData.selectedVertices});

            this.on('selectAll', this.onSelectAll);
            this.on('down', this.move);
            this.on('up', this.move);
            this.on('contextmenu', this.onContextMenu);

            _.defer(function() {
                this.$node.scrollTop(0);
            }.bind(this))
        });

        this.onContextMenu = function(event) {
            var $target = $(event.target).closest('.vertex-item'),
                vertexId = $target.data('vertexId');

            event.preventDefault();
            event.stopPropagation();

            this.trigger($target, 'showVertexContextMenu', {
                vertexId: vertexId,
                position: {
                    x: event.pageX,
                    y: event.pageY
                }
            });
        };

        this.move = function(e, data) {
            var previousSelected = this.$node.find('.active')[e.type === 'up' ? 'first' : 'last'](),
                moveTo = previousSelected[e.type === 'up' ? 'prev' : 'next']('.vertex-item');

            if (moveTo.length) {

                var selected = [];

                if (data.shiftKey) {
                    selected = selected.concat(appData.selectedVertices);
                    selected.push(appData.vertex(moveTo.data('vertexId')));
                } else {
                    selected.push(appData.vertex(moveTo.data('vertexId')));
                }

                this.trigger(document, 'defocusVertices');
                this.trigger('selectObjects', { vertices: selected });
            }
        };

        this.onSelectAll = function(e) {
            e.stopPropagation();

            var items = this.$node.find('.vertex-item').addClass('active');
            this.selectItems(items);
        };

        this.after('teardown', function() {
            this.$node.off('mouseenter mouseleave');
            this.scrollNode.off('scroll.vertexList');
            this.$node.empty();
        });

        this.attachEvents = function() {
            this.scrollNode = this.$node;
            while (this.scrollNode.length && this.scrollNode.css('overflow') !== 'auto') {
                this.scrollNode = this.scrollNode.parent();
            }
            this.scrollNode.on('scroll.vertexList', this.onResultsScroll.bind(this));

            this.$node.on('mouseenter mouseleave', '.vertex-item', this.onHoverItem.bind(this));

            this.on(document, 'verticesAdded', this.onVerticesUpdated);
            this.on(document, 'verticesUpdated', this.onVerticesUpdated);
            this.on(document, 'verticesDeleted', this.onVerticesDeleted);
            this.on(document, 'objectsSelected', this.onObjectsSelected);
            this.on(document, 'switchWorkspace', this.onWorkspaceClear);
            this.on(document, 'workspaceDeleted', this.onWorkspaceClear);
            this.on(document, 'workspaceLoaded', this.onWorkspaceLoaded);
            this.on('addInfiniteVertices', this.onAddInfiniteVertices);
        };

        this.setupDraggables = function() {
            this.applyDraggable(this.$node.find('a'));
            this.$node.droppable({ accept: '*', tolerance: 'pointer' });
        };

        this.onHoverItem = function(evt) {
            if (this.disableHover === 'defocused') {
                return;
            } else if (this.disableHover) {
                this.disableHover = 'defocused';
                return this.trigger(document, 'defocusVertices');
            }

            var id = $(evt.target).closest('.vertex-item').data('vertexId');
            if (evt.type == 'mouseenter' && id) {
                this.trigger(document, 'focusVertices', { vertexIds: [id] });
            } else {
                this.trigger(document, 'defocusVertices');
            }
        };

        this.onResultsScroll = function(e) {
            if (!this.disableHover) {
                this.disableHover = true;
            }

            this.loadVisibleResultPreviews();

            if (this.attr.infiniteScrolling) {
                this.triggerInfiniteScrollRequest();
            }
        };

        this.triggerInfiniteScrollRequest = function() {
            if (!this.attr.infiniteScrolling) return;

            var loadingListElement = this.$node.find('.infinite-loading');

            if (this.scrollNode.length) {
                loadingListElement = loadingListElement.withinScrollable(this.scrollNode);
            }

            if (loadingListElement.length) {
                var data = { conceptType: this.attr.verticesConceptId };
                if (!this.offset) this.offset = this.attr.nextOffset;
                data.paging = {
                    offset: this.offset,
                };
                this.trigger('infiniteScrollRequest', data);
            }
        };

        this.onAddInfiniteVertices = function(evt, data) {
            var loading = this.$node.find('.infinite-loading');

            if (!data.success) {
                loading.html(alertTemplate({ error: 'Error loading search results' }));
                this.attr.infiniteScrolling = false;
            } else if (data.vertices.length === 0) {
                loading.remove();
                this.attr.infiniteScrolling = false;
            } else {
                this.offset = data.nextOffset;
                var clsMap = this.classNameMapForVertices(data.vertices),
                    added = data.vertices.map(function(vertex) {
                        return vertexTemplate({
                            vertex: vertex,
                            classNamesForVertex: clsMap,
                            F: F
                        });
                    }),
                    lastItem = loading.prev();

                loading.before(added);

                var total = data.total || this.attr.total || 0;
                if (total === this.$node.find('.vertex-item').length) {
                    loading.remove();
                    this.attr.infiniteScrolling = false;
                } else {
                    this.triggerInfiniteScrollRequest();
                }

                this.loadVisibleResultPreviews();

                this.applyDraggable(this.$node.find('a'));
            }
        };

        this.loadVisibleResultPreviews = function() {
            var self = this;

            this.disableHover = false;

            var lisVisible = this.$node.find('.nav-list').children('li');
            if (this.scrollNode.length) {
                lisVisible = lisVisible.withinScrollable(this.scrollNode);
            }

            lisVisible.each(function() {
                var li = $(this),
                    vertex = appData.vertex(li.data('vertexId'));

                if (vertex && !li.data('previewLoaded')) {

                    var preview = li.data('previewLoaded', true)
                                    .find('.preview');

                    if (vertex.imageFramesSrc) {
                        VideoScrubber.attachTo(preview, {
                            posterFrameUrl: vertex.imageSrc,
                            videoPreviewImageUrl: vertex.imageFramesSrc
                        });
                    } else {
                        preview.css('background-image', 'url(' + vertex.imageSrc + ')');
                    }
                }
            });
        };

        this.applyDraggable = function(el) {
            var self = this;

            el.draggable({
                helper: 'clone',
                appendTo: 'body',
                revert: 'invalid',
                revertDuration: 250,
                scroll: false,
                zIndex: 100,
                distance: 10,
                multi: true,
                otherDraggablesClass: 'vertex-dragging',
                start: function(ev, ui) {
                    $(ui.helper).addClass('vertex-dragging');
                },
                selection: function(ev, ui) {
                    self.selectItems(ui.selected);
                }
            });
        };

        this.selectItems = function(items) {
            var vertices = appData.vertices(items.map(function() {
                    return $(this).data('vertexId');
                }).toArray());

            if (vertices.length > 1) {
                vertices.forEach(function(vertex) {
                    vertex.workspace = {
                        selected: true
                    };
                });
            }
            if (vertices.length === 0) {
                return;
            }
            this.trigger(document, 'defocusVertices');
            this.trigger('selectObjects', { vertices: vertices });
        };

        this.onWorkspaceLoaded = function(evt, workspace) {
            this.onVerticesUpdated(evt, workspace.data || {});
        };

        // Track changes to vertices so we display the "Displayed in Graph" icon
        // in search results
        this.toggleItemIcons = function(id, data) {
            this.$node
                .find('li.' + this.vertexIdToClassName(id))
                .toggleClass('graph-displayed', data.inGraph)
                .toggleClass('map-displayed', data.inMap);
        };

        // Switching workspaces should clear the icon state and vertices
        this.onWorkspaceClear = function() {
            this.$node.find('li.graph-displayed').removeClass('graph-displayed');
            this.$node.find('li.map-displayed').removeClass('map-displayed');
        };

        this.onVerticesUpdated = function(event, data) {
            var self = this;
            (data.vertices || []).forEach(function(vertex) {
                self.toggleItemIcons(vertex.id, self.stateForVertex(vertex));
                var li = self.$node.find('li.' + self.vertexIdToClassName(vertex.id)),
                    currentAnchor = li.children('a'),
                    newAnchor = $(vertexTemplate({
                        vertex: vertex,
                        classNamesForVertex: self.classNameMapForVertices([vertex]),
                        F: F
                    })).children('a'),
                    currentHtml = currentAnchor.html(),
                    src = vertex.imageSrc,
                    showImageSrc = src && !vertex.imageSrcIsFromConcept;

                if (currentAnchor.length) {
                    if (showImageSrc) {
                        $('<img/>').attr('src', src).appendTo(newAnchor.find('.preview'));
                    }

                    var newHtml = newAnchor.html();
                    if (currentAnchor.length && newHtml !== currentHtml) {
                        li.data('previewLoaded', null);
                    }
                }
            });

            this.loadVisibleResultPreviews();
        };

        this.onVerticesDeleted = function(event, data) {
            var self = this;
            (data.vertices || []).forEach(function(vertex) {
                self.toggleItemIcons(vertex.id, { inGraph: false, inMap: false });
            });
        };

        this.onObjectsSelected = function(event, data) {
            this.$node.find('.active').removeClass('active');

            var self = this,
                ids = _.chain(data.vertices)
                    .map(function(v) {
                        return '.' + self.vertexIdToClassName(v.id);
                    })
                    .value().join(',');

            $(ids, this.node).addClass('active');
        };
    }
});
<commit_msg>Fix map icon not showing in list<commit_after>
define([
    'flight/lib/component',
    'flight/lib/registry',
    'data',
    'tpl!./list',
    'tpl!./item',
    'tpl!util/alert',
    'promise!util/service/ontologyPromise',
    'util/video/scrubber',
    'util/vertex/formatters',
    'util/popovers/withVertexScrollingPositionUpdates',
    'util/jquery.withinScrollable',
    'util/jquery.ui.draggable.multiselect'
], function(
    defineComponent,
    registry,
    appData,
    template,
    vertexTemplate,
    alertTemplate,
    ontologyPromise,
    VideoScrubber,
    F,
    withPositionUpdates) {
    'use strict';

    return defineComponent(List, withPositionUpdates);

    function List() {

        this.defaultAttrs({
            itemSelector: '.vertex-item',
            infiniteScrolling: false
        });

        this.stateForVertex = function(vertex) {
            var inWorkspace = appData.inWorkspace(vertex);
            return {
                inGraph: inWorkspace,
                inMap: inWorkspace && _.some(vertex.properties, function(p) {
                    var ontologyProperty = ontologyPromise.propertiesByTitle[p.name];
                    return ontologyProperty && ontologyProperty.dataType === 'geoLocation';
                })
            };
        };

        this.vertexIdToClassName = function(id) {
            var className = this.classNameLookup[id] = (this.classNameLookup[id] || ('vId' + (++this.classNameIndex)));
            return className;
        };

        this.classNameMapForVertices = function(vertices) {
            var self = this,
                classNamesForVertex = {};

            vertices.forEach(function(v) {

                var className = self.vertexIdToClassName(v.id),
                    classes = [className],
                    vertexState = self.stateForVertex(v);

                if (vertexState.inGraph) classes.push('graph-displayed');
                if (vertexState.inMap) classes.push('map-displayed');

                classes.push('has_preview');

                classNamesForVertex[v.id] = classes.join(' ');
            });

            return classNamesForVertex;
        };

        this.after('initialize', function() {
            var self = this;

            this.classNameIndex = 0;
            this.classNameLookup = {};

            this.$node
                .addClass('vertex-list')
                .html(template({
                    vertices: this.attr.vertices,
                    infiniteScrolling: this.attr.infiniteScrolling && this.attr.total !== this.attr.vertices.length,
                    classNamesForVertex: this.classNameMapForVertices(this.attr.vertices),
                    F: F
                }));

            this.attachEvents();

            this.loadVisibleResultPreviews = _.debounce(this.loadVisibleResultPreviews.bind(this), 1000);
            this.loadVisibleResultPreviews();

            this.triggerInfiniteScrollRequest = _.debounce(this.triggerInfiniteScrollRequest.bind(this), 1000);
            this.triggerInfiniteScrollRequest();

            this.setupDraggables();

            this.onObjectsSelected(null, { edges: [], vertices: appData.selectedVertices});

            this.on('selectAll', this.onSelectAll);
            this.on('down', this.move);
            this.on('up', this.move);
            this.on('contextmenu', this.onContextMenu);

            _.defer(function() {
                this.$node.scrollTop(0);
            }.bind(this))
        });

        this.onContextMenu = function(event) {
            var $target = $(event.target).closest('.vertex-item'),
                vertexId = $target.data('vertexId');

            event.preventDefault();
            event.stopPropagation();

            this.trigger($target, 'showVertexContextMenu', {
                vertexId: vertexId,
                position: {
                    x: event.pageX,
                    y: event.pageY
                }
            });
        };

        this.move = function(e, data) {
            var previousSelected = this.$node.find('.active')[e.type === 'up' ? 'first' : 'last'](),
                moveTo = previousSelected[e.type === 'up' ? 'prev' : 'next']('.vertex-item');

            if (moveTo.length) {

                var selected = [];

                if (data.shiftKey) {
                    selected = selected.concat(appData.selectedVertices);
                    selected.push(appData.vertex(moveTo.data('vertexId')));
                } else {
                    selected.push(appData.vertex(moveTo.data('vertexId')));
                }

                this.trigger(document, 'defocusVertices');
                this.trigger('selectObjects', { vertices: selected });
            }
        };

        this.onSelectAll = function(e) {
            e.stopPropagation();

            var items = this.$node.find('.vertex-item').addClass('active');
            this.selectItems(items);
        };

        this.after('teardown', function() {
            this.$node.off('mouseenter mouseleave');
            this.scrollNode.off('scroll.vertexList');
            this.$node.empty();
        });

        this.attachEvents = function() {
            this.scrollNode = this.$node;
            while (this.scrollNode.length && this.scrollNode.css('overflow') !== 'auto') {
                this.scrollNode = this.scrollNode.parent();
            }
            this.scrollNode.on('scroll.vertexList', this.onResultsScroll.bind(this));

            this.$node.on('mouseenter mouseleave', '.vertex-item', this.onHoverItem.bind(this));

            this.on(document, 'verticesAdded', this.onVerticesUpdated);
            this.on(document, 'verticesUpdated', this.onVerticesUpdated);
            this.on(document, 'verticesDeleted', this.onVerticesDeleted);
            this.on(document, 'objectsSelected', this.onObjectsSelected);
            this.on(document, 'switchWorkspace', this.onWorkspaceClear);
            this.on(document, 'workspaceDeleted', this.onWorkspaceClear);
            this.on(document, 'workspaceLoaded', this.onWorkspaceLoaded);
            this.on('addInfiniteVertices', this.onAddInfiniteVertices);
        };

        this.setupDraggables = function() {
            this.applyDraggable(this.$node.find('a'));
            this.$node.droppable({ accept: '*', tolerance: 'pointer' });
        };

        this.onHoverItem = function(evt) {
            if (this.disableHover === 'defocused') {
                return;
            } else if (this.disableHover) {
                this.disableHover = 'defocused';
                return this.trigger(document, 'defocusVertices');
            }

            var id = $(evt.target).closest('.vertex-item').data('vertexId');
            if (evt.type == 'mouseenter' && id) {
                this.trigger(document, 'focusVertices', { vertexIds: [id] });
            } else {
                this.trigger(document, 'defocusVertices');
            }
        };

        this.onResultsScroll = function(e) {
            if (!this.disableHover) {
                this.disableHover = true;
            }

            this.loadVisibleResultPreviews();

            if (this.attr.infiniteScrolling) {
                this.triggerInfiniteScrollRequest();
            }
        };

        this.triggerInfiniteScrollRequest = function() {
            if (!this.attr.infiniteScrolling) return;

            var loadingListElement = this.$node.find('.infinite-loading');

            if (this.scrollNode.length) {
                loadingListElement = loadingListElement.withinScrollable(this.scrollNode);
            }

            if (loadingListElement.length) {
                var data = { conceptType: this.attr.verticesConceptId };
                if (!this.offset) this.offset = this.attr.nextOffset;
                data.paging = {
                    offset: this.offset,
                };
                this.trigger('infiniteScrollRequest', data);
            }
        };

        this.onAddInfiniteVertices = function(evt, data) {
            var loading = this.$node.find('.infinite-loading');

            if (!data.success) {
                loading.html(alertTemplate({ error: 'Error loading search results' }));
                this.attr.infiniteScrolling = false;
            } else if (data.vertices.length === 0) {
                loading.remove();
                this.attr.infiniteScrolling = false;
            } else {
                this.offset = data.nextOffset;
                var clsMap = this.classNameMapForVertices(data.vertices),
                    added = data.vertices.map(function(vertex) {
                        return vertexTemplate({
                            vertex: vertex,
                            classNamesForVertex: clsMap,
                            F: F
                        });
                    }),
                    lastItem = loading.prev();

                loading.before(added);

                var total = data.total || this.attr.total || 0;
                if (total === this.$node.find('.vertex-item').length) {
                    loading.remove();
                    this.attr.infiniteScrolling = false;
                } else {
                    this.triggerInfiniteScrollRequest();
                }

                this.loadVisibleResultPreviews();

                this.applyDraggable(this.$node.find('a'));
            }
        };

        this.loadVisibleResultPreviews = function() {
            var self = this;

            this.disableHover = false;

            var lisVisible = this.$node.find('.nav-list').children('li');
            if (this.scrollNode.length) {
                lisVisible = lisVisible.withinScrollable(this.scrollNode);
            }

            lisVisible.each(function() {
                var li = $(this),
                    vertex = appData.vertex(li.data('vertexId'));

                if (vertex && !li.data('previewLoaded')) {

                    var preview = li.data('previewLoaded', true)
                                    .find('.preview');

                    if (vertex.imageFramesSrc) {
                        VideoScrubber.attachTo(preview, {
                            posterFrameUrl: vertex.imageSrc,
                            videoPreviewImageUrl: vertex.imageFramesSrc
                        });
                    } else {
                        preview.css('background-image', 'url(' + vertex.imageSrc + ')');
                    }
                }
            });
        };

        this.applyDraggable = function(el) {
            var self = this;

            el.draggable({
                helper: 'clone',
                appendTo: 'body',
                revert: 'invalid',
                revertDuration: 250,
                scroll: false,
                zIndex: 100,
                distance: 10,
                multi: true,
                otherDraggablesClass: 'vertex-dragging',
                start: function(ev, ui) {
                    $(ui.helper).addClass('vertex-dragging');
                },
                selection: function(ev, ui) {
                    self.selectItems(ui.selected);
                }
            });
        };

        this.selectItems = function(items) {
            var vertices = appData.vertices(items.map(function() {
                    return $(this).data('vertexId');
                }).toArray());

            if (vertices.length > 1) {
                vertices.forEach(function(vertex) {
                    vertex.workspace = {
                        selected: true
                    };
                });
            }
            if (vertices.length === 0) {
                return;
            }
            this.trigger(document, 'defocusVertices');
            this.trigger('selectObjects', { vertices: vertices });
        };

        this.onWorkspaceLoaded = function(evt, workspace) {
            this.onVerticesUpdated(evt, workspace.data || {});
        };

        // Track changes to vertices so we display the "Displayed in Graph" icon
        // in search results
        this.toggleItemIcons = function(id, data) {
            this.$node
                .find('li.' + this.vertexIdToClassName(id))
                .toggleClass('graph-displayed', data.inGraph)
                .toggleClass('map-displayed', data.inMap);
        };

        // Switching workspaces should clear the icon state and vertices
        this.onWorkspaceClear = function() {
            this.$node.find('li.graph-displayed').removeClass('graph-displayed');
            this.$node.find('li.map-displayed').removeClass('map-displayed');
        };

        this.onVerticesUpdated = function(event, data) {
            var self = this;
            (data.vertices || []).forEach(function(vertex) {
                self.toggleItemIcons(vertex.id, self.stateForVertex(vertex));
                var li = self.$node.find('li.' + self.vertexIdToClassName(vertex.id)),
                    currentAnchor = li.children('a'),
                    newAnchor = $(vertexTemplate({
                        vertex: vertex,
                        classNamesForVertex: self.classNameMapForVertices([vertex]),
                        F: F
                    })).children('a'),
                    currentHtml = currentAnchor.html(),
                    src = vertex.imageSrc,
                    showImageSrc = src && !vertex.imageSrcIsFromConcept;

                if (currentAnchor.length) {
                    if (showImageSrc) {
                        $('<img/>').attr('src', src).appendTo(newAnchor.find('.preview'));
                    }

                    var newHtml = newAnchor.html();
                    if (currentAnchor.length && newHtml !== currentHtml) {
                        li.data('previewLoaded', null);
                    }
                }
            });

            this.loadVisibleResultPreviews();
        };

        this.onVerticesDeleted = function(event, data) {
            var self = this;
            (data.vertices || []).forEach(function(vertex) {
                self.toggleItemIcons(vertex.id, { inGraph: false, inMap: false });
            });
        };

        this.onObjectsSelected = function(event, data) {
            this.$node.find('.active').removeClass('active');

            var self = this,
                ids = _.chain(data.vertices)
                    .map(function(v) {
                        return '.' + self.vertexIdToClassName(v.id);
                    })
                    .value().join(',');

            $(ids, this.node).addClass('active');
        };
    }
});
<|endoftext|>


<commit_before>'use strict';
var logger = require('../logger'),
async = require('async'),
crypto = require('crypto'),
nodemailer = require('nodemailer'),
util = require('util'),
config = require('config').email,
addTags = function (req, tag1, tag2, tag3, cb) {
  var tagValues = [ 30, 20, 10];

  async.parallel([

    function (done) {
      req.app.get('database').model.Tag.findOrCreate({"name": tag1}).success(function (item) {
        item.increment('count', tagValues[0]).success(function () {
          done();
        }).failure(function (err) { cb(err); });
      }).failure(function (err) { cb(err); });
    },
    function (done) {
      req.app.get('database').model.Tag.findOrCreate({"name": tag2}).success(function (item) {
        item.increment('count', tagValues[1]).success(function () {
          done();
        }).failure(function (err) { cb(err); });
      }).failure(function (err) { cb(err); });
    },
    function (done) {
      req.app.get('database').model.Tag.findOrCreate({"name": tag3}).success(function (item) {
        item.increment('count', tagValues[2]).success(function () {
          done();
        }).failure(function (err) { cb(err); });
      }).failure(function (err) { cb(err); });
    }], function (err) {
      cb(err);
    });
},
welcomeEmail = function (to, token, done) {

  var options = {},
  smtpTransport,
  body;
  options.host = config.smtpHost;
  options.secureConnection = config.secureConnection;
  options.port = config.port;
  if (config.auth) {
    options.auth = config.auth;
  }

  smtpTransport = nodemailer.createTransport("SMTP", options);

  body = 'Sie haben sich zum BarCamp erfolgreich angemeldet.\n' +
  'Um sich wieder abzumelden verwenden Sie bitte folgenden Link:\n\n' +
  'http://barcamp.seepaul.org/cancel/' + token + '\n\n';

  smtpTransport.sendMail({
    from: config.sender,
    to: to,
    subject: config.subjectWelcome,
    text: body
  }, function (error, response) {
    if (error) {
      console.log(error);
      smtpTransport.close();
      done(error);
    } else {
      logger.info("Message sent: " + response.message);
      smtpTransport.close();
      done(null);
    }
  });
};

exports.add = function (req, res, next) {

  req.assert('tag1', 'Invalid input').notEmpty().tag();
  req.assert('tag2', 'Invalid input').notEmpty().tag();
  req.assert('tag3', 'Invalid input').notEmpty().tag();

  if (req.validationErrors()) {
    next(new Error('Malformed input'));
  }

  addTags(req, req.body.tag1, req.body.tag2, req.body.tag3, function (err) {
    if (err) { next(err); }
    res.render('form');
  });
};

exports.doRegister = function (req, res, next) {

  console.log(req.body);

  req.assert('firstName', 'Invalid input.').notEmpty().validName();
  req.assert('lastName', 'Invalid input.').optional().validName();
  req.assert('email', 'Invalid input').notEmpty().isEmail();
  req.assert('tag1', 'Invalid input').notEmpty().tag();
  req.assert('tag2', 'Invalid input').notEmpty().tag();
  req.assert('tag3', 'Invalid input').notEmpty().tag();
  req.assert('preferredCamp').optional().isIn(['uxcamp', 'politcamp', 'startcamp', 'designcamp', 'appdevcamp', 'wissenscamp']);
  req.assert('shirtSize').optional().isIn(['S', 'M', 'L', 'XL', 'none']);
  req.assert('note', 'Invalid input').optional();
  req.assert('children', 'Invalid input').optional();
  req.assert('newcomer', 'Invalid input').optional();

  var errors = req.validationErrors();

  if (errors) {
    res.send('There have been validation errors: ' + util.inspect(errors), 400);
    return;
  }

  req.sanitize('email').normalizeEmail();

  crypto.randomBytes(20, function (err, buf) {
    if (err) { next(err); }
    var token = buf.toString('hex');

    req.app.get('database').model.User.create({
      firstName: req.body.firstName,
      lastName: req.body.lastName,
      email: req.body.email,
      token: token,
      preferredCamp: req.body.preferredCamp,
      shirtSize: req.body.shirtSize,
      note: req.body.note,
      children: req.body.children,
      newcomer: req.body.newcomer
    }).success(function () {

      welcomeEmail(req.body.email, token, function () {
        res.render('thankyou');
      });

      /* ERROR */
      /*addTags(req, req.body.tag1, req.body.tag2, req.body.tag3, function (err) {
        if (err) { next(err); }

        welcomeEmail(req.body.email, token, function () {
          res.render('thankyou');
        });

  });*/

    }).error(next);
  });
};

exports.cancelRegistration = function (req, res, next) {

  req.assert('token', 'Invalid Input.').notEmpty().isHexadecimal();

  if (req.validationErrors()) {
    next(new Error('Malformed input'));
  }

  req.app.get('database').model.User.find({ where: { token: req.params.token } }).success(function (user) {
    if (!user) {
      next(new Error('Password reset token is invalid or has expired.'));
    }

    user.destroy().success(function () {
      res.render('cancel');
    });

  });

};
<commit_msg>coding standard<commit_after>'use strict';
var logger = require('../logger'),
  async = require('async'),
  crypto = require('crypto'),
  nodemailer = require('nodemailer'),
  util = require('util'),
  config = require('config').email,
  addTags = function (req, tag1, tag2, tag3, cb) {
    var tagValues = [ 30, 20, 10];

    async.parallel([

      function (done) {
        req.app.get('database').model.Tag.findOrCreate({"name": tag1}).success(function (item) {
          item.increment('count', tagValues[0]).success(function () {
            done();
          }).failure(function (err) { cb(err); });
        }).failure(function (err) { cb(err); });
      },
      function (done) {
        req.app.get('database').model.Tag.findOrCreate({"name": tag2}).success(function (item) {
          item.increment('count', tagValues[1]).success(function () {
            done();
          }).failure(function (err) { cb(err); });
        }).failure(function (err) { cb(err); });
      },
      function (done) {
        req.app.get('database').model.Tag.findOrCreate({"name": tag3}).success(function (item) {
          item.increment('count', tagValues[2]).success(function () {
            done();
          }).failure(function (err) { cb(err); });
        }).failure(function (err) { cb(err); });
      }], function (err) {
      cb(err);
    });
  },
  welcomeEmail = function (to, token, done) {

    var options = {},
      smtpTransport,
      body;
    options.host = config.smtpHost;
    options.secureConnection = config.secureConnection;
    options.port = config.port;
    if (config.auth) {
      options.auth = config.auth;
    }

    smtpTransport = nodemailer.createTransport("SMTP", options);

    body = 'Sie haben sich zum BarCamp erfolgreich angemeldet.\n' +
      'Um sich wieder abzumelden verwenden Sie bitte folgenden Link:\n\n' +
      'http://barcamp.seepaul.org/cancel/' + token + '\n\n';

    smtpTransport.sendMail({
      from: config.sender,
      to: to,
      subject: config.subjectWelcome,
      text: body
    }, function (error, response) {
      if (error) {
        console.log(error);
        smtpTransport.close();
        done(error);
      } else {
        logger.info("Message sent: " + response.message);
        smtpTransport.close();
        done(null);
      }
    });
  };

exports.add = function (req, res, next) {

  req.assert('tag1', 'Invalid input').notEmpty().tag();
  req.assert('tag2', 'Invalid input').notEmpty().tag();
  req.assert('tag3', 'Invalid input').notEmpty().tag();

  if (req.validationErrors()) {
    next(new Error('Malformed input'));
  }

  addTags(req, req.body.tag1, req.body.tag2, req.body.tag3, function (err) {
    if (err) { next(err); }
    res.render('form');
  });
};

exports.doRegister = function (req, res, next) {

  console.log(req.body);

  req.assert('firstName', 'Invalid input.').notEmpty().validName();
  req.assert('lastName', 'Invalid input.').optional().validName();
  req.assert('email', 'Invalid input').notEmpty().isEmail();
  req.assert('tag1', 'Invalid input').notEmpty().tag();
  req.assert('tag2', 'Invalid input').notEmpty().tag();
  req.assert('tag3', 'Invalid input').notEmpty().tag();
  req.assert('preferredCamp').optional().isIn(['uxcamp', 'politcamp', 'startcamp', 'designcamp', 'appdevcamp', 'wissenscamp']);
  req.assert('shirtSize').optional().isIn(['S', 'M', 'L', 'XL', 'none']);
  req.assert('note', 'Invalid input').optional();
  req.assert('children', 'Invalid input').optional();
  req.assert('newcomer', 'Invalid input').optional();

  var errors = req.validationErrors();

  if (errors) {
    res.send('There have been validation errors: ' + util.inspect(errors), 400);
    return;
  }

  req.sanitize('email').normalizeEmail();

  crypto.randomBytes(20, function (err, buf) {
    if (err) { next(err); }
    var token = buf.toString('hex');

    req.app.get('database').model.User.create({
      firstName: req.body.firstName,
      lastName: req.body.lastName,
      email: req.body.email,
      token: token,
      preferredCamp: req.body.preferredCamp,
      shirtSize: req.body.shirtSize,
      note: req.body.note,
      children: req.body.children,
      newcomer: req.body.newcomer
    }).success(function () {

      welcomeEmail(req.body.email, token, function () {
        res.render('thankyou');
      });

      /* ERROR */
      /*addTags(req, req.body.tag1, req.body.tag2, req.body.tag3, function (err) {
        if (err) { next(err); }

        welcomeEmail(req.body.email, token, function () {
          res.render('thankyou');
        });

  });*/

    }).error(next);
  });
};

exports.cancelRegistration = function (req, res, next) {

  req.assert('token', 'Invalid Input.').notEmpty().isHexadecimal();

  if (req.validationErrors()) {
    next(new Error('Malformed input'));
  }

  req.app.get('database').model.User.find({ where: { token: req.params.token } }).success(function (user) {
    if (!user) {
      next(new Error('Password reset token is invalid or has expired.'));
    }

    user.destroy().success(function () {
      res.render('cancel');
    });

  });

};
<|endoftext|>


<commit_before>var tag = document.createElement('script');
		tag.src = 'https://www.youtube.com/player_api';
var firstScriptTag = document.getElementsByTagName('script')[0];
		firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var tv,
		playerDefaults = {autoplay: 0, autohide: 1, modestbranding: 0, rel: 0, showinfo: 0, controls: 0, disablekb: 1, enablejsapi: 0, iv_load_policy: 3};
var vid = [
			{'videoId': 'EmnSm_d2ll4', 'startSeconds': 0, 'endSeconds': 276, 'suggestedQuality': 'hd720'}//,
			/*
			{'videoId': 'F4gJsKZvqE4', 'startSeconds': 0, 'endSeconds': 148, 'suggestedQuality': 'hd720'},
			{'videoId': 'RfJgT89hEME', 'startSeconds': 0, 'endSeconds': 160, 'suggestedQuality': 'hd720'},
			{'videoId': 'ViuDsy7yb8M', 'startSeconds': 0, 'endSeconds': 139, 'suggestedQuality': 'hd720'},
			{'videoId': 'gLJdzky63BA', 'startSeconds': 6, 'endSeconds': 152, 'suggestedQuality': 'hd720'},
			{'videoId': 'deSRpSn8Pyk', 'startSeconds': 0, 'endSeconds': 121, 'suggestedQuality': 'hd720'},
			{'videoId': 'QEAW49qjBtc', 'startSeconds': 2, 'endSeconds': 30, 'suggestedQuality': 'hd720'}
			*/
		],
		randomvid = Math.floor(Math.random() * (vid.length - 1 + 1));

function onYouTubePlayerAPIReady(){
  tv = new YT.Player('tv', {events: {'onReady': onPlayerReady, 'onStateChange': onPlayerStateChange}, playerVars: playerDefaults});
}

function onPlayerReady(){
  tv.loadVideoById(vid[randomvid]);
  tv.mute();
}

function onPlayerStateChange(e) {
  if (e.data === 1){
    $('#tv').addClass('active');
  } else if (e.data === 0){
    tv.seekTo(vid[randomvid].startSeconds)
  }
}

function vidRescale(){

  var w = $(window).width()+200,
    h = $(window).height()+200;

  if (w/h > 16/9){
    tv.setSize(w, w/16*9);
    $('.tv .screen').css({'left': '0px'});
  } else {
    tv.setSize(h/9*16, h);
    $('.tv .screen').css({'left': -($('.tv .screen').outerWidth()-w)/2});
  }
}

$(window).on('load resize', function(){
  vidRescale();
});

$('.hi span').on('click', function(){
  $('#tv').toggleClass('mute');
  if($('#tv').hasClass('mute')){
    tv.mute();
  } else {
    tv.unMute();
  }
});
<commit_msg>Delete landing.js<commit_after><|endoftext|>


<commit_before>/*global $:Cookies */
function toggleRollup(c_name) {
    // Check whether user has consented to cookie usage
    if (Cookies.get('cb-enabled') === "accepted") {
        if (Cookies.get("rollup_" + c_name) === "hidden") {
		    $(c_name).show("blind");
            Cookies.get("rollup_" + c_name, "shown");
        } else {
		    $(c_name).hide("blind");
            Cookies.get("rollup_" + c_name, "hidden");
        }
    } else {
        $(c_name).toggle("blind");
    }
}
<commit_msg>Changes JSHint settings<commit_after>/*jshint unused:false */
/*global Cookies */
function toggleRollup(c_name) {
    // Check whether user has consented to cookie usage
    if (Cookies.get('cb-enabled') === "accepted") {
        if (Cookies.get("rollup_" + c_name) === "hidden") {
		    $(c_name).show("blind");
            Cookies.get("rollup_" + c_name, "shown");
        } else {
		    $(c_name).hide("blind");
            Cookies.get("rollup_" + c_name, "hidden");
        }
    } else {
        $(c_name).toggle("blind");
    }
}
<|endoftext|>


<commit_before>(function () {

	$.extend(ch.util, {

		/**
		 * Reference to the index page
		 * @name $mainView
		 * @memberOf ch.util
		 * @type {Selector}
		 */
		'$mainView': (function () {
			var $view = $('div[data-page=index]');

			if ($view.length === 0) {
				alert('Chico Mobile Error\n$mainView: The document doesn\'t contain an index "page" view.');
				throw new Error('Chico Mobile Error\n$mainView: The document doesn\'t contain an index "page" view.');
			}

			return $view;
		}()),

		/**
		 * Fixes the broken iPad/iPhone form label click issue.
		 * @name fixLabels
		 * @methodOf ch.util
		 * @see Based on: http://www.quirksmode.org/dom/getstyles.html
		 */
		'fixLabels': function () {
			var labels = document.getElementsByTagName('label'),
				target_id,
				el,
				i = 0;

			function labelClick() {
				el = document.getElementById(this.getAttribute('for'));
				if (['radio', 'checkbox'].indexOf(el.getAttribute('type')) != -1) {
					el.setAttribute('selected', !el.getAttribute('selected'));
				} else {
					el.focus();
				}
			}

			for (; labels[i]; i += 1) {
				if (labels[i].getAttribute('for')) {
					$(labels[i]).bind(ch.events.TAP, labelClick);
				}
			}
		},

		/*!
		 * MBP - Mobile boilerplate helper functions
		 * @name MBP
		 * @memberOf ch.util
		 * @namespace
		 * @see View on https://github.com/h5bp/mobile-boilerplate
		 */
		'MBP': {

			// Fix for iPhone viewport scale bug
			// http://www.blog.highub.com/mobile-2/a-fix-for-iphone-viewport-scale-bug/
			'viewportmeta': $('meta[name=viewport]'),

			'gestureStart': function () {
				ch.util.MBP.viewportmeta.content = 'width=device-width, minimum-scale=0.25, maximum-scale=1.6';
			},

			'scaleFix': function () {
				if (ch.util.MBP.viewportmeta && /iPhone|iPad|iPod/.test(userAgent) && !/Opera Mini/.test(userAgent)) {
					ch.util.MBP.viewportmeta.content = 'width=device-width, minimum-scale=1.0, maximum-scale=1.0';
					document.addEventListener('gesturestart', ch.util.MBP.gestureStart, false);
				}
			},

			/*
			* Normalized hide address bar for iOS & Android
			* (c) Scott Jehl, scottjehl.com
			* MIT License
			*/
			// If we cache this we don't need to re-calibrate everytime we call
			// the hide url bar
			'BODY_SCROLL_TOP': false,

			// So we don't redefine this function everytime we
			// we call hideUrlBar
			'getScrollTop': function () {
				return window.pageYOffset || document.compatMode === 'CSS1Compat' && document.documentElement.scrollTop || document.body.scrollTop || 0;
			},

			// It should be up to the mobile
			'hideUrlBar': function () {
				// if there is a hash, or MBP.BODY_SCROLL_TOP hasn't been set yet, wait till that happens
				if (!window.location.hash && ch.util.MBP.BODY_SCROLL_TOP !== false) {
					window.scrollTo( 0, ch.util.MBP.BODY_SCROLL_TOP === 1 ? 0 : 1 );
				}
			},

			'hideUrlBarOnLoad': function () {
				// If there's a hash, or addEventListener is undefined, stop here
				if( !window.location.hash && window.addEventListener ) {

					//scroll to 1
					window.scrollTo(0, 1);
					ch.util.MBP.BODY_SCROLL_TOP = 1;

					//reset to 0 on bodyready, if needed
					var bodycheck = setInterval(function () {
						if(body) {
							clearInterval(bodycheck);
							ch.util.MBP.BODY_SCROLL_TOP = ch.util.MBP.getScrollTop();
							ch.util.MBP.hideUrlBar();
						}
					}, 15 );

					window.addEventListener('load', function() {
						setTimeout(function () {
							//at load, if user hasn't scrolled more than 20 or so...
							if(ch.util.MBP.getScrollTop() < 20) {
								//reset to hide addr bar at onload
								ch.util.MBP.hideUrlBar();
							}
						}, 0);
					});
				}
			},

			// Prevent iOS from zooming onfocus
			// https://github.com/h5bp/mobile-boilerplate/pull/108
			'preventZoom': function () {
				var formFields = $('input, select, textarea'),
					contentString = 'width=device-width,initial-scale=1,maximum-scale=',
					i = 0;
				for (; i < formFields.length; i += 1) {

					formFields[i].onfocus = function() {
						ch.util.MBP.viewportmeta.content = contentString + '1';
					};

					formFields[i].onblur = function () {
						ch.util.MBP.viewportmeta.content = contentString + '10';
					};
				}
			}
		}

	});

}());<commit_msg>GH-896 Change ch.events.TAP by ch.events.pointer.TAP<commit_after>(function () {

	$.extend(ch.util, {

		/**
		 * Reference to the index page
		 * @name $mainView
		 * @memberOf ch.util
		 * @type {Selector}
		 */
		'$mainView': (function () {
			var $view = $('div[data-page=index]');

			if ($view.length === 0) {
				alert('Chico Mobile Error\n$mainView: The document doesn\'t contain an index "page" view.');
				throw new Error('Chico Mobile Error\n$mainView: The document doesn\'t contain an index "page" view.');
			}

			return $view;
		}()),

		/**
		 * Fixes the broken iPad/iPhone form label click issue.
		 * @name fixLabels
		 * @methodOf ch.util
		 * @see Based on: http://www.quirksmode.org/dom/getstyles.html
		 */
		'fixLabels': function () {
			var labels = document.getElementsByTagName('label'),
				target_id,
				el,
				i = 0;

			function labelClick() {
				el = document.getElementById(this.getAttribute('for'));
				if (['radio', 'checkbox'].indexOf(el.getAttribute('type')) != -1) {
					el.setAttribute('selected', !el.getAttribute('selected'));
				} else {
					el.focus();
				}
			}

			for (; labels[i]; i += 1) {
				if (labels[i].getAttribute('for')) {
					$(labels[i]).bind(ch.events.pointer.TAP, labelClick);
				}
			}
		},

		/*!
		 * MBP - Mobile boilerplate helper functions
		 * @name MBP
		 * @memberOf ch.util
		 * @namespace
		 * @see View on https://github.com/h5bp/mobile-boilerplate
		 */
		'MBP': {

			// Fix for iPhone viewport scale bug
			// http://www.blog.highub.com/mobile-2/a-fix-for-iphone-viewport-scale-bug/
			'viewportmeta': $('meta[name=viewport]'),

			'gestureStart': function () {
				ch.util.MBP.viewportmeta.content = 'width=device-width, minimum-scale=0.25, maximum-scale=1.6';
			},

			'scaleFix': function () {
				if (ch.util.MBP.viewportmeta && /iPhone|iPad|iPod/.test(userAgent) && !/Opera Mini/.test(userAgent)) {
					ch.util.MBP.viewportmeta.content = 'width=device-width, minimum-scale=1.0, maximum-scale=1.0';
					document.addEventListener('gesturestart', ch.util.MBP.gestureStart, false);
				}
			},

			/*
			* Normalized hide address bar for iOS & Android
			* (c) Scott Jehl, scottjehl.com
			* MIT License
			*/
			// If we cache this we don't need to re-calibrate everytime we call
			// the hide url bar
			'BODY_SCROLL_TOP': false,

			// So we don't redefine this function everytime we
			// we call hideUrlBar
			'getScrollTop': function () {
				return window.pageYOffset || document.compatMode === 'CSS1Compat' && document.documentElement.scrollTop || document.body.scrollTop || 0;
			},

			// It should be up to the mobile
			'hideUrlBar': function () {
				// if there is a hash, or MBP.BODY_SCROLL_TOP hasn't been set yet, wait till that happens
				if (!window.location.hash && ch.util.MBP.BODY_SCROLL_TOP !== false) {
					window.scrollTo( 0, ch.util.MBP.BODY_SCROLL_TOP === 1 ? 0 : 1 );
				}
			},

			'hideUrlBarOnLoad': function () {
				// If there's a hash, or addEventListener is undefined, stop here
				if( !window.location.hash && window.addEventListener ) {

					//scroll to 1
					window.scrollTo(0, 1);
					ch.util.MBP.BODY_SCROLL_TOP = 1;

					//reset to 0 on bodyready, if needed
					var bodycheck = setInterval(function () {
						if(body) {
							clearInterval(bodycheck);
							ch.util.MBP.BODY_SCROLL_TOP = ch.util.MBP.getScrollTop();
							ch.util.MBP.hideUrlBar();
						}
					}, 15 );

					window.addEventListener('load', function() {
						setTimeout(function () {
							//at load, if user hasn't scrolled more than 20 or so...
							if(ch.util.MBP.getScrollTop() < 20) {
								//reset to hide addr bar at onload
								ch.util.MBP.hideUrlBar();
							}
						}, 0);
					});
				}
			},

			// Prevent iOS from zooming onfocus
			// https://github.com/h5bp/mobile-boilerplate/pull/108
			'preventZoom': function () {
				var formFields = $('input, select, textarea'),
					contentString = 'width=device-width,initial-scale=1,maximum-scale=',
					i = 0;
				for (; i < formFields.length; i += 1) {

					formFields[i].onfocus = function() {
						ch.util.MBP.viewportmeta.content = contentString + '1';
					};

					formFields[i].onblur = function () {
						ch.util.MBP.viewportmeta.content = contentString + '10';
					};
				}
			}
		}

	});

}());<|endoftext|>


<commit_before>/**:showChartType( type, containerID )

    Hides div elements inside the container that don't have a class with the given type.
    Requires a container element with ID 'containerID' holding divs with class 'chart'.
    These divs with class 'chart' also have a class that determines type, e.g. 'bar' or 'pie'
    This function is practically used to switch between bar and pie charts.

    :param string type:
        The class of the HTML element holding the chart to be shown.
        The HTML element must also have a class of chart.
    :param string containerID:
        The ID of the HTML holding the different charts.
        Each element holding a chart in the container must have a class of both "chart"
        and an identifying type e.g. "bar" or "pie".

*/
function showChartType( type, containerID ){
  $('#'+containerID+' .chart').not('.'+type).addClass('hidden');
  $('#'+containerID+' .'+type).removeClass('hidden');
}

/**:drawBarChart( containerID, data, percent )

    Draws a bar chart in the DOM element with the given containerID using the
    data in the given data object. If percent is set to true, we use percentage rather than numbers.

    :param string containerID:
        The ID of the HTML element to hold the chart.
    :param object data:
        The data object as built by the misc.js function `makeDataObject()`.
    :param boolean percent:
        If true, data will be first converted to percentages, where each datum become the its
        percentage of the total data set: (datum value/total value)*100.
 */
function drawBarChart( containerID, data, percent ){

  console.log( data );

  //We want to work with a clone of the data, not the data itself.
  data = $.extend(true, {}, data);

  //Hack to get plot to size correctly when being drawn into a hidden object.
  //If the object is hidden, set the plot width to the inner width of the parent.
  //Otherwise, leave as undefined as specified in the highcharts api.
  var plotWidth;
  if( $('#'+containerID).hasClass('hidden') ){
    plotWidth = $('#'+containerID).parent().width();
  }

  var tooltip = function(){
    return this.series.name + ': ' + this.point.y;
  };
  var units = 'Number';
  //If percent is set to true, convert data to percentages and store both in the data object.
  //This means both percent and count can be referenced in tooltip.
  if( percent ){

    data.week_val = data.week;
    data.year_val = data.year;
    data.week = calc_percent_dist(data.week);
    data.year = calc_percent_dist(data.year);
    data.week = data.week.map( function (e, i) { return {"y":e, "val": data.week_val[i] }; });
    data.year = data.year.map( function (e, i) { return {"y":e, "val": data.year_val[i] }; });

    units=i18n.gettext('Percent %');
    tooltip = function (){
      return this.series.name + ': ' + this.point.y + '% (' + this.point.val + ')';
    };
  }

  $('#'+containerID).highcharts({
    chart: {
      type: 'column',
      width: plotWidth
    },
    title: '',
    tooltip: {
      formatter: tooltip
    },
    xAxis: {
      categories: data.labels,
      title: {
        text: null
      }
    },
    yAxis: {
      min: 0,
      title: {
        text: units,
        align: 'high'
      },
      labels: {
        overflow: 'justify'
      }
    },
    series: [{
      name: i18n.gettext('This Year'),
      data:  data.year
    },{
      name: i18n.gettext('This Week'),
      data:  data.week
    }],
  });

  //Get rid of the highcharts logo.
  $( '#'+containerID+" text:contains('Highcharts.com')" ).remove();

}

/**:drawPieCharts( containerID, data, percent )

    Draws pie charts in the DOM element with the given containerID using the
    data in the given data object. If percent is set to true, we use percentage rather than numbers.
    Two pie charts are drawn, one for the previous week, and one for the cumulative total during the
    current year.

    :param string containerID:
        The ID of the HTML element to hold the chart.
    :param object data:
        The data object as built by the misc.js function `makeDataObject()`.
    :param boolean percent:
        If true, data will first be converted to percentages, where each datum become the its
        percentage of the total data set: (datum value/total value)*100.
 */
function drawPieCharts( containerID, data, percent ){

  //We want to work with a clone of the data, not the data itself.
  data = $.extend(true, {}, data);

  //Hack to get plot to size correctly when being drawn into a hidden object.
  //If the object is hidden, set the plot width to the inner width of the parent.
  //Otherwise, leave as undefined (as specified in the highcharts api).
  var plotWidth;
  if( $('#'+containerID).hasClass('hidden') ){
    plotWidth = $('#'+containerID).parent().width();
  }
  var restructured = {};
  var units = 'Number';
  var tooltip = function(){
    return this.series.name + ': ' + this.point.y;
  };
  //If percent is set to true, convert data to percentages and store both in the data object.
  //This means both percent and count can be referenced in tooltip.
  if( percent ){

    data.week_val = data.week;
    data.year_val = data.year;
    data.week = calc_percent_dist(data.week);
    data.year = calc_percent_dist(data.year);

    //Restructure the data object for pie charts.
    restructured.week = data.week.map( function (e, i) {
      return {name: data.labels[i], y:e, val: data.week_val[i] };
    });
    restructured.year = data.year.map( function (e, i) {
      return {name: data.labels[i], y:e, val: data.year_val[i] };
    });

    units=i18n.gettext('Percent %');
    tooltip = function (){
      return this.series.name + ': ' + this.point.y + '% (' + this.point.val + ')';
    };

  }else{
    //Restructure the data object for pie charts.
    restructured = {week:[], year:[]};
    for( var i=0; i<data.labels.length; i++ ){
      restructured.week[i] = { name: data.labels[i], y: data.week[i] };
      restructured.year[i] = { name: data.labels[i], y: data.year[i] };
    }
  }

  //Draw the graph.
  $( '#'+containerID ).highcharts({
    chart: {
      plotBackgroundColor: null,
      plotBorderWidth: null,
      plotShadow: false,
      type: 'pie',
      width: plotWidth
    },
    title: '',
    tooltip: {
      formatter:tooltip
    },
    plotOptions: {
      pie: {
        allowPointSelect: true,
        cursor: 'pointer',
        dataLabels: {
          enabled: false
        },
        showInLegend: true
      }
    },
    series: [{
      name: i18n.gettext('This Week'),
      center: ['20%','50%'],
      size: "70%",
      colorByPoint: true,
      showInLegend:true,
      title: { text: 'Week', verticalAlign: 'top', y: -40 },
      data: restructured.week
    },{
      name: i18n.gettext('This Year'),
      center: ['80%','50%'],
      size: "70%",
      colorByPoint: true,
      showInLegend:false,
      title: { text: 'Year', verticalAlign: 'top', y: -40 },
      data: restructured.year
    }]
  });

  //Get rid of the highcharts.com logo.
  $( '#'+containerID+" text:contains('Highcharts.com')" ).remove();

}

/**:drawTimeCharts( varID, locID, containerID )

    Draws a timeline bar chart showing the number of cases in each epi week this current year.

    :param string varID:
        The ID of the variable to be plotted (taken from Meerkat Abacus).
    :param string locID:
        The ID of the location by which to filter the data.
    :param string containerID:
        The ID of the HTML element to hold the chart.
 */
function drawTimeChart( varID, locID, containerID ){

  $.getJSON( api_root + '/aggregate_year/' + varID + '/'+locID, function(data){

      console.log('DRAW TIME CHART');
      console.log('Time series data for diseases:');
      console.log(data);
    var labels = [];
    var values = [];

    for( var i = 1; i <= get_epi_week(); i++ ){

      labels.push(i.toString());

      if( typeof(data.weeks[i]) !== 'undefined' ){
        values.push( data.weeks[i] );
      }else{
        values.push( 0 );
      }

    }

    //Hack to get plot to size correctly when being drawn into a hidden object.
    //If the object is hidden, set the plot width to the inner width of the parent.
    //Otherwise, leave as undefined as specified in the highcharts api.
    var plotWidth;
    if( $('#'+containerID).hasClass('hidden') ){
      plotWidth = $('#'+containerID).parent().width();
    }

    $('#'+containerID).highcharts({
    chart: {
      type: 'column',
      width: plotWidth
    },
    title: '',
    xAxis: {
      categories: labels,
      title: {
        text: i18n.gettext('Epidemiological Week')
      }
    },
    legend:{ enabled:false },
    yAxis: {
      min: 0,
      title: {
        text: i18n.gettext('Number of Reported Cases'),
        align: 'high'
      },
      labels: {
        overflow: 'justify'
      }
    },
    series: [{
      name: 'Year',
      data:  values
    }],
    });

    //Get rid of the highcharts logo.
    $( '#'+containerID+" text:contains('Highcharts.com')" ).remove();
  });

}

/**:drawCompletenessGraph( containerID, locID )

   Draws a timeline line chart showing the percentage of overall completeness and completeness for each clinic in each epi week this current year.
   :param string containerID:
   The ID of the HTML element to hold the chart.
   :param string locID:
   The ID of the location by which to filter the data.
*/
function drawCompletenessGraph( containerID, regionID ){
    $.getJSON( api_root+"/locations", function( locations ){
        $.getJSON( api_root+"/completeness/reg_1/" + regionID + "/5", function( data ){
            //create a data series for each location
            var dataPrepared = [];
            var timeseries = [];
            var scoreKeys = Object.keys(data.timeline);
            var index = 0;
            for (var i=0; i<scoreKeys.length;i++){
                index = scoreKeys[scoreKeys.length - i -1];
                tl = data.timeline[index];
                var dt = [];
                var dtReady = [];
                var noWeeks = tl.weeks.length;
                var weeks = lastWeeks (get_epi_week(), noWeeks +1 ); //last completeness is from previous week
                //dropping the very last week in the data since we can only estimate it's completeness
                for (var j = 1; j < noWeeks; j++){
                    dt = [weeks[noWeeks - j],Number(Number(10 * (tl.values[j-1] + tl.values[j])).toFixed(0))];
                    dtReady.push(dt);
                         }

                var datum = {
                    name: locations[index].name,
                    data: dtReady,
                    color: 'grey'
                };

                if(locations[index].id === regionID){ //parent location
                    datum.color= 'rgb(100,0,221)';
                }
                timeseries.push(datum);
            }

            //hovering should give all the information about given clinick and sublocation
            $('#' + containerID).highcharts({
                chart: {
                    type: 'spline'
                },
                title: {
                    text: ''
                },
                legend:{ enabled:false },
                xAxis: {
                    title: {
                        text: 'EPI week'
                    },
                    labels: {
                        overflow: 'justify'
                    },
                    allowDecimals: false
                },
                yAxis: {
                    max: 100,
                    title: {
                        text: 'Completness'
                    },
                    minorGridLineWidth: 0,
                    gridLineWidth: 0,
                    alternateGridColor: null,
                    plotBands: [{ //RED
                        from: 0,
                        to: 50,
                        color: 'rgba(255, 0, 0, 0.5)'
                    }, { //YELLOW
                        from: 50,
                        to: 80,
                        color: 'rgba(255, 255, 0, 0.5)'
                    }, { // GREEN
                        from: 80,
                        to: 100,
                        color: 'rgba(0, 128, 0,0.5)'
                    }]
                },
                tooltip: {
                    valueSuffix: '%'
                },
                plotOptions: {
                    spline: {
                        lineWidth: 3,
                        states: {
                            hover: {
                                enabled: true,
                                lineWidth: 5
                            }
                        },
                        marker: {
                            enabled: false
                        },
                        pointStart:0,
                        events: {
                            mouseOver: function () {
                                if(this.chart.series[this.index].color === 'grey'){
                                    this.chart.series[this.index].update({
                                        color: 'blue'
                                    });
                                }
                            },
                            //http://forum.highcharts.com/highcharts-usage/how-do-i-change-line-colour-when-hovering-t35536/
                            mouseOut: function () {
                                if(this.chart.series[this.index].color === 'blue'){
                                    this.chart.series[this.index].update({
                                        color: "grey"
                                    });
                                }
                            }
                        }
                    }
                },
                series: timeseries,
                navigation: {
                    menuItemStyle: {
                        fontSize: '10px'
                    }
                }
            }); //highchart

        });//getJSON completeness
    });//getJSON locations
}

Highcharts.setOptions({
  colors: ["#0090CA", "#D9692A", "#89B6A5", "#e94f37", "#393e41", "#F1E8B8",
          "#CDEDF6", "#690500", "#77477B", "#40476D","#042A2B" ],
  chart: {
    backgroundColor: null,
    style: {
      fontFamily: 'Helvetica Neue", Helvetica, Arial, sans-serif'
    }
  },
  credits: {
    enabled: false
  },
  exporting: {
    enabled: false
  }

});

<commit_msg>display values weekly and change colours<commit_after>/**:showChartType( type, containerID )

    Hides div elements inside the container that don't have a class with the given type.
    Requires a container element with ID 'containerID' holding divs with class 'chart'.
    These divs with class 'chart' also have a class that determines type, e.g. 'bar' or 'pie'
    This function is practically used to switch between bar and pie charts.

    :param string type:
        The class of the HTML element holding the chart to be shown.
        The HTML element must also have a class of chart.
    :param string containerID:
        The ID of the HTML holding the different charts.
        Each element holding a chart in the container must have a class of both "chart"
        and an identifying type e.g. "bar" or "pie".

*/
function showChartType( type, containerID ){
  $('#'+containerID+' .chart').not('.'+type).addClass('hidden');
  $('#'+containerID+' .'+type).removeClass('hidden');
}

/**:drawBarChart( containerID, data, percent )

    Draws a bar chart in the DOM element with the given containerID using the
    data in the given data object. If percent is set to true, we use percentage rather than numbers.

    :param string containerID:
        The ID of the HTML element to hold the chart.
    :param object data:
        The data object as built by the misc.js function `makeDataObject()`.
    :param boolean percent:
        If true, data will be first converted to percentages, where each datum become the its
        percentage of the total data set: (datum value/total value)*100.
 */
function drawBarChart( containerID, data, percent ){

  console.log( data );

  //We want to work with a clone of the data, not the data itself.
  data = $.extend(true, {}, data);

  //Hack to get plot to size correctly when being drawn into a hidden object.
  //If the object is hidden, set the plot width to the inner width of the parent.
  //Otherwise, leave as undefined as specified in the highcharts api.
  var plotWidth;
  if( $('#'+containerID).hasClass('hidden') ){
    plotWidth = $('#'+containerID).parent().width();
  }

  var tooltip = function(){
    return this.series.name + ': ' + this.point.y;
  };
  var units = 'Number';
  //If percent is set to true, convert data to percentages and store both in the data object.
  //This means both percent and count can be referenced in tooltip.
  if( percent ){

    data.week_val = data.week;
    data.year_val = data.year;
    data.week = calc_percent_dist(data.week);
    data.year = calc_percent_dist(data.year);
    data.week = data.week.map( function (e, i) { return {"y":e, "val": data.week_val[i] }; });
    data.year = data.year.map( function (e, i) { return {"y":e, "val": data.year_val[i] }; });

    units=i18n.gettext('Percent %');
    tooltip = function (){
      return this.series.name + ': ' + this.point.y + '% (' + this.point.val + ')';
    };
  }

  $('#'+containerID).highcharts({
    chart: {
      type: 'column',
      width: plotWidth
    },
    title: '',
    tooltip: {
      formatter: tooltip
    },
    xAxis: {
      categories: data.labels,
      title: {
        text: null
      }
    },
    yAxis: {
      min: 0,
      title: {
        text: units,
        align: 'high'
      },
      labels: {
        overflow: 'justify'
      }
    },
    series: [{
      name: i18n.gettext('This Year'),
      data:  data.year
    },{
      name: i18n.gettext('This Week'),
      data:  data.week
    }],
  });

  //Get rid of the highcharts logo.
  $( '#'+containerID+" text:contains('Highcharts.com')" ).remove();

}

/**:drawPieCharts( containerID, data, percent )

    Draws pie charts in the DOM element with the given containerID using the
    data in the given data object. If percent is set to true, we use percentage rather than numbers.
    Two pie charts are drawn, one for the previous week, and one for the cumulative total during the
    current year.

    :param string containerID:
        The ID of the HTML element to hold the chart.
    :param object data:
        The data object as built by the misc.js function `makeDataObject()`.
    :param boolean percent:
        If true, data will first be converted to percentages, where each datum become the its
        percentage of the total data set: (datum value/total value)*100.
 */
function drawPieCharts( containerID, data, percent ){

  //We want to work with a clone of the data, not the data itself.
  data = $.extend(true, {}, data);

  //Hack to get plot to size correctly when being drawn into a hidden object.
  //If the object is hidden, set the plot width to the inner width of the parent.
  //Otherwise, leave as undefined (as specified in the highcharts api).
  var plotWidth;
  if( $('#'+containerID).hasClass('hidden') ){
    plotWidth = $('#'+containerID).parent().width();
  }
  var restructured = {};
  var units = 'Number';
  var tooltip = function(){
    return this.series.name + ': ' + this.point.y;
  };
  //If percent is set to true, convert data to percentages and store both in the data object.
  //This means both percent and count can be referenced in tooltip.
  if( percent ){

    data.week_val = data.week;
    data.year_val = data.year;
    data.week = calc_percent_dist(data.week);
    data.year = calc_percent_dist(data.year);

    //Restructure the data object for pie charts.
    restructured.week = data.week.map( function (e, i) {
      return {name: data.labels[i], y:e, val: data.week_val[i] };
    });
    restructured.year = data.year.map( function (e, i) {
      return {name: data.labels[i], y:e, val: data.year_val[i] };
    });

    units=i18n.gettext('Percent %');
    tooltip = function (){
      return this.series.name + ': ' + this.point.y + '% (' + this.point.val + ')';
    };

  }else{
    //Restructure the data object for pie charts.
    restructured = {week:[], year:[]};
    for( var i=0; i<data.labels.length; i++ ){
      restructured.week[i] = { name: data.labels[i], y: data.week[i] };
      restructured.year[i] = { name: data.labels[i], y: data.year[i] };
    }
  }

  //Draw the graph.
  $( '#'+containerID ).highcharts({
    chart: {
      plotBackgroundColor: null,
      plotBorderWidth: null,
      plotShadow: false,
      type: 'pie',
      width: plotWidth
    },
    title: '',
    tooltip: {
      formatter:tooltip
    },
    plotOptions: {
      pie: {
        allowPointSelect: true,
        cursor: 'pointer',
        dataLabels: {
          enabled: false
        },
        showInLegend: true
      }
    },
    series: [{
      name: i18n.gettext('This Week'),
      center: ['20%','50%'],
      size: "70%",
      colorByPoint: true,
      showInLegend:true,
      title: { text: 'Week', verticalAlign: 'top', y: -40 },
      data: restructured.week
    },{
      name: i18n.gettext('This Year'),
      center: ['80%','50%'],
      size: "70%",
      colorByPoint: true,
      showInLegend:false,
      title: { text: 'Year', verticalAlign: 'top', y: -40 },
      data: restructured.year
    }]
  });

  //Get rid of the highcharts.com logo.
  $( '#'+containerID+" text:contains('Highcharts.com')" ).remove();

}

/**:drawTimeCharts( varID, locID, containerID )

    Draws a timeline bar chart showing the number of cases in each epi week this current year.

    :param string varID:
        The ID of the variable to be plotted (taken from Meerkat Abacus).
    :param string locID:
        The ID of the location by which to filter the data.
    :param string containerID:
        The ID of the HTML element to hold the chart.
 */
function drawTimeChart( varID, locID, containerID ){

  $.getJSON( api_root + '/aggregate_year/' + varID + '/'+locID, function(data){

      console.log('DRAW TIME CHART');
      console.log('Time series data for diseases:');
      console.log(data);
    var labels = [];
    var values = [];

    for( var i = 1; i <= get_epi_week(); i++ ){

      labels.push(i.toString());

      if( typeof(data.weeks[i]) !== 'undefined' ){
        values.push( data.weeks[i] );
      }else{
        values.push( 0 );
      }

    }

    //Hack to get plot to size correctly when being drawn into a hidden object.
    //If the object is hidden, set the plot width to the inner width of the parent.
    //Otherwise, leave as undefined as specified in the highcharts api.
    var plotWidth;
    if( $('#'+containerID).hasClass('hidden') ){
      plotWidth = $('#'+containerID).parent().width();
    }

    $('#'+containerID).highcharts({
    chart: {
      type: 'column',
      width: plotWidth
    },
    title: '',
    xAxis: {
      categories: labels,
      title: {
        text: i18n.gettext('Epidemiological Week')
      }
    },
    legend:{ enabled:false },
    yAxis: {
      min: 0,
      title: {
        text: i18n.gettext('Number of Reported Cases'),
        align: 'high'
      },
      labels: {
        overflow: 'justify'
      }
    },
    series: [{
      name: 'Year',
      data:  values
    }],
    });

    //Get rid of the highcharts logo.
    $( '#'+containerID+" text:contains('Highcharts.com')" ).remove();
  });

}

/**:drawCompletenessGraph( containerID, locID )

   Draws a timeline line chart showing the percentage of overall completeness and completeness for each clinic in each epi week this current year.
   :param string containerID:
   The ID of the HTML element to hold the chart.
   :param string locID:
   The ID of the location by which to filter the data.
*/
function drawCompletenessGraph( containerID, regionID ){
    $.getJSON( api_root+"/locations", function( locations ){
        $.getJSON( api_root+"/completeness/reg_1/" + regionID + "/5", function( data ){
            //create a data series for each location
            var dataPrepared = [];
            var timeseries = [];
            var scoreKeys = Object.keys(data.timeline);
            var index = 0;
            for (var i=0; i<scoreKeys.length;i++){
                index = scoreKeys[scoreKeys.length - i -1];
                tl = data.timeline[index];
                var dt = [];
                var dtReady = [];
                var noWeeks = tl.weeks.length;
                var weeks = lastWeeks (get_epi_week(), noWeeks +1 ); //last completeness is from previous week
                //dropping the very last week in the data since we can only estimate it's completeness
                for (var j = 0; j < noWeeks; j++){
                    dt = [weeks[noWeeks - j -1],Number(Number(20 * (tl.values[j])).toFixed(0))];
                    dtReady.push(dt);
                         }

                var datum = {
                    name: locations[index].name,
                    data: dtReady,
                    color: 'lightgrey'
                };

                if(locations[index].id === regionID){ //parent location
                    datum.color= 'blue';
                    datum.lineWidth='5';
                }
                timeseries.push(datum);
            }

            //hovering should give all the information about given clinick and sublocation
            $('#' + containerID).highcharts({
                chart: {
                    type: 'spline'
                },
                title: {
                    text: ''
                },
                legend:{ enabled:false },
                xAxis: {
                    title: {
                        text: 'EPI week'
                    },
                    labels: {
                        overflow: 'justify'
                    },
                    allowDecimals: false
                },
                yAxis: {
                    max: 100,
                    title: {
                        text: 'Completness'
                    },
                    minorGridLineWidth: 0,
                    gridLineWidth: 0,
                    alternateGridColor: null,
                    plotBands: [{ //RED
                        from: 0,
                        to: 50,
                        color: 'rgba(255, 0, 0, 0.5)'
                    }, { //YELLOW
                        from: 50,
                        to: 80,
                        color: 'rgba(255, 255, 0, 0.5)'
                    }, { // GREEN
                        from: 80,
                        to: 100,
                        color: 'rgba(0, 128, 0,0.5)'
                    }]
                },
                tooltip: {
                    valueSuffix: '%'
                },
                plotOptions: {
                    spline: {
                        lineWidth: 3,
                        states: {
                            hover: {
                                enabled: true,
                                lineWidth: 5
                            }
                        },
                        marker: {
                            enabled: false
                        },
                        pointStart:0,
                        events: {
                            mouseOver: function () {
                                if(this.chart.series[this.index].color === 'lightgrey'){
                                    this.chart.series[this.index].update({
                                        color: 'purple'
                                    });
                                }
                            },
                            //http://forum.highcharts.com/highcharts-usage/how-do-i-change-line-colour-when-hovering-t35536/
                            mouseOut: function () {
                                if(this.chart.series[this.index].color === 'purple'){
                                    this.chart.series[this.index].update({
                                        color: "lightgrey"
                                    });
                                }
                            }
                        }
                    }
                },
                series: timeseries,
                navigation: {
                    menuItemStyle: {
                        fontSize: '10px'
                    }
                }
            }); //highchart

        });//getJSON completeness
    });//getJSON locations
}

Highcharts.setOptions({
  colors: ["#0090CA", "#D9692A", "#89B6A5", "#e94f37", "#393e41", "#F1E8B8",
          "#CDEDF6", "#690500", "#77477B", "#40476D","#042A2B" ],
  chart: {
    backgroundColor: null,
    style: {
      fontFamily: 'Helvetica Neue", Helvetica, Arial, sans-serif'
    }
  },
  credits: {
    enabled: false
  },
  exporting: {
    enabled: false
  }

});

<|endoftext|>


<commit_before>var Survey = require('../models/Survey'),
    SurveyResponse = require('../models/SurveyResponse');

// Respond with the appropriate content, depending on the messaging provider
// Right now, it's either Twilio or Telerivet
function respond(message, request, response) {
    // Render appropriate response
    response.type('text/xml');
    response.send('<Response><Message>'+message+'</Message></Response>');
}

// A webhook to be used by Twilio or Telerivet to build a survey response
exports.webhook = function(request, response) {
    var phoneNumber = request.param('From'),
        messageBody = request.param('Body');

    Survey.findById(request.param('id'), function(err, survey) {
        var msg = 'No survey found for this phone number.';

        // If we found the survey, continue
        if (survey) {
            // Find survey response for the current phone number and survey
            SurveyResponse.findOne({
                _surveyId: survey._id,
                phoneNumber: phoneNumber,
                complete: false
            }, function(err, surveyResponse) {
                // The message to be returned to the user after the latest
                // input
                function processed(err, message) {
                    if (err) {
                        message = 'There was an error processing your response, please try again.';
                    }
                    respond(message, request, response);
                }

                // Process from an existing response or create new
                if (surveyResponse) {
                    surveyResponse.processMessage(survey, messageBody, phoneNumber, processed);
                } else {
                    var newSurveyResponse = new SurveyResponse({
                        phoneNumber: phoneNumber,
                        _surveyId: survey._id
                    });
                    newSurveyResponse.save(function(err, nsr) {
                        if (nsr) {
                            nsr.processMessage(survey, messageBody, phoneNumber, processed);
                        } else {
                            processed(true);
                        }
                    });
                }

            }); // end find survey response
        }
    }); // end find survey
};<commit_msg>process telerivet inputs<commit_after>var Survey = require('../models/Survey'),
    SurveyResponse = require('../models/SurveyResponse');

// Respond with the appropriate content, depending on the messaging provider
// Right now, it's either Twilio or Telerivet
function respond(message, gateway, request, response) {
    if (gateway === 'telerivet') {
        // Telerivet requires JSON response
        var res = {
            messages: [ { content: message } ]
        };
        response.send(res);
    } else {
        // Render Twilio-style response
        response.type('text/xml');
        response.send('<Response><Message>'+message+'</Message></Response>');
    }
}

// A webhook to be used by Twilio or Telerivet to build a survey response
exports.webhook = function(request, response) {
    var gateway = 'twilio', phoneNumber, messageBody;

    // determine which messaging provider we are dealing with
    if (request.param('from_number')) {
        // this is a Telerviet webhook
        gateway = 'telerivet';
        phoneNumber = request.param('from_number'),
        messageBody = request.param('content');
    } else {
        // Default is Twilio
        phoneNumber = request.param('From'),
        messageBody = request.param('Body');
    }

    // Find the webhook associated with this phone
    Survey.findById(request.param('id'), function(err, survey) {
        var msg = 'No survey found for this phone number.';

        // If we found the survey, continue
        if (survey) {
            // Find survey response for the current phone number and survey
            SurveyResponse.findOne({
                _surveyId: survey._id,
                phoneNumber: phoneNumber,
                complete: false
            }, function(err, surveyResponse) {
                // The message to be returned to the user after the latest
                // input
                function processed(err, message) {
                    if (err) {
                        message = 'There was an error processing your response, please try again.';
                    }
                    respond(message, gateway, request, response);
                }

                // Process from an existing response or create new
                if (surveyResponse) {
                    surveyResponse.processMessage(survey, messageBody, phoneNumber, processed);
                } else {
                    var newSurveyResponse = new SurveyResponse({
                        phoneNumber: phoneNumber,
                        _surveyId: survey._id
                    });
                    newSurveyResponse.save(function(err, nsr) {
                        if (nsr) {
                            nsr.processMessage(survey, messageBody, phoneNumber, processed);
                        } else {
                            processed(true);
                        }
                    });
                }

            }); // end find survey response
        }
    }); // end find survey
};<|endoftext|>


<commit_before>angular.module('vc.home', [])

.controller('HomeCtrl', function($scope){
	$scope.map = (function(elemId) {
		myPos = {
			lon: 4.871454,
			lat: 45.784011,
			zoom: 13
		}
		var myIcon = L.divIcon({
			className: 'station-marker',
			html: '',
			iconSize: [35, 35],
			iconAnchor: [35, 35]
		});

		var map = L.map(elemId);

		L.tileLayer('http://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', {
		    maxZoom: 18
		}).addTo(map);
		//map.locate({setView: true, maxZoom: 16});
		var position = L.latLng(myPos.lat, myPos.lon);
		map.setView(position, myPos.zoom);

		function onLocationFound(e) {
		    var radius = e.accuracy / 2;

		    L.marker(e.latlng).addTo(map)
		        .bindPopup("You are within " + radius + " meters from this point").openPopup();

		    L.circle(e.latlng, radius).addTo(map);
		}

		map.on('locationfound', onLocationFound);

		function onLocationError(e) {
		    alert(e.message);
		}

		map.on('locationerror', onLocationError);

		var marker = L.marker(position, {
			icon: myIcon
		}).addTo(map);

		return {
			addStations: function(stations) {
				for st of stations:
					console.log(st);
			}
		}

		/*
		map = new ol.Map(elemId);
    var mapnik         = new ol.Layer.OSM();
    var fromProjection = new ol.Projection("EPSG:4326");   // Transform from WGS 1984
    var toProjection   = new ol.Projection("EPSG:900913"); // to Spherical Mercator Projection
    var position       = new ol.LonLat(MyPos.lon, MyPos.lat).transform(fromProjection, toProjection);
    var zoom           = MyPos.zoom;
    var newLayer = new ol.Layer.OSM("Map", "http://b.tile.openstreetmap.fr/hot/${z}/${x}/${y}.png");
    map.addLayer(newLayer);
    map.setCenter(position, zoom);

    // Defines vector overlay
    var vectorLayer = new ol.Layer.Vector("Overlay");

    return {
    	setCenter: function(position, zoom) {
    		var position = new ol.LonLat(MyPos.lon, MyPos.lat).transform(fromProjection, toProjection);
    		var zoom     = MyPos.zoom;
    		map.setCenter(position, zoom);
    	},
    	addStations: function(stations) {
    		//GIGIDI
    	}
    };
*/
	})("main-map");
});<commit_msg>( <---- fix '<commit_after>angular.module('vc.home', [])

.controller('HomeCtrl', function($scope){
	$scope.map = (function(elemId) {
		myPos = {
			lon: 4.871454,
			lat: 45.784011,
			zoom: 13
		}
		var myIcon = L.divIcon({
			className: 'station-marker',
			html: '',
			iconSize: [35, 35],
			iconAnchor: [35, 35]
		});

		var map = L.map(elemId);

		L.tileLayer('http://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png', {
		    maxZoom: 18
		}).addTo(map);
		//map.locate({setView: true, maxZoom: 16});
		var position = L.latLng(myPos.lat, myPos.lon);
		map.setView(position, myPos.zoom);

		function onLocationFound(e) {
		    var radius = e.accuracy / 2;

		    L.marker(e.latlng).addTo(map)
		        .bindPopup("You are within " + radius + " meters from this point").openPopup();

		    L.circle(e.latlng, radius).addTo(map);
		}

		map.on('locationfound', onLocationFound);

		function onLocationError(e) {
		    alert(e.message);
		}

		map.on('locationerror', onLocationError);

		var marker = L.marker(position, {
			icon: myIcon
		}).addTo(map);

		return {
			addStations: function(stations) {
				for(st of stations){
					console.log(st);
				}
			}
		}

		/*
		map = new ol.Map(elemId);
    var mapnik         = new ol.Layer.OSM();
    var fromProjection = new ol.Projection("EPSG:4326");   // Transform from WGS 1984
    var toProjection   = new ol.Projection("EPSG:900913"); // to Spherical Mercator Projection
    var position       = new ol.LonLat(MyPos.lon, MyPos.lat).transform(fromProjection, toProjection);
    var zoom           = MyPos.zoom;
    var newLayer = new ol.Layer.OSM("Map", "http://b.tile.openstreetmap.fr/hot/${z}/${x}/${y}.png");
    map.addLayer(newLayer);
    map.setCenter(position, zoom);

    // Defines vector overlay
    var vectorLayer = new ol.Layer.Vector("Overlay");

    return {
    	setCenter: function(position, zoom) {
    		var position = new ol.LonLat(MyPos.lon, MyPos.lat).transform(fromProjection, toProjection);
    		var zoom     = MyPos.zoom;
    		map.setCenter(position, zoom);
    	},
    	addStations: function(stations) {
    		//GIGIDI
    	}
    };
*/
	})("main-map");
});<|endoftext|>