<commit_before>/*global

$: true,
playlistManager: true,
loadPlaylistView: true,

*/

/** EVENTS
 ****************************************************************************/

function deleteVideoButtonClicked(li) {
    var playlist = playlistManager.getCurrentlySelectedPlaylist();
    var allSelectedVideos = li.parent().find('.video.selected');

    $.each(allSelectedVideos, function(index, item) {
        $video = $(item);
        playlist.deleteVideo($video.index());
        $video.remove();
    });

    playlistManager.save();
}

function playlistMouseDown(event) {
	$('#left-menu li').removeClass('selected');
	$(this).addClass('selected');
}

function loadPlaylist(playlistId) {
    $.ajax({
        url: '/api/playlists/' + playlistId,
        type: 'GET',
        statusCode: {
            200: function(data) {
                var playlist = new Playlist(data.title, data.videos, data.remoteId, data.owner, data.isPrivate);
                playlist.createViews();
                loadPlaylistView(playlist);
            },
            404: function(data) {
                alert("No such playlist found");
            }
        }
    });
}

function followPlaylist(event) {
    var $playlistBar = $('#right > .playlists .info');
    var playlist = $playlistBar.data('model');

    playlist.createViews();
    playlistManager.addPlaylist(playlist);
    playlist.getMenuView().appendTo('#left .playlists ul');

    if (logged_in) {
        playlist.subscribe(function() {
            playlistManager.save();
            playlist.getMenuView().addClass('remote');
        });
    } else {
        playlist.remoteId = null;
        playlistManager.save();
    }

    $playlistBar.find('.copy').hide();
}

function savePlaylistButtonClicked(event) {
    var $playlistBar = $('#right > .playlists .info');
    var playlist = $playlistBar.data('model');
    var newPlaylist = playlist.copy(); // create copy without connection to remote

    newPlaylist.createViews();
    playlistManager.addPlaylist(newPlaylist);
    newPlaylist.getMenuView().appendTo('#left .playlists ul');

    if (logged_in) {
        newPlaylist.createNewPlaylistOnRemote(function() {
            playlistManager.save();
            newPlaylist.getMenuView().addClass('remote');
        });
    } else {
        playlistManager.save();
    }

    $playlistBar.find('.copy').hide();
}

function syncPlaylistButtonClicked(event) {
    var playlist = playlistManager.getCurrentlySelectedPlaylist();
    console.log('syncing playlist ' + playlist.title);
    playlist.sync(function() {
        updatePlaylistBar(playlist);
        playlistManager.save();
        playlist.getMenuView().addClass('remote');
        history.pushState(null, null, playlist.getUrl());
    });
}

function showPlaylistSharePopup(playlist, elem, arrowDirection) {
    $('#share-playlist-popup .link input').val(playlist.getUrl());

    $('#share-playlist-popup .twitter')
        .unbind('click')
        .click(function(event) {
            event.preventDefault();
            window.open(playlist.getTwitterShareUrl(), 'Share playlist on Twitter', 400, 400);
            return false;
        });

    $('#share-playlist-popup .facebook')
        .unbind('click')
        .click(function(event) {
            event.preventDefault();
            window.open(playlist.getFacebookShareUrl(), 'Share playlist on Facebook', 400, 400);
            return false;
        });

    elem.arrowPopup('#share-playlist-popup', arrowDirection);
}

function shareButtonClicked(event) {
    var playlistBar = $(this).parent();
    var playlist = playlistBar.data('playlist');
    showPlaylistSharePopup(playlist, $(this), 'up');
}

function updatePlaylistBar(playlist) {
    var $playlistBar = $('#right > .playlists .info');
    $playlistBar.data('model', playlist);
    $playlistBar.find('.title').text(playlist.title);
    $playlistBar.find('.owner').hide();
    $playlistBar.find('.copy').hide().unbind('click');
    $playlistBar.find('.sync').hide().unbind('click');
    $playlistBar.find('.subscribe').hide().unbind('click');

    if (playlist.owner) {
        $playlistBar.find('.owner').click(function() {
            history.pushState(null, null, '/users/' + playlist.owner.id);
            Menu.deSelectAll();
            UserManager.loadProfile(playlist.owner.id);
        }).text(playlist.owner.displayname).show();

        // Add save button if not already saved
        if (!playlistManager.getPlaylistsMap().hasOwnProperty(playlist.remoteId)) {
           $playlistBar.find('.copy').show().one('click', savePlaylistButtonClicked);
        }
        if (Number(playlist.owner.id) !== Number(UserManager.currentUser.id) && logged_in && playlist.isSubcription === false) {
            $playlistBar.find('.subscribe').click(function() {
                playlist.subscribe();
            });
        }
    } else if (logged_in) {
        $playlistBar.find('.sync').show().one('click', syncPlaylistButtonClicked);
    }
}

function loadPlaylistView(playlist) {
    $('#right > div').hide();

	$('#right > .playlists .pane').hide().removeClass('active');
    $('#left .menu li').removeClass('selected');

    playlist.playlistDOMHandle.addClass('active');
    playlist.leftMenuDOMHandle.addClass('selected');

    updatePlaylistBar(playlist);

    if (playlist.playlistDOMHandle.find('.video').length !== playlist.videos.length) {
        playlist.playlistDOMHandle.html('');
        $.each(playlist.videos, function(i, item) {
            if (item) {
                $video = item.createListView();
                $video.data('additionalMenuButtons', [{
                    title: 'Delete',
                    args: $video,
                    callback: deleteVideoButtonClicked
                }]);
                $video.addClass('droppable');
                $video.addClass('draggable');
                $video.addClass('reorderable');
                $video.appendTo(playlist.playlistDOMHandle);
            }
        });
    }
	playlist.playlistDOMHandle.show();
    $('#right > .playlists').show();
}

/**
 * Mark the playlistElem in the #left as selected, then
 * fill #playlist with the contained videos.
 */
function playlistClicked(event) {
    var playlist = $(this).data('model');

    if (playlist.remoteId) {
        history.pushState(null, null, playlist.getUrl());
    } else {
        history.pushState(null, null, '/');
    }

    loadPlaylistView(playlist);
}

/** CLASS PLAYLIST
 ****************************************************************************/

function Playlist(title, videos, remoteId, owner, isPrivate, followers) {
    var i,
        self = this;
    self.title = title;
    self.videos = [];
    /* The loop that adds videos to self.videos is moved to the end of the class to avoid reference errors */
    self.remoteId = remoteId || null;
    self.owner = owner;
    self.isPrivate = isPrivate || false;
    self.followers = followers || [];
    self.synced = true; // not part of JSON structure
    self.syncing = false; // not part of JSON structure
    self.isSubcription = false;
    for (i = 0; i < self.followers.length; i++) {
        if (Number(self.followers[i].id) === Number(my_user_id)) {
            self.isSubcription = true;
            break;
        }
    }
    self.leftMenuDOMHandle = null;
    self.playlistDOMHandle = null;

    self.getTwitterShareUrl = function() {
        var url = self.getUrl(),
            text = "Check out self playlist!" + ' -- ' + self.title;
        return encodeURI('http://twitter.com/share?related=youtify&via=youtify' + '&url=' + url + '&counturl=' + url + '&text=' + text);
    };

    self.getFacebookShareUrl = function() {
        var url = self.getUrl();
        return 'http://facebook.com/sharer.php?u=' + url;
    };

    self.getUrl = function() {
        return location.protocol + '//' + location.host + '/users/' + self.owner.id + '/playlists/' + self.remoteId;
    };

    self.copy = function() {
        return new Playlist(self.title, self.videos);
    };

    self.getMenuView = function() {
        if (self.leftMenuDOMHandle === null) {
            self.createViews();
        }
        return self.leftMenuDOMHandle;
    };

    self.setAsPlaying = function() {
        $('#left .menu li').removeClass('playing');
        self.getMenuView().addClass('playing');
    };

    self.rename = function(newTitle) {
        var title = $.trim(newTitle);
        if (title.length > 0 && title.length < 50) {
            self.title = newTitle;
        }
        self.synced = false;
        if (self.leftMenuDOMHandle) {
            self.leftMenuDOMHandle.find('.title').text(newTitle);
        }
    };

    self.unsync = function(callback) {
        var url = '/api/playlists/' + self.remoteId;
        if (self.isSubscription) {
            url = '/api/playlists/follow/' + self.remoteId
        }
        $.ajax({
            type: 'DELETE',
            url: url,
			statusCode: {
				200: function(data) {
					if (callback) {
						callback();
					}
				},
				404: function(data) {
					alert(TranslationSystem.translations['No such playlist found']);
				},
				409: function(data) {
                    new ReloadDialog().show();
				}
			}
        });

        self.remoteId = null;
        self.owner = null;
    };

    self.subscribe = function(callback) {
        var params = {
            'device': device
        };

        self.syncing = true;
        $.ajax({
            type: 'POST',
            url: '/api/playlists/follow/' + self.remoteId,
            data: params,
            statusCode: {
                200: function(data, textStatus) {
                    self.syncing = false;
                    self.isSubscription = true;
                    self.followers.push(UserManager.currentUser);
                    if (textStatus === 'ok') {
                        self.synced = true;
                    } else {
                        alert('Failed to create new playlist ' + self.title);
                    }
                    if (callback) {
                        callback();
                    }
                },
                404: function(data) {
                    alert(TranslationSystem.translations['No such playlist found']);
                },
                409: function(data) {
                    new ReloadDialog().show();
                }
            }
        });
    };

    self.createNewPlaylistOnRemote = function(callback) {
        var params = {
                'json': JSON.stringify(self.toJSON()),
				'device': device
            };

        self.syncing = true;

		$.ajax({
            type: 'POST',
            url: '/api/playlists',
			data: params,
			statusCode: {
				200: function(data, textStatus) {
					self.syncing = false;
					if (textStatus === 'success') {
						self.remoteId = data.remoteId;
						self.owner = data.owner;
						self.synced = true;
                    } else {
						alert('Failed to create new playlist ' + self.title);
					}
					if (callback) {
						callback();
					}
				},
				409: function(data) {
                    new ReloadDialog().show();
				}
			}
        });
    };

    self.updatePlaylistOnRemote = function(callback) {
        if (self.isSubscription) {
            return;
        }
        var params = {
                'json': JSON.stringify(self.toJSON()),
				'device': device
            };

        self.syncing = true;

		$.ajax({
            type: 'POST',
            url: '/api/playlists/' + self.remoteId,
			data: params,
			statusCode: {
				200: function(data, textStatus) {
					self.syncing = false;
					if (textStatus === 'success') {
						self.synced = true;
					} else {
						alert('Failed to create new playlist ' + self.title);
					}
					if (callback) {
						callback();
					}
				},
				404: function(data) {
					alert(TranslationSystem.translations['No such playlist found']);
				},
				409: function(data) {
                    new ReloadDialog().show();
				}
			}
        });
    };

    self.sync = function(callback) {
        if (self.remoteId && self.synced) {
            callback();
        } else if (self.remoteId) {
            self.updatePlaylistOnRemote(callback);
        } else {
            self.createNewPlaylistOnRemote(callback);
        }
    };

    self.addVideo = function(video) {
        if (self.isSubscription) {
            return;
        }
        if (self.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        var newVideo = video.clone();
        newVideo.onPlayCallback = self.setAsPlaying;
        self.videos.push(newVideo);

        var $video = newVideo.createListView();
        $video.data('additionalMenuButtons', [{
            title: 'Delete',
            args: $video,
            callback: deleteVideoButtonClicked
        }]);
        $video.addClass('droppable');
        $video.addClass('draggable');
        $video.addClass('reorderable');
        $video.appendTo(self.playlistDOMHandle);

        self.synced = false;
    };

    self.moveVideo = function(sourceIndex, destIndex) {
        if (self.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        var tmp;

        if (destIndex > sourceIndex) {
            destIndex -= 1;
        }

        tmp = self.videos.splice(sourceIndex, 1)[0];
        self.videos.splice(destIndex, 0, tmp);

        self.synced = false;
    };

    self.deleteVideo = function(index) {
        if (self.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        self.videos.splice(index, 1);
        self.synced = false;
    };

    self.toJSON = function() {
        return {
            title: self.title,
            videos: self.videos,
            remoteId: self.remoteId,
            owner: self.owner,
            isPrivate: self.isPrivate
        };
    };

    self.createViews = function() {
        var table = $('
')
                .addClass('pane')
                .addClass('tracklist')
                .appendTo('#right > .playlists')
                .data('model', self),
            li = $('
')
                .addClass("playlistElem")
                .addClass('droppable')
                .data('model', self)
                .bind('contextmenu', showPlaylistContextMenu)
                .mousedown(playlistMouseDown)
                .click(playlistClicked);

        $('').text(self.title).appendTo(li);

        if (self.isSubscription) {
            li.addClass('subscription');
        }

        if (self.remoteId) {
            li.addClass('remote');
        } else {
            li.addClass('local');
        }

        if (self.isPrivate) {
            li.addClass('private');
        }
        self.leftMenuDOMHandle = li;
        self.playlistDOMHandle = table;
    };

	self.removeDuplicates = function() {
		var deleted = 0,
            i, j;
		for (i = self.videos.length-1; i > 0; i -= 1) {
			for (j = i-1; j >= 0; j -= 1) {
				if (self.videos[i].videoId === self.videos[j].videoId) {
					self.deleteVideo(j);
					deleted += 1;
					break;
				}
			}
		}
		playlistManager.save();
		loadPlaylistView(self);
		return deleted;
	};

    for (i = 0; i < videos.length; i+= 1) {
        if (videos[i]) {
            var video = new Video({
                videoId: videos[i].videoId,
                title: videos[i].title,
                type: videos[i].type,
                duration: videos[i].duration,
                onPlayCallback: self.setAsPlaying
            });
            self.videos.push(video);
        }
    }
}
<commit_msg>Added subscription button<commit_after>/*global

$: true,
playlistManager: true,
loadPlaylistView: true,

*/

/** EVENTS
 ****************************************************************************/

function deleteVideoButtonClicked(li) {
    var playlist = playlistManager.getCurrentlySelectedPlaylist();
    var allSelectedVideos = li.parent().find('.video.selected');

    $.each(allSelectedVideos, function(index, item) {
        $video = $(item);
        playlist.deleteVideo($video.index());
        $video.remove();
    });

    playlistManager.save();
}

function playlistMouseDown(event) {
	$('#left-menu li').removeClass('selected');
	$(this).addClass('selected');
}

function loadPlaylist(playlistId) {
    $.ajax({
        url: '/api/playlists/' + playlistId,
        type: 'GET',
        statusCode: {
            200: function(data) {
                var playlist = new Playlist(data.title, data.videos, data.remoteId, data.owner, data.isPrivate, data.followers);
                playlist.createViews();
                loadPlaylistView(playlist);
            },
            404: function(data) {
                alert("No such playlist found");
            }
        }
    });
}

function followPlaylist(event) {
    var $playlistBar = $('#right > .playlists .info');
    var playlist = $playlistBar.data('model');

    playlist.createViews();
    playlistManager.addPlaylist(playlist);
    playlist.getMenuView().appendTo('#left .playlists ul');

    if (logged_in) {
        playlist.subscribe(function() {
            playlistManager.save();
            playlist.getMenuView().addClass('remote');
        });
    } else {
        playlist.remoteId = null;
        playlistManager.save();
    }

    $playlistBar.find('.copy').hide();
}

function savePlaylistButtonClicked(event) {
    var $playlistBar = $('#right > .playlists .info');
    var playlist = $playlistBar.data('model');
    var newPlaylist = playlist.copy(); // create copy without connection to remote

    newPlaylist.createViews();
    playlistManager.addPlaylist(newPlaylist);
    newPlaylist.getMenuView().appendTo('#left .playlists ul');

    if (logged_in) {
        newPlaylist.createNewPlaylistOnRemote(function() {
            playlistManager.save();
            newPlaylist.getMenuView().addClass('remote');
        });
    } else {
        playlistManager.save();
    }

    $playlistBar.find('.copy').hide();
}

function syncPlaylistButtonClicked(event) {
    var playlist = playlistManager.getCurrentlySelectedPlaylist();
    console.log('syncing playlist ' + playlist.title);
    playlist.sync(function() {
        updatePlaylistBar(playlist);
        playlistManager.save();
        playlist.getMenuView().addClass('remote');
        history.pushState(null, null, playlist.getUrl());
    });
}

function showPlaylistSharePopup(playlist, elem, arrowDirection) {
    $('#share-playlist-popup .link input').val(playlist.getUrl());

    $('#share-playlist-popup .twitter')
        .unbind('click')
        .click(function(event) {
            event.preventDefault();
            window.open(playlist.getTwitterShareUrl(), 'Share playlist on Twitter', 400, 400);
            return false;
        });

    $('#share-playlist-popup .facebook')
        .unbind('click')
        .click(function(event) {
            event.preventDefault();
            window.open(playlist.getFacebookShareUrl(), 'Share playlist on Facebook', 400, 400);
            return false;
        });

    elem.arrowPopup('#share-playlist-popup', arrowDirection);
}

function shareButtonClicked(event) {
    var playlistBar = $(this).parent();
    var playlist = playlistBar.data('playlist');
    showPlaylistSharePopup(playlist, $(this), 'up');
}

function updatePlaylistBar(playlist) {
    var $playlistBar = $('#right > .playlists .info');
    $playlistBar.data('model', playlist);
    $playlistBar.find('.title').text(playlist.title);
    $playlistBar.find('.owner').hide();
    $playlistBar.find('.copy').hide().unbind('click');
    $playlistBar.find('.sync').hide().unbind('click');
    $playlistBar.find('.subscribe').hide().unbind('click');

    if (playlist.owner) {
        $playlistBar.find('.owner').click(function() {
            history.pushState(null, null, '/users/' + playlist.owner.id);
            Menu.deSelectAll();
            UserManager.loadProfile(playlist.owner.id);
        }).text(playlist.owner.displayname).show();

        // Add save button if not already saved
        if (!playlistManager.getPlaylistsMap().hasOwnProperty(playlist.remoteId)) {
           $playlistBar.find('.copy').show().one('click', savePlaylistButtonClicked);
        }
        /* Show subscription button */
        if (Number(playlist.owner.id) !== Number(UserManager.currentUser.id) && logged_in && playlist.isSubscription === false) {
            console.log(playlist);
            for (var i = 0; i < playlist.followers.length; i++) {
                if (Number(playlist.followers[i].id) === Number(UserManager.currentUser.id)) {
                    return;
                }
            }
            $playlistBar.find('.subscribe').click(function() {
                playlist.subscribe();
            }).show();
        }
    } else if (logged_in) {
        $playlistBar.find('.sync').show().one('click', syncPlaylistButtonClicked);
    }
}

function loadPlaylistView(playlist) {
    $('#right > div').hide();

	$('#right > .playlists .pane').hide().removeClass('active');
    $('#left .menu li').removeClass('selected');

    playlist.playlistDOMHandle.addClass('active');
    playlist.leftMenuDOMHandle.addClass('selected');

    updatePlaylistBar(playlist);
    console.log(playlist.isSubscription);
    if (playlist.playlistDOMHandle.find('.video').length !== playlist.videos.length) {
        playlist.playlistDOMHandle.html('');
        $.each(playlist.videos, function(i, item) {
            if (item) {
                $video = item.createListView();
                $video.addClass('droppable');
                $video.addClass('draggable');
                if (!playlist.isSubscription) {
                    $video.data('additionalMenuButtons', [{
                        title: 'Delete',
                        args: $video,
                        callback: deleteVideoButtonClicked
                    }]);

                    $video.addClass('reorderable');
                }
                $video.appendTo(playlist.playlistDOMHandle);
            }
        });
    }
	playlist.playlistDOMHandle.show();
    $('#right > .playlists').show();
}

/**
 * Mark the playlistElem in the #left as selected, then
 * fill #playlist with the contained videos.
 */
function playlistClicked(event) {
    var playlist = $(this).data('model');

    if (playlist.remoteId) {
        history.pushState(null, null, playlist.getUrl());
    } else {
        history.pushState(null, null, '/');
    }

    loadPlaylistView(playlist);
}

/** CLASS PLAYLIST
 ****************************************************************************/

function Playlist(title, videos, remoteId, owner, isPrivate, followers) {
    var i,
        self = this;
    self.title = title;
    self.videos = [];
    /* The loop that adds videos to self.videos is moved to the end of the class to avoid reference errors */
    self.remoteId = remoteId || null;
    self.owner = owner;
    self.isPrivate = isPrivate || false;
    self.followers = followers || [];
    self.synced = true; // not part of JSON structure
    self.syncing = false; // not part of JSON structure
    self.isSubscription = false;
    for (i = 0; i < self.followers.length; i++) {
        if (Number(self.followers[i].id) === Number(my_user_id)) {
            self.isSubscription = true;
            break;
        }
    }
    self.leftMenuDOMHandle = null;
    self.playlistDOMHandle = null;

    self.getTwitterShareUrl = function() {
        var url = self.getUrl(),
            text = "Check out self playlist!" + ' -- ' + self.title;
        return encodeURI('http://twitter.com/share?related=youtify&via=youtify' + '&url=' + url + '&counturl=' + url + '&text=' + text);
    };

    self.getFacebookShareUrl = function() {
        var url = self.getUrl();
        return 'http://facebook.com/sharer.php?u=' + url;
    };

    self.getUrl = function() {
        return location.protocol + '//' + location.host + '/users/' + self.owner.id + '/playlists/' + self.remoteId;
    };

    self.copy = function() {
        return new Playlist(self.title, self.videos);
    };

    self.getMenuView = function() {
        if (self.leftMenuDOMHandle === null) {
            self.createViews();
        }
        return self.leftMenuDOMHandle;
    };

    self.setAsPlaying = function() {
        $('#left .menu li').removeClass('playing');
        self.getMenuView().addClass('playing');
    };

    self.rename = function(newTitle) {
        var title = $.trim(newTitle);
        if (title.length > 0 && title.length < 50) {
            self.title = newTitle;
        }
        self.synced = false;
        if (self.leftMenuDOMHandle) {
            self.leftMenuDOMHandle.find('.title').text(newTitle);
        }
    };

    self.unsync = function(callback) {
        var url = '/api/playlists/' + self.remoteId;
        if (self.isSubscription) {
            url = '/api/playlists/follow/' + self.remoteId
        }
        $.ajax({
            type: 'DELETE',
            url: url,
			statusCode: {
				200: function(data) {
					if (callback) {
						callback();
					}
				},
				404: function(data) {
					alert(TranslationSystem.translations['No such playlist found']);
				},
				409: function(data) {
                    new ReloadDialog().show();
				}
			}
        });

        self.remoteId = null;
        self.owner = null;
    };

    self.subscribe = function(callback) {
        for (var i = 0; i < self.followers.length; i++) {
            if (Number(self.followers[i].id) ===Number(UserManager.currentUser.id)) {
                return;
            }
        }

        var params = {
            'device': device
        };

        self.syncing = true;
        $.ajax({
            type: 'POST',
            url: '/api/playlists/follow/' + self.remoteId,
            data: params,
            statusCode: {
                200: function(data, textStatus) {
                    self.syncing = false;
                    self.isSubscription = true;
                    self.followers.push(UserManager.currentUser);
                    if (textStatus === 'success') {
                        self.synced = true;
                    } else {
                        alert('Failed to create new playlist ' + self.title);
                    }
                    if (callback) {
                        callback();
                    }
                },
                404: function(data) {
                    alert(TranslationSystem.translations['No such playlist found']);
                },
                409: function(data) {
                    new ReloadDialog().show();
                }
            }
        });
    };

    self.createNewPlaylistOnRemote = function(callback) {
        var params = {
                'json': JSON.stringify(self.toJSON()),
				'device': device
            };

        self.syncing = true;

		$.ajax({
            type: 'POST',
            url: '/api/playlists',
			data: params,
			statusCode: {
				200: function(data, textStatus) {
					self.syncing = false;
					if (textStatus === 'success') {
						self.remoteId = data.remoteId;
						self.owner = data.owner;
						self.synced = true;
                    } else {
						alert('Failed to create new playlist ' + self.title);
					}
					if (callback) {
						callback();
					}
				},
				409: function(data) {
                    new ReloadDialog().show();
				}
			}
        });
    };

    self.updatePlaylistOnRemote = function(callback) {
        if (self.isSubscription) {
            return;
        }
        var params = {
                'json': JSON.stringify(self.toJSON()),
				'device': device
            };

        self.syncing = true;

		$.ajax({
            type: 'POST',
            url: '/api/playlists/' + self.remoteId,
			data: params,
			statusCode: {
				200: function(data, textStatus) {
					self.syncing = false;
					if (textStatus === 'success') {
						self.synced = true;
					} else {
						alert('Failed to create new playlist ' + self.title);
					}
					if (callback) {
						callback();
					}
				},
				404: function(data) {
					alert(TranslationSystem.translations['No such playlist found']);
				},
				409: function(data) {
                    new ReloadDialog().show();
				}
			}
        });
    };

    self.sync = function(callback) {
        if (self.remoteId && self.synced) {
            callback();
        } else if (self.remoteId) {
            self.updatePlaylistOnRemote(callback);
        } else {
            self.createNewPlaylistOnRemote(callback);
        }
    };

    self.addVideo = function(video) {
        if (self.isSubscription) {
            return;
        }
        if (self.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        var newVideo = video.clone();
        newVideo.onPlayCallback = self.setAsPlaying;
        self.videos.push(newVideo);

        var $video = newVideo.createListView();
        $video.data('additionalMenuButtons', [{
            title: 'Delete',
            args: $video,
            callback: deleteVideoButtonClicked
        }]);
        $video.addClass('droppable');
        $video.addClass('draggable');
        $video.addClass('reorderable');
        $video.appendTo(self.playlistDOMHandle);

        self.synced = false;
    };

    self.moveVideo = function(sourceIndex, destIndex) {
        if (self.isSubscription) {
            return;
        }
        if (self.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        var tmp;

        if (destIndex > sourceIndex) {
            destIndex -= 1;
        }

        tmp = self.videos.splice(sourceIndex, 1)[0];
        self.videos.splice(destIndex, 0, tmp);

        self.synced = false;
    };

    self.deleteVideo = function(index) {
        if (self.isSubscription) {
            return;
        }
        if (self.syncing) {
            alert("Please wait until the playlist is synced");
            return;
        }

        self.videos.splice(index, 1);
        self.synced = false;
    };

    self.toJSON = function() {
        return {
            title: self.title,
            videos: self.videos,
            remoteId: self.remoteId,
            owner: self.owner,
            isPrivate: self.isPrivate
        };
    };

    self.createViews = function() {
        var table = $('
')
                .addClass('pane')
                .addClass('tracklist')
                .appendTo('#right > .playlists')
                .data('model', self),
            li = $('
')
                .addClass("playlistElem")
                .data('model', self)
                .bind('contextmenu', showPlaylistContextMenu)
                .mousedown(playlistMouseDown)
                .click(playlistClicked);

        $('').text(self.title).appendTo(li);

        if (self.isSubscription) {
            li.addClass('subscription');
        } else {
            li.addClass('droppable')
        }

        if (self.remoteId) {
            li.addClass('remote');
        } else {
            li.addClass('local');
        }

        if (self.isPrivate) {
            li.addClass('private');
        }
        self.leftMenuDOMHandle = li;
        self.playlistDOMHandle = table;
    };

	self.removeDuplicates = function() {
		var deleted = 0,
            i, j;
		for (i = self.videos.length-1; i > 0; i -= 1) {
			for (j = i-1; j >= 0; j -= 1) {
				if (self.videos[i].videoId === self.videos[j].videoId) {
					self.deleteVideo(j);
					deleted += 1;
					break;
				}
			}
		}
		playlistManager.save();
		loadPlaylistView(self);
		return deleted;
	};

    for (i = 0; i < videos.length; i+= 1) {
        if (videos[i]) {
            var video = new Video({
                videoId: videos[i].videoId,
                title: videos[i].title,
                type: videos[i].type,
                duration: videos[i].duration,
                onPlayCallback: self.setAsPlaying
            });
            self.videos.push(video);
        }
    }
}
<|endoftext|>


<commit_before>var Game = G3.Game.extend({
  init: function(el) {
    this._super(el);

    // make a cube and a light
    this.cube = new Cube(this);
    this.light = new G3.Light(this, 0xFFFFFF, new THREE.Vector3(400, 300, -400));

    // show objects
    this.cube.show(true);
    this.light.show();
  }
});

var Cube = G3.Model.extend({
  init: function(game) {
    this._super(game);

    // set up geometry
    var grey = new THREE.MeshLambertMaterial({color: 0xCCCCCC});
    this.cube = new THREE.Mesh(new THREE.CubeGeometry(200, 200, 200), grey);

    // set object
    this.setMesh(this.cube);
  },

  mousedrag: function(event) {
    var dx = event.delta2D.x;
    var dy = event.delta2D.y;
    this.cube.position.x += 2*dx;
    this.cube.position.z += 2*dy;
  },

  mousedrop: function(event) { }
});
<commit_msg>removed mousedrop<commit_after>var Game = G3.Game.extend({
  init: function(el) {
    this._super(el);

    // make a cube and a light
    this.cube = new Cube(this);
    this.light = new G3.Light(this, 0xFFFFFF, new THREE.Vector3(400, 300, -400));

    // show objects
    this.cube.show(true);
    this.light.show();
  }
});

var Cube = G3.Model.extend({
  init: function(game) {
    this._super(game);

    // set up geometry
    var grey = new THREE.MeshLambertMaterial({color: 0xCCCCCC});
    this.cube = new THREE.Mesh(new THREE.CubeGeometry(200, 200, 200), grey);

    // set object
    this.setMesh(this.cube);
  },

  mousedrag: function(event) {
    var dx = event.delta2D.x;
    var dy = event.delta2D.y;
    this.cube.position.x += 2*dx;
    this.cube.position.z += 2*dy;
  }
});
<|endoftext|>


<commit_before>const rgbControls = require('./RGB_control');
var fs = require('fs');
var defaultAnimations = "anims.json";
var userAnimations = "anims-user.json";

var animations = {};

function writeAnimFile() {
    var json = JSON.stringify(animations);
    fs.writeFile(userAnimations, json, 'utf8', function () {
        console.log("Saving animation file done.")
    });
}

function readAnimFile() {
    var content = fs.readFileSync(defaultAnimations);
    animations = JSON.parse(content);
    if (fs.existsSync(userAnimations)) {
        content = fs.readFileSync(userAnimations);
        var userAnimations = JSON.parse(content);
        Object.assign(animations, userAnimations);
    }
}

function getAnimNames() {
    var keys = Object.keys(animations);
    var ret = {};
    ret.animations = keys;
    return ret;
}

function getAnim(name) {
    var ret = {};
    ret[name] = animations[name];
    return ret;
}

function saveAnim(name, data) {
    animations[name] = {};
    animations[name] = data;
    writeAnimFile();
    if (curAnim == name)
        startAnim(name);
}

function deleteAnim(name) {
    delete animations[name];
    writeAnimFile();
}

var animIdx = 0;
var animLength;
var curAnim = "";
var animTimeout;

function startAnim(name) {
    stopAnim();
    curAnim = name;
    animLength = animations[name].length;
    //animTimeout = setTimeout(function(){
    doFrame(animations[name][0]);
    //}, 0);
}

function changeRoom(obj, roomNumber) {
    var mac = rgbControls.roomToMAC(roomNumber);

    if (obj.fade == 0) {
        rgbControls.sendRGB(mac, obj.color);
    }
    else {
        rgbControls.sendFade(mac, obj.color, obj.fade);
    }
}

function doFrame(frame) {
    var frameData = frame.frameData;
    frameData.forEach(function (obj) { //TODO all rooms
        if (Array.isArray(obj.room)) {
            obj.room.forEach(function (room) {
                changeRoom(obj, room);
            });
        } else {
            changeRoom(obj, obj.room);
        }
    });

    ++animIdx;
    if (animIdx >= animLength)
        animIdx = 0;
    animTimeout = setTimeout(function () {
        doFrame(animations[curAnim][animIdx])
    }, frame.pause);
}

function stopAnim() {
    animIdx = 0;
    clearTimeout(animTimeout);
}

readAnimFile();

module.exports = {getAnimNames, getAnim, saveAnim, deleteAnim, startAnim, stopAnim}
<commit_msg>turn off lights after animation<commit_after>const rgbControls = require('./RGB_control');
var fs = require('fs');
var defaultAnimations = "anims.json";
var userAnimations = "anims-user.json";

var animations = {};

function writeAnimFile() {
    var json = JSON.stringify(animations);
    fs.writeFile(userAnimations, json, 'utf8', function () {
        console.log("Saving animation file done.")
    });
}

function readAnimFile() {
    var content = fs.readFileSync(defaultAnimations);
    animations = JSON.parse(content);
    if (fs.existsSync(userAnimations)) {
        content = fs.readFileSync(userAnimations);
        var userAnimations = JSON.parse(content);
        Object.assign(animations, userAnimations);
    }
}

function getAnimNames() {
    var keys = Object.keys(animations);
    var ret = {};
    ret.animations = keys;
    return ret;
}

function getAnim(name) {
    var ret = {};
    ret[name] = animations[name];
    return ret;
}

function saveAnim(name, data) {
    animations[name] = {};
    animations[name] = data;
    writeAnimFile();
    if (curAnim == name)
        startAnim(name);
}

function deleteAnim(name) {
    delete animations[name];
    writeAnimFile();
}

var animIdx = 0;
var animLength;
var curAnim = "";
var animTimeout;

function startAnim(name) {
    stopAnim();
    curAnim = name;
    animLength = animations[name].length;
    //animTimeout = setTimeout(function(){
    doFrame(animations[name][0]);
    //}, 0);
}

function changeRoom(obj, roomNumber) {
    var mac = rgbControls.roomToMAC(roomNumber);

    if (obj.fade == 0) {
        rgbControls.sendRGB(mac, obj.color);
    }
    else {
        rgbControls.sendFade(mac, obj.color, obj.fade);
    }
}

function doFrame(frame) {
    var frameData = frame.frameData;
    frameData.forEach(function (obj) { //TODO all rooms
        if (Array.isArray(obj.room)) {
            obj.room.forEach(function (room) {
                changeRoom(obj, room);
            });
        } else {
            changeRoom(obj, obj.room);
        }
    });

    ++animIdx;
    if (animIdx >= animLength)
        animIdx = 0;
    animTimeout = setTimeout(function () {
        doFrame(animations[curAnim][animIdx])
    }, frame.pause);
}

function stopAnim() {
    animIdx = 0;
    clearTimeout(animTimeout);
    rgbControls.setMasterOverride(0);
}

readAnimFile();

module.exports = {getAnimNames, getAnim, saveAnim, deleteAnim, startAnim, stopAnim}
<|endoftext|>


<commit_before>
var clojjs = require('..');
var symbols = require('../lib/symbol');
var lists = require('../lib/list');
var parsers = require('../lib/parser');
var path = require('path');
var fs = require('fs');

function compile(name, expected, test, contained) {
    var sourcefile = path.join(__dirname, 'files', name + '.cljs');
    var targetfile = path.join(__dirname, 'output', name + '.js');
    clojjs.compileFile(sourcefile, targetfile);
    var result = fs.readFileSync(targetfile).toString();
    if (contained)
        test.ok(result.indexOf(expected) >= 0);
    else
        test.strictEqual(result, expected + '\n');
}

exports['Compile integer to file'] = function (test) {
    compile('integer', '42', test);
};

exports['Compile string'] = function (test) {
    compile('string', '"foo"', test);
};

exports['Compile nil'] = function (test) {
    compile('nil', 'null', test);
};

exports['Compile symbol in default namespace'] = function (test) {
    compile('symbol', 'cljs.core.first', test);
};

exports['Compile symbol with namespace'] = function (test) {
    compile('nssymbol', 'ns.first', test);
};

exports['Compile def in default namespace'] = function (test) {
    compile('defone', 'cljs.core.one = 1', test, true);
};

exports['Compile def in current namespace'] = function (test) {
    if (typeof user != 'undefined')
        delete user;
    compile('nsdefone', 'user.one = 1', test, true);
    test.ok(user);
    test.ok(user.one);
    test.equal(user.one, 1);
};
<commit_msg>Compile file test refactor<commit_after>
const clojjs = require('..');
const symbols = require('../lib/symbol');
const lists = require('../lib/list');
const parsers = require('../lib/parser');
const path = require('path');
const fs = require('fs');

function compile(name, expected, test, contained) {
    const sourcefile = path.join(__dirname, 'files', name + '.cljs');
    const targetfile = path.join(__dirname, 'output', name + '.js');

    clojjs.compileFile(sourcefile, targetfile);

    const result = fs.readFileSync(targetfile).toString();

    if (contained)
        test.ok(result.indexOf(expected) >= 0);
    else
        test.strictEqual(result, expected + '\n');
}

exports['Compile integer to file'] = function (test) {
    compile('integer', '42', test);
};

exports['Compile string'] = function (test) {
    compile('string', '"foo"', test);
};

exports['Compile nil'] = function (test) {
    compile('nil', 'null', test);
};

exports['Compile symbol in default namespace'] = function (test) {
    compile('symbol', 'cljs.core.first', test);
};

exports['Compile symbol with namespace'] = function (test) {
    compile('nssymbol', 'ns.first', test);
};

exports['Compile def in default namespace'] = function (test) {
    compile('defone', 'cljs.core.one = 1', test, true);
};

exports['Compile def in current namespace'] = function (test) {
    if (typeof user != 'undefined')
        delete user;

    compile('nsdefone', 'user.one = 1', test, true);
    test.ok(user);
    test.ok(user.one);
    test.equal(user.one, 1);
};
<|endoftext|>


<commit_before>"use strict";

const net = require('net')
const dgram = require('dgram')
const WSServer = require('ws').Server
const Split = require('stream-split')
const NALSeparator = new Buffer([0,0,0,1])
const express = require('express')
const systemd = require('systemd')
const app = express()

var wsServer, conf = require('nconf'), headers = []
conf.argv().defaults({
	tcpport: false,
	udpport: false,
	wsport: false,
	queryport: false
})
if (conf.get('tcpport') && conf.get('udpport')) throw new Error('dont use tcp and udp together')

if (conf.get('queryport')) {
	app.get('/', (req, res) => {
		var count = 0
		wsServer.clients.forEach((ws) => {
			if (ws.readyState == 1) {
				count++
			}
		})
		res.set('Content-type', 'text/plain')
		res.send(count.toString())
	})
	app.listen(conf.get('queryport'))
}

function broadcast(data) {
	wsServer.clients.forEach((ws) => {
		if (ws.readyState == 1) {
			ws.send(data, { binary: true }, (e) => {})
		}
	})
}

if (conf.get('tcpport')) {
	const tcpServer = net.createServer((socket) => {
		console.log('streamer connected')
		socket.on('end', () => {
			console.log('streamer disconnected')
		})
		headers = []
		const NALSplitter = new Split(NALSeparator)
		NALSplitter.on('data', (data) => {
			if (wsServer && wsServer.clients.length > 0) {
				data = Buffer.concat([NALSeparator, data])
				if (headers.length < 3) headers.push(data)
				broadcast(data)
			}
		}).on('error', (e) => {
			console.log('splitter error '+e)
			process.exit(0)
		})
		socket.pipe(NALSplitter)
	})
	tcpServer.listen(conf.get('tcpport'))
	if (conf.get('tcpport') == 'systemd') {
		console.log('TCP server listening on systemd socket')
	} else {
		var address = tcpServer.address()
		if (address) console.log(`TCP server listening on ${address.address}:${address.port}`)
	}
}

if (conf.get('udpport')) {
	const udpServer = dgram.createSocket('udp4')
	udpServer.on('listening', () => {
		var address = udpServer.address()
		console.log(`UDP server listening on ${address.address}:${address.port}`)
	})
	const NALSplitter = new Split(NALSeparator)
	NALSplitter.on('data', (data) => {
		if (wsServer && wsServer.clients.length > 0) {
			data = Buffer.concat([NALSeparator, data])
			broadcast(data)
		}
	}).on('error', (e) => {
		console.log('splitter error '+e)
		process.exit(0)
	})
	udpServer.on('message', (msg, rinfo) => {
		NALSplitter.write(msg)
	})
	udpServer.bind(conf.get('udpport'))
}

if (conf.get('wsport')) {
	wsServer = new WSServer({ port: conf.get('wsport') })
	console.log(`WS server listening on ${wsServer.options.host}:${wsServer.options.port}`)
	wsServer.on('connection', (ws) => {
		console.log('client connected, watching '+wsServer.clients.length)
		for(let i in headers) {
			ws.send(headers[i])
		}
		ws.on('close', (ws, id) => {
			console.log('client disconnected, watching '+wsServer.clients.length)
		})
	})
}

<commit_msg>optimize<commit_after>"use strict";

const net = require('net')
const dgram = require('dgram')
const WSServer = require('ws').Server
const Split = require('stream-split')
const NALSeparator = new Buffer([0,0,0,1])
const express = require('express')
const systemd = require('systemd')
const app = express()

var wsServer, conf = require('nconf'), headers = []
conf.argv().defaults({
	tcpport: false,
	udpport: false,
	wsport: false,
	queryport: false
})
if (conf.get('tcpport') && conf.get('udpport')) throw new Error('dont use tcp and udp together')

if (conf.get('queryport')) {
	app.get('/', (req, res) => {
		var count = 0
		wsServer.clients.forEach((ws) => {
			if (ws.readyState == 1) {
				count++
			}
		})
		res.set('Content-type', 'text/plain')
		res.send(count.toString())
	})
	app.listen(conf.get('queryport'))
}

function broadcast(data) {
	wsServer.clients.forEach((ws) => {
		if (ws.readyState == 1) {
			ws.send(data, { binary: true }, (e) => {})
		}
	})
}

if (conf.get('tcpport')) {
	const tcpServer = net.createServer((socket) => {
		console.log('streamer connected')
		socket.on('end', () => {
			console.log('streamer disconnected')
		})
		headers = []
		const NALSplitter = new Split(NALSeparator)
		NALSplitter.on('data', (data) => {
			if (wsServer && wsServer.clients.length > 0) {
				//data = Buffer.concat([NALSeparator, data])
				if (headers.length < 3) headers.push(data)
				broadcast(data)
			}
		}).on('error', (e) => {
			console.log('splitter error '+e)
			process.exit(0)
		})
		socket.pipe(NALSplitter)
	})
	tcpServer.listen(conf.get('tcpport'))
	if (conf.get('tcpport') == 'systemd') {
		console.log('TCP server listening on systemd socket')
	} else {
		var address = tcpServer.address()
		if (address) console.log(`TCP server listening on ${address.address}:${address.port}`)
	}
}

if (conf.get('udpport')) {
	const udpServer = dgram.createSocket('udp4')
	udpServer.on('listening', () => {
		var address = udpServer.address()
		console.log(`UDP server listening on ${address.address}:${address.port}`)
	})
	const NALSplitter = new Split(NALSeparator)
	NALSplitter.on('data', (data) => {
		if (wsServer && wsServer.clients.length > 0) {
			//data = Buffer.concat([NALSeparator, data])
			broadcast(data)
		}
	}).on('error', (e) => {
		console.log('splitter error '+e)
		process.exit(0)
	})
	udpServer.on('message', (msg, rinfo) => {
		NALSplitter.write(msg)
	})
	udpServer.bind(conf.get('udpport'))
}

if (conf.get('wsport')) {
	wsServer = new WSServer({ port: conf.get('wsport') })
	console.log(`WS server listening on ${wsServer.options.host}:${wsServer.options.port}`)
	wsServer.on('connection', (ws) => {
		console.log('client connected, watching '+wsServer.clients.length)
		for(let i in headers) {
			ws.send(headers[i])
		}
		ws.on('close', (ws, id) => {
			console.log('client disconnected, watching '+wsServer.clients.length)
		})
	})
}

<|endoftext|>


<commit_before>const DEFAULT_OCTAVE = 3;
const DEFAULT_DELAY = 1000;
const DEFAULT_INSTRUMENT = 1;

// Array of notes played in function play
var notes = [];

// Delay between two notes
var delay = DEFAULT_DELAY;

var octave = DEFAULT_OCTAVE;
var instrument = DEFAULT_INSTRUMENT;

var noteArray = {
    'c-'    :   -1,
    'c'     :   0,
    'c#'    :   1,
    'd-'    :   1,
    'd'     :   2,
    'd#'    :   3,
    'e-'    :   3,
    'e'     :   4,
    'f-'    :   4,
    'f'     :   5,
    'f#'    :   6,
    'g-'    :   6,
    'g'     :   7,
    'g#'    :   8,
    'a-'    :   8,
    'a'     :   9,
    'a#'    :   10,
    'b-'    :   10,
    'b'     :   11,
    'b#'    :   12
};

var isFlattedOrSharpened = {
    'c-'    :   0,
    'c'     :   0,
    'c#'    :   0,
    'd-'    :   0,
    'd'     :   0,
    'd#'    :   0,
    'e-'    :   0,
    'e'     :   0,
    'f-'    :   0,
    'f'     :   0,
    'f#'    :   0,
    'g-'    :   0,
    'g'     :   0,
    'g#'    :   0,
    'a-'    :   0,
    'a'     :   0,
    'a#'    :   0,
    'b-'    :   0,
    'b'     :   0,
    'b#'    :   0
};

function convertNoteToNumber(note){
    note = note.toLowerCase();
    console.log(note);
    var noteNumber = noteArray[note] + ((octave + 1)*12);
    console.log(noteNumber);
    noteNumber += isFlattedOrSharpened[note];
    if(noteNumber > 127){
        alert("KÄÄÄK");
    }else if(noteNumber < 0){
        alert("GAAH");
    }

    return noteNumber;
}

// Add note to noteArray
function addNote(note){
    note = convertNoteToNumber(note);
    if(note <= 127 && note >= 0){
        notes.push([note]);
    }
    console.log(notes);
}

function __addNote(line, note){
    note = convertNoteToNumber(note);
    if(note <= 127 && note >= 0){
        notes.push([note]);
        console.log("Playing line " + line );
    }
    console.log(notes);
}

function addBreak(){
    notes.push([]);
}

function addChord(chord){
    var broken = false;
    for(var i = 0; i < chord.length; i++){
        chord[i] = convertNoteToNumber(chord[i]);
        if(chord[i] > 127 || chord[i] < 0){
            broken = true;
        }
    }
    if(!broken){
        notes.push(chord);
    }

}

function flatten(note){
    isFlattedOrSharpened[note.toLowerCase()]--;
}

function sharpen(note){
    isFlattedOrSharpened[note.toLowerCase()]++;
}

function setDelay(newDelay){
    delay = newDelay;
}

function setOctave(newOctave){
    // Normalize the octave
    octave = newOctave + 3;
}

function setInstrument(newInstrument){
    instrument = newInstrument;
}

// Play one note using soundfont
function soundfontPlay(note){

    for(var i = 0; i < note.length; i++){
        T.soundfont.play(note[i]);
    }
}

function preload(){
    var preloadNotes = [];
    for(var i = 0; i < notes.length; i++){
        for(var j = 0; j < notes[i].length; j++){
            preloadNotes.push(notes[i][j]);
        }
    }
    T.soundfont.preload(preloadNotes);
}

// Play the song
function play(){
    preload();
    T.soundfont.setInstrument(instrument);
    for(var i = 0; i < notes.length; i++){
        if(notes[i].length != 0){
            setTimeout(soundfontPlay, i*delay, notes[i]);
        }
    }
}

function resetFlatsAndSharps(){
    isFlattedOrSharpened = {
    'c-'    :   0,
    'c'     :   0,
    'c#'    :   0,
    'd-'    :   0,
    'd'     :   0,
    'd#'    :   0,
    'e-'    :   0,
    'e'     :   0,
    'f-'    :   0,
    'f'     :   0,
    'f#'    :   0,
    'g-'    :   0,
    'g'     :   0,
    'g#'    :   0,
    'a-'    :   0,
    'a'     :   0,
    'a#'    :   0,
    'b-'    :   0,
    'b'     :   0,
    'b#'    :   0
};
}

// Reset parametres
function reset(){
    notes = [];
    delay = DEFAULT_DELAY;
    octave = DEFAULT_OCTAVE;
    instrument = DEFAULT_INSTRUMENT;
    isFlattedOrSharpened = {
    'c-'    :   0,
    'c'     :   0,
    'c#'    :   0,
    'd-'    :   0,
    'd'     :   0,
    'd#'    :   0,
    'e-'    :   0,
    'e'     :   0,
    'f-'    :   0,
    'f'     :   0,
    'f#'    :   0,
    'g-'    :   0,
    'g'     :   0,
    'g#'    :   0,
    'a-'    :   0,
    'a'     :   0,
    'a#'    :   0,
    'b-'    :   0,
    'b'     :   0,
    'b#'    :   0
};
}
<commit_msg>purkkaa yhteissoittoon<commit_after>const DEFAULT_OCTAVE = 3;
const DEFAULT_DELAY = 1000;
const DEFAULT_INSTRUMENT = 1;

// Array of notes played in function play
var notes = [];

// Delay between two notes
var delay = DEFAULT_DELAY;

var octave = DEFAULT_OCTAVE;
var instrument = DEFAULT_INSTRUMENT;

var noteArray = {
    'c-'    :   -1,
    'c'     :   0,
    'c#'    :   1,
    'd-'    :   1,
    'd'     :   2,
    'd#'    :   3,
    'e-'    :   3,
    'e'     :   4,
    'f-'    :   4,
    'f'     :   5,
    'f#'    :   6,
    'g-'    :   6,
    'g'     :   7,
    'g#'    :   8,
    'a-'    :   8,
    'a'     :   9,
    'a#'    :   10,
    'b-'    :   10,
    'b'     :   11,
    'b#'    :   12
};

var isFlattedOrSharpened = {
    'c-'    :   0,
    'c'     :   0,
    'c#'    :   0,
    'd-'    :   0,
    'd'     :   0,
    'd#'    :   0,
    'e-'    :   0,
    'e'     :   0,
    'f-'    :   0,
    'f'     :   0,
    'f#'    :   0,
    'g-'    :   0,
    'g'     :   0,
    'g#'    :   0,
    'a-'    :   0,
    'a'     :   0,
    'a#'    :   0,
    'b-'    :   0,
    'b'     :   0,
    'b#'    :   0
};

function convertNoteToNumber(note){
    note = note.toLowerCase();
    console.log(note);
    var noteNumber = noteArray[note] + ((octave + 1)*12);
    console.log(noteNumber);
    noteNumber += isFlattedOrSharpened[note];
    if(noteNumber > 127){
        alert("KÄÄÄK");
    }else if(noteNumber < 0){
        alert("GAAH");
    }

    return noteNumber;
}

// Add note to noteArray
function addNote(note){
    note = convertNoteToNumber(note);
    if(note <= 127 && note >= 0){
        notes.push([[note], instrument]);
    }
    console.log(notes);
}

function __addNote(line, note){
    note = convertNoteToNumber(note);
    if(note <= 127 && note >= 0){
        notes.push([[note], instrument]);
        console.log("Playing line " + line );
    }
    console.log(notes);
}

function addBreak(){
    notes.push([]);
}

function addChord(chord){
    var broken = false;
    for(var i = 0; i < chord.length; i++){
        chord[i] = convertNoteToNumber(chord[i]);
        if(chord[i] > 127 || chord[i] < 0){
            broken = true;
        }
    }
    if(!broken){
        notes.push([chord, instrument]);
    }

}

function flatten(note){
    isFlattedOrSharpened[note.toLowerCase()]--;
}

function sharpen(note){
    isFlattedOrSharpened[note.toLowerCase()]++;
}

function setDelay(newDelay){
    delay = newDelay;
}

function setOctave(newOctave){
    // Normalize the octave
    octave = newOctave + 3;
}

function setInstrument(newInstrument){
    instrument = newInstrument;
}

// Play one note using soundfont
function soundfontPlay(note){
    console.log(note);
    for(var i = 0; i < note[0].length; i++){
        T.soundfont.setInstrument(note[1]);
        T.soundfont.play(note[0][i]);
    }
}

// Play the song
function play(){
    T.soundfont.setInstrument(instrument);
    for(var i = 0; i < notes.length; i++){
        for(var j = 0; j < notes[i][0].length; j++){
            if(notes[i][0][j].length != 0){
                setTimeout(soundfontPlay, i*delay, notes[i]);
            }
        }
    }
}

function resetFlatsAndSharps(){
    isFlattedOrSharpened = {
    'c-'    :   0,
    'c'     :   0,
    'c#'    :   0,
    'd-'    :   0,
    'd'     :   0,
    'd#'    :   0,
    'e-'    :   0,
    'e'     :   0,
    'f-'    :   0,
    'f'     :   0,
    'f#'    :   0,
    'g-'    :   0,
    'g'     :   0,
    'g#'    :   0,
    'a-'    :   0,
    'a'     :   0,
    'a#'    :   0,
    'b-'    :   0,
    'b'     :   0,
    'b#'    :   0
};
}

// Reset parametres
function reset(){
    notes = [];
    delay = DEFAULT_DELAY;
    octave = DEFAULT_OCTAVE;
    instrument = DEFAULT_INSTRUMENT;
    isFlattedOrSharpened = {
    'c-'    :   0,
    'c'     :   0,
    'c#'    :   0,
    'd-'    :   0,
    'd'     :   0,
    'd#'    :   0,
    'e-'    :   0,
    'e'     :   0,
    'f-'    :   0,
    'f'     :   0,
    'f#'    :   0,
    'g-'    :   0,
    'g'     :   0,
    'g#'    :   0,
    'a-'    :   0,
    'a'     :   0,
    'a#'    :   0,
    'b-'    :   0,
    'b'     :   0,
    'b#'    :   0
};
}
<|endoftext|>


<commit_before>import path from 'path'
import test from 'ava'
import fileUtils from '../src/fileUtils'
import config from '../src/config'
import utils from './helpers/utils'

const fixturesDir = `${__dirname}${path.sep}fixtures`

function getTestDir(root = false) {
  const rootDir = `${__dirname}${path.sep}config-test`
  return root ? rootDir : `${rootDir}${path.sep}${utils.randomString()}`
}

test.before(async () => {
  await fileUtils.remove(getTestDir(true))
})

test.after(async () => {
  await fileUtils.remove(getTestDir(true))
})

test('should getConfigPath', async t => {
  const testDir = getTestDir()
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  const configPath = await config.getConfigPath(testDir)
  t.is(configPath, `${testDir}${path.sep}evermark.json`)

  t.throws(config.getConfigPath(`${path.sep}test`),
    'Please run `evermark init [destination]` to init a new Evermark folder')
})

test('should getDbPath', async t => {
  const testDir = getTestDir()
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  const dbPath = await config.getDbPath(testDir)
  t.is(dbPath, `${testDir}${path.sep}evermark.db`)
})

test('should readConfig', async t => {
  const testDir = getTestDir()
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  const conf = await config.readConfig(testDir)
  t.is(conf.token, 'foo')
  t.false(conf.china)
  t.true(conf.sandbox)
})

test('should readConfig error when config file invalid', async t => {
  t.throws(config.readConfig(),
    'Please run `evermark init [destination]` to init a new Evermark folder')

  const testDir = getTestDir()
  const configPath = `${testDir}/evermark.json`
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  await fileUtils.writeFile(configPath, 'token')
  await t.throws(config.readConfig(testDir),
    `Please write to ${configPath}:\n\n` +
    `{\n  "token": "xxx",\n  "china": xxx\n}`)

  await fileUtils.writeFile(configPath, '{ "china": true }')
  t.throws(config.readConfig(testDir),
    `Please write developer token to ${configPath}\n\n` +
    'To get a developer token, please visit:\n  ' +
    'https://www.evernote.com/api/DeveloperToken.action or ' +
    'https://app.yinxiang.com/api/DeveloperToken.action')
})

test('should getConfig', async t => {
  const testDir = getTestDir()
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  const token = await config.getConfig('token', testDir)
  const china = await config.getConfig('china', testDir)
  const sandbox = await config.getConfig('sandbox', testDir)
  const hello = await config.getConfig('hello', testDir)

  t.is(token, 'foo')
  t.false(china)
  t.true(sandbox)
  t.is(hello, undefined)
})

test('should setConfig', async t => {
  const testDir = getTestDir()
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  let result = await config.setConfig('token', 'bar', testDir)
  t.is(result, `{
  "token": "bar",
  "china": false,
  "sandbox": true
}`)

  result = await config.setConfig('china', 'true', testDir)
  t.is(result, `{
  "token": "bar",
  "china": true,
  "sandbox": true
}`)

  result = await config.setConfig('hello', 'false', testDir)
  t.is(result, `{
  "token": "bar",
  "china": true,
  "sandbox": true,
  "hello": false
}`)

  const conf = await config.readConfig(testDir)
  t.is(conf.token, 'bar')
  t.true(conf.china)
  t.true(conf.sandbox)
  t.false(conf.hello)
  t.is(conf.hi, undefined)
})

test('should setConfig error when json stringify error', async t => {
  const testDir = getTestDir()
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  t.throws(config.setConfig('token', {
    get foo() { throw new Error('Mock stringify error') },
  }, testDir), 'Mock stringify error')
})

test('should initConfig', async t => {
  let testDir = getTestDir()
  await config.initConfig(testDir)

  let conf = await config.readConfig(testDir)
  t.is(conf.token, 'Your developer token')
  t.true(conf.china)
  t.false(conf.sandbox)
  t.is(conf.highlight, 'github')

  testDir = `${testDir}${path.sep}`
  await config.initConfig(testDir)

  conf = await config.readConfig(testDir)
  t.is(conf.token, 'Your developer token')
  t.true(conf.china)
  t.false(conf.sandbox)
  t.is(conf.highlight, 'github')
})
<commit_msg>refactor(config): replace '/' with 'path.sep'<commit_after>import path from 'path'
import test from 'ava'
import fileUtils from '../src/fileUtils'
import config from '../src/config'
import utils from './helpers/utils'

const fixturesDir = `${__dirname}${path.sep}fixtures`

function getTestDir(root = false) {
  const rootDir = `${__dirname}${path.sep}config-test`
  return root ? rootDir : `${rootDir}${path.sep}${utils.randomString()}`
}

test.before(async () => {
  await fileUtils.remove(getTestDir(true))
})

test.after(async () => {
  await fileUtils.remove(getTestDir(true))
})

test('should getConfigPath', async t => {
  const testDir = getTestDir()
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  const configPath = await config.getConfigPath(testDir)
  t.is(configPath, `${testDir}${path.sep}evermark.json`)

  t.throws(config.getConfigPath(`${path.sep}test`),
    'Please run `evermark init [destination]` to init a new Evermark folder')
})

test('should getDbPath', async t => {
  const testDir = getTestDir()
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  const dbPath = await config.getDbPath(testDir)
  t.is(dbPath, `${testDir}${path.sep}evermark.db`)
})

test('should readConfig', async t => {
  const testDir = getTestDir()
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  const conf = await config.readConfig(testDir)
  t.is(conf.token, 'foo')
  t.false(conf.china)
  t.true(conf.sandbox)
})

test('should readConfig error when config file invalid', async t => {
  t.throws(config.readConfig(),
    'Please run `evermark init [destination]` to init a new Evermark folder')

  const testDir = getTestDir()
  const configPath = `${testDir}${path.sep}evermark.json`
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  await fileUtils.writeFile(configPath, 'token')
  await t.throws(config.readConfig(testDir),
    `Please write to ${configPath}:\n\n` +
    `{\n  "token": "xxx",\n  "china": xxx\n}`)

  await fileUtils.writeFile(configPath, '{ "china": true }')
  t.throws(config.readConfig(testDir),
    `Please write developer token to ${configPath}\n\n` +
    'To get a developer token, please visit:\n  ' +
    'https://www.evernote.com/api/DeveloperToken.action or ' +
    'https://app.yinxiang.com/api/DeveloperToken.action')
})

test('should getConfig', async t => {
  const testDir = getTestDir()
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  const token = await config.getConfig('token', testDir)
  const china = await config.getConfig('china', testDir)
  const sandbox = await config.getConfig('sandbox', testDir)
  const hello = await config.getConfig('hello', testDir)

  t.is(token, 'foo')
  t.false(china)
  t.true(sandbox)
  t.is(hello, undefined)
})

test('should setConfig', async t => {
  const testDir = getTestDir()
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  let result = await config.setConfig('token', 'bar', testDir)
  t.is(result, `{
  "token": "bar",
  "china": false,
  "sandbox": true
}`)

  result = await config.setConfig('china', 'true', testDir)
  t.is(result, `{
  "token": "bar",
  "china": true,
  "sandbox": true
}`)

  result = await config.setConfig('hello', 'false', testDir)
  t.is(result, `{
  "token": "bar",
  "china": true,
  "sandbox": true,
  "hello": false
}`)

  const conf = await config.readConfig(testDir)
  t.is(conf.token, 'bar')
  t.true(conf.china)
  t.true(conf.sandbox)
  t.false(conf.hello)
  t.is(conf.hi, undefined)
})

test('should setConfig error when json stringify error', async t => {
  const testDir = getTestDir()
  await fileUtils.fs.copyAsync(fixturesDir, testDir)

  t.throws(config.setConfig('token', {
    get foo() { throw new Error('Mock stringify error') },
  }, testDir), 'Mock stringify error')
})

test('should initConfig', async t => {
  let testDir = getTestDir()
  await config.initConfig(testDir)

  let conf = await config.readConfig(testDir)
  t.is(conf.token, 'Your developer token')
  t.true(conf.china)
  t.false(conf.sandbox)
  t.is(conf.highlight, 'github')

  testDir = `${testDir}${path.sep}`
  await config.initConfig(testDir)

  conf = await config.readConfig(testDir)
  t.is(conf.token, 'Your developer token')
  t.true(conf.china)
  t.false(conf.sandbox)
  t.is(conf.highlight, 'github')
})
<|endoftext|>


<commit_before>(function() {
	"use strict";

	var defaultDirectiveReturnValue = {
			'restrict' : 'AE',
			'replace': true,
			'template' : '
{{token}}<input ng-model="token">
'
	};

    var defaultDirectiveTranscludeReturnValue = {
        'restrict' : 'AE',
        'replace': true,
        'transclude': true,
        'template' : '
{{token}}<input ng-model="token">

'
    };

	angular.module('inspector-test-mocks', ['ngRoute'])
    .config( ['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
        $routeProvider
            .when('/primitive', {
                template: '<input ng-model="primitive">'
            })
            .when('/object', {
                template: '<input ng-model="obj.key">'
            })
            .otherwise({redirectTo: '/index'});
        $locationProvider.html5Mode(true);
    }])
	.directive('directiveSharedScope', function() {
		return angular.extend({}, defaultDirectiveReturnValue);
	})
	.directive('directiveSharedScopeExplicit', function() {
		return angular.extend({'scope': false}, defaultDirectiveReturnValue);
	})
	.directive('directiveIsolatedScope', function() {
		return angular.extend({'scope': {}}, defaultDirectiveReturnValue);
	})
	.directive('directiveIsolatedScopeWithString', function() {
		return angular.extend({'scope' : {'token': '@'}}, defaultDirectiveReturnValue);
	})
	.directive('directiveIsolatedScopeWithObject', function() {
		var dest = {
                        'scope':    {
                            'tokenobj': '='
                        }
					};
		var retVal = angular.extend(dest, defaultDirectiveReturnValue);
		retVal.template = '
{{tokenobj.token}}<input ng-model="tokenobj.token">
';
		return retVal;
	})
	.directive('directiveIsolatedScopeWithFunction', function() {
		var dest = {
					'scope':    {
									'fun': '&'
								}
                    };
		var retVal = angular.extend(dest, defaultDirectiveReturnValue);
		retVal.template = '
{{token}}
';
		return retVal;
	})
    // with transclude
    .directive('directiveSharedScopeWithTransclude', function() {
        return angular.extend({}, defaultDirectiveTranscludeReturnValue);
    })
    .directive('directiveSharedScopeExplicitWithTransclude', function() {
        return angular.extend({'scope': false}, defaultDirectiveTranscludeReturnValue);
    })
    .directive('directiveIsolatedScopeWithTransclude', function() {
        return angular.extend({'scope': {}}, defaultDirectiveTranscludeReturnValue);
    })
    .directive('directiveIsolatedScopeWithStringWithTransclude', function() {
        return angular.extend({'scope' : {'token': '@'}}, defaultDirectiveTranscludeReturnValue);
    })
    .directive('directiveIsolatedScopeWithObjectWithTransclude', function() {
        var dest = {
            'scope':    {
                'tokenobj': '='
            }
        };
        var retVal = angular.extend(dest, defaultDirectiveTranscludeReturnValue);
        retVal.template = '

{{tokenobj.token}}

';
        return retVal;
    })
    .directive('directiveIsolatedScopeWithFunctionWithTransclude', function() {
        var dest = {
            'scope':    {
                'fun': '&'
            }
        };
        var retVal = angular.extend(dest, defaultDirectiveTranscludeReturnValue);
        retVal.template = '

{{token}}

';
        return retVal;
    })
    .controller('Ctrl', ['$scope', function($scope) {
        $scope.primitive = 'val';
        $scope.obj = { key : 'val' };
    }])
    .controller('SubCtrl',['$scope', function($scope) {
    }]);
})();<commit_msg>scope:true directives added<commit_after>(function() {
	"use strict";

	var defaultDirectiveReturnValue = {
			'restrict' : 'AE',
			'replace': true,
			'template' : '
{{token}}<input ng-model="token">
'
	};

    var defaultDirectiveTranscludeReturnValue = {
        'restrict' : 'AE',
        'replace': true,
        'transclude': true,
        'template' : '
{{token}}<input ng-model="token">

'
    };

	angular.module('inspector-test-mocks', ['ngRoute'])
    .config( ['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {
        $routeProvider
            .when('/primitive', {
                template: '<input ng-model="primitive">'
            })
            .when('/object', {
                template: '<input ng-model="obj.key">'
            })
            .otherwise({redirectTo: '/index'});
        $locationProvider.html5Mode(true);
    }])
	.directive('directiveSharedScope', function() {
		return angular.extend({}, defaultDirectiveReturnValue);
	})
	.directive('directiveSharedScopeExplicit', function() {
		return angular.extend({'scope': false}, defaultDirectiveReturnValue);
	})
    .directive('directiveSharedScopeExplicitTrue', function() {
        return angular.extend({'scope': true}, defaultDirectiveReturnValue);
    })
    .directive('directiveSharedScopeExplicitTrueWithObject', function() {
        var retVal = angular.extend({'scope': true}, defaultDirectiveReturnValue);
        retVal.template = '
{{tokenobj.token}}<input ng-model="tokenobj.token">
';
        return retVal;
    })
	.directive('directiveIsolatedScope', function() {
		return angular.extend({'scope': {}}, defaultDirectiveReturnValue);
	})
	.directive('directiveIsolatedScopeWithString', function() {
		return angular.extend({'scope' : {'token': '@'}}, defaultDirectiveReturnValue);
	})
	.directive('directiveIsolatedScopeWithObject', function() {
		var dest = {
                        'scope':    {
                            'tokenobj': '='
                        }
					};
		var retVal = angular.extend(dest, defaultDirectiveReturnValue);
		retVal.template = '
{{tokenobj.token}}<input ng-model="tokenobj.token">
';
		return retVal;
	})
	.directive('directiveIsolatedScopeWithFunction', function() {
		var dest = {
					'scope':    {
									'fun': '&'
								}
                    };
		var retVal = angular.extend(dest, defaultDirectiveReturnValue);
		retVal.template = '
{{token}}
';
		return retVal;
	})
    // with transclude
    .directive('directiveSharedScopeWithTransclude', function() {
        return angular.extend({}, defaultDirectiveTranscludeReturnValue);
    })
    .directive('directiveSharedScopeExplicitWithTransclude', function() {
        return angular.extend({'scope': false}, defaultDirectiveTranscludeReturnValue);
    })
    .directive('directiveIsolatedScopeWithTransclude', function() {
        return angular.extend({'scope': {}}, defaultDirectiveTranscludeReturnValue);
    })
    .directive('directiveIsolatedScopeWithStringWithTransclude', function() {
        return angular.extend({'scope' : {'token': '@'}}, defaultDirectiveTranscludeReturnValue);
    })
    .directive('directiveIsolatedScopeWithObjectWithTransclude', function() {
        var dest = {
            'scope':    {
                'tokenobj': '='
            }
        };
        var retVal = angular.extend(dest, defaultDirectiveTranscludeReturnValue);
        retVal.template = '

{{tokenobj.token}}

';
        return retVal;
    })
    .directive('directiveIsolatedScopeWithFunctionWithTransclude', function() {
        var dest = {
            'scope':    {
                'fun': '&'
            }
        };
        var retVal = angular.extend(dest, defaultDirectiveTranscludeReturnValue);
        retVal.template = '

{{token}}

';
        return retVal;
    })
    .controller('Ctrl', ['$scope', function($scope) {
        $scope.primitive = 'val';
        $scope.obj = { key : 'val' };
    }])
    .controller('SubCtrl',['$scope', function($scope) {
    }]);
})();<|endoftext|>


<commit_before>const {getDomain} = require('./domain.js');

//Endpoint to handle requests to access participant data
//queries databse for a specific url corresponding to a certain group
//of users and returns all rows in the evidence table with that url
//Returns 200 unless there was an error with the database query
function dataEndpoint(pool, request, response) {
  const token = request.headers['x-teachermoments-token'];
  const domain = getDomain(request);
  const location = `${domain}/teachermoments/turner?KevinTesting20180319`;

  checkAccess(pool, location, token)
    .then(isTokenAuthorized => {
      if (isTokenAuthorized) {
        getData(pool, location)
          .then(results => {
            response.set('Content-Type', 'application/json');
            response.json({
              evidence: {rows: results}
            });
            return response.status(200).end();
          });
      }
      else{
        console.log('Researcher is not authorized to see this data');
        return response.status(403).end();
      }
    })
    .catch(err => {
      console.log('Error with database query:', err);
      return response.status(500).end();
    });
}

// Spoofing the part where I confirm a token is allowed to view data from
// a specific location. Location is currently hard coded so this is fine.
function checkAccess(pool, location, token) {
  return Promise.resolve(true);
}

// This gets list of consenting participant emails and then only grabs
// data with specified url and emails
// Some testing notes:
//      I've confirmed emails not in the consented_email table do not show up
//      I've confirmed emails that have false in any of audio/permission/consent do not show up
function getData(pool, location){
  const dataValues = [location];
  const dataSQL = `
    SELECT *
    FROM evidence
    WHERE 1=1
      AND json->'GLOBAL'->>'location' = $1
      AND json->>'email' IN (SELECT email FROM consented_email WHERE audio='t' AND permission='t' AND consent='t')
    ORDER BY json->>'sessionId', id ASC;`;

  return pool.query(dataSQL,dataValues)
    .then(results => results.rows)
    .catch(err => {
      console.log('Error with database query:', err);
    });
}

module.exports = {
  dataEndpoint
};<commit_msg>hard code location into getData for extra safety<commit_after>const {getDomain} = require('./domain.js');

//Endpoint to handle requests to access participant data
//queries databse for a specific url corresponding to a certain group
//of users and returns all rows in the evidence table with that url
//Returns 200 unless there was an error with the database query
function dataEndpoint(pool, request, response) {
  const token = request.headers['x-teachermoments-token'];
  const domain = getDomain(request);
  const location = `${domain}/teachermoments/turner?KevinTesting20180319`;

  checkAccess(pool, location, token)
    .then(isTokenAuthorized => {
      if (isTokenAuthorized) {
        getData(pool, location)
          .then(results => {
            response.set('Content-Type', 'application/json');
            response.json({
              evidence: {rows: results}
            });
            return response.status(200).end();
          });
      }
      else{
        console.log('Researcher is not authorized to see this data');
        return response.status(403).end();
      }
    })
    .catch(err => {
      console.log('Error with database query:', err);
      return response.status(500).end();
    });
}

// Spoofing the part where I confirm a token is allowed to view data from
// a specific location. Location is currently hard coded so this is fine.
function checkAccess(pool, location, token) {
  const domain = getDomain();
  if (location ===`${domain}/teachermoments/turner?KevinTesting20180319`) {
    return Promise.resolve(true);
  }
  else{
    return Promise.reject();
  }
}

// This gets list of consenting participant emails and then only grabs
// data with specified url and emails
// Some testing notes:
//      I've confirmed emails not in the consented_email table do not show up
//      I've confirmed emails that have false in any of audio/permission/consent do not show up
function getData(pool, location){
  //hard coding location until I can restrict access
  const domain = getDomain();
  location = `${domain}/teachermoments/turner?KevinTesting20180319`;

  const dataValues = [location];
  const dataSQL = `
    SELECT *
    FROM evidence
    WHERE 1=1
      AND json->'GLOBAL'->>'location' = $1
      AND json->>'email' IN (SELECT email FROM consented_email WHERE audio='t' AND permission='t' AND consent='t')
    ORDER BY json->>'sessionId', id ASC;`;

  return pool.query(dataSQL,dataValues)
    .then(results => results.rows)
    .catch(err => {
      console.log('Error with database query:', err);
    });
}

module.exports = {
  dataEndpoint
};<|endoftext|>


<commit_before>var Turbo = (function () {
    'use strict';

    var MSG_CMD_ON        = 1,
        MSG_CMD_OFF       = 2,
        MSG_CMD_SET       = 3,
        MSG_CMD_UPDATE    = 4,
        MSG_CMD_REMOVE    = 5,
        MSG_CMD_TRANS_SET = 6,
        MSG_CMD_PUSH      = 7,
        MSG_CMD_TRANS_GET = 8,
        MSG_CMD_AUTH      = 9,
        MSG_CMD_UNAUTH    = 10,
        MSG_CMD_ACK       = 11;

    var EVENT_TYPE_VALUE         = 1,
        EVENT_TYPE_CHILD_ADDED   = 2,
        EVENT_TYPE_CHILD_CHANGED = 3,
        EVENT_TYPE_CHILD_MOVED   = 4,
        EVENT_TYPE_CHILD_REMOVED = 5;

    var EVENT_TYPE_VALUE_STR         = 'value',
        EVENT_TYPE_CHILD_ADDED_STR   = 'child_added',
        EVENT_TYPE_CHILD_CHANGED_STR = 'child_changed',
        EVENT_TYPE_CHILD_MOVED_STR   = 'child_moved',
        EVENT_TYPE_CHILD_REMOVED_STR = 'child_removed';

    var _ws = undefined;
    var _listeners = {};
    var _ack = 0;
    var _ackCallbacks = {};
    var _token = undefined;
    var _isOffline = true;
    var _offlineQueue = [];

    var _send = function _send(val) {
        if (_isOffline) {
            _offlineQueue.push(val);
        } else {
            if (!_ws) throw 'Must be connected to the server to send a message';
            _ws.send(val);
        }
    };

    var _connect = function _connect(url, onConnect) {
        console.log('Connecting to ' + url);
        _ws = new WebSocket(url);
        _ws.onopen = function(evt) {
            _isOffline = false;
            if (onConnect) onConnect(evt);
            console.log('Connection opened.', evt);
        };
        _ws.onclose = function(evt) {
            _isOffline = true;
            console.log('Connection closed.', evt);
        };
        _ws.onerror = function(evt) {
            console.log('Connection had an error.', evt);
        };
        _ws.onmessage = function(evt) {
            if (!evt) return;
            if (!evt.data) return;

            try {
                var msg = JSON.parse(evt.data);
                switch (msg.type) {
                    case MSG_TYPE_ACK:
                        if (_ackCallbacks[msg.ack]) {
                            _ackCallbacks[msg.ack](msg.err, msg.res);
                            delete _ackCallbacks[msg.ack];
                        }
                        break;
                    case MSG_TYPE_AUTH_ACK:
                        if (_ackCallbacks[msg.ack]) {
                            _token = msg.token;
                            _ackCallbacks[msg.ack](msg.err, msg.res);
                            delete _ackCallbacks[msg.ack];
                        }
                        break;
                    case MSG_TYPE_ON:
                        if (_listeners[msg.path] && _listeners[msg.path][msg.eventType]) {
                            var listenerMap = _listeners[msg.path][msg.eventType];
                            for (var listenerRef in listenerMap) {
                                var listener;
                                if (listener = listenerMap[listenerRef]) {
                                    var context = listener.context || listenerRef;
                                    if (listener.callback) {
                                        // TODO: this needs to be a snapshot
                                        listener.callback.call(context, msg.value);
                                    }
                                }
                            }
                        }
                }
            } catch (e) {
                console.log('Could not process message; json parsing is failing')
            }
        };
    };

    var _disconnect = function _disconnect() {
        console.log('Disconnecting');
        _isOffline = true;
        _ws.close();
        _ws = undefined;
    };

    var _attemptTransSet = function _attemptTransSet(path, value, revision, transform, done) {
        ack = _ack++;
        _send(JSON.stringify({
            'cmd': CMD_TRANS_SET,
            'path': path,
            'revision': revision,
            'value': transform(value),
            'ack': ack
        }));
        _ackCallbacks[ack] = function(err, newValue, newRevision) {
            if (err === 'conflict') _attemptTransSet(path, newValue, newRevision, transform, done);
            else if (err) done(err);
            else done(undefined, newValue);
        };
    };

    var _eventType = function _eventType(eventTypeStr) {
        switch (eventType) {
        case EVENT_TYPE_VALUE_STR:
            return EVENT_TYPE_VALUE;
        case EVENT_TYPE_CHILD_ADDED_STR:
            return EVENT_TYPE_CHILD_ADDED;
        case EVENT_TYPE_CHILD_CHANGED_STR:
            return EVENT_TYPE_CHILD_CHANGED;
        case EVENT_TYPE_CHILD_MOVED_STR:
            return EVENT_TYPE_CHILD_MOVED;
        case EVENT_TYPE_CHILD_REMOVED:
            return EVENT_TYPE_CHILD_REMOVED;
        }
        return null;
    };

    var Client = function(url, path) {
        if (url === null || url === undefined || !(typeof url === 'string'))
            url = window.location.host;
        if (path === null || path === undefined || !(typeof path === 'string'))
            path = '/';

        if (url.charAt(0) === '/') url = window.location.host + url;
        if (url.indexOf('ws://') !== 0) url = 'ws://' + url;
        if (url.charAt(url.length - 1) === '/') url = url.slice(0, -1);

        this._url = url;
        this._path = path;

        if (!_ws) _connect(url, function (evt) {
            var msg;
            while ((msg = _offlineQueue.shift())) {
                _ws.send(msg);
            }
        });
    };

    Client.prototype.on = function(eventTypeStr, callback, cancelCallback, context) {
        var eventType = _eventType(eventTypeStr);
        if (!eventType)
            throw 'Unsupported event type \'' + eventTypeStr + '\'';

        if (!callback || typeof callback !== 'function') throw 'Callback was not a function';
        if (cancelCallback && !context && typeof cancelCallback === 'object') {
            context = cancelCallback;
            cancelCallback = undefined;
        }

        var self = this;
        var path = self._path;
        _send(JSON.stringify({
            'cmd': CMD_ON,
            'eventType': eventType,
            'path': path
        }));

        if (!_listeners[path]) _listeners[path] = {};
        if (!_listeners[path][eventType]) _listeners[path][eventType] = {};
        _listeners[path][eventType][self] = {
            callback: callback,
            context: context,
            cancelCallback: cancelCallback
        };

        return callback;
    };

    Client.prototype.off = function(eventType, callback, context) {
        var eventType = _eventType(eventTypeStr);
        if (!eventType)
            throw 'Unsupported event type \'' + eventTypeStr + '\'';

        if (!callback || typeof callback !== 'function') throw 'Callback was not a function';

        var self = this;
        var path = self._path;

        if (!_listeners[path]) return;
        if (!_listeners[path][eventType]) return;
        if (!_listeners[path][eventType][self]) return;
        delete _listeners[path][eventType][self];

        _send(JSON.stringify({
            'cmd': CMD_OFF,
            'eventType': eventType,
            'path': path
        }));
    };

    Client.prototype.child = function(childPath) {
        var newPath = this._path === '/' ? ('/' + childPath) : (this._path + '/' + childPath);
        return new Client(this._url, newPath);
    };

    Client.prototype.parent = function() {
        if (this._path === '/') return this;
        var newPath = this._path.slice(0, this._path.lastIndexOf('/'));
        return new Client(this._url, newPath);
    };

    Client.prototype.root = function() {
        return new Client(this._url, '/');
    };

    Client.prototype.toString = function() {
        return this._path;
    };

    Client.prototype.set = function(value, onComplete) {
        var self = this;
        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': CMD_SET,
            'path': self._path,
            'value': value,
            'ack': ack
        }));
        _ackCallbacks[ack] = onComplete;
    };

    Client.prototype.update = function(objectToMerge, onComplete) {
        var self = this;
        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': CMD_UPDATE,
            'path': self._path,
            'value': objectToMerge,
            'ack': ack
        }));
        _ackCallbacks[ack] = onComplete;
    };

    Client.prototype.name = function() {
        return this._path.split('/').pop();
    };

    Client.prototype.setWithPriority = function(newVal, newPriority, onComplete) {
        throw 'Turbo does not support setWithPriority(...) right now';
    };

    Client.prototype.remove = function(onComplete) {
        var self = this;
        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': CMD_REMOVE,
            'path': self._path,
            'ack': ack
        }));
        _ackCallbacks[ack] = onComplete;
    };

    Client.prototype.transaction = function(transactionUpdate, onComplete, applyLocally) {
        var self = this;
        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': CMD_TRANS_GET,
            'path': self._path,
            'ack': ack
        }));
        _ackCallbacks[ack] = function(err, value, revision) {
            if (err) onComplete(err);
            else _attemptTransSet(self._path, value, revision, onComplete);
        };
    };

    Client.prototype.setPriority = function(priority, opt_onComplete) {
        throw 'Turbo does not support setPriority(...) right now';
    };

    Client.prototype.push = function(value, onComplete) {
        var self = this;
        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': CMD_PUSH,
            'path': self._path,
            'value': value,
            'ack': ack
        }));
        _ackCallbacks[ack] = onComplete;
    };

    Client.prototype.onDisconnect = function() {
        throw 'Turbo does not support onDisconnect(...) right now';
    };

    Client.prototype.removeOnDisconnect = function() {
        throw 'Turbo does not support removeOnDisconnect(...) right now';
    };

    Client.prototype.setOnDisconnect = function(onDc) {
        throw 'Turbo does not support setOnDisconnect(...) right now';
    };

    Client.prototype.auth = function(cred, onComplete, onCancel) {
        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': CMD_AUTH,
            'cred': cred,
            'ack': ack
        }));
        _ackCallbacks[ack] = onComplete;
    };

    Client.prototype.unauth = function(onComplete) {
        if (!_token) throw 'Cannout unauth if not authed yet';

        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': CMD_UNAUTH,
            'token': _token,
            'ack': ack
        }));
        _ackCallbacks[ack] = function(err, res) {
            _token = undefined;
            onComplete(err, res);
        };
    };

    Client.goOffline = function() {
        _disconnect();
    };

    Client.goOnline = function() {
        _connect(this._url, function (evt) {
            var msg;
            while ((msg = _offlineQueue.shift())) {
                _ws.send(msg);
            }
        });
    };

    Client.enableLogging = function(logger, persistent) {
        throw 'Turbo does not support enableLogging(...) right now';
    };

    return Client;
})();<commit_msg>We did a thing batman<commit_after>var Turbo = (function () {
    'use strict';

    var MSG_CMD_ON        = 1,
        MSG_CMD_OFF       = 2,
        MSG_CMD_SET       = 3,
        MSG_CMD_UPDATE    = 4,
        MSG_CMD_REMOVE    = 5,
        MSG_CMD_TRANS_SET = 6,
        MSG_CMD_PUSH      = 7,
        MSG_CMD_TRANS_GET = 8,
        MSG_CMD_AUTH      = 9,
        MSG_CMD_UNAUTH    = 10,
        MSG_CMD_ACK       = 11;

    var EVENT_TYPE_VALUE         = 1,
        EVENT_TYPE_CHILD_ADDED   = 2,
        EVENT_TYPE_CHILD_CHANGED = 3,
        EVENT_TYPE_CHILD_MOVED   = 4,
        EVENT_TYPE_CHILD_REMOVED = 5;

    var EVENT_TYPE_VALUE_STR         = 'value',
        EVENT_TYPE_CHILD_ADDED_STR   = 'child_added',
        EVENT_TYPE_CHILD_CHANGED_STR = 'child_changed',
        EVENT_TYPE_CHILD_MOVED_STR   = 'child_moved',
        EVENT_TYPE_CHILD_REMOVED_STR = 'child_removed';

    var _ws = undefined;
    var _listeners = {};
    var _ack = 0;
    var _ackCallbacks = {};
    var _token = undefined;
    var _isOffline = true;
    var _offlineQueue = [];

    var _send = function _send(val) {
        if (_isOffline) {
            _offlineQueue.push(val);
        } else {
            if (!_ws) throw 'Must be connected to the server to send a message';
            _ws.send(val);
        }
    };

    var _connect = function _connect(url, onConnect) {
        console.log('Connecting to ' + url);
        _ws = new WebSocket(url);
        _ws.onopen = function(evt) {
            _isOffline = false;
            if (onConnect) onConnect(evt);
            console.log('Connection opened.', evt);
        };
        _ws.onclose = function(evt) {
            _isOffline = true;
            console.log('Connection closed.', evt);
        };
        _ws.onerror = function(evt) {
            console.log('Connection had an error.', evt);
        };
        _ws.onmessage = function(evt) {
            if (!evt) return;
            if (!evt.data) return;

            try {
                var msg = JSON.parse(evt.data);
                switch (msg.type) {
                    case MSG_CMD_ACK:
                        if (_ackCallbacks[msg.ack]) {
                            _ackCallbacks[msg.ack](msg.err, msg.res);
                            delete _ackCallbacks[msg.ack];
                        }
                        break;
                    default:
			if (!msg.eventType || !msg.path) return; // Filter for 'on' events

                        if (_listeners[msg.path] && _listeners[msg.path][msg.eventType]) {
                            var listenerMap = _listeners[msg.path][msg.eventType];
                            for (var listenerRef in listenerMap) {
                                var listener;
                                if (listener = listenerMap[listenerRef]) {
                                    var context = listener.context || listenerRef;
                                    if (listener.callback) {
                                        // TODO: this needs to be a snapshot
                                        listener.callback.call(context, msg.value);
                                    }
                                }
                            }
                        }
                }
            } catch (e) {
                console.log('Could not process message; json parsing is failing', e);
            }
        };
    };

    var _disconnect = function _disconnect() {
        console.log('Disconnecting');
        _isOffline = true;
        _ws.close();
        _ws = undefined;
    };

    var _attemptTransSet = function _attemptTransSet(path, value, revision, transform, done) {
        ack = _ack++;
        _send(JSON.stringify({
            'cmd': MSG_CMD_TRANS_SET,
            'path': path,
            'revision': revision,
            'value': transform(value),
            'ack': ack
        }));
        _ackCallbacks[ack] = function(err, newValue, newRevision) {
            if (err === 'conflict') _attemptTransSet(path, newValue, newRevision, transform, done);
            else if (err) done(err);
            else done(undefined, newValue);
        };
    };

    var _eventType = function _eventType(eventTypeStr) {
        switch (eventTypeStr) {
        case EVENT_TYPE_VALUE_STR:
            return EVENT_TYPE_VALUE;
        case EVENT_TYPE_CHILD_ADDED_STR:
            return EVENT_TYPE_CHILD_ADDED;
        case EVENT_TYPE_CHILD_CHANGED_STR:
            return EVENT_TYPE_CHILD_CHANGED;
        case EVENT_TYPE_CHILD_MOVED_STR:
            return EVENT_TYPE_CHILD_MOVED;
        case EVENT_TYPE_CHILD_REMOVED:
            return EVENT_TYPE_CHILD_REMOVED;
        }
        return null;
    };

    var Client = function(url, path) {
        if (url === null || url === undefined || !(typeof url === 'string'))
            url = window.location.host;
        if (path === null || path === undefined || !(typeof path === 'string'))
            path = '/';

        if (url.charAt(0) === '/') url = window.location.host + url;
        if (url.indexOf('ws://') !== 0) url = 'ws://' + url;
        if (url.charAt(url.length - 1) === '/') url = url.slice(0, -1);

        this._url = url;
        this._path = path;

        if (!_ws) _connect(url, function (evt) {
            var msg;
            while ((msg = _offlineQueue.shift())) {
                _ws.send(msg);
            }
        });
    };

    Client.prototype.on = function(eventTypeStr, callback, cancelCallback, context) {
        var eventType = _eventType(eventTypeStr);
        if (!eventType)
            throw 'Unsupported event type \'' + eventTypeStr + '\'';

        if (!callback || typeof callback !== 'function') throw 'Callback was not a function';
        if (cancelCallback && !context && typeof cancelCallback === 'object') {
            context = cancelCallback;
            cancelCallback = undefined;
        }

        var self = this;
        var path = self._path;
        _send(JSON.stringify({
            'cmd': MSG_CMD_ON,
            'eventType': eventType,
            'path': path
        }));

        if (!_listeners[path]) _listeners[path] = {};
        if (!_listeners[path][eventType]) _listeners[path][eventType] = {};
        _listeners[path][eventType][self] = {
            callback: callback,
            context: context,
            cancelCallback: cancelCallback
        };

        return callback;
    };

    Client.prototype.off = function(eventType, callback, context) {
        var eventType = _eventType(eventTypeStr);
        if (!eventType)
            throw 'Unsupported event type \'' + eventTypeStr + '\'';

        if (!callback || typeof callback !== 'function') throw 'Callback was not a function';

        var self = this;
        var path = self._path;

        if (!_listeners[path]) return;
        if (!_listeners[path][eventType]) return;
        if (!_listeners[path][eventType][self]) return;
        delete _listeners[path][eventType][self];

        _send(JSON.stringify({
            'cmd': MSG_CMD_OFF,
            'eventType': eventType,
            'path': path
        }));
    };

    Client.prototype.child = function(childPath) {
        var newPath = this._path === '/' ? ('/' + childPath) : (this._path + '/' + childPath);
        return new Client(this._url, newPath);
    };

    Client.prototype.parent = function() {
        if (this._path === '/') return this;
        var newPath = this._path.slice(0, this._path.lastIndexOf('/'));
        return new Client(this._url, newPath);
    };

    Client.prototype.root = function() {
        return new Client(this._url, '/');
    };

    Client.prototype.toString = function() {
        return this._path;
    };

    Client.prototype.set = function(value, onComplete) {
        var self = this;
        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': MSG_CMD_SET,
            'path': self._path,
            'value': value,
            'ack': ack
        }));
        _ackCallbacks[ack] = onComplete;
    };

    Client.prototype.update = function(objectToMerge, onComplete) {
        var self = this;
        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': MSG_CMD_UPDATE,
            'path': self._path,
            'value': objectToMerge,
            'ack': ack
        }));
        _ackCallbacks[ack] = onComplete;
    };

    Client.prototype.name = function() {
        return this._path.split('/').pop();
    };

    Client.prototype.setWithPriority = function(newVal, newPriority, onComplete) {
        throw 'Turbo does not support setWithPriority(...) right now';
    };

    Client.prototype.remove = function(onComplete) {
        var self = this;
        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': MSG_CMD_REMOVE,
            'path': self._path,
            'ack': ack
        }));
        _ackCallbacks[ack] = onComplete;
    };

    Client.prototype.transaction = function(transactionUpdate, onComplete, applyLocally) {
        var self = this;
        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': MSG_CMD_TRANS_GET,
            'path': self._path,
            'ack': ack
        }));
        _ackCallbacks[ack] = function(err, value, revision) {
            if (err) onComplete(err);
            else _attemptTransSet(self._path, value, revision, onComplete);
        };
    };

    Client.prototype.setPriority = function(priority, opt_onComplete) {
        throw 'Turbo does not support setPriority(...) right now';
    };

    Client.prototype.push = function(value, onComplete) {
        var self = this;
        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': MSG_CMD_PUSH,
            'path': self._path,
            'value': value,
            'ack': ack
        }));
        _ackCallbacks[ack] = onComplete;
    };

    Client.prototype.onDisconnect = function() {
        throw 'Turbo does not support onDisconnect(...) right now';
    };

    Client.prototype.removeOnDisconnect = function() {
        throw 'Turbo does not support removeOnDisconnect(...) right now';
    };

    Client.prototype.setOnDisconnect = function(onDc) {
        throw 'Turbo does not support setOnDisconnect(...) right now';
    };

    Client.prototype.auth = function(cred, onComplete, onCancel) {
        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': MSG_CMD_AUTH,
            'cred': cred,
            'ack': ack
        }));
        _ackCallbacks[ack] = onComplete;
    };

    Client.prototype.unauth = function(onComplete) {
        if (!_token) throw 'Cannout unauth if not authed yet';

        var ack = _ack++;
        _send(JSON.stringify({
            'cmd': MSG_CMD_UNAUTH,
            'token': _token,
            'ack': ack
        }));
        _ackCallbacks[ack] = function(err, res) {
            _token = undefined;
            onComplete(err, res);
        };
    };

    Client.goOffline = function() {
        _disconnect();
    };

    Client.goOnline = function() {
        _connect(this._url, function (evt) {
            var msg;
            while ((msg = _offlineQueue.shift())) {
                _ws.send(msg);
            }
        });
    };

    Client.enableLogging = function(logger, persistent) {
        throw 'Turbo does not support enableLogging(...) right now';
    };

    return Client;
})();
<|endoftext|>