<commit_before>
define([
    'require',
    'jscache',
    './cacheDecisions'
], function(require, Cache, cacheDecisions) {
    'use strict';

        // Object cache per workspace
    var KIND_TO_CACHE = {
            vertex: 'vertices',
            edge: 'edges',
            workspace: 'workspace',
            cachedIds: 'cachedIds'
        },
        workspaceCaches = {},

        api = {

            logStatistics: function() {
                _.each(workspaceCaches, function(cache, workspaceId) {
                    var v = cache.vertices.getStats(),
                        e = cache.edges.getStats();
                    console.log(
                        'V(size:%s hits:%s miss:%s) E(size:%s hits:%s miss:%s)',
                        cache.vertices.size(),
                        v.hits,
                        v.misses,
                        cache.edges.size(),
                        e.hits,
                        e.misses,
                        workspaceId
                    );
                })
            },

            getObject: function(workspaceId, kind, objectId) {
                var result = api.getObjects(workspaceId, kind, objectId ? [objectId] : null);
                if (objectId) {
                    return result.length ? result[0] : null;
                }
                return result;
            },

            getObjects: function(workspaceId, kind, objectIds) {
                if (!(kind in KIND_TO_CACHE)) {
                    throw new Error('kind parameter not valid', kind);
                }

                var workspaceCache = cacheForWorkspace(workspaceId, { create: false }),
                    cache = workspaceCache && workspaceCache[KIND_TO_CACHE[kind]];

                if (objectIds) {
                    return objectIds.map(function(oId) {
                        return cache && cache.getItem(oId);
                    });
                }

                return cache;
            },

            removeObject: function(workspaceId, kind, objectId) {
                if (!(kind in KIND_TO_CACHE)) {
                    throw new Error('kind parameter not valid', kind);
                }

                var workspaceCache = cacheForWorkspace(workspaceId, { create: false }),
                    cache = workspaceCache && workspaceCache[KIND_TO_CACHE[kind]];

                if (cache && objectId) {
                    cache.removeItem(objectId);
                }
            },

            setWorkspace: function(workspace) {
                if (_.isArray(workspace.vertices)) {
                    workspace.vertices = _.indexBy(workspace.vertices, 'vertexId');
                }
                parseJsonLayoutForVertices(workspace.vertices);
                var workspaceCache = cacheForWorkspace(workspace.workspaceId);
                workspaceCache.workspace = workspace;
                return workspace;
            },

            updateWorkspace: function(workspaceId, changes) {
                var workspace = JSON.parse(JSON.stringify(api.getObject(workspaceId, 'workspace')));
                changes.entityUpdates.forEach(function(entityUpdate) {
                    var workspaceVertex = _.findWhere(workspace.vertices, { vertexId: entityUpdate.vertexId });
                    if (workspaceVertex) {
                        if ('graphPosition' in entityUpdate) {
                            workspaceVertex.graphPosition = entityUpdate.graphPosition;
                        } else {
                            delete workspaceVertex.graphPosition;
                        }
                        if ('graphLayoutJson' in entityUpdate) {
                            workspaceVertex.graphLayoutJson = entityUpdate.graphLayoutJson;
                        } else {
                            delete workspaceVertex.graphLayoutJson;
                        }
                    } else {
                        workspace.vertices[entityUpdate.vertexId] =
                            _.pick(entityUpdate, 'vertexId', 'graphPosition', 'graphLayoutJson');
                    }
                });
                workspace.vertices = _.omit(workspace.vertices, changes.entityDeletes);
                if (changes.title) {
                    workspace.title = changes.title
                }

                var updatedIds = _.pluck(changes.userUpdates, 'userId');
                updatedIds.concat(changes.userDeletes).forEach(function(userId) {
                    for (var i = 0; i < workspace.users.length; i++) {
                        if (workspace.users[i].userId === userId) {
                            workspace.users.splice(i, 1);
                            return;
                        }
                    }
                });
                workspace.users = workspace.users.concat(changes.userUpdates);

                api.workspaceWasChangedRemotely(workspace);
                return workspace;
            },

            removeWorkspace: function(workspaceId) {
                if (workspaceId in workspaceCaches) {
                    delete workspaceCaches[workspaceId];
                }
            },

            workspaceWasChangedRemotely: function(remoteWorkspace) {
                var user = _.findWhere(remoteWorkspace.users, { userId: publicData.currentUser.id });
                remoteWorkspace.editable = /WRITE/i.test(user && user.access);
                remoteWorkspace.commentable = /(COMMENT|WRITE)/i.test(user && user.access);
                remoteWorkspace.isSharedToUser = remoteWorkspace.createdBy !== publicData.currentUser.id;
                if (('vertices' in remoteWorkspace)) {
                    remoteWorkspace.vertices = _.indexBy(remoteWorkspace.vertices, 'vertexId');
                    parseJsonLayoutForVertices(remoteWorkspace.vertices);
                }
                var workspace = api.getObject(remoteWorkspace.workspaceId, 'workspace');
                if (!workspace || !_.isEqual(remoteWorkspace, workspace)) {
                    console.groupCollapsed('Workspace Update')
                    console.debug('old', workspace)
                    console.debug('new', remoteWorkspace)
                    console.groupEnd('Workspace Update')

                    var vertexIds = _.keys(remoteWorkspace.vertices),
                        vertexIdsPrevious = workspace ? _.keys(workspace.vertices) : [],
                        addedIds = _.difference(vertexIds, vertexIdsPrevious),
                        removedIds = _.difference(vertexIdsPrevious, vertexIds),
                        updatedIds = _.without.apply(_, [vertexIds].concat(addedIds)),
                        added = _.values(_.pick(remoteWorkspace.vertices, addedIds)),
                        updated = _.compact(_.map(updatedIds, function(vId) {
                            return (workspace && _.isEqual(
                                remoteWorkspace.vertices[vId],
                                workspace.vertices[vId]
                            )) ? null : remoteWorkspace.vertices[vId];
                        }));

                    require(['../services/vertex'], function(vertex) {
                        vertex.store({ vertexIds: addedIds })
                            .done(function(newVertices) {
                                api.setWorkspace(remoteWorkspace);
                                dispatchMain('workspaceUpdated', {
                                    workspace: remoteWorkspace,
                                    newVertices: newVertices,
                                    entityUpdates: updated.concat(added),
                                    entityDeletes: removedIds,
                                    userUpdates: [],
                                    userDeletes: []
                                });
                            });
                    });
                }
            },

            workspaceShouldSave: function(workspace, changes) {
                var willChange = false;

                willChange = willChange || (changes.title && changes.title !== workspace.title);

                willChange = willChange || changes.userDeletes.length;
                willChange = willChange || changes.userUpdates.length;

                willChange = willChange || changes.entityDeletes.length;
                willChange = willChange || _.any(changes.entityUpdates, function(entityUpdate) {
                    var workspaceVertex = _.findWhere(workspace.vertices, { vertexId: entityUpdate.vertexId });
                    if (workspaceVertex) {
                        return !_.isEqual(workspaceVertex, entityUpdate);
                    } else {
                        return true;
                    }
                });

                return willChange;
            },

            updateObject: function(data, options) {
                var onlyIfExists = options && options.onlyIfExists === true,
                    cached;

                if (!data.workspaceId) {
                    data.workspaceId = publicData.currentWorkspaceId;
                }

                var cachedIds = api.getObject(data.workspaceId, 'cachedIds');
                if (data.vertex && resemblesVertex(data.vertex)) {
                    cached = api.getObject(data.workspaceId, 'vertex', data.vertex.id)
                    if (cached || (cachedIds && (data.vertex.id in cachedIds)) || !onlyIfExists) {
                        cacheVertices(data.workspaceId, [data.vertex]);
                    }
                }

                if (data.edge) {
                    var toCache;

                    if (resemblesEdge(data.edge)) {
                        toCache = data.edge;
                    } else {
                        if (data.edge.sourceVertexId && data.edge.destVertexId) {
                            // Load vertices from cache
                            cached = _.compact(api.getObjects(data.workspaceId, 'vertex', [
                                data.edge.sourceVertexId,
                                data.edge.destVertexId
                            ]));

                            if (cached && cached.length === 2) {
                                toCache = _.extend({}, _.omit(data.edge, 'sourceVertexId', 'destVertexId'), {
                                    source: cached[0],
                                    target: cached[1]
                                });
                            }
                        }
                    }

                    if (toCache) {
                        cacheEdges(data.workspaceId, [toCache]);
                    }
                }
            },

            checkAjaxForPossibleCaching: function(xhr, json, workspaceId, request) {
                var url = request.url,
                    cacheable;

                if (cacheDecisions.shouldCacheObjectsAtUrl(url)) {
                    if (resemblesVertex(json)) {
                        if (cacheDecisions.shouldCacheVertexAtUrl(json, url)) {
                            console.debug(request.url, 'causing vertex to cache', json);
                            cacheVertices(workspaceId, [json], cachePriorityForUrl(request.url));
                        }
                    }
                    if (resemblesVertices(json.vertices)) {
                        cacheable = _.filter(json.vertices, function(v) {
                            return cacheDecisions.shouldCacheVertexAtUrl(v, url);
                        })
                        if (cacheable.length) {
                            console.debug(request.url, 'causing vertices to cache', json.vertices);
                            cacheVertices(workspaceId, cacheable, cachePriorityForUrl(request.url));
                        }
                    }
                    if (resemblesEdge(json)) {
                        if (cacheDecisions.shouldCacheEdgeAtUrl(json, url)) {
                            cacheEdges(workspaceId, [json]);
                        }
                    }
                    if (resemblesEdges(json.edges)) {
                        cacheable = _.filter(json.edges, function(e) {
                            return cacheDecisions.shouldCacheEdgeAtUrl(e, url);
                        })
                        if (cacheable.length) {
                            cacheEdges(workspaceId, cacheable);
                        }
                    }
                }
            },

        };

    return api;

    function cachePriorityForUrl(url) {
        if (url === '/vertex/search') {
            return Cache.Priority.LOW;
        }
    }

    function parseJsonLayoutForVertices(workspaceVertices) {
        if (workspaceVertices) {
            _.each(workspaceVertices, function(wv) {
                if (('graphLayoutJson' in wv) && _.isString(wv.graphLayoutJson)) {
                    wv.graphLayoutJson = JSON.parse(wv.graphLayoutJson);
                }
            })
        }
    }

    function cacheForWorkspace(workspaceId, options) {
        if (!workspaceId) {
            workspaceId = publicData.currentWorkspaceId;
        }

        if (workspaceId in workspaceCaches) {
            return workspaceCaches[workspaceId];
        }

        if (options && options.create === false) {
            return null;
        }

        workspaceCaches[workspaceId] = {
            vertices: new Cache(),
            edges: new Cache(),
            cachedIds: {}
        };

        return workspaceCaches[workspaceId];
    }

    function getCacheOptions(kind, callback) {
        require(['data/web-worker/services/config'], function(config) {
            config.properties()
                .then(function(properties) {
                    var lruSeconds = parseInt(properties['cache.' + kind + '.lru.expiration.seconds'], 10),
                        maxCacheSizeVertices = parseInt(properties['cache.' + kind + '.max_size'], 10);
                    return {
                        expirationSliding: lruSeconds === -1 ? null : lruSeconds,
                        maxSize: maxCacheSizeVertices
                    }
                })
                .then(callback)
                .done();
        });
    }

    function cacheVertices(workspaceId, vertices, priority) {
        getCacheOptions('vertex', function(cacheOptions) {
            var workspaceCache = cacheForWorkspace(workspaceId),
                workspace = api.getObject(workspaceId, 'workspace'),
                vertexCache = workspaceCache.vertices,
                cachedIds = workspaceCache.cachedIds;

            vertexCache.resize(cacheOptions.maxSize);

            var added = [],
                updated = _.compact(vertices.map(function(v) {
                // Search puts a score, but we don't use it and it breaks
                // our cache update check
                if ('score' in v) {
                    delete v.score;
                }

                var previous = vertexCache.getItem(v.id);
                if (previous && _.isEqual(v, previous)) {
                    return;
                }

                cachedIds[v.id] = true;

                var inWorkspace = workspace && workspace.vertices && (v.id in workspace.vertices),
                    cachePriority = inWorkspace ? Cache.Priority.HIGH : (priority || Cache.Priority.NORMAL);

                vertexCache.setItem(v.id, v, {
                    expirationAbsolute: null,
                    expirationSliding: cacheOptions.expirationSliding,
                    priority: cachePriority
                    //callback: function(k, v) {}
                });

                if (previous) {
                    //console.debug('Vertex updated previous:', previous, 'new:', v)
                    return v;
                } else {
                    added.push(v);
                }
            }));

            if (updated.length && workspaceId === publicData.currentWorkspaceId) {
                dispatchMain('storeObjectsUpdated', { vertices: updated });
            }

            if (updated.length || added.length) {
                dispatchMain('rebroadcastEvent', {
                    eventName: 'storeVerticesChanged',
                    data: {
                        updated: updated,
                        added: added
                    }
                });
            }
        });
    }

    function cacheEdges(workspaceId, edges) {
        getCacheOptions('edge', function(cacheOptions) {
            var edgeCache = cacheForWorkspace(workspaceId).edges,
                workspace = api.getObject(workspaceId, 'workspace');

            edgeCache.resize(cacheOptions.maxSize);

            var updated = _.compact(edges.map(function(e) {
                    var previous = edgeCache.getItem(e.id),
                        bothVerticesInWorkspace = workspace &&
                            e.source.id in workspace.vertices &&
                            e.target.id in workspace.vertices;

                    if ((previous && _.isEqual(e, previous)) || !bothVerticesInWorkspace) {
                        return;
                    }

                    edgeCache.setItem(e.id, e, {
                        expirationAbsolute: null,
                        expirationSliding: cacheOptions.expirationSliding,
                        priority: Cache.Priority.NORMAL,
                        //callback: function(k, v) { }
                    });

                    // console.debug('Edge updated previous:', previous, 'new:', e)
                    return e;
                }));

            if (updated.length && workspaceId === publicData.currentWorkspaceId) {
                dispatchMain('storeObjectsUpdated', { edges: updated });
            }
        });
    }

    function resemblesEdge(val) {
        return (
            _.isObject(val) &&
            val.type === 'edge' &&
            _.has(val, 'id') &&
            _.has(val, 'label') &&
            !_.isEmpty(val.source) &&
            !_.isEmpty(val.target)
        );
    }

    function resemblesEdges(val) {
        return _.isArray(val) && val.length && resemblesEdge(val[0]);
    }

    function resemblesVertex(val) {
        return (
            _.isObject(val) &&
            _.has(val, 'id') &&
            _.has(val, 'sandboxStatus') &&
            _.has(val, 'properties') &&
            _.isArray(val.properties) &&
            !_.has(val, 'sourceVertexId') &&
            !_.has(val, 'destVertexId')
        );
    }

    function resemblesVertices(val) {
        return _.isArray(val) && val.length && resemblesVertex(val[0]);
    }
});
<commit_msg>Fix sharing workspace showing in wrong section<commit_after>
define([
    'require',
    'jscache',
    './cacheDecisions'
], function(require, Cache, cacheDecisions) {
    'use strict';

        // Object cache per workspace
    var KIND_TO_CACHE = {
            vertex: 'vertices',
            edge: 'edges',
            workspace: 'workspace',
            cachedIds: 'cachedIds'
        },
        workspaceCaches = {},

        api = {

            logStatistics: function() {
                _.each(workspaceCaches, function(cache, workspaceId) {
                    var v = cache.vertices.getStats(),
                        e = cache.edges.getStats();
                    console.log(
                        'V(size:%s hits:%s miss:%s) E(size:%s hits:%s miss:%s)',
                        cache.vertices.size(),
                        v.hits,
                        v.misses,
                        cache.edges.size(),
                        e.hits,
                        e.misses,
                        workspaceId
                    );
                })
            },

            getObject: function(workspaceId, kind, objectId) {
                var result = api.getObjects(workspaceId, kind, objectId ? [objectId] : null);
                if (objectId) {
                    return result.length ? result[0] : null;
                }
                return result;
            },

            getObjects: function(workspaceId, kind, objectIds) {
                if (!(kind in KIND_TO_CACHE)) {
                    throw new Error('kind parameter not valid', kind);
                }

                var workspaceCache = cacheForWorkspace(workspaceId, { create: false }),
                    cache = workspaceCache && workspaceCache[KIND_TO_CACHE[kind]];

                if (objectIds) {
                    return objectIds.map(function(oId) {
                        return cache && cache.getItem(oId);
                    });
                }

                return cache;
            },

            removeObject: function(workspaceId, kind, objectId) {
                if (!(kind in KIND_TO_CACHE)) {
                    throw new Error('kind parameter not valid', kind);
                }

                var workspaceCache = cacheForWorkspace(workspaceId, { create: false }),
                    cache = workspaceCache && workspaceCache[KIND_TO_CACHE[kind]];

                if (cache && objectId) {
                    cache.removeItem(objectId);
                }
            },

            setWorkspace: function(workspace) {
                if (_.isArray(workspace.vertices)) {
                    workspace.vertices = _.indexBy(workspace.vertices, 'vertexId');
                }
                parseJsonLayoutForVertices(workspace.vertices);
                var workspaceCache = cacheForWorkspace(workspace.workspaceId);
                workspaceCache.workspace = workspace;
                return workspace;
            },

            updateWorkspace: function(workspaceId, changes) {
                var workspace = JSON.parse(JSON.stringify(api.getObject(workspaceId, 'workspace')));
                changes.entityUpdates.forEach(function(entityUpdate) {
                    var workspaceVertex = _.findWhere(workspace.vertices, { vertexId: entityUpdate.vertexId });
                    if (workspaceVertex) {
                        if ('graphPosition' in entityUpdate) {
                            workspaceVertex.graphPosition = entityUpdate.graphPosition;
                        } else {
                            delete workspaceVertex.graphPosition;
                        }
                        if ('graphLayoutJson' in entityUpdate) {
                            workspaceVertex.graphLayoutJson = entityUpdate.graphLayoutJson;
                        } else {
                            delete workspaceVertex.graphLayoutJson;
                        }
                    } else {
                        workspace.vertices[entityUpdate.vertexId] =
                            _.pick(entityUpdate, 'vertexId', 'graphPosition', 'graphLayoutJson');
                    }
                });
                workspace.vertices = _.omit(workspace.vertices, changes.entityDeletes);
                if (changes.title) {
                    workspace.title = changes.title
                }

                var updatedIds = _.pluck(changes.userUpdates, 'userId');
                updatedIds.concat(changes.userDeletes).forEach(function(userId) {
                    for (var i = 0; i < workspace.users.length; i++) {
                        if (workspace.users[i].userId === userId) {
                            workspace.users.splice(i, 1);
                            return;
                        }
                    }
                });
                workspace.users = workspace.users.concat(changes.userUpdates);

                api.workspaceWasChangedRemotely(workspace);
                return workspace;
            },

            removeWorkspace: function(workspaceId) {
                if (workspaceId in workspaceCaches) {
                    delete workspaceCaches[workspaceId];
                }
            },

            workspaceWasChangedRemotely: function(remoteWorkspace) {
                var user = _.findWhere(remoteWorkspace.users, { userId: publicData.currentUser.id });
                remoteWorkspace.editable = /WRITE/i.test(user && user.access);
                remoteWorkspace.commentable = /(COMMENT|WRITE)/i.test(user && user.access);
                remoteWorkspace.sharedToUser = remoteWorkspace.createdBy !== publicData.currentUser.id;
                if (('vertices' in remoteWorkspace)) {
                    remoteWorkspace.vertices = _.indexBy(remoteWorkspace.vertices, 'vertexId');
                    parseJsonLayoutForVertices(remoteWorkspace.vertices);
                }
                var workspace = api.getObject(remoteWorkspace.workspaceId, 'workspace');
                if (!workspace || !_.isEqual(remoteWorkspace, workspace)) {
                    console.groupCollapsed('Workspace Update')
                    console.debug('old', workspace)
                    console.debug('new', remoteWorkspace)
                    console.groupEnd('Workspace Update')

                    var vertexIds = _.keys(remoteWorkspace.vertices),
                        vertexIdsPrevious = workspace ? _.keys(workspace.vertices) : [],
                        addedIds = _.difference(vertexIds, vertexIdsPrevious),
                        removedIds = _.difference(vertexIdsPrevious, vertexIds),
                        updatedIds = _.without.apply(_, [vertexIds].concat(addedIds)),
                        added = _.values(_.pick(remoteWorkspace.vertices, addedIds)),
                        updated = _.compact(_.map(updatedIds, function(vId) {
                            return (workspace && _.isEqual(
                                remoteWorkspace.vertices[vId],
                                workspace.vertices[vId]
                            )) ? null : remoteWorkspace.vertices[vId];
                        }));

                    require(['../services/vertex'], function(vertex) {
                        vertex.store({ vertexIds: addedIds })
                            .done(function(newVertices) {
                                api.setWorkspace(remoteWorkspace);
                                dispatchMain('workspaceUpdated', {
                                    workspace: remoteWorkspace,
                                    newVertices: newVertices,
                                    entityUpdates: updated.concat(added),
                                    entityDeletes: removedIds,
                                    userUpdates: [],
                                    userDeletes: []
                                });
                            });
                    });
                }
            },

            workspaceShouldSave: function(workspace, changes) {
                var willChange = false;

                willChange = willChange || (changes.title && changes.title !== workspace.title);

                willChange = willChange || changes.userDeletes.length;
                willChange = willChange || changes.userUpdates.length;

                willChange = willChange || changes.entityDeletes.length;
                willChange = willChange || _.any(changes.entityUpdates, function(entityUpdate) {
                    var workspaceVertex = _.findWhere(workspace.vertices, { vertexId: entityUpdate.vertexId });
                    if (workspaceVertex) {
                        return !_.isEqual(workspaceVertex, entityUpdate);
                    } else {
                        return true;
                    }
                });

                return willChange;
            },

            updateObject: function(data, options) {
                var onlyIfExists = options && options.onlyIfExists === true,
                    cached;

                if (!data.workspaceId) {
                    data.workspaceId = publicData.currentWorkspaceId;
                }

                var cachedIds = api.getObject(data.workspaceId, 'cachedIds');
                if (data.vertex && resemblesVertex(data.vertex)) {
                    cached = api.getObject(data.workspaceId, 'vertex', data.vertex.id)
                    if (cached || (cachedIds && (data.vertex.id in cachedIds)) || !onlyIfExists) {
                        cacheVertices(data.workspaceId, [data.vertex]);
                    }
                }

                if (data.edge) {
                    var toCache;

                    if (resemblesEdge(data.edge)) {
                        toCache = data.edge;
                    } else {
                        if (data.edge.sourceVertexId && data.edge.destVertexId) {
                            // Load vertices from cache
                            cached = _.compact(api.getObjects(data.workspaceId, 'vertex', [
                                data.edge.sourceVertexId,
                                data.edge.destVertexId
                            ]));

                            if (cached && cached.length === 2) {
                                toCache = _.extend({}, _.omit(data.edge, 'sourceVertexId', 'destVertexId'), {
                                    source: cached[0],
                                    target: cached[1]
                                });
                            }
                        }
                    }

                    if (toCache) {
                        cacheEdges(data.workspaceId, [toCache]);
                    }
                }
            },

            checkAjaxForPossibleCaching: function(xhr, json, workspaceId, request) {
                var url = request.url,
                    cacheable;

                if (cacheDecisions.shouldCacheObjectsAtUrl(url)) {
                    if (resemblesVertex(json)) {
                        if (cacheDecisions.shouldCacheVertexAtUrl(json, url)) {
                            console.debug(request.url, 'causing vertex to cache', json);
                            cacheVertices(workspaceId, [json], cachePriorityForUrl(request.url));
                        }
                    }
                    if (resemblesVertices(json.vertices)) {
                        cacheable = _.filter(json.vertices, function(v) {
                            return cacheDecisions.shouldCacheVertexAtUrl(v, url);
                        })
                        if (cacheable.length) {
                            console.debug(request.url, 'causing vertices to cache', json.vertices);
                            cacheVertices(workspaceId, cacheable, cachePriorityForUrl(request.url));
                        }
                    }
                    if (resemblesEdge(json)) {
                        if (cacheDecisions.shouldCacheEdgeAtUrl(json, url)) {
                            cacheEdges(workspaceId, [json]);
                        }
                    }
                    if (resemblesEdges(json.edges)) {
                        cacheable = _.filter(json.edges, function(e) {
                            return cacheDecisions.shouldCacheEdgeAtUrl(e, url);
                        })
                        if (cacheable.length) {
                            cacheEdges(workspaceId, cacheable);
                        }
                    }
                }
            },

        };

    return api;

    function cachePriorityForUrl(url) {
        if (url === '/vertex/search') {
            return Cache.Priority.LOW;
        }
    }

    function parseJsonLayoutForVertices(workspaceVertices) {
        if (workspaceVertices) {
            _.each(workspaceVertices, function(wv) {
                if (('graphLayoutJson' in wv) && _.isString(wv.graphLayoutJson)) {
                    wv.graphLayoutJson = JSON.parse(wv.graphLayoutJson);
                }
            })
        }
    }

    function cacheForWorkspace(workspaceId, options) {
        if (!workspaceId) {
            workspaceId = publicData.currentWorkspaceId;
        }

        if (workspaceId in workspaceCaches) {
            return workspaceCaches[workspaceId];
        }

        if (options && options.create === false) {
            return null;
        }

        workspaceCaches[workspaceId] = {
            vertices: new Cache(),
            edges: new Cache(),
            cachedIds: {}
        };

        return workspaceCaches[workspaceId];
    }

    function getCacheOptions(kind, callback) {
        require(['data/web-worker/services/config'], function(config) {
            config.properties()
                .then(function(properties) {
                    var lruSeconds = parseInt(properties['cache.' + kind + '.lru.expiration.seconds'], 10),
                        maxCacheSizeVertices = parseInt(properties['cache.' + kind + '.max_size'], 10);
                    return {
                        expirationSliding: lruSeconds === -1 ? null : lruSeconds,
                        maxSize: maxCacheSizeVertices
                    }
                })
                .then(callback)
                .done();
        });
    }

    function cacheVertices(workspaceId, vertices, priority) {
        getCacheOptions('vertex', function(cacheOptions) {
            var workspaceCache = cacheForWorkspace(workspaceId),
                workspace = api.getObject(workspaceId, 'workspace'),
                vertexCache = workspaceCache.vertices,
                cachedIds = workspaceCache.cachedIds;

            vertexCache.resize(cacheOptions.maxSize);

            var added = [],
                updated = _.compact(vertices.map(function(v) {
                // Search puts a score, but we don't use it and it breaks
                // our cache update check
                if ('score' in v) {
                    delete v.score;
                }

                var previous = vertexCache.getItem(v.id);
                if (previous && _.isEqual(v, previous)) {
                    return;
                }

                cachedIds[v.id] = true;

                var inWorkspace = workspace && workspace.vertices && (v.id in workspace.vertices),
                    cachePriority = inWorkspace ? Cache.Priority.HIGH : (priority || Cache.Priority.NORMAL);

                vertexCache.setItem(v.id, v, {
                    expirationAbsolute: null,
                    expirationSliding: cacheOptions.expirationSliding,
                    priority: cachePriority
                    //callback: function(k, v) {}
                });

                if (previous) {
                    //console.debug('Vertex updated previous:', previous, 'new:', v)
                    return v;
                } else {
                    added.push(v);
                }
            }));

            if (updated.length && workspaceId === publicData.currentWorkspaceId) {
                dispatchMain('storeObjectsUpdated', { vertices: updated });
            }

            if (updated.length || added.length) {
                dispatchMain('rebroadcastEvent', {
                    eventName: 'storeVerticesChanged',
                    data: {
                        updated: updated,
                        added: added
                    }
                });
            }
        });
    }

    function cacheEdges(workspaceId, edges) {
        getCacheOptions('edge', function(cacheOptions) {
            var edgeCache = cacheForWorkspace(workspaceId).edges,
                workspace = api.getObject(workspaceId, 'workspace');

            edgeCache.resize(cacheOptions.maxSize);

            var updated = _.compact(edges.map(function(e) {
                    var previous = edgeCache.getItem(e.id),
                        bothVerticesInWorkspace = workspace &&
                            e.source.id in workspace.vertices &&
                            e.target.id in workspace.vertices;

                    if ((previous && _.isEqual(e, previous)) || !bothVerticesInWorkspace) {
                        return;
                    }

                    edgeCache.setItem(e.id, e, {
                        expirationAbsolute: null,
                        expirationSliding: cacheOptions.expirationSliding,
                        priority: Cache.Priority.NORMAL,
                        //callback: function(k, v) { }
                    });

                    // console.debug('Edge updated previous:', previous, 'new:', e)
                    return e;
                }));

            if (updated.length && workspaceId === publicData.currentWorkspaceId) {
                dispatchMain('storeObjectsUpdated', { edges: updated });
            }
        });
    }

    function resemblesEdge(val) {
        return (
            _.isObject(val) &&
            val.type === 'edge' &&
            _.has(val, 'id') &&
            _.has(val, 'label') &&
            !_.isEmpty(val.source) &&
            !_.isEmpty(val.target)
        );
    }

    function resemblesEdges(val) {
        return _.isArray(val) && val.length && resemblesEdge(val[0]);
    }

    function resemblesVertex(val) {
        return (
            _.isObject(val) &&
            _.has(val, 'id') &&
            _.has(val, 'sandboxStatus') &&
            _.has(val, 'properties') &&
            _.isArray(val.properties) &&
            !_.has(val, 'sourceVertexId') &&
            !_.has(val, 'destVertexId')
        );
    }

    function resemblesVertices(val) {
        return _.isArray(val) && val.length && resemblesVertex(val[0]);
    }
});
<|endoftext|>


<commit_before>$(document).ready(function () {
    $('[data-toggle="confirmation"]').confirmation();

    $('.addtocart-btn').on('click', function(e){
        e.preventDefault();
        //define var
        var cartObj;

        //get all cart
        if (Cookies.get('cart')) {
            cartObj = JSON.parse(Cookies.get('cart'));
        } else {
            cartObj = {};
        }

        //get new vars
        var productRow = $(this).closest('.id-row');

        var productIdRaw = productRow.data('id');
        var productId = toPositiveInt(productIdRaw);

        var productQuantityRaw = productRow.find('.addtocart-input').val();
        var productQuantity = toPositiveInt(productQuantityRaw);
        if (isNaN(productQuantity)) {
            productQuantity = 1;
        }

        var productPriceRaw = productRow.parent().find('.price span').text();
        var productPrice = toPositiveInt(productPriceRaw);
        addToNavbarCart(productQuantity, productPrice);

        //record to cart
        if (cartObj[productId]) {
            cartObj[productId] = cartObj[productId] + productQuantity;
        } else {
            cartObj[productId] = productQuantity;
        }

        //set cookie
        Cookies.set('cart', JSON.stringify(cartObj));
    });

    $('.product-remove').on('click', function(e){
        e.preventDefault();
        var productRecord = $(this).closest('tr');
        productRecord.remove();

        recalculateCart();
    });

    $('.clear-cart').on('click', function(e){
        e.preventDefault();
        $('.product-position').each(function () {
                $(this).remove();
            }
        );
        recalculateCart();
    });

    $(".quantity").bind('keyup change click', function (e) {
        if (! $(this).data("previousValue") || $(this).data("previousValue") != $(this).val()) {
            $(this).data("previousValue", $(this).val());

            //if quantity changed
            recalculateCart();
        }
    });

    $(".quantity").each(function () {
        $(this).data("previousValue", $(this).val());
    });
});

function recalculateCart(){
    var totalSum = 0;
    var totalQuantity = 0;
    var cartObj = {};

    $('.product-position').each(function () {
        var quantityInput = $(this).find('.quantity');

        //get all values
        var productId = toPositiveInt(quantityInput.data('id'));
        var productQuantity = toPositiveInt(quantityInput.val());
        var productPrice = toPositiveInt($(this).find('.price span').text());
        var productSum = productPrice * productQuantity;

        //show new sum
        var productSumSelector = $(this).find('.sum');
        productSumSelector.html(productSum);

        //record to obj
        cartObj[productId] = productQuantity;

        totalSum += productSum;
        totalQuantity += productQuantity;
    });

    //show new total sum
    var totalSumSelector = $('.totalsum');
    totalSumSelector.html(totalSum);

    //update navbar cart
    updateNavbarCart(totalQuantity, totalSum);

    //update cookies
    Cookies.remove('cart');
    Cookies.set('cart', JSON.stringify(cartObj));
}

function toPositiveInt(rawVal) {
    return Math.abs(Math.round(rawVal));
}

function addToNavbarCart(quantity, price){
    //find selectors
    var quantitySelector = $('#cart-quantity');
    var sumSelector = $('#cart-sum');

    var oldQuantity = toPositiveInt(quantitySelector.text());
    var oldSum = toPositiveInt(sumSelector.text());

    if (quantity > 0 && price > 0) {
        var newQuantity = oldQuantity + quantity;
        var newSum = oldSum + (price * quantity);

        quantitySelector.text(newQuantity);
        sumSelector.text(newSum);
    }
}

function updateNavbarCart(totalQuantity, totalSum){
    //find selectors
    var quantitySelector = $('#cart-quantity');
    var sumSelector = $('#cart-sum');

    //show new values
    quantitySelector.text(totalQuantity);
    sumSelector.text(totalSum);
}<commit_msg>fix product add to cart click trigger<commit_after>$(document).ready(function () {
    $('[data-toggle="confirmation"]').confirmation();

    $(document).on('click', '.addtocart-btn', function (e) {
        e.preventDefault();
        //define var
        var cartObj;

        //get all cart
        if (Cookies.get('cart')) {
            cartObj = JSON.parse(Cookies.get('cart'));
        } else {
            cartObj = {};
        }

        //get new vars
        var productRow = $(this).closest('.id-row');

        var productIdRaw = productRow.data('id');
        var productId = toPositiveInt(productIdRaw);

        var productQuantityRaw = productRow.find('.addtocart-input').val();
        var productQuantity = toPositiveInt(productQuantityRaw);
        if (isNaN(productQuantity)) {
            productQuantity = 1;
        }

        var productPriceRaw = productRow.parent().find('.price span').text();
        var productPrice = toPositiveInt(productPriceRaw);
        addToNavbarCart(productQuantity, productPrice);

        //record to cart
        if (cartObj[productId]) {
            cartObj[productId] = cartObj[productId] + productQuantity;
        } else {
            cartObj[productId] = productQuantity;
        }

        //set cookie
        Cookies.set('cart', JSON.stringify(cartObj));
    });

    $('.product-remove').on('click', function(e){
        e.preventDefault();
        var productRecord = $(this).closest('tr');
        productRecord.remove();

        recalculateCart();
    });

    $('.clear-cart').on('click', function(e){
        e.preventDefault();
        $('.product-position').each(function () {
                $(this).remove();
            }
        );
        recalculateCart();
    });

    $(".quantity").bind('keyup change click', function (e) {
        if (! $(this).data("previousValue") || $(this).data("previousValue") != $(this).val()) {
            $(this).data("previousValue", $(this).val());

            //if quantity changed
            recalculateCart();
        }
    });

    $(".quantity").each(function () {
        $(this).data("previousValue", $(this).val());
    });
});

function recalculateCart(){
    var totalSum = 0;
    var totalQuantity = 0;
    var cartObj = {};

    $('.product-position').each(function () {
        var quantityInput = $(this).find('.quantity');

        //get all values
        var productId = toPositiveInt(quantityInput.data('id'));
        var productQuantity = toPositiveInt(quantityInput.val());
        var productPrice = toPositiveInt($(this).find('.price span').text());
        var productSum = productPrice * productQuantity;

        //show new sum
        var productSumSelector = $(this).find('.sum');
        productSumSelector.html(productSum);

        //record to obj
        cartObj[productId] = productQuantity;

        totalSum += productSum;
        totalQuantity += productQuantity;
    });

    //show new total sum
    var totalSumSelector = $('.totalsum');
    totalSumSelector.html(totalSum);

    //update navbar cart
    updateNavbarCart(totalQuantity, totalSum);

    //update cookies
    Cookies.remove('cart');
    Cookies.set('cart', JSON.stringify(cartObj));
}

function toPositiveInt(rawVal) {
    return Math.abs(Math.round(rawVal));
}

function addToNavbarCart(quantity, price){
    //find selectors
    var quantitySelector = $('#cart-quantity');
    var sumSelector = $('#cart-sum');

    var oldQuantity = toPositiveInt(quantitySelector.text());
    var oldSum = toPositiveInt(sumSelector.text());

    if (quantity > 0 && price > 0) {
        var newQuantity = oldQuantity + quantity;
        var newSum = oldSum + (price * quantity);

        quantitySelector.text(newQuantity);
        sumSelector.text(newSum);
    }
}

function updateNavbarCart(totalQuantity, totalSum){
    //find selectors
    var quantitySelector = $('#cart-quantity');
    var sumSelector = $('#cart-sum');

    //show new values
    quantitySelector.text(totalQuantity);
    sumSelector.text(totalSum);
}<|endoftext|>


<commit_before>
'use strict';
var AWS = require('aws-sdk');
var dynamodb = new AWS.DynamoDB({apiVersion: '2012-08-10'});

module.exports.saveEmailStatus = (event, context, callback) => {

	var addressList = [];

	console.log("Message", event.Records[0].Sns.Message);

	event.Records[0].Sns.Message.mail.destination.forEach((addr) => {
		addressList.push(addr);
	})

	var status;
	if (event.Records[0].Sns.Message.mail.notificationType === "Delivery") {
		status = "Delivered";
	} else if (event.Records[0].Sns.Message.mail.bounce) {
		if (event.Records[0].Sns.Message.mail.bounce.bounceSubtype === "General") {
			status = "No domain";
		} else {
			status = "Bad email address";
		}
	} else {
		status = "Complaint";
	}

	var messageId = event.Records[0].Sns.Message.mail.messageId;

	var params = {
		"Key": {
			"MessageId": {
				S: messageId
			}
		},
		"ReturnValues":"NONE",
		"ExpressionAttributeNames": {
			"#AL": "Addresses",
			"#S":"Status"
		},
		"ExpressionAttributeValues": {
			":al": {
				"SS":addressList
			},
			":s": {
				"S":status
			}
		},
		"UpdateExpression": "SET #AL = :al, #S = :s",
  		"TableName": "SentEmailStatus"
	};

	postToDynamoDB(params).then((res) => {
		console.log("resForPost", res);
	})

};

function postToDynamoDB(params) {
	return new Promise((resolve, reject) => {
		dynamodb.updateItem(params, (err, data) => {
			if (err) {
				console.log(err);
				console.log("These params were rejected: ", params);
				reject(err);
			} else {
				resolve(data);
			}
		})
	})
}
<commit_msg>Add more logging.<commit_after>
'use strict';
var AWS = require('aws-sdk');
var dynamodb = new AWS.DynamoDB({apiVersion: '2012-08-10'});

module.exports.saveEmailStatus = (event, context, callback) => {

	var addressList = [];

	console.log("Message", event.Records[0].Sns.Message);
	console.log("Mail", event.Records[0].Sns.Message.mail);

	if (event.Records[0].Sns.Message.mail.destination !== null) {
		event.Records[0].Sns.Message.mail.destination.forEach((addr) => {
			addressList.push(addr);
		})

		var status;
		if (event.Records[0].Sns.Message.mail.notificationType === "Delivery") {
			status = "Delivered";
		} else if (event.Records[0].Sns.Message.mail.bounce) {
			if (event.Records[0].Sns.Message.mail.bounce.bounceSubtype === "General") {
				status = "No domain";
			} else {
				status = "Bad email address";
			}
		} else {
			status = "Complaint";
		}

		var messageId = event.Records[0].Sns.Message.mail.messageId;

		var params = {
			"Key": {
				"MessageId": {
					S: messageId
				}
			},
			"ReturnValues":"NONE",
			"ExpressionAttributeNames": {
				"#AL": "Addresses",
				"#S":"Status"
			},
			"ExpressionAttributeValues": {
				":al": {
					"SS":addressList
				},
				":s": {
					"S":status
				}
			},
			"UpdateExpression": "SET #AL = :al, #S = :s",
  			"TableName": "SentEmailStatus"
		};

		postToDynamoDB(params).then((res) => {
			console.log("resForPost", res);
		}
	} else {
		console.log("Destination was null ");
	}
};

function postToDynamoDB(params) {
	return new Promise((resolve, reject) => {
		dynamodb.updateItem(params, (err, data) => {
			if (err) {
				console.log(err);
				console.log("These params were rejected: ", params);
				reject(err);
			} else {
				resolve(data);
			}
		})
	})
}
<|endoftext|>


<commit_before>var transformer = require('validate'); // todo: require('transformer');

module.exports = function(req, res, next) {
    /**
     * @param {Object|Object[]} objectOrArray
     * @param {Object}          map
     * @param {Object}          [meta]
     */
    res.sendObject = function(objectOrArray, map, meta) {
        var data;

        if (objectOrArray instanceof Array) {
            data = objectOrArray.map(function(object) {
                return transformer(object, map).clean().filter().result;
            });
        } else {
            data = transformer(objectOrArray, map).clean().filter().result;
        }

        return res.sendData(data, meta);
    };

    next();
};<commit_msg>transformResponse<commit_after>var transformer = require('validate'); // todo: require('transformer');

var transformResponse = function(object, map) {
    return transformer(object, map).clean().filter().result;
};

module.exports = function(req, res, next) {
    /**
     * @param {Object|Object[]} objectOrArray
     * @param {Object}          map
     * @param {Object}          [meta]
     */
    res.sendObject = function(objectOrArray, map, meta) {
        var data;

        if (objectOrArray instanceof Array) {
            data = objectOrArray.map(function(object) {
                return transformResponse(object, map);
            });
        } else {
            data = transformResponse(objectOrArray, map);
        }

        return res.sendData(data, meta);
    };

    next();
};<|endoftext|>


<commit_before>'use strict';

var Page = require('./../base');

var groupsSection = element(by.id('groups'));

module.exports = Page.extend({

  selectSystemNavbarItem: function(navbarItem) {
    var index = [
      'General',
      'License Key'
    ];
    var item;
    var itemIndex = index.indexOf(navbarItem) + 2;

    if (itemIndex)
      item = groupsSection.element(by.css('.sidebar-nav ul li:nth-child(' + itemIndex + ')'));
    else
      item = groupsSection.element(by.css('.sidebar-nav ul li:nth-child(1)'));

    item.click();
    return item;
  },

  boxHeader: function() {
    return groupsSection.element(by.css('legend')).getText();
  }

});<commit_msg>test(admin/e2e): change header selector<commit_after>'use strict';

var Page = require('./../base');

var groupsSection = element(by.css('section'));

module.exports = Page.extend({

  selectSystemNavbarItem: function(navbarItem) {
    var index = [
      'General',
      'License Key'
    ];
    var item;
    var itemIndex = index.indexOf(navbarItem) + 2;

    if (itemIndex)
      item = groupsSection.element(by.css('.sidebar-nav ul li:nth-child(' + itemIndex + ')'));
    else
      item = groupsSection.element(by.css('.sidebar-nav ul li:nth-child(1)'));

    item.click();
    return item;
  },

  boxHeader: function() {
    return groupsSection.element(by.css('legend')).getText();
  }

});
<|endoftext|>


<commit_before>var async = require('async');
var _ = require('lodash');

module.exports = function(self, cursor) {

  // With docs in general it doesn't make sense to show unpublished docs most
  // of the time, however with pages it makes sense to show them as long as the
  // user has permission, which is checked for separately
  cursor.filters.published.def = null;

  cursor.addFilter('ancestors', {
    def: false,
    after: function(results, callback) {
      var options = cursor.get('ancestors');

      if (!options) {
        return setImmediate(callback);
      }

      return async.eachSeries(results, function(page, callback) {
        var req = cursor.get('req');

        var aCursor = self.find(req).areas(false);

        var parameters = applySubcursorOptions(aCursor, options, [ 'depth' ]);

        var components = page.path.split('/');
        var paths = [];
        var path = '';
        _.each(components, function(component) {
          path += component;
          // Don't redundantly load ourselves
          if (path === page.path) {
            return;
          }
          // Special case: the path of the homepage
          // is /, not an empty string
          var queryPath = path;
          if (queryPath === '') {
            queryPath = '/';
          }
          paths.push(queryPath);
          path += '/';
        });

        if (parameters.depth !== undefined) {
          paths = paths.slice(- parameters.depth);
        }

        aCursor.and({
          path: { $in: paths }
        });

        aCursor.sort({ path: 1 });

        return aCursor.toArray(function(err, _ancestors) {
          if (err) {
            return callback(err);
          }
          page._ancestors = _ancestors;
          return callback(null);
        });
      }, callback);
    }
  });

  cursor.addFilter('children', {
    def: false,
    after: function(results, callback) {
      var value = cursor.get('children');
      if (!value) {
        return setImmediate(callback);
      }

      var cCursor = self.find(cursor.get('req')).areas(false);

      var parameters = applySubcursorOptions(cCursor, value, [ 'depth' ]);

      var depth = parameters.depth;
      // Careful, let them specify a depth of 0 but still have a good default
      if (depth === undefined) {
        depth = 1;
      }
      if (!depth) {
        return setImmediate(callback);
      }

      var clauses = [];

      _.each(results, function(page) {
        clauses.push({
          $and: [
            {
              path: new RegExp('^' + self.apos.utils.regExpQuote(self.apos.utils.addSlashIfNeeded(page.path))),
              level: { $gt: page.level, $lte: page.level + depth }
            }
          ]
        });
      });

      // Because mongo is incredibly stubborn in
      // that awful mysql way now
      if (clauses.length) {
        cCursor.and({ $or: clauses });
      } else {
        cCursor.and({ ___neverEverDefined: true });
      }

      cCursor.sort({ level: 1, rank: 1 });

      var pagesByPath = {};
      _.each(results, function(page) {
        pagesByPath[page.path] = page;
        page._children = [];
      });

      return cCursor.toArray(function(err, descendants) {
        if (err) {
          return callback(err);
        }

        try {
          _.each(descendants, function(page) {
            if (_.has(pagesByPath, page.path)) {
              // This object is one of the original results
              // but was also returned as a descendant of
              // another original result. Ignore it so the
              // chain of children is attached to the
              // original result instead
              return;
            }
            page._children = [];
            pagesByPath[page.path] = page;
            var last = page.path.lastIndexOf('/');
            var parentPath = page.path.substr(0, last);
            if (parentPath === '') {
              parentPath = '/';
            }
            if (pagesByPath[parentPath]) {
              pagesByPath[parentPath]._children.push(page);
            } else {
              throw new Error('internal inconsistency in children()');
            }
          });
        } catch (e) {
          return callback(e);
        }
        return callback(null);
      });
    }
  });

  // Use .reorganize(true) to return only pages that
  // are suitable for display in the reorganize view.
  // For instance, if you have thousands of subpages
  // of a "blog" page, you might want to hide them from
  // the global reorganize interface by setting their
  // reorganize property to false. —Tom and Sam

  cursor.addFilter('reorganize', {
    def: null,
    finalize: function() {
      var state = cursor.get('reorganize');
      if (state === null) {
        return;
      } else if (state === true) {
        cursor.and({
          reorganize: { $ne: false }
        });
      } else if (state === false) {
        cursor.and({
          reorganize: false
        });
      }
    }
  });
};

function applySubcursorOptions(aCursor, options, ours) {
  var parameters = {};
  if (options === true) {
    // OK, go with defaults
  } else if (typeof(options) === 'object') {
    parameters = _.pick(options, ours);

    // Pass everything that's not a parameter to
    // cursor used to get ancestors
    _.each(_.omit(options, ours), function(val, key) {
      aCursor[key](val);
    });
    if (options.callback) {
      options.callback(aCursor);
    }
  } else if (typeof(options) === 'function') {
    options(aCursor);
  } else {
    // something else truthy, go with defaults
  }
  return parameters;
}
<commit_msg>fixed the logic for not loading the page itself as one of its ancestors, also the logic for ensuring that if we are fetching children of several pages they are attached to the original page and not an object fetched as a child of one of the others<commit_after>var async = require('async');
var _ = require('lodash');

module.exports = function(self, cursor) {

  // With docs in general it doesn't make sense to show unpublished docs most
  // of the time, however with pages it makes sense to show them as long as the
  // user has permission, which is checked for separately
  cursor.filters.published.def = null;

  cursor.addFilter('ancestors', {
    def: false,
    after: function(results, callback) {
      var options = cursor.get('ancestors');

      if (!options) {
        return setImmediate(callback);
      }

      return async.eachSeries(results, function(page, callback) {
        var req = cursor.get('req');

        var aCursor = self.find(req).areas(false);

        var parameters = applySubcursorOptions(aCursor, options, [ 'depth' ]);

        var components = page.path.split('/');
        var paths = [];
        var path = '';
        _.each(components, function(component) {
          path += component;
          // Special case: the path of the homepage
          // is /, not an empty string
          var queryPath = path;
          if (queryPath === '') {
            queryPath = '/';
          }
          // Don't redundantly load ourselves
          if (queryPath === page.path) {
            return;
          }
          paths.push(queryPath);
          path += '/';
        });

        if (parameters.depth !== undefined) {
          paths = paths.slice(- parameters.depth);
        }

        aCursor.and({
          path: { $in: paths }
        });

        aCursor.sort({ path: 1 });

        return aCursor.toArray(function(err, _ancestors) {
          if (err) {
            return callback(err);
          }
          page._ancestors = _ancestors;
          return callback(null);
        });
      }, callback);
    }
  });

  cursor.addFilter('children', {
    def: false,
    after: function(results, callback) {
      var value = cursor.get('children');
      if (!value) {
        return setImmediate(callback);
      }

      var cCursor = self.find(cursor.get('req')).areas(false);

      var parameters = applySubcursorOptions(cCursor, value, [ 'depth' ]);

      var depth = parameters.depth;
      // Careful, let them specify a depth of 0 but still have a good default
      if (depth === undefined) {
        depth = 1;
      }
      if (!depth) {
        return setImmediate(callback);
      }

      var clauses = [];

      _.each(results, function(page) {
        clauses.push({
          $and: [
            {
              path: new RegExp('^' + self.apos.utils.regExpQuote(self.apos.utils.addSlashIfNeeded(page.path))),
              level: { $gt: page.level, $lte: page.level + depth }
            }
          ]
        });
      });

      // Because mongo is incredibly stubborn in
      // that awful mysql way now
      if (clauses.length) {
        cCursor.and({ $or: clauses });
      } else {
        cCursor.and({ ___neverEverDefined: true });
      }

      cCursor.sort({ level: 1, rank: 1 });

      var pagesByPath = {};
      _.each(results, function(page) {
        pagesByPath[page.path] = page;
        page._children = [];
      });

      return cCursor.toArray(function(err, descendants) {
        if (err) {
          return callback(err);
        }

        try {
          _.each(descendants, function(page) {
            if (!_.has(pagesByPath, page.path)) {
              page._children = [];
              pagesByPath[page.path] = page;
            }
            var last = page.path.lastIndexOf('/');
            var parentPath = page.path.substr(0, last);
            if (parentPath === '') {
              parentPath = '/';
            }
            if (pagesByPath[parentPath]) {
              pagesByPath[parentPath]._children.push(page);
            } else {
              throw new Error('internal inconsistency in children()');
            }
          });
        } catch (e) {
          return callback(e);
        }
        return callback(null);
      });
    }
  });

  // Use .reorganize(true) to return only pages that
  // are suitable for display in the reorganize view.
  // For instance, if you have thousands of subpages
  // of a "blog" page, you might want to hide them from
  // the global reorganize interface by setting their
  // reorganize property to false. —Tom and Sam

  cursor.addFilter('reorganize', {
    def: null,
    finalize: function() {
      var state = cursor.get('reorganize');
      if (state === null) {
        return;
      } else if (state === true) {
        cursor.and({
          reorganize: { $ne: false }
        });
      } else if (state === false) {
        cursor.and({
          reorganize: false
        });
      }
    }
  });
};

function applySubcursorOptions(aCursor, options, ours) {
  var parameters = {};
  if (options === true) {
    // OK, go with defaults
  } else if (typeof(options) === 'object') {
    parameters = _.pick(options, ours);

    // Pass everything that's not a parameter to
    // cursor used to get ancestors
    _.each(_.omit(options, ours), function(val, key) {
      aCursor[key](val);
    });
    if (options.callback) {
      options.callback(aCursor);
    }
  } else if (typeof(options) === 'function') {
    options(aCursor);
  } else {
    // something else truthy, go with defaults
  }
  return parameters;
}
<|endoftext|>


<commit_before>/**
 * Copyright 2016 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

module.exports = function(context) {
  return {
    ExportNamedDeclaration: function(node) {
      if (node.declaration) {
        const {declaration} = node;
        if (declaration.type === 'VariableDeclaration') {
          declaration.declarations
            .map(function(declarator) {
              return declarator.init;
            })
            .filter(function(init) {
              return init && /(?:Call|New)Expression/.test(init.type);
            })
            .forEach(function(init) {
              context.report({
                node: init,
                message: 'Cannot export side-effect',
              });
            });
        }
      } else if (node.specifiers) {
        context.report({
          node,
          message: 'Side-effect linting not implemented',
        });
      }
    },
  };
};
<commit_msg>Removes extra check (#22913)<commit_after>/**
 * Copyright 2016 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

module.exports = function(context) {
  return {
    ExportNamedDeclaration: function(node) {
      if (node.declaration) {
        const {declaration} = node;
        if (declaration.type === 'VariableDeclaration') {
          declaration.declarations
            .map(function(declarator) {
              return declarator.init;
            })
            .filter(function(init) {
              return init && /(?:Call|New)Expression/.test(init.type);
            })
            .forEach(function(init) {
              context.report({
                node: init,
                message: 'Cannot export side-effect',
              });
            });
        }
      }
    },
  };
};
<|endoftext|>


<commit_before>import EditorControllerMixin from 'ghost/mixins/editor-base-controller';

var EditorNewController = Ember.ObjectController.extend(EditorControllerMixin, {
    actions: {
        /**
          * Redirect to editor after the first save
          */
        save: function () {
            var self = this;
            this._super().then(function (model) {
                if (model.get('id')) {
                    self.transitionTo('editor.edit', model);
                }
                return model;
            });
        }
    }
});

export default EditorNewController;
<commit_msg>Fix warning about transitionTo being deprecated<commit_after>import EditorControllerMixin from 'ghost/mixins/editor-base-controller';

var EditorNewController = Ember.ObjectController.extend(EditorControllerMixin, {
    actions: {
        /**
          * Redirect to editor after the first save
          */
        save: function () {
            var self = this;
            this._super().then(function (model) {
                if (model.get('id')) {
                    self.transitionToRoute('editor.edit', model);
                }
                return model;
            });
        }
    }
});

export default EditorNewController;
<|endoftext|>


<commit_before>function PhotoLibrary() {}

PhotoLibrary.imageFromImage = function (imgElm, successCallback, failureCallback) {
  if (!imgElm.complete) {
    failureCallback && failureCallback('Image has not been loaded')
    return
  }

  var canvas = document.createElement('canvas')
  var ctx = canvas.getContext('2d')
  var devicePixelRatio = window.devicePixelRatio || 1
  var backingStoreRatio = ctx.webkitBackingStorePixelRatio || 1
  var ratio = devicePixelRatio / backingStoreRatio

  canvas.width = imgElm.naturalWidth * ratio
  canvas.height = imgElm.naturalHeight * ratio
  ctx.scale(ratio, ratio)

  ctx.drawImage(imgElm, 0, 0, img.naturalWidth, img.naturalHeight)

  return PhotoLibrary.imageFromCanvas(canvas)
}

PhotoLibrary.imageFromCanvas = function (canvas, successCallback, failureCallback) {
  var base64Str = canvas.toDataURL().replace(/data:image\/png;base64,/,'')
  return PhotoLibrary.imageFromBase64(base64Str, successCallback, failureCallback)
}

PhotoLibrary.imageFromBase64 = function (base64Str, successCallback, failureCallback) {
  return PhotoLibrary.imageFromUrl('data:;base64,' + base64Str, successCallback, failureCallback)
}

PhotoLibrary.imageFromUrl = function (url, successCallback, failureCallback) {
  return cordova.exec(successCallback, failureCallback, 'PhotoLibrary', 'imageFromUrl', [url])
}

PhotoLibrary.videoFromUrl = function (url, successCallback, failureCallback) {
  return cordova.exec(successCallback, failureCallback, 'PhotoLibrary', 'videoFromUrl', [url])
}

module.exports = PhotoLibrary
<commit_msg>fix local parameter name of PhotoLibrary.imageFromImage<commit_after>function PhotoLibrary() {}

PhotoLibrary.imageFromImage = function (imgElm, successCallback, failureCallback) {
  if (!imgElm.complete) {
    failureCallback && failureCallback('Image has not been loaded')
    return
  }

  var canvas = document.createElement('canvas')
  var ctx = canvas.getContext('2d')
  var devicePixelRatio = window.devicePixelRatio || 1
  var backingStoreRatio = ctx.webkitBackingStorePixelRatio || 1
  var ratio = devicePixelRatio / backingStoreRatio

  canvas.width = imgElm.naturalWidth * ratio
  canvas.height = imgElm.naturalHeight * ratio
  ctx.scale(ratio, ratio)

  ctx.drawImage(imgElm, 0, 0, imgElm.naturalWidth, imgElm.naturalHeight)

  return PhotoLibrary.imageFromCanvas(canvas)
}

PhotoLibrary.imageFromCanvas = function (canvas, successCallback, failureCallback) {
  var base64Str = canvas.toDataURL().replace(/data:image\/png;base64,/,'')
  return PhotoLibrary.imageFromBase64(base64Str, successCallback, failureCallback)
}

PhotoLibrary.imageFromBase64 = function (base64Str, successCallback, failureCallback) {
  return PhotoLibrary.imageFromUrl('data:;base64,' + base64Str, successCallback, failureCallback)
}

PhotoLibrary.imageFromUrl = function (url, successCallback, failureCallback) {
  return cordova.exec(successCallback, failureCallback, 'PhotoLibrary', 'imageFromUrl', [url])
}

PhotoLibrary.videoFromUrl = function (url, successCallback, failureCallback) {
  return cordova.exec(successCallback, failureCallback, 'PhotoLibrary', 'videoFromUrl', [url])
}

module.exports = PhotoLibrary
<|endoftext|>


<commit_before>"use strict";

var assert = require('assert');

var Game = function() {
  return {
    score: function() {
      return '0 - 0';
    }
  };
};

describe('tennis', function() {
  describe('game', function() {
    it('starts at 0-0', function() {
      var game = new Game('Joe', 'Fred');
      assert.equal('Joe 0 - Fred 0', game.score());
    });
  });
});
<commit_msg>make the players names work<commit_after>"use strict";

var assert = require('assert');

var Game = function(player1,player2) {
  return {
    score: function() {
      return player1 + ' 0 - ' + player2 + ' 0';
    }
  };
};

describe('tennis', function() {
  describe('game', function() {
    it('starts at 0-0', function() {
      var game = new Game('Joe', 'Fred');
      assert.equal('Joe 0 - Fred 0', game.score());
    });
  });
});
<|endoftext|>