<commit_before>/**
 * Created by binarylu on 3/18/16.
 */

var github_op = new github_op();

$(function() {
    restore_options();
    $("#login").click(oauth);
    $("#logout").click(logout);
    $("#repo_add").click(save_repo);
    $("input:checkbox[name=commit]").change(save_commit);
    $("input:radio[name=ac_difficulty]").change(save_ac_difficulty);
    $("input:radio[name=auto_commit]").change(save_auto_commit);
    $("input:radio[name=progress]").change(save_progress);
    $("input:radio[name=countdown]").change(save_countdown);
    $("#comment").on("input", save_comment);
});

function restore_options() {
    chrome.storage.sync.get({
        oauth_token: '',
        repo_name: '',
        repo_private: 0,
        commit: [],
        ac_difficulty: 'show',
        comment: '[{title}][{state}]committed by LeetCode Extension',
        auto_commit: 'question',
        progress: 'show',
        countdown: 'yes'
    }, function(items) {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
        }
        $("#repo_name").val(items.repo_name);
        $("input:radio[name=repo_private]")[items.repo_private].checked = true;

        $('input[name="commit"]').each(function() {
            if (typeof(items.commit) !== 'object') {
                this.checked = true;
            } else {
                this.checked = $.inArray($(this).val(), items.commit) !== -1;
            }
        });

        $('input[name="ac_difficulty"]').each(function() {
            this.checked = this.value == items.ac_difficulty;
        });
        $('input[name="auto_commit"]').each(function() {
            this.checked = this.value == items.auto_commit;
        });
        $('input[name="progress"]').each(function() {
            this.checked = this.value == items.progress;
        });
        $('input[name="countdown"]').each(function() {
            this.checked = this.value == items.countdown;
        });
        $("#comment").val(items.comment);
        save_comment();

        if (items.oauth_token != "") {
            github_op.set_token(items.oauth_token, cb_check_token);
        }
    });
}

function oauth() {
    token_fetcher.get_token(true, function(err, token) {
        if (err) {
            chrome.storage.sync.set({
                oauth_token: "",
                user: ""
            });
            $("#repository_row").hide();
            console.log(err);
            return false;
        }
        github_op.set_token(token, cb_check_token);
    });
}

function logout() {
    chrome.storage.sync.get({
        oauth_token: ''
    }, function(items) {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
        }
        token_fetcher.logout(items.oauth_token);
        cb_check_token("logout:" + items.oauth_token);
        clear_status();
        chrome.storage.sync.set({
            oauth_token: "",
            user: ""
        });
    });
}

function save_repo() {
    var repo_name = $.trim($("#repo_name").val()).replace(/ /g, '-');
    if (repo_name === "") {
        chrome.storage.sync.set({
            repo_name: "",
            repo_private: 0
        }, function() {
            if(chrome.runtime.lastError) {
                console.log(chrome.runtime.lastError.message);
                return;
            }
            set_status("Repository is cleared. Repository will neither be created nor be deleted.", "succ");
        });
    } else {
        github_op.get_repo(repo_name, cb_add_repo);
    }
}

function cb_check_token(err, token, scopes, user) {
    if (err) {
        chrome.storage.sync.set({
            oauth_token: "",
            user: ""
        });
        $("#repository_row").hide();
        $("#login_prompt").show();
        $("#logout_prompt").hide();
        console.log(err);
        return false;
    }
    chrome.storage.sync.set({
        oauth_token: token,
        user: user
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
        if ($.inArray("repo", scopes) != -1) {
            $("[name='repo_private']").attr("disabled", false);
            $("#r_pub,#r_pri").attr("style", "color:black");
        } else if ($.inArray("public_repo", scopes) != -1) {
            $("[name='repo_private']:first").attr("disabled", false);
            $("[name='repo_private']:last").attr("disabled", true);
            $("[name='repo_private']:first").prop("checked", true);
            $("#r_pub").attr("style", "color:black");
            $("#r_pri").attr("style", "color:gray");
        } else {
            $("[name='repo_private']").attr("disabled", true);
            $("#r_pub,#r_pri").attr("style", "color:gray");
            set_status("'repo' permission is required.", "err");
        }
        $("#username").html(user);
        $("#login_prompt").hide();
        $("#logout_prompt").show();
        $("#repository_row").show();

        var repo_name = $("#repo_name").val();
        if (repo_name != "") {
            github_op.get_repo(repo_name, cb_check_repo);
        }
    });
}

function cb_check_repo(err, repo_name, pri, user) {
    if (err) {
        set_status('Repository "' + repo_name + '" is not available.', "err");
        console.log(err);
        return false;
    }
    chrome.storage.sync.set({
        repo_name: repo_name,
        repo_private: pri,
        user: user
    }, function () {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
        $("#repo_name").val(repo_name);
        $("input:radio[name=repo_private]")[pri].checked = true;
    });
}

function cb_add_repo(err, repo_name, pri, user, url) {
    if (err) {
        if (err['status'] == 404) {
            var repo_private = $("input:radio[name=repo_private]:checked").val();
            github_op.create_repo({repo_name: repo_name, repo_private: repo_private}, cb_create_repo);
        } else {
            set_status('Failed to add reporitory "' + repo_name + '".', "err");
            console.log(err);
        }
        return false;
    }
    chrome.storage.sync.set({
        repo_name: repo_name,
        repo_private: pri,
        user: user
    }, function () {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
        $("#repo_name").val(repo_name);
        $("input:radio[name=repo_private]")[pri].checked = true;
        var tip = pri == 1 ? 'Private' : 'Public';
        tip += ' repository "' + repo_name + '" has been added. URL: ';
        tip += '' + url + '';
        set_status(tip, "succ");
    });
}

function cb_create_repo(err, repo_name, pri, url, user) {
    if (err) {
        var tip = "Failed to create repository! Make sure you grant 'repo' or 'public_repo' permission. If you are creating a private repository, make sure you have the permission to create a private repository.";
        set_status(tip, "err");
        console.log(err);
        return false;
    }
    chrome.storage.sync.set({
        repo_name: repo_name,
        repo_private: pri,
        user: user
    }, function () {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
        $("#repo_name").val(repo_name);
        $("input:radio[name=repo_private]")[pri].checked = true;
        var tip = pri == 1 ? 'Private' : 'Public';
        tip += ' repository "' + repo_name + '" has been created. URL: ';
        tip += '' + url + '';
        set_status(tip, "succ");
        setTimeout(function() {
            add_readme();
        }, 2000);
    });
}

function cb_commit_file(err) {
    if (err) {
        set_status("Failed to create README.md", "err");
        console.log(err);
        return false;
    }
    set_status("Create README.md successfully.", "succ");
}

function add_readme() {
    $.get("https://raw.githubusercontent.com/binarylu/leetcode-ext/master/README.md", function(data) {
        var filename = "README.md";
        var content = data;
        var message = "Initialized by LeetCode Extension";
        github_op.commit_file({filename: filename, message: message, content: content, sha: null}, cb_commit_file);
    });
}

function save_commit() {
    var ci = [];
    $('input[name="commit"]:checked').each(function(){
        ci.push($(this).val());
    });

    chrome.storage.sync.set({
        commit: ci
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
    });
}

function save_ac_difficulty() {
    var ac = $("input:radio[name=ac_difficulty]:checked").val();
    chrome.storage.sync.set({
        ac_difficulty: ac
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
    });
}

function save_auto_commit() {
    var auto_commit = $("input:radio[name=auto_commit]:checked").val();
    chrome.storage.sync.set({
        auto_commit: auto_commit
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
    });
}

function save_progress() {
    var pr = $("input:radio[name=progress]:checked").val();
    chrome.storage.sync.set({
        progress: pr
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
    });
}

function save_countdown() {
    var cd = $("input:radio[name=countdown]:checked").val();
    chrome.storage.sync.set({
        countdown: cd
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
    });
}

function save_comment() {
    var comment = $("#comment").val();
    chrome.storage.sync.set({
        comment: comment
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
        }
    });
}

var t;
function set_status(content, status) {
    if (content === "") {
        return false;
    }
    clearTimeout(t);
    var $obj = $("#status");
    if (status == "succ") {
        var old = "";
        if ($obj.attr("class") == "succ") {
            old = $obj.html() + "
";
        }
        $obj.html(old + content);
        $obj.attr("class", "succ");
        $obj.show();
        t = setTimeout(function() {
            $obj.attr("class", "");
            $obj.html("");
            $obj.hide();
        }, 5000);
    } else {
        $obj.html(content);
        $obj.attr("class", "err");
        $obj.show();
    }
}

function clear_status() {
    $("#status").attr("class", "");
    $("#status").html("");
    $("#status").hide();
}<commit_msg>bugfix<commit_after>/**
 * Created by binarylu on 3/18/16.
 */

var github_op = new github_op();

$(function() {
    restore_options();
    $("#login").click(oauth);
    $("#logout").click(logout);
    $("#repo_add").click(save_repo);
    $("input:checkbox[name=commit]").change(save_commit);
    $("input:radio[name=ac_difficulty]").change(save_ac_difficulty);
    $("input:radio[name=auto_commit]").change(save_auto_commit);
    $("input:radio[name=progress]").change(save_progress);
    $("input:radio[name=countdown]").change(save_countdown);
    $("#comment").on("input", save_comment);
});

function restore_options() {
    chrome.storage.sync.get({
        oauth_token: '',
        repo_name: '',
        repo_private: 0,
        commit: [],
        ac_difficulty: 'show',
        comment: '[{title}][{state}]committed by LeetCode Extension',
        auto_commit: 'none',
        progress: 'show',
        countdown: 'yes'
    }, function(items) {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
        }
        $("#repo_name").val(items.repo_name);
        $("input:radio[name=repo_private]")[items.repo_private].checked = true;

        $('input[name="commit"]').each(function() {
            if (typeof(items.commit) !== 'object') {
                this.checked = true;
            } else {
                this.checked = $.inArray($(this).val(), items.commit) !== -1;
            }
        });

        $('input[name="ac_difficulty"]').each(function() {
            this.checked = this.value == items.ac_difficulty;
        });
        $('input[name="auto_commit"]').each(function() {
            this.checked = this.value == items.auto_commit;
        });
        $('input[name="progress"]').each(function() {
            this.checked = this.value == items.progress;
        });
        $('input[name="countdown"]').each(function() {
            this.checked = this.value == items.countdown;
        });
        $("#comment").val(items.comment);
        save_comment();

        if (items.oauth_token != "") {
            github_op.set_token(items.oauth_token, cb_check_token);
        }
    });
}

function oauth() {
    token_fetcher.get_token(true, function(err, token) {
        if (err) {
            chrome.storage.sync.set({
                oauth_token: "",
                user: ""
            });
            $("#repository_row").hide();
            console.log(err);
            return false;
        }
        github_op.set_token(token, cb_check_token);
    });
}

function logout() {
    chrome.storage.sync.get({
        oauth_token: ''
    }, function(items) {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
        }
        token_fetcher.logout(items.oauth_token);
        cb_check_token("logout:" + items.oauth_token);
        clear_status();
        chrome.storage.sync.set({
            oauth_token: "",
            user: ""
        });
    });
}

function save_repo() {
    var repo_name = $.trim($("#repo_name").val()).replace(/ /g, '-');
    if (repo_name === "") {
        chrome.storage.sync.set({
            repo_name: "",
            repo_private: 0
        }, function() {
            if(chrome.runtime.lastError) {
                console.log(chrome.runtime.lastError.message);
                return;
            }
            set_status("Repository is cleared. Repository will neither be created nor be deleted.", "succ");
        });
    } else {
        github_op.get_repo(repo_name, cb_add_repo);
    }
}

function cb_check_token(err, token, scopes, user) {
    if (err) {
        chrome.storage.sync.set({
            oauth_token: "",
            user: ""
        });
        $("#repository_row").hide();
        $("#login_prompt").show();
        $("#logout_prompt").hide();
        console.log(err);
        return false;
    }
    chrome.storage.sync.set({
        oauth_token: token,
        user: user
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
        if ($.inArray("repo", scopes) != -1) {
            $("[name='repo_private']").attr("disabled", false);
            $("#r_pub,#r_pri").attr("style", "color:black");
        } else if ($.inArray("public_repo", scopes) != -1) {
            $("[name='repo_private']:first").attr("disabled", false);
            $("[name='repo_private']:last").attr("disabled", true);
            $("[name='repo_private']:first").prop("checked", true);
            $("#r_pub").attr("style", "color:black");
            $("#r_pri").attr("style", "color:gray");
        } else {
            $("[name='repo_private']").attr("disabled", true);
            $("#r_pub,#r_pri").attr("style", "color:gray");
            set_status("'repo' permission is required.", "err");
        }
        $("#username").html(user);
        $("#login_prompt").hide();
        $("#logout_prompt").show();
        $("#repository_row").show();

        var repo_name = $("#repo_name").val();
        if (repo_name != "") {
            github_op.get_repo(repo_name, cb_check_repo);
        }
    });
}

function cb_check_repo(err, repo_name, pri, user) {
    if (err) {
        set_status('Repository "' + repo_name + '" is not available.', "err");
        console.log(err);
        return false;
    }
    chrome.storage.sync.set({
        repo_name: repo_name,
        repo_private: pri,
        user: user
    }, function () {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
        $("#repo_name").val(repo_name);
        $("input:radio[name=repo_private]")[pri].checked = true;
    });
}

function cb_add_repo(err, repo_name, pri, user, url) {
    if (err) {
        if (err['status'] == 404) {
            var repo_private = $("input:radio[name=repo_private]:checked").val();
            github_op.create_repo({repo_name: repo_name, repo_private: repo_private}, cb_create_repo);
        } else {
            set_status('Failed to add reporitory "' + repo_name + '".', "err");
            console.log(err);
        }
        return false;
    }
    chrome.storage.sync.set({
        repo_name: repo_name,
        repo_private: pri,
        user: user
    }, function () {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
        $("#repo_name").val(repo_name);
        $("input:radio[name=repo_private]")[pri].checked = true;
        var tip = pri == 1 ? 'Private' : 'Public';
        tip += ' repository "' + repo_name + '" has been added. URL: ';
        tip += '' + url + '';
        set_status(tip, "succ");
    });
}

function cb_create_repo(err, repo_name, pri, url, user) {
    if (err) {
        var tip = "Failed to create repository! Make sure you grant 'repo' or 'public_repo' permission. If you are creating a private repository, make sure you have the permission to create a private repository.";
        set_status(tip, "err");
        console.log(err);
        return false;
    }
    chrome.storage.sync.set({
        repo_name: repo_name,
        repo_private: pri,
        user: user
    }, function () {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
        $("#repo_name").val(repo_name);
        $("input:radio[name=repo_private]")[pri].checked = true;
        var tip = pri == 1 ? 'Private' : 'Public';
        tip += ' repository "' + repo_name + '" has been created. URL: ';
        tip += '' + url + '';
        set_status(tip, "succ");
        setTimeout(function() {
            add_readme();
        }, 2000);
    });
}

function cb_commit_file(err) {
    if (err) {
        set_status("Failed to create README.md", "err");
        console.log(err);
        return false;
    }
    set_status("Create README.md successfully.", "succ");
}

function add_readme() {
    $.get("https://raw.githubusercontent.com/binarylu/leetcode-ext/master/README.md", function(data) {
        var filename = "README.md";
        var content = data;
        var message = "Initialized by LeetCode Extension";
        github_op.commit_file({filename: filename, message: message, content: content, sha: null}, cb_commit_file);
    });
}

function save_commit() {
    var ci = [];
    $('input[name="commit"]:checked').each(function(){
        ci.push($(this).val());
    });

    chrome.storage.sync.set({
        commit: ci
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
    });
}

function save_ac_difficulty() {
    var ac = $("input:radio[name=ac_difficulty]:checked").val();
    chrome.storage.sync.set({
        ac_difficulty: ac
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
    });
}

function save_auto_commit() {
    var auto_commit = $("input:radio[name=auto_commit]:checked").val();
    chrome.storage.sync.set({
        auto_commit: auto_commit
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
    });
}

function save_progress() {
    var pr = $("input:radio[name=progress]:checked").val();
    chrome.storage.sync.set({
        progress: pr
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
    });
}

function save_countdown() {
    var cd = $("input:radio[name=countdown]:checked").val();
    chrome.storage.sync.set({
        countdown: cd
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
            return;
        }
    });
}

function save_comment() {
    var comment = $("#comment").val();
    chrome.storage.sync.set({
        comment: comment
    }, function() {
        if(chrome.runtime.lastError) {
            console.log(chrome.runtime.lastError.message);
        }
    });
}

var t;
function set_status(content, status) {
    if (content === "") {
        return false;
    }
    clearTimeout(t);
    var $obj = $("#status");
    if (status == "succ") {
        var old = "";
        if ($obj.attr("class") == "succ") {
            old = $obj.html() + "
";
        }
        $obj.html(old + content);
        $obj.attr("class", "succ");
        $obj.show();
        t = setTimeout(function() {
            $obj.attr("class", "");
            $obj.html("");
            $obj.hide();
        }, 5000);
    } else {
        $obj.html(content);
        $obj.attr("class", "err");
        $obj.show();
    }
}

function clear_status() {
    $("#status").attr("class", "");
    $("#status").html("");
    $("#status").hide();
}<|endoftext|>


<commit_before>import ListenerGenerator from './../src/listeners';
import helpers from './helpers';

it('has field dependent rule', () => {
    const lg = new ListenerGenerator({ name: 'el'}, '', '', {});
    expect(lg._hasFieldDependency('confirmed:field|required')).toBe('field');
    expect(lg._hasFieldDependency('required|before:field')).toBe('field');
    expect(lg._hasFieldDependency('after:field')).toBe('field');

    // If no field was mentioned, we don't have to search for one
    expect(lg._hasFieldDependency('required|after')).toBe(false);
    expect(lg._hasFieldDependency('required|confirmed')).toBe(false);
    expect(lg._hasFieldDependency('required|before')).toBe(false);

    // custom user declared rules
    expect(lg._hasFieldDependency('required|before_time:10')).toBe(false);
    expect(lg._hasFieldDependency('required|only_after:10')).toBe(false);
});

it('detects input listener events', () => {

    const el = document.createElement("input");
    el.name = 'field';
    el.dataset = {};

    const valid = [
        ['file', '_fileListener', ['change']],
        ['radio', '_radioListener', ['change']],
        ['checkbox', '_checkboxListener', ['change']],
        ['text', '_inputListener', ['input', 'blur']]
    ];

    valid.forEach(([type, callback, event]) => {
        el.type = type;
        const lg = new ListenerGenerator(el, '', '', {})._getSuitableListener();
        expect(lg.listener.name).toBe(callback);
        expect(lg.names).toEqual(event);
    });
});

it('detects custom listener events', () => {

    const el = document.createElement("input");
    el.name = 'field';
    el.dataset = {};

    const valid = [
        'foo|bar',
        'baz'
    ];

    valid.forEach(event => {
        el.dataset.validateOn = event;
        const lg = new ListenerGenerator(el, '', '', {})._getSuitableListener();
        expect(lg.names).toEqual(event.split('|'));
    });
});

<commit_msg>fix failing test after prefixing the datasets<commit_after>import ListenerGenerator from './../src/listeners';
import helpers from './helpers';

it('has field dependent rule', () => {
    const lg = new ListenerGenerator({ name: 'el'}, '', '', {});
    expect(lg._hasFieldDependency('confirmed:field|required')).toBe('field');
    expect(lg._hasFieldDependency('required|before:field')).toBe('field');
    expect(lg._hasFieldDependency('after:field')).toBe('field');

    // If no field was mentioned, we don't have to search for one
    expect(lg._hasFieldDependency('required|after')).toBe(false);
    expect(lg._hasFieldDependency('required|confirmed')).toBe(false);
    expect(lg._hasFieldDependency('required|before')).toBe(false);

    // custom user declared rules
    expect(lg._hasFieldDependency('required|before_time:10')).toBe(false);
    expect(lg._hasFieldDependency('required|only_after:10')).toBe(false);
});

it('detects input listener events', () => {

    const el = document.createElement("input");
    el.name = 'field';
    el.dataset = {};

    const valid = [
        ['file', '_fileListener', ['change']],
        ['radio', '_radioListener', ['change']],
        ['checkbox', '_checkboxListener', ['change']],
        ['text', '_inputListener', ['input', 'blur']]
    ];

    valid.forEach(([type, callback, event]) => {
        el.type = type;
        const lg = new ListenerGenerator(el, '', '', {})._getSuitableListener();
        expect(lg.listener.name).toBe(callback);
        expect(lg.names).toEqual(event);
    });
});

it('detects custom listener events', () => {

    const el = document.createElement("input");
    el.name = 'field';
    el.dataset = {};

    const valid = [
        'foo|bar',
        'baz'
    ];

    valid.forEach(event => {
        el.dataset.vvValidateOn = event;
        const lg = new ListenerGenerator(el, '', '', {})._getSuitableListener();
        expect(lg.names).toEqual(event.split('|'));
    });
});
<|endoftext|>


<commit_before>// tutorial code

// Create a new instance of the WebClient class with the token stored in your environment variable
const web = new WebClient(process.env.SLACK_ACCESS_TOKEN);
// The current date
const currentTime = new Date().toTimeString();

// Use the `apps.permissions.resources.list` method to find the conversation ID for an app home
web.apps.permissions.resources.list()
  .then((res) => {
    // Find the app home to use as the conversation to post a message
    // At this point, there should only be one app home in the whole response since only one user has installed the app
    const appHome = res.resources.find(r => r.type === 'app_home');

    // Use the `chat.postMessage` method to send a message from this app
    return web.chat.postMessage({
      channel: appHome.id,
      text: `The current time is ${currentTime}`,
    });
  })
  .then((res) => {
    console.log('Message posted!');
  })
  .catch(console.error);<commit_msg>New tutorial code<commit_after>// tutorial code
const { RTMClient } = require('@slack/client');

// An access token (from your Slack app or custom integration - usually xoxb)
const token = process.env.SLACK_TOKEN;

// The client is initialized and then started to get an active connection to the platform
const rtm = new RTMClient(token);
rtm.start();

// This argument can be a channel ID, a DM ID, a MPDM ID, or a group ID
// See the "Combining with the WebClient" topic below for an example of how to get this ID
const conversationId = 'C1232456';

// The RTM client can send simple string messages
rtm.sendMessage('Hello there', conversationId)
  .then((res) => {
    // `res` contains information about the posted message
    console.log('Message sent: ', res.ts);
  })
  .catch(console.error);<|endoftext|>


<commit_before>// TODO: test these as they are data related
export function findBy(params, collection, json) {
  const models = json[collection]
  if (!models) {
    return null
  }
  for (const modelId in models) {
    if (models.hasOwnProperty(modelId)) {
      const model = models[modelId]
      let found = true
      for (const propName in params) {
        if (model[propName] !== params[propName]) {
          found = false
          break
        }
      }
      if (found) {
        return model
      }
    }
  }
  return null
}

export function findModel(json, initModel) {
  if (!initModel || !initModel.findObj || !initModel.collection) {
    return null
  }
  return findBy(initModel.findObj, initModel.collection, json)
}

export function getLinkObject(model, identifier, json) {
  if (!model.links || !model.links[identifier]) { return null }
  const key = model.links[identifier].id || model.links[identifier]
  const collection = model.links[identifier].type || identifier
  const deletedCollection = json[`deleted_${collection}`]
  if (key &&
      json[collection] &&
      json[collection][key] &&
      (!deletedCollection || deletedCollection.indexOf(key) === -1)) {
    return json[collection][key]
  }
  return null
}

export function getLinkArray(model, identifier, json) {
  if (!model.links || !model.links[identifier]) { return null }
  const keys = model.links[identifier].ids || model.links[identifier]
  const collection = model.links[identifier].type || identifier
  const deletedCollection = json[`deleted_${collection}`]
  if (keys.length && json[collection]) {
    // filter they keys so that models that don't exist
    // aren't added to the link object mainly used for
    // when a model gets deleted ie: post or comment
    const filteredKeys = keys.filter((key) =>
      json[collection][key] && (!deletedCollection || deletedCollection.indexOf(key) === -1)
    )
    return filteredKeys.map((key) => json[collection][key])
  }
  return null
}

<commit_msg>Guard against a model not existing in json helper.<commit_after>// TODO: test these as they are data related
export function findBy(params, collection, json) {
  const models = json[collection]
  if (!models) {
    return null
  }
  for (const modelId in models) {
    if (models.hasOwnProperty(modelId)) {
      const model = models[modelId]
      let found = true
      for (const propName in params) {
        if (model[propName] !== params[propName]) {
          found = false
          break
        }
      }
      if (found) {
        return model
      }
    }
  }
  return null
}

export function findModel(json, initModel) {
  if (!initModel || !initModel.findObj || !initModel.collection) {
    return null
  }
  return findBy(initModel.findObj, initModel.collection, json)
}

export function getLinkObject(model, identifier, json) {
  if (!model || !model.links || !model.links[identifier]) { return null }
  const key = model.links[identifier].id || model.links[identifier]
  const collection = model.links[identifier].type || identifier
  const deletedCollection = json[`deleted_${collection}`]
  if (key &&
      json[collection] &&
      json[collection][key] &&
      (!deletedCollection || deletedCollection.indexOf(key) === -1)) {
    return json[collection][key]
  }
  return null
}

export function getLinkArray(model, identifier, json) {
  if (!model || !model.links || !model.links[identifier]) { return null }
  const keys = model.links[identifier].ids || model.links[identifier]
  const collection = model.links[identifier].type || identifier
  const deletedCollection = json[`deleted_${collection}`]
  if (keys.length && json[collection]) {
    // filter they keys so that models that don't exist
    // aren't added to the link object mainly used for
    // when a model gets deleted ie: post or comment
    const filteredKeys = keys.filter((key) =>
      json[collection][key] && (!deletedCollection || deletedCollection.indexOf(key) === -1)
    )
    return filteredKeys.map((key) => json[collection][key])
  }
  return null
}

<|endoftext|>


<commit_before>'use strict';

var buffer = require('./../../../core/lib/helpers/buffer'),
    getColorsArray = require('./../helpers/Fn').getColorsArray;
/**
 * Loader strategy to handle Points object
 * @method Points
 * @memberof K3D.Providers.ThreeJS.Objects
 * @param {Object} config all configurations params from JSON
 * @return {Object} 3D object ready to render
 */
module.exports = function (config) {
    var modelMatrix = new THREE.Matrix4(),
        color = new THREE.Color(config.color || 65280),
        pointPositions = config.positions.buffer,
        pointColors = (config.colors && config.colors.buffer) || null,
        shader = config.shader || '3dSpecular',
        colors,
        object,
        material,
        colorsToFloat32Array = buffer.colorsToFloat32Array,
        fragmentShader,
        fragmentShaderMap = {
            'flat': require('./shaders/Points.flat.fragment.glsl'),
            '3d': require('./shaders/Points.3d.fragment.glsl'),
            '3dSpecular': require('./shaders/Points.3d.fragment.glsl')
        };

    fragmentShader = fragmentShaderMap[shader] || fragmentShaderMap.flat;

    material = new THREE.ShaderMaterial({
        uniforms: THREE.UniformsUtils.merge([
            THREE.UniformsLib.lights,
            THREE.UniformsLib.points
        ]),
        defines: {
            USE_SPECULAR: (shader === '3dSpecular' ? 1 : 0)
        },
        vertexShader: require('./shaders/Points.vertex.glsl'),
        fragmentShader: fragmentShader,
        lights: true,
        extensions: {
            fragDepth: true
        }
    });

    // monkey-patching for imitate THREE.PointsMaterial
    material.size = config.point_size;
    material.map = null;
    material.isPointsMaterial = true;

    colors = ( pointColors && pointColors.length === pointPositions.length / 3 ?
            colorsToFloat32Array(pointColors) : getColorsArray(color, pointPositions.length / 3)
    );

    object = new THREE.Points(getGeometry(pointPositions, colors), material);

    modelMatrix.set.apply(modelMatrix, config.model_matrix.buffer);
    object.applyMatrix(modelMatrix);

    object.updateMatrixWorld();

    return Promise.resolve(object);
};

/**
 * Setup BufferGeometry
 * @inner
 * @memberof K3D.Providers.ThreeJS.Objects.Points
 * @param  {Float32Array} positions
 * @param  {Float32Array} colors
 * @return {THREE.BufferGeometry}
 */
function getGeometry(positions, colors) {
    var geometry = new THREE.BufferGeometry();

    geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
    geometry.addAttribute('color', new THREE.BufferAttribute(colors, 3));
    geometry.computeBoundingSphere();
    geometry.computeBoundingBox();

    return geometry;
}
<commit_msg>fixing bounding box calculation for Points and black (=0) color.<commit_after>'use strict';

var buffer = require('./../../../core/lib/helpers/buffer'),
    getColorsArray = require('./../helpers/Fn').getColorsArray;
/**
 * Loader strategy to handle Points object
 * @method Points
 * @memberof K3D.Providers.ThreeJS.Objects
 * @param {Object} config all configurations params from JSON
 * @return {Object} 3D object ready to render
 */
module.exports = function (config) {
    var modelMatrix = new THREE.Matrix4(),
        color = typeof(config.color) !== 'number' || config.color < 0 || config.color > 0xffffff ?
            0xff00 : new THREE.Color(config.color),
        pointPositions = config.positions.buffer,
        pointColors = (config.colors && config.colors.buffer) || null,
        shader = config.shader || '3dSpecular',
        colors,
        object,
        material,
        colorsToFloat32Array = buffer.colorsToFloat32Array,
        fragmentShader,
        bbox,
        fragmentShaderMap = {
            'flat': require('./shaders/Points.flat.fragment.glsl'),
            '3d': require('./shaders/Points.3d.fragment.glsl'),
            '3dSpecular': require('./shaders/Points.3d.fragment.glsl')
        };

    fragmentShader = fragmentShaderMap[shader] || fragmentShaderMap.flat;

    material = new THREE.ShaderMaterial({
        uniforms: THREE.UniformsUtils.merge([
            THREE.UniformsLib.lights,
            THREE.UniformsLib.points
        ]),
        defines: {
            USE_SPECULAR: (shader === '3dSpecular' ? 1 : 0)
        },
        vertexShader: require('./shaders/Points.vertex.glsl'),
        fragmentShader: fragmentShader,
        lights: true,
        extensions: {
            fragDepth: true
        }
    });

    // monkey-patching for imitate THREE.PointsMaterial
    material.size = config.point_size;
    material.map = null;
    material.isPointsMaterial = true;

    colors = ( pointColors && pointColors.length === pointPositions.length / 3 ?
            colorsToFloat32Array(pointColors) : getColorsArray(color, pointPositions.length / 3)
    );

    object = new THREE.Points(getGeometry(pointPositions, colors), material);

    bbox = object.geometry.boundingBox;
    bbox.min.x -= config.point_size * 0.5;
    bbox.max.x += config.point_size * 0.5;
    bbox.min.y -= config.point_size * 0.5;
    bbox.max.y += config.point_size * 0.5;
    bbox.min.z -= config.point_size * 0.5;
    bbox.max.z += config.point_size * 0.5;

    modelMatrix.set.apply(modelMatrix, config.model_matrix.buffer);
    object.applyMatrix(modelMatrix);

    object.updateMatrixWorld();

    return Promise.resolve(object);
};

/**
 * Setup BufferGeometry
 * @inner
 * @memberof K3D.Providers.ThreeJS.Objects.Points
 * @param  {Float32Array} positions
 * @param  {Float32Array} colors
 * @return {THREE.BufferGeometry}
 */
function getGeometry(positions, colors) {
    var geometry = new THREE.BufferGeometry();

    geometry.addAttribute('position', new THREE.BufferAttribute(positions, 3));
    geometry.addAttribute('color', new THREE.BufferAttribute(colors, 3));
    geometry.computeBoundingSphere();
    geometry.computeBoundingBox();

    return geometry;
}
<|endoftext|>


<commit_before>Board = function () {
  injectFAFontFace()

  this.onBoardLoad(() => this._build())
}

Board.prototype = {
  get hasBoardWrapper () {
    return doc.one`.board-wrapper`
  },

  onBoardLoad (cb) {
    if (this.hasBoardWrapper)
      this._build()

    let boardHasBeenLoaded = new MutationObserver(() => {
      if (this.hasBoardWrapper) {
        cb()
      }
    })

    let content = doc.one`#content`
    boardHasBeenLoaded.observe(content, { childList: true })
  },

  _build() {
    _.in(1000, () => {
       replcaeToggleMenuIcons()
       injectTagsFilter()
    })

    let lists = doc.all`.list-cards`
    _.in(0, () => lists.each(l => new CardsList(l)))
  }
}

UniqueLabels = function () {
  let allLabels = doc.all`.card-label`

  let uniqueLabels = allLabels.reduce((unique, label) => {
    if (!unique.find(l => l.textContent == label.textContent))
      unique.push(label)

    return unique
  }, [])

  return uniqueLabels.map(l => new Label(l))
}

Array.prototype.each = Array.prototype.forEach

Array.prototype.as = function (module) {
  this.each(item => { _.extend(module, item); module.included.call(item) })
  return this
}

injectTagsFilter = function () {
  let rightMenuToggleButton = doc.one`.mod-right`
  let tagsFilter =
    a`#tags-filter`.with(
      TagsList(UniqueLabels()),
      an.i`.fa.fa-lg.fa-tags`
    )
  rightMenuToggleButton.appendChild(tagsFilter)

  let lists = doc.all`.list-cards`
  lists.each(list =>
    CardCreatedObserver(list, card =>
      _toggleCardVisibilityByFilters(card)
    )
  )

  let cards = doc.all`.list-card`.as(Card.prototype)

  cards.each(card => {
    card.onLabelsChange(() => {
      _toggleCardVisibilityByFilters(card)
    })
  })

  let tags = rightMenuToggleButton.all`.pmt-card-tags > *`

  tags.each(tag => {
    tag.onclick = e => {
      tag.classList.toggle('selected')

      tagsFilter.classList.remove('has-some-selected-tags')

      let selectedFilters = tagsFilter.all`.selected`
      if (selectedFilters.length)
        tagsFilter.classList.add('has-some-selected-tags')

      doc.all`.list-card`.each(card => {
        _toggleCardVisibilityByFilters(card)
      })
    }
  })
}

function _toggleCardVisibilityByFilters(card) {
  let selectedFilters = doc.all`#tags-filter .selected`
  let cardTags = card.all`.pmt-card-tags > *`

  let hasAllFilteredTags = selectedFilters.every(filter =>
    cardTags.some(tag =>
      filter.tagName     == tag.tagName &&
      filter.textContent == tag.textContent &&
      (filter.tagName == 'I' ?
       filter.style.color == tag.style.color :
       filter.className.includes(tag.className) &&
       filter.style.backgroundColor == tag.style.backgroundColor)
    ))

  card.classList.remove('hide')

  if (!hasAllFilteredTags)
    card.classList.add('hide')
}
<commit_msg>cosmetic change<commit_after>Board = function () {
  injectFAFontFace()

  this.onBoardLoad(() => this._build())
}

Board.prototype = {
  get hasBoardWrapper () {
    return doc.one`.board-wrapper`
  },

  onBoardLoad (cb) {
    if (this.hasBoardWrapper)
      this._build()

    let boardHasBeenLoaded = new MutationObserver(() => {
      if (this.hasBoardWrapper) {
        cb()
      }
    })

    let content = doc.one`#content`
    boardHasBeenLoaded.observe(content, { childList: true })
  },

  _build() {
    _.in(1000, () => {
       replcaeToggleMenuIcons()
       injectTagsFilter()
    })

    let lists = doc.all`.list-cards`
    _.in(0, () => lists.each(l => new CardsList(l)))
  }
}

UniqueLabels = function () {
  let allLabels = doc.all`.card-label`

  let uniqueLabels = allLabels.reduce((unique, label) => {
    if (!unique.find(l => l.textContent == label.textContent))
      unique.push(label)

    return unique
  }, [])

  return uniqueLabels.map(l => new Label(l))
}

Array.prototype.each = Array.prototype.forEach

Array.prototype.as = function (module) {
  this.each(item => { _.extend(module, item); module.included.call(item) })
  return this
}

injectTagsFilter = function () {
  let rightMenuToggleButton = doc.one`.mod-right`
  let tagsFilter =
    a`#tags-filter`.with(
      TagsList(UniqueLabels()),
      an.i`.fa.fa-lg.fa-tags`
    )
  rightMenuToggleButton.appendChild(tagsFilter)

  let lists = doc.all`.list-cards`
  lists.each(list =>
    CardCreatedObserver(list,
      _toggleCardVisibilityByFilters)
  )

  let cards = doc.all`.list-card`.as(Card.prototype)

  cards.each(card => {
    card.onLabelsChange(() => {
      _toggleCardVisibilityByFilters(card)
    })
  })

  let tags = rightMenuToggleButton.all`.pmt-card-tags > *`

  tags.each(tag => {
    tag.onclick = e => {
      tag.classList.toggle('selected')

      tagsFilter.classList.remove('has-some-selected-tags')

      let selectedFilters = tagsFilter.all`.selected`
      if (selectedFilters.length)
        tagsFilter.classList.add('has-some-selected-tags')

      doc.all`.list-card`.each(
        _toggleCardVisibilityByFilters)
    }
  })
}

function _toggleCardVisibilityByFilters(card) {
  let selectedFilters = doc.all`#tags-filter .selected`
  let cardTags = card.all`.pmt-card-tags > *`

  let hasAllFilteredTags = selectedFilters.every(filter =>
    cardTags.some(tag =>
      filter.tagName     == tag.tagName &&
      filter.textContent == tag.textContent &&
      (filter.tagName == 'I' ?
       filter.style.color == tag.style.color :
       filter.className.includes(tag.className) &&
       filter.style.backgroundColor == tag.style.backgroundColor)
    ))

  card.classList.remove('hide')

  if (!hasAllFilteredTags)
    card.classList.add('hide')
}
<|endoftext|>


<commit_before>import fs from 'fs';
import {CommandClient} from 'eris';
import request from 'request';
import mongoose from 'mongoose';
import querystring from 'querystring';

import SetTokenCommand from './Command/SetTokenCommand';
import InfoCommand from './Command/InfoCommand';
import IgnoreCommand from './Command/IgnoreCommand';
import UnignoreCommand from './Command/UnignoreCommand';
import ChannelLeaderboardCommand from './Command/ChannelLeaderboardCommand';
import LeaderboardCommand from './Command/LeaderboardCommand';
import StatsCommand from './Command/StatsCommand';
import CleanCommand from './Command/CleanCommand';
import RestartCommand from './Command/RestartCommand';
import EvalCommand from './Command/EvalCommand';

import ReadyHandler from './Handler/ReadyHandler';
import VoiceEvent from './Model/VoiceEvent';
import Aggregator from "./Aggregator";

const AGGREGATOR_INTERVAL = 1 * 60 * 1000;

export default class Kernel {
    constructor() {
        try {
            fs.writeFileSync(__dirname + '/../config.json', '{}', {flag: 'wx'});
        } catch (e) {}
        try {
            this.config = JSON.parse(fs.readFileSync(__dirname + '/../config.json'));
        } catch (e) {
            this.config = {};
        }

        mongoose.connect(process.env.MONGO_URL);
        var db = mongoose.connection;
        db.on('error', console.error.bind(console, 'connection error:'));
        db.once('open', function() {
            console.log("DB Connected");
        });

        this.client = new CommandClient(process.env.BOT_TOKEN, {
            messageLimit: 5,
        }, {
            owner:       "Aaron",
            description: "Google Analytics for your Discord Server!",
            prefix:      process.env.NODE_ENV === 'development' ? '\\' : '/'
        });

        let cmds = [
            SetTokenCommand,
            EvalCommand,
            RestartCommand,
            StatsCommand,
            InfoCommand,
            UnignoreCommand,
            IgnoreCommand,
            ChannelLeaderboardCommand,
            LeaderboardCommand,
            CleanCommand
        ];
        for (let cmd of cmds) {
            this.client.registerCommand(cmd.name, this.wrapError.bind(this, cmd.run.bind(this)), cmd.config);
        }

        ReadyHandler.run.call(this);

        this.client.on('err', console.error);
        this.client.on('error', console.error);

        process.on('SIGUSR2', () => {
            console.log("SIGUSR2");
            this.gracefulShutdown();
        });

        Aggregator.aggregate();
        setInterval(Aggregator.aggregate, AGGREGATOR_INTERVAL);
    }

    track(action, server, user) {
        if (!action) {
            console.log("No action!");
            return;
        }

        if (server && user) {
            let tokens = [process.env.BOT_ANALYTICS];
            if (this.getConfig(server).token) {
                tokens.push(this.getConfig(server).token);
            }

            let data = {v: 1, t: 'event', cid: user, ec: server, ea: action, el: user};

            tokens.forEach(token => {
                request.post(
                    `https://www.google-analytics.com/collect?tid=${token}&${querystring.stringify(data)}`,
                    err => {
                        if (err) {
                            console.log(err);
                        } else {
                            //console.log(`TRACKED EVENT: ${action}, ${server}, ${user}`);
                        }
                    }
                )
            });
        }
    }

    async checkVoiceChannelStates() {
        let results;
        try {
            results = await VoiceEvent.find({hasLeft: false});
        } catch (e) {
            console.log(e);
            return;
        }

        if (results.length === 0) {
            return;
        }

        for (let result of results) {
            if (!result) {
                console.log(result);
                continue;
            }

            try {
                let guild = this.client.guilds.get(result.guild.toString()), user;
                if (guild) {
                    user = guild.members.get(result.user.toString());
                    if (user && user.voiceState && user.voiceState.channelID) {
                        if (user.voiceState.channelID != result.channel) {
                            console.log("User in a different in voice, stopping and starting event approximately.");
                            ReadyHandler.stopVoiceEvent(user, guild.channels.get(result.channel.toString()), true);
                            ReadyHandler.startVoiceEvent(user, guild.channels.get(user.voiceState.channelID), true);
                            continue;
                        }

                        if (user.voiceState.deaf || user.voiceState.selfDeaf) {
                            console.log("User no longer in voice undeafened, stopping event approximately.");
                            ReadyHandler.stopVoiceEvent(user, guild.channels.get(result.channel.toString()), true);
                        }
                        continue;
                    }

                    console.log("User no longer in voice, stopping event approximately.");
                    ReadyHandler.stopVoiceEvent(user, guild.channels.get(result.channel.toString()), true);
                    continue;
                }

                result.remove().catch(console.error);
            } catch (e) {
                console.error(e)
            }
        }
    }

    embedError(channel, error) {
        channel.createMessage({
            embed: {
                author:      {
                    name: "Error!"
                },
                title:       error.message || error,
                description: error.stack || error,
                timestamp:   new Date(),
                color:       0xFF0000
            }
        }).catch(e => console.log(e.response));
    }

    getConfig(guildId) {
        if (!this.config[guildId]) {
            this.config[guildId] = {
                token:           undefined,
                ignoredUsers:    [],
                ignoredChannels: []
            };
        }

        return this.config[guildId];
    }

    wrapError(func, msg, args) {
        (function(msg, args) {
            try {
                func(msg, args);
            } catch (e) {
                console.log(e);
            }
        })(msg, args);
    }

    saveConfig() {
        try {
            fs.writeFile(
                fs.realpathSync(__dirname + '/../config.json'),
                JSON.stringify(this.config, null, 4),
                err => {
                    if (err) {
                        console.error(err);
                    }
                }
            );
        } catch (e) {
            console.error(e);
        }
    }

    gracefulShutdown() {
        console.log("Process killed.");
        this.client.editStatus("dnd", {name: "Restarting"});

        setTimeout(() => {
            this.client.disconnect({reconnect: false});
            delete this.client;
            process.exit(0);
        }, 300)
    }

    run() {
        console.log("Starting bot!");
        this.client.connect();
        setInterval(this.sendServerCount.bind(this), 60000);
    }

    sendServerCount() {
        request({
            uri:     'https://bots.discord.pw/api/bots/264569236129579008/stats',
            method:  'POST',
            headers: {
                Authorization: process.env.BOTS_DISCORD_PW_KEY
            },
            json:    {
                server_count: this.client.guilds.size
            }
        }, err => {
            if (err) {
                console.log(err)
            }
        });

        request({
            uri:     'https://www.carbonitex.net/discord/data/botdata.php?debug=true',
            method:  'POST',
            json:    {
                key:         process.env.CARBONITE_KEY,
                servercount: this.client.guilds.size
            }
        }, err => {
            if (err) {
                console.log(err)
            }
        });
    }
}
<commit_msg>Getting all users<commit_after>import fs from "fs";
import {CommandClient} from "eris";
import request from "request";
import mongoose from "mongoose";
import querystring from "querystring";

import SetTokenCommand from "./Command/SetTokenCommand";
import InfoCommand from "./Command/InfoCommand";
import IgnoreCommand from "./Command/IgnoreCommand";
import UnignoreCommand from "./Command/UnignoreCommand";
import ChannelLeaderboardCommand from "./Command/ChannelLeaderboardCommand";
import LeaderboardCommand from "./Command/LeaderboardCommand";
import StatsCommand from "./Command/StatsCommand";
import CleanCommand from "./Command/CleanCommand";
import RestartCommand from "./Command/RestartCommand";
import EvalCommand from "./Command/EvalCommand";

import ReadyHandler from "./Handler/ReadyHandler";
import VoiceEvent from "./Model/VoiceEvent";
import Aggregator from "./Aggregator";

const AGGREGATOR_INTERVAL = 1 * 60 * 1000;

export default class Kernel {
    constructor() {
        try {
            fs.writeFileSync(__dirname + '/../config.json', '{}', {flag: 'wx'});
        } catch (e) {
        }
        try {
            this.config = JSON.parse(fs.readFileSync(__dirname + '/../config.json'));
        } catch (e) {
            this.config = {};
        }

        mongoose.connect(process.env.MONGO_URL);
        var db = mongoose.connection;
        db.on('error', console.error.bind(console, 'connection error:'));
        db.once('open', function () {
            console.log("DB Connected");
        });

        this.client = new CommandClient(process.env.BOT_TOKEN, {
            messageLimit: 5,
            getAllUsers:  true,
        }, {
            owner:       "Aaron",
            description: "Google Analytics for your Discord Server!",
            prefix:      process.env.NODE_ENV === 'development' ? '\\' : '/'
        });

        let cmds = [
            SetTokenCommand,
            EvalCommand,
            RestartCommand,
            StatsCommand,
            InfoCommand,
            UnignoreCommand,
            IgnoreCommand,
            ChannelLeaderboardCommand,
            LeaderboardCommand,
            CleanCommand
        ];
        for (let cmd of cmds) {
            this.client.registerCommand(cmd.name, this.wrapError.bind(this, cmd.run.bind(this)), cmd.config);
        }

        ReadyHandler.run.call(this);

        this.client.on('err', console.error);
        this.client.on('error', console.error);

        process.on('SIGUSR2', () => {
            console.log("SIGUSR2");
            this.gracefulShutdown();
        });

        Aggregator.aggregate();
        setInterval(Aggregator.aggregate, AGGREGATOR_INTERVAL);
    }

    track(action, server, user) {
        if (!action) {
            console.log("No action!");
            return;
        }

        if (server && user) {
            let tokens = [process.env.BOT_ANALYTICS];
            if (this.getConfig(server).token) {
                tokens.push(this.getConfig(server).token);
            }

            let data = {v: 1, t: 'event', cid: user, ec: server, ea: action, el: user};

            tokens.forEach(token => {
                request.post(
                    `https://www.google-analytics.com/collect?tid=${token}&${querystring.stringify(data)}`,
                    err => {
                        if (err) {
                            console.log(err);
                        } else {
                            //console.log(`TRACKED EVENT: ${action}, ${server}, ${user}`);
                        }
                    }
                )
            });
        }
    }

    async checkVoiceChannelStates() {
        let results;
        try {
            results = await VoiceEvent.find({hasLeft: false});
        } catch (e) {
            console.log(e);
            return;
        }

        if (results.length === 0) {
            return;
        }

        for (let result of results) {
            if (!result) {
                console.log(result);
                continue;
            }

            try {
                let guild = this.client.guilds.get(result.guild.toString()), user;
                if (guild) {
                    user = guild.members.get(result.user.toString());
                    if (user && user.voiceState && user.voiceState.channelID) {
                        if (user.voiceState.channelID != result.channel) {
                            console.log("User in a different in voice, stopping and starting event approximately.");
                            ReadyHandler.stopVoiceEvent(user, guild.channels.get(result.channel.toString()), true);
                            ReadyHandler.startVoiceEvent(user, guild.channels.get(user.voiceState.channelID), true);
                            continue;
                        }

                        if (user.voiceState.deaf || user.voiceState.selfDeaf) {
                            console.log("User no longer in voice undeafened, stopping event approximately.");
                            ReadyHandler.stopVoiceEvent(user, guild.channels.get(result.channel.toString()), true);
                        }
                        continue;
                    }

                    console.log("User no longer in voice, stopping event approximately.");
                    ReadyHandler.stopVoiceEvent(user, guild.channels.get(result.channel.toString()), true);
                    continue;
                }

                result.remove().catch(console.error);
            } catch (e) {
                console.error(e)
            }
        }
    }

    embedError(channel, error) {
        channel.createMessage({
            embed: {
                author:      {
                    name: "Error!"
                },
                title:       error.message || error,
                description: error.stack || error,
                timestamp:   new Date(),
                color:       0xFF0000
            }
        }).catch(e => console.log(e.response));
    }

    getConfig(guildId) {
        if (!this.config[guildId]) {
            this.config[guildId] = {
                token:           undefined,
                ignoredUsers:    [],
                ignoredChannels: []
            };
        }

        return this.config[guildId];
    }

    wrapError(func, msg, args) {
        (function (msg, args) {
            try {
                func(msg, args);
            } catch (e) {
                console.log(e);
            }
        })(msg, args);
    }

    saveConfig() {
        try {
            fs.writeFile(
                fs.realpathSync(__dirname + '/../config.json'),
                JSON.stringify(this.config, null, 4),
                err => {
                    if (err) {
                        console.error(err);
                    }
                }
            );
        } catch (e) {
            console.error(e);
        }
    }

    gracefulShutdown() {
        console.log("Process killed.");
        this.client.editStatus("dnd", {name: "Restarting"});

        setTimeout(() => {
            this.client.disconnect({reconnect: false});
            delete this.client;
            process.exit(0);
        }, 300)
    }

    run() {
        console.log("Starting bot!");
        this.client.connect();
        setInterval(this.sendServerCount.bind(this), 60000);
    }

    sendServerCount() {
        request({
            uri:     'https://bots.discord.pw/api/bots/264569236129579008/stats',
            method:  'POST',
            headers: {
                Authorization: process.env.BOTS_DISCORD_PW_KEY
            },
            json:    {
                server_count: this.client.guilds.size
            }
        }, err => {
            if (err) {
                console.log(err)
            }
        });

        request({
            uri:    'https://www.carbonitex.net/discord/data/botdata.php?debug=true',
            method: 'POST',
            json:   {
                key:         process.env.CARBONITE_KEY,
                servercount: this.client.guilds.size
            }
        }, err => {
            if (err) {
                console.log(err)
            }
        });
    }
}
<|endoftext|>


<commit_before>/******************************************************************************
 *                                  ~cassie~                                  *
 *                                ‾‾‾‾‾‾‾‾‾‾‾‾                                *
 * Simple future library for JS. Ready to be violently raped by Ajax!         *
 *     _________________________________________________________________      *
 *        Copyright (c) 2011 Quildreen Motta // Licenced under MIT/X11        *
 ******************************************************************************/

//// Module Cassie /////////////////////////////////////////////////////////////
//
// Cassie (short for lil' Cassandra) is a deliciously short future
// library for JavaScript. It provides a simple Promise object that can
// be used as the return value of any asynchronous call.
//
// The idea behind promises is that you can manipulate the return value
// of an asynchronous function before the function has been
// resolved. This allows you to write in a clear chaining DSL rather
// than using a clusterfuck of callbacks.
//
// Take an Ajax request, for example. The usual way::
//
//     var req = ajax.get('data.json'
//               , function (resp) { /* success */
//                   req.update('#data', JSON.parse(resp.responseText))
//               }
//               , function (resp) { /* fail */
//                   req.show_error()
//               })
//     setTimeout(req.fail, 10000)
//
// With promises, you could get this::
//
//     var req = ajax.get('data.json')
//                   .ok().update('#data')
//                   .failed().show_error()
//                   .timeout(10)
//
// You can pass this ``req`` object around, and other functions can add
// their own manipulations to the object as well::
//
//     function log_it(req) {
//         return req.ok(log('success'))
//                   .failed(log('failed'))
//                   .clear_timer() /* disables the timeout */
//     }
//     var req = log_it(ajax.get('data.json').timeout(10))
//

'@cassie',
function (root) {
    if (typeof exports == 'undefined') {
        old    = root.cassie
        cassie = root.cassie = {}
        cassie.clean = function() {
            root.cassie = old
            return cassie
        }}
    else
        cassie = exports

    var cassie, old
      , slice = Array.prototype.slice

      // Constants with values for errors
      , forgotten = {}
      , timeouted = {}

    ///// Object Promise ///////////////////////////////////////////////////////
    //
    // Creates a deferred object, that can be manipulated before the
    // value is actually resolved. As soon as it is fulfilled, this
    // promise will apply the pending actions.
    //
    // You can either return the promise directly, or take full
    // advantage of it by inheriting the ``Promise``'s prototoype and
    // adding your own custom methods.
    //
    function Promise () {
        this.callbacks   = {}
        this.flush_queue = []
        this.value       = null
        this.timer       = null
        this.defaultev   = 'done'
    }
    Promise.prototype = function() {
        return { add:         add
               , flush:       flush
               , done:        done
               , bind:        bind
               , fail:        fail
               , timeout:     timeout
               , clear_timer: clear_timer
               , forget:      forget

               // Shortcuts for add(event[, callback])
               , ok:          ok
               , failed:      failed
               , timeouted:   _timeouted
               , forgotten:   _forgotten }

        ////// Function add_callback ///////////////////////////////////////////
        // ::
        //     add_callback(Obj promise, Str event, Fn callback) → Fn
        //
        // Adds a callback to a ``Promise``.
        //
        // The callback will be called whenever the given event happens
        // within the given promise, in the context of the promise (ie.:
        // ``this`` inside the callback will refer to the given promise)
        // and the arguments provided when the promise was fulfilled.
        //
        // Returns the given callback function.
        //
        function add_callback(promise, event, callback) {
            get_queue(promise, event).push(callback)
            return callback
        }

        function get_queue(promise, event) {
            return promise.callbacks[event]
                || (promise.callbacks[event] = [])
        }

        ////// Method add //////////////////////////////////////////////////////
        // ::
        //     add(Str event[, Fn callback]) → Promise
        //
        // Adds a callback to the ``Promise``.
        //
        // Passing a callback directly to the add method is optional, to
        // leverage more specialized promises, Cassie supports defining
        // a default event to which callbacks are bound.
        //
        // For example, instead of writting the following::
        //
        //     promise.add('ok', foo).add('ok', bar)
        //
        // You could go with::
        //
        //     promise.add('ok').foo().bar()
        //
        // Of course, given you have a specialized promise implementing
        // `foo` and `bar`.
        //
        // The default event persists until another `add` call with an
        // explicit event is issued.
        //
        // See :fn:`add_callback` for more information.
        //
        function add(event, callback) {
            if (typeof event == 'function') {
                callback = event
                event    = this.defaultev }

            _add(this, event, callback)
            return this
        }

        function _add(promise, event, callback) {
            promise.defaultev = event
            if (promise.value)
                fire(promise, event, callback)
            else
                callback && add_callback(promise, event, callback)
        }

        function fire(promise, event, callback) {
            var queue = get_queue(promise, event)
            if (callback && queue.flushed)
                return callback.apply(promise, promise.value)
        }

        ////// Method flush ////////////////////////////////////////////////////
        // ::
        //     flush(Str event) → Promise
        //
        // Calls all callbacks associated with the given event.
        //
        // The callbacks are called in the context of this ``Promise``
        // (ie.: ``this`` inside such callback will refer to this
        // ``Promise``), and with any arguments that have been passed to
        // the promise when it was fulfilled.
        //
        function flush(event) {
            if (!this.value)
                event && this.flush_queue.push(event)
            else while (event = this.flush_queue.shift())
                flush_ev(this, event)

            return this
        }

        function flush_ev(promise, event) {
            var callbacks = promise.callbacks[event] || []
              , current

            while (current = callbacks.shift())
                current.apply(promise, promise.value)

            callbacks.flushed = true
        }

        ////// Method done /////////////////////////////////////////////////////
        // ::
        //     done(ArrayLike values) → Promise
        //
        // Resolves the promise to the given values and call the
        // callbacks defined for ``done``.
        //
        // The given value array is cloned, then assigned to the
        // promise. This makes it easier for caller functions to just
        // pass the ``arguments`` object straight up to this function.
        //
        // If the promise has already been resolved, this method is a
        // noop.
        //
        function done(values) {
            if (!this.value) {
                this.clear_timer().flush('done')
                this.value = slice.call(values)
                this.flush() }
            return this
        }

        ////// Method fail /////////////////////////////////////////////////////
        // ::
        //     fail(Obj error) → Promise
        //
        // Fails to fulfill the promise, and calls all the ``fail``
        // callbacks passing the error as parameter.
        //
        // See :fn:`done` for more information.
        //
        function fail() {
            return this.flush('fail').done(arguments)
        }

        ////// Method bind /////////////////////////////////////////////////////
        // ::
        //     bind(values...) → Promise
        //
        // Successfully fulfills the promise, and calls the ``bind``
        // callbacks passing the values as parameter.
        //
        // See :fn:`resolve` for more information.
        //
        function bind() {
            return this.flush('ok').done(arguments)
        }

        ////// Method timeout //////////////////////////////////////////////////
        // ::
        //     timeout(Num delay) → Promise
        //
        // Fails to fulfill the promise after the given number of
        // seconds.
        //
        // The promise fails with the value of ``timeouted``.
        //
        function timeout(delay) {
            var promise = this
            this.timer = setTimeout(function(){
                promise.flush('timeouted')
                       .fail(timeouted)
            }, delay * 1000)
            return this
        }

        ////// Method clear_timer //////////////////////////////////////////////
        // ::
        //     clear_timer() → Promise
        //
        // Clears any timer that may exist for this promise.
        //
        function clear_timer() {
            clearTimeout(this.timer)
            return this
        }

        ////// Method forget ///////////////////////////////////////////////////
        // ::
        //     forget() → Promise
        //
        // Cancels the promise, and fails with the value of ``forgotten``.
        //
        function forget() {
            return this.flush('forgotten').fail(forgotten)
        }

        ////// -Shortcuts for add(event[, callback]) //////////////////////////
        function ok(fn)         { return this.add('ok',        fn) }
        function failed(fn)     { return this.add('fail',      fn) }
        function _timeouted(fn) { return this.add('timeouted', fn) }
        function _forgotten(fn) { return this.add('forgotten', fn) }
    }()

    ///// Exṕorts //////////////////////////////////////////////////////////////
    cassie.Promise      = Promise
    cassie.forgotten    = forgotten
    cassie.timeouted    = timeouted
}(this)<commit_msg>Summary: Small style change in variables and code layout.<commit_after>/******************************************************************************
 *                                  ~cassie~                                  *
 *                                ‾‾‾‾‾‾‾‾‾‾‾‾                                *
 * Simple future library for JS. Ready to be violently raped by Ajax!         *
 *     _________________________________________________________________      *
 *        Copyright (c) 2011 Quildreen Motta // Licenced under MIT/X11        *
 ******************************************************************************/

//// Module Cassie /////////////////////////////////////////////////////////////
//
// Cassie (short for lil' Cassandra) is a deliciously short future
// library for JavaScript. It provides a simple Promise object that can
// be used as the return value of any asynchronous call.
//
// The idea behind promises is that you can manipulate the return value
// of an asynchronous function before the function has been
// resolved. This allows you to write in a clear chaining DSL rather
// than using a clusterfuck of callbacks.
//
// Take an Ajax request, for example. The usual way::
//
//     var req = ajax.get('data.json'
//               , function (resp) { /* success */
//                   req.update('#data', JSON.parse(resp.responseText))
//               }
//               , function (resp) { /* fail */
//                   req.show_error()
//               })
//     setTimeout(req.fail, 10000)
//
// With promises, you could get this::
//
//     var req = ajax.get('data.json')
//                   .ok().update('#data')
//                   .failed().show_error()
//                   .timeout(10)
//
// You can pass this ``req`` object around, and other functions can add
// their own manipulations to the object as well::
//
//     function log_it(req) {
//         return req.ok(log('success'))
//                   .failed(log('failed'))
//                   .clear_timer() /* disables the timeout */
//     }
//     var req = log_it(ajax.get('data.json').timeout(10))
//

'@cassie',
function (root) { var cassie, old

    // Aliases for some long properties
    ,slice = Array.prototype.slice

    // Constants with values for errors
    ,forgotten = {}
    ,timeouted = {}

    if (typeof exports == 'undefined') {
        old    = root.cassie
        cassie = root.cassie = {}

        // Removes `cassie' from the global object
        cassie.clean = function() {
            root.cassie = old
            return cassie
        }}
    else
        cassie = exports

    ///// Object Promise ///////////////////////////////////////////////////////
    //
    // Creates a deferred object, that can be manipulated before the
    // value is actually resolved. As soon as it is fulfilled, this
    // promise will apply the pending actions.
    //
    // You can either return the promise directly, or take full
    // advantage of it by inheriting the ``Promise``'s prototoype and
    // adding your own custom methods.
    //
    function Promise () {
        this.callbacks   = {}
        this.flush_queue = []
        this.value       = null
        this.timer       = null
        this.defaultev   = 'done'
    }
    Promise.prototype = function() {
        return { add:         add
               , flush:       flush
               , done:        done
               , bind:        bind
               , fail:        fail
               , timeout:     timeout
               , clear_timer: clear_timer
               , forget:      forget

               // Shortcuts for add(event[, callback])
               , ok:          ok
               , failed:      failed
               , timeouted:   _timeouted
               , forgotten:   _forgotten }

        ////// Function add_callback ///////////////////////////////////////////
        // ::
        //     add_callback(Obj promise, Str event, Fn callback)
        //
        // Adds a callback to a ``Promise``.
        //
        // The callback will be called whenever the given event happens
        // within the given promise, in the context of the promise (ie.:
        // ``this`` inside the callback will refer to the given promise)
        // and the arguments provided when the promise was fulfilled.
        //
        // Returns the given callback function.
        //
        function add_callback(promise, event, callback) {
            if (callback)
                get_queue(promise, event).push(callback)
        }

        function get_queue(promise, event) {
            return  promise.callbacks[event]
                || (promise.callbacks[event] = [])
        }

        ////// Method add //////////////////////////////////////////////////////
        // ::
        //     add(Str event[, Fn callback]) → Promise
        //
        // Adds a callback to the ``Promise``.
        //
        // Passing a callback directly to the add method is optional, to
        // leverage more specialized promises, Cassie supports defining
        // a default event to which callbacks are bound.
        //
        // For example, instead of writting the following::
        //
        //     promise.add('ok', foo).add('ok', bar)
        //
        // You could go with::
        //
        //     promise.add('ok').foo().bar()
        //
        // Of course, given you have a specialized promise implementing
        // `foo` and `bar`.
        //
        // The default event persists until another `add` call with an
        // explicit event is issued.
        //
        // See :fn:`add_callback` for more information.
        //
        function add(event, callback) {
            if (typeof event == 'function') {
                callback = event
                event    = this.defaultev }

            _add(this, event, callback)
            return this
        }

        function _add(promise, event, callback) {
            promise.defaultev = event
            if (promise.value)
                fire(promise, event, callback)
            else
                add_callback(promise, event, callback)
        }

        function fire(promise, event, callback) { var queue
            queue = get_queue(promise, event)
            if (callback && queue.flushed)
                return callback.apply(promise, promise.value)
        }

        ////// Method flush ////////////////////////////////////////////////////
        // ::
        //     flush(Str event) → Promise
        //
        // Calls all callbacks associated with the given event.
        //
        // The callbacks are called in the context of this ``Promise``
        // (ie.: ``this`` inside such callback will refer to this
        // ``Promise``), and with any arguments that have been passed to
        // the promise when it was fulfilled.
        //
        function flush(event) {
            if (!this.value)
                event && this.flush_queue.push(event)
            else while (event = this.flush_queue.shift())
                flush_ev(this, event)

            return this
        }

        function flush_ev(promise, event) { var callbacks, current
            callbacks = promise.callbacks[event] || []
            while (current = callbacks.shift())
                current.apply(promise, promise.value)

            callbacks.flushed = true
        }

        ////// Method done /////////////////////////////////////////////////////
        // ::
        //     done(ArrayLike values) → Promise
        //
        // Resolves the promise to the given values and call the
        // callbacks defined for ``done``.
        //
        // The given value array is cloned, then assigned to the
        // promise. This makes it easier for caller functions to just
        // pass the ``arguments`` object straight up to this function.
        //
        // If the promise has already been resolved, this method is a
        // noop.
        //
        function done(values) {
            if (!this.value) {
                this.clear_timer().flush('done')
                this.value = slice.call(values)
                this.flush() }
            return this
        }

        ////// Method fail /////////////////////////////////////////////////////
        // ::
        //     fail(Obj error) → Promise
        //
        // Fails to fulfill the promise, and calls all the ``fail``
        // callbacks passing the error as parameter.
        //
        // See :fn:`done` for more information.
        //
        function fail() {
            return this.flush('fail').done(arguments)
        }

        ////// Method bind /////////////////////////////////////////////////////
        // ::
        //     bind(values...) → Promise
        //
        // Successfully fulfills the promise, and calls the ``bind``
        // callbacks passing the values as parameter.
        //
        // See :fn:`resolve` for more information.
        //
        function bind() {
            return this.flush('ok').done(arguments)
        }

        ////// Method timeout //////////////////////////////////////////////////
        // ::
        //     timeout(Num delay) → Promise
        //
        // Fails to fulfill the promise after the given number of
        // seconds.
        //
        // The promise fails with the value of ``timeouted``.
        //
        function timeout(delay) { var self
            self = this
            this.timer = setTimeout(function(){
                self.flush('timeouted').fail(timeouted)
            }, delay * 1000)
            return this
        }

        ////// Method clear_timer //////////////////////////////////////////////
        // ::
        //     clear_timer() → Promise
        //
        // Clears any timer that may exist for this promise.
        //
        function clear_timer() {
            clearTimeout(this.timer)
            return this
        }

        ////// Method forget ///////////////////////////////////////////////////
        // ::
        //     forget() → Promise
        //
        // Cancels the promise, and fails with the value of ``forgotten``.
        //
        function forget() {
            return this.flush('forgotten').fail(forgotten)
        }

        ////// -Shortcuts for add(event[, callback]) //////////////////////////
        function ok(fn)         { return this.add('ok',        fn) }
        function failed(fn)     { return this.add('fail',      fn) }
        function _timeouted(fn) { return this.add('timeouted', fn) }
        function _forgotten(fn) { return this.add('forgotten', fn) }
    }()

    ///// Exṕorts //////////////////////////////////////////////////////////////
    cassie.Promise      = Promise
    cassie.forgotten    = forgotten
    cassie.timeouted    = timeouted
}(this)<|endoftext|>


<commit_before>// https://gist.github.com/harrison @ https://gist.github.com/gocardless
// ---------------------------------------------------------
// Heavily inspired by https://github.com/twilson63/ngUpload

// AngularJS file upload directive
//
// Creates a new inherited child scope and adds a $isUploading property
// Use this property to show loading messages and to disable the submit button
//
// The attribute directive takes an options hash:
// options = { onUploadEnd: function onUploadEnd(content) {}  }
// Use ng-submit if you want to know when the upload starts
//
//

//

//    <form action="/uploads" gc-upload="{
//        onUploadEnd: onUploadEnd
//      }">
//      <input type="file" name="file" ng-required="true">
//      <input type="submit" value="Upload" ng-disabled="$isUploading">
//    </form>
//

//

//
//  angular.module('app', ['gcUpload'])
//    .controller('ctrl', function($scope) {
//      $scope.onUploadEnd = function onUploadEnd(content) {
//        console.log(content);
//      }
//  });

'use strict';

angular.module('gcUpload', [])
  .directive('gcUpload', [
    '$log',
    function gcUploadDirective($log) {
      return {
        scope: true,
        require: 'form',
        link: function gcUploadLink(scope, element, attrs, ctrl) {
          // Give each directive instance a new id
          var iframeID = _.uniqueId();

          var options = scope.$eval(attrs.gcUpload) || {};

          function getActionAttrValue() {
            var action = element.attr('action');
            var separator = action.indexOf('?') === -1 ? '?' : '&';
            var tStamp = +(new Date());

            // Append a timestamp field to the url
            // to prevent browser caching results
            return action + separator + '_t=' + tStamp;
          }

          function setLoadingState(state) {
            scope.$isUploading = state;
          }

          element.attr({
            'target': 'upload-iframe-' + iframeID,
            'method': 'post',
            'action': getActionAttrValue(),
            'enctype': 'multipart/form-data',
            'encoding': 'multipart/form-data'
          });

          var iframe = angular.element(
            ''
          );

          element.after(iframe);

          setLoadingState(false);

          // Start upload
          element.bind('submit', function uploadStart() {
            scope.$apply(function() {
              setLoadingState(true);
            });

            // Finish upload
            iframe.bind('load', function uploadEnd() {
              iframe.unbind('load');
              // Reset form
              element[0].reset();
              ctrl.$setPristine();

              scope.$apply(function() {
                setLoadingState(false);
              });

              // Get iframe body contents
              var bodyContent = (iframe[0].contentDocument ||
                iframe[0].contentWindow.document).body;
              var content;
              try {
                content = angular.fromJson(bodyContent.innerText);
              } catch (e) {
                // Fall back to html if json parse failed
                content = bodyContent.innerHTML;
                $log.warn('Response is not valid JSON');
              }

              if (angular.isFunction(options.onUploadEnd)) {
                scope.$apply(function() {
                  options.onUploadEnd(content);
                });
              }
            });
          });
        }
      };
    }
  ]);
<commit_msg>Fix FF issue - use angular.element.text<commit_after>// https://gist.github.com/harrison @ https://gist.github.com/gocardless
// ---------------------------------------------------------
// Heavily inspired by https://github.com/twilson63/ngUpload

// AngularJS file upload directive
//
// Creates a new inherited child scope and adds a $isUploading property
// Use this property to show loading messages and to disable the submit button
//
// The attribute directive takes an options hash:
// options = { onUploadEnd: function onUploadEnd(content) {}  }
// Use ng-submit if you want to know when the upload starts
//
//

//

//    <form action="/uploads" gc-upload="{
//        onUploadEnd: onUploadEnd
//      }">
//      <input type="file" name="file" ng-required="true">
//      <input type="submit" value="Upload" ng-disabled="$isUploading">
//    </form>
//

//

//
//  angular.module('app', ['gcUpload'])
//    .controller('ctrl', function($scope) {
//      $scope.onUploadEnd = function onUploadEnd(content) {
//        console.log(content);
//      }
//  });

'use strict';

angular.module('gcUpload', [])
  .directive('gcUpload', [
    '$log',
    function gcUploadDirective($log) {

      function getActionAttrValue(element) {
        var action = element.attr('action');
        var separator = action.indexOf('?') === -1 ? '?' : '&';
        var tStamp = +(new Date());

        // Append a timestamp field to the url
        // to prevent browser caching results
        return action + separator + '_t=' + tStamp;
      }

      return {
        scope: true,
        require: 'form',
        link: function gcUploadLink(scope, element, attrs, ctrl) {
          // Give each directive instance a new id
          var iframeID = _.uniqueId();

          var options = scope.$eval(attrs.gcUpload) || {};

          function setLoadingState(state) {
            scope.$isUploading = state;
          }

          element.attr({
            'target': 'upload-iframe-' + iframeID,
            'method': 'post',
            'action': getActionAttrValue(element),
            'enctype': 'multipart/form-data',
            'encoding': 'multipart/form-data'
          });

          var iframe = angular.element(
            ''
          );

          element.after(iframe);

          setLoadingState(false);

          // Start upload
          element.bind('submit', function uploadStart() {
            scope.$apply(function() {
              setLoadingState(true);
            });

            // Finish upload
            iframe.bind('load', function uploadEnd() {
              iframe.unbind('load');
              // Reset form
              element[0].reset();
              ctrl.$setPristine();

              scope.$apply(function() {
                setLoadingState(false);
              });

              // Get iframe body contents
              var bodyElement = (iframe[0].contentDocument ||
                iframe[0].contentWindow.document).body;
              var content = angular.element(bodyElement).text();
              try {
                content = angular.fromJson(content);
              } catch (e) {
                $log.warn('Response is not valid JSON');
              }

              if (angular.isFunction(options.onUploadEnd)) {
                scope.$apply(function() {
                  options.onUploadEnd(content);
                });
              }
            });
          });
        }
      };
    }
  ]);
<|endoftext|>