<commit_before>var request = require('request'),
    async = require('async');

var now = function() { return (new Date()).getTime(); },
    second = 1000,
    minute = second * 60;

module.exports = function () {
    var self = this;

    self.cache = {
        expires: now(),
        projects: {}
    };

    function log () {
      if (self.config.debug) {
        var msg = [new Date().toLocaleTimeString(), '| GitLab |'];
        for (var i in arguments) {
          msg.push(arguments[i]);
        }
        console.log.apply(this, msg);
      }
    }

    function getDefaultExpiration() {
        return now() + self.config.intervals.disabled;
    }

    function getProjectExpiration(project) {
        if (project.builds_enabled !== true) {
            return getDefaultExpiration();
        } else if (!Object.keys(project.builds).length) {
            return now() + self.config.intervals.empty;
        } else {
            return now() + self.config.intervals.default;
        }
    }

    function getBuildExpiration(build) {
        if (build.status !== 'running') {
            return getDefaultExpiration();
        } else {
            return now();
        }
    }

    function getRequestHeaders() {
        return {
             'PRIVATE-TOKEN': self.config.token
        };
    }

    function getProjectsApiUrl (page, per_page) {
        var base = self.config.url + '/',
            query = '?page=' + page + '&per_page=' + per_page;
        return base + 'api/v3/projects' + query;
    }

    function getProjectBuildsApiUrl (project, page, per_page) {
        var base = self.config.url + '/',
            query = '?page=' + page + '&per_page=' + per_page;
        return base + 'api/v3/projects/' + project.id + '/builds' + query;
    }

    function getBuildApiUrl (project, build) {
        var base = self.config.url + '/';
        return base + 'api/v3/projects/' + project.id + '/builds/' + build.id;
    }

    function getBuildId (project, build) {
        return project.id + '-' + build.ref + '-' + build.stage;
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildNumber (project, build) {
        return project.name_with_namespace;
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildProject (project, build) {
        return build.ref;
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildIsRunning (project, build) {
        return (build.status === 'running' ||
                build.status === 'pending');
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildStartedAt (project, build) {
        if (typeof build.started_at === 'string') {
            return new Date(build.started_at);
        } else if (build.status === 'pending') {
            return now();
        } else {
            return undefined;
        }
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildFinishedAt (project, build) {
        if (build.status === 'failed') {
            return now();  // sort failed builds on top
        } else if (typeof build.finished_at === 'string') {
            return new Date(build.finished_at);
        } else {
            return undefined;
        }
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildRequestedFor (project, build) {
        return build.commit && build.commit.author_name;
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildStatus (project, build) {
        switch (build.status) {
            case 'pending':
                return '#ffa500';
            case 'running':
                return 'Blue';
            case 'failed':
                return 'Red';
            case 'success':
                return 'Green';
            default:
                return 'Gray';
        }
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildStatusText (project, build) {
        return build.stage + ' ' + build.status;
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildReason (project, build) {
        return build.commit && build.commit.message;

    }

    function getBuildUrl (project, build) {
        var base = self.config.url + '/';
        return base + project.path_with_namespace + '/builds/' + build.id;
    }

    function getBuildMonitorBuild (project, build) {
        return {
            id: getBuildId(project, build),
            number: getBuildNumber(project, build),
            project: getBuildProject(project, build),
            isRunning: getBuildIsRunning(project, build),
            startedAt: getBuildStartedAt(project, build),
            finishedAt: getBuildFinishedAt(project, build),
            requestedFor: getBuildRequestedFor(project, build),
            status: getBuildStatus(project, build),
            statusText: getBuildStatusText(project, build),
            reason: getBuildReason(project, build),
            hasErrors: false,
            hasWarnings: false,
            url: getBuildUrl(project, build)
        };
    }

    function requestFirstPage(getPagedApiUrl, callback) {
        log('Fetching', getPagedApiUrl(1, 100));
        request({
            headers: getRequestHeaders(),
            url: getPagedApiUrl(1, 100),
            json: true
        }, function (err, response, body) {
            if (!err && response.statusCode == 200) {
                process.nextTick(function() {
                    callback(body);
                });
            } else {
                log('Error', body);
                process.nextTick(function() {
                    callback([]);
                });
            }
        });
    }

    function requestAllPages(getPagedApiUrl, callback) {
        log('Fetching', getPagedApiUrl(1, 100));
        request({
            headers: getRequestHeaders(),
            url: getPagedApiUrl(1, 100),
            json: true
        }, function(err, response, body) {
            if (!err && response.statusCode == 200) {
                var urls = [], pages = Math.ceil(
                    parseInt(response.headers['x-total-pages'], 10));
                for (var i = 2; i <= pages; i = i + 1) {
                    urls.push(getPagedApiUrl(i, 100));
                }

                process.nextTick(function() {
                    callback(body);
                });

                async.mapSeries(urls, function(url, pass) {
                    log('Fetching', url);
                    request({
                        headers: getRequestHeaders(),
                        url: url,
                        json: true
                    }, function (err, response, body) {
                        if (!err && response.statusCode == 200) {
                            process.nextTick(function() {
                                callback(body);
                            });
                            process.nextTick(function() {
                                pass(null, body);
                            });
                        } else {
                            log('Error', body);
                            process.nextTick(function() {
                                callback([]);
                            });
                            process.nextTick(function() {
                                pass(null, []);
                            });
                        }
                    });
                });
            } else {
                log('Error', body);
                process.nextTick(function() {
                    callback([]);
                });
            }
        });
    }

    function updateBuild(project, build, callback) {
        log('Fetching', getBuildApiUrl(project, build));
        request({
            headers: getRequestHeaders(),
            url: getBuildApiUrl(project, build),
            json: true
        }, function(err, response, body) {
            if (!err && response.statusCode == 200) {
                body.monitor = getBuildMonitorBuild(project, body);
                body.expires = getBuildExpiration(body);
                project.builds[body.monitor.id] = body;
                if (typeof callback === 'function') {
                    process.nextTick(function() {
                        callback(body);
                    });
                }
            } else {
                log('Error', body);
                if (typeof callback === 'function') {
                    process.nextTick(function() {
                        callback(build);
                    });
                }
            }
        });
    }

    function reduceBuilds(builds, callback) {
        var seen = {};
        async.filter(builds, function(build, include) {
            var key = build.monitor.id;
            if (typeof seen[key] === 'undefined') {
                seen[key] = build;
                process.nextTick(function() {
                    include(true);
                });
            } else if (seen[key].monitor.startedAt <
                       build.monitor.startedAt) {
                seen[key] = build;
                process.nextTick(function() {
                    include(true);
                });
            } else {
                process.nextTick(function() {
                    include(false);
                });
            }
        }, function(results) {
            var latest = null;
            async.filter(results, function(build, include) {
                if (!latest || build.monitor.startedAt > latest) {
                    latest = build.monitor.startedAt;
                    include(true);
                } else {
                    include(build.monitor.isRunning ||
                            build.status === 'failing');
                }
            }, function(results) {
                if (typeof callback === 'function') {
                    process.nextTick(function() {
                        callback(results);
                    });
                }
            });
        });

    }

    function fetchProjectBuilds(project, callback) {
        requestFirstPage(function (page, per_page) {
            return getProjectBuildsApiUrl(project, page, per_page);
        }, function (results) {
            async.mapSeries(results, function(build, pass) {
                build.monitor = getBuildMonitorBuild(project, build);
                build.expires = getBuildExpiration(build);
                pass(null, build);
            }, function(err, results) {
                process.nextTick(function() {
                    reduceBuilds(results, function(results) {
                        if (results.length) {
                            log(project.name_with_namespace + ' | ' +
                                results.length + ' current builds.');
                        }
                        process.nextTick(function() {
                            callback(results);
                        });
                    });
                });
            });
        });
    }

    function updateProject(project, callback) {
        log('Updating project:', project.name_with_namespace);
        if (self.config.slugs.indexOf('*/*') > -1 || self.config.slugs.indexOf(project.path_with_namespace) > -1) {
          if (typeof project.builds === 'undefined') {
              project.builds = {};
          }
          if (project.builds_enabled === true) {
              fetchProjectBuilds(project, function(results) {
                  var i, build, builds = {};
                  for (i = 0; i < results.length; i = i + 1) {
                      build = results[i];
                      builds[build.monitor.id] = build;
                  }
                  if (Object.keys(builds).length) {
                      project.builds = builds;
                  }
                  project.expires = getProjectExpiration(project);
                  self.cache.projects[project.id] = project;
                  if (typeof callback === 'function') {
                      process.nextTick(function() {
                          callback(project);
                      });
                  }
              });
          } else {
              project.builds = {};
              project.expires = getProjectExpiration(project);
              self.cache.projects[project.id] = project;
              if (typeof callback === 'function') {
                  process.nextTick(function() {
                      callback(project);
                  });
              }
          }
        } else {
          if (typeof callback === 'function') {
              process.nextTick(function() {
                  callback(project);
              });
          }
        }
    }

    function fetchNewProjects(callback) {
        self.cache.expires = getDefaultExpiration();

        log('Fetching new projects...');
        requestAllPages(getProjectsApiUrl, function (projects) {
            async.filter(projects, function (project, include) {
                if (typeof self.cache.projects[project.id] === 'undefined') {
                    include(true);
                } else if (self.cache.projects[project.id]
                                     .builds_enabled === false) {
                   include(true);
                } else {
                    include(false);
                }
            }, function (results) {
                async.mapSeries(results, function (project, pass) {
                    updateProject(project, function(project) {
                        pass(null, project);
                    });
                }, function (err, results) {
                    log('Found', results.length + ' new projects.');
                    if (typeof callback === 'function') {
                        process.nextTick(function() {
                            callback(results);
                        });
                    }
                });
            });
        });
    }

    self.check = function (callback) {
        // Trigger fetch for new projects
        if (now() > self.cache.expires) {
            process.nextTick(fetchNewProjects);
        }

        // Iterate through already cached projects
        async.mapSeries(Object.keys(self.cache.projects),
                        function(key, pass) {
            var project = self.cache.projects[key];

            // Trigger fetch for new builds for projects with expired cache
            if (now() > project.expires) {
                process.nextTick(function () {
                    updateProject(project);
                });
            }

            // Iterate through already cached builds for the project
            async.mapSeries(Object.keys(project.builds),
                            function(key, pass) {
                var build = project.builds[key];

                // Trigger fetch for build with expired cache
                if (now() > build.expires) {
                    process.nextTick(function() {
                        updateBuild(project, build);
                    });
                }

                // Pass along the monitor version of the build info
                process.nextTick(function() {
                    pass(null, build.monitor);
                });
            }, function(err, results) {

                // Pass along all project builds
                process.nextTick(function() {
                    pass(null, results);
                });
            });
        }, function(err, builds) {

            // Reduce builds from all projects into a flat array
            async.reduce(builds, [], function(memo, item, pass) {
                process.nextTick(function() {
                    pass(null, memo.concat(item));
                });
            }, function(err, builds) {
                process.nextTick(function() {
                    callback(err, builds);
                });
            });
        });
    };

    self.configure = function (config) {
        self.config = config;
        if (typeof self.config.intervals === 'undefined') {
            self.config.intervals = {};
        }
        if (typeof self.config.intervals.disabled === 'undefined') {
            self.config.intervals.disabled = 12 * 60 * minute;
        }
        if (typeof self.config.intervals.empty === 'undefined') {
            self.config.intervals.empty = 10 * minute;
        }
        if (typeof self.config.intervals.default === 'undefined') {
            self.config.intervals.default = minute;
        }
        if (typeof self.config.slugs === 'undefined') {
            self.config.slugs = ['*/*'];
        }
        if (typeof process.env.GITLAB_TOKEN !== 'undefined') {
            self.config.token = process.env.GITLAB_TOKEN;
        }
        if (typeof self.config.caPath !== 'undefined') {
            request = request.defaults({
                agentOptions: {
                    ca: require('fs').readFileSync(self.config.caPath).toString().split("\n\n")
                }
            });
        }
        for (var key in self.config) {
          if (key !== 'token') {
            log(key + ':', self.config[key]);
          }
        }
    };
};
<commit_msg>Fixed GitLab support.<commit_after>var request = require('request'),
    async = require('async');

var now = function() { return (new Date()).getTime(); },
    second = 1000,
    minute = second * 60;

module.exports = function () {
    var self = this;

    self.cache = {
        expires: now(),
        projects: {}
    };

    function log () {
      if (self.config.debug) {
        var msg = [new Date().toLocaleTimeString(), '| GitLab |'];
        for (var i in arguments) {
          msg.push(arguments[i]);
        }
        console.log.apply(this, msg);
      }
    }

    function getDefaultExpiration() {
        return now() + self.config.intervals.disabled;
    }

    function getProjectExpiration(project) {
        if (project.builds_enabled !== true) {
            return getDefaultExpiration();
        } else if (!Object.keys(project.builds).length) {
            return now() + self.config.intervals.empty;
        } else {
            return now() + self.config.intervals.default;
        }
    }

    function getBuildExpiration(build) {
        if (build.status !== 'running') {
            return getDefaultExpiration();
        } else {
            return now();
        }
    }

    function getRequestHeaders() {
        return {
             'PRIVATE-TOKEN': self.config.token
        };
    }

    function getProjectsApiUrl (page, per_page) {
        var base = self.config.url + '/',
            query = '?page=' + page + '&per_page=' + per_page;
        return base + 'api/v3/projects' + query;
    }

    function getProjectBuildsApiUrl (project, page, per_page) {
        var base = self.config.url + '/',
            query = '?page=' + page + '&per_page=' + per_page;
        return base + 'api/v3/projects/' + project.id + '/builds' + query;
    }

    function getBuildApiUrl (project, build) {
        var base = self.config.url + '/';
        return base + 'api/v3/projects/' + project.id + '/builds/' + build.id;
    }

    function getBuildId (project, build) {
        return project.id + '-' + build.ref + '-' + build.stage;
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildNumber (project, build) {
        return project.name_with_namespace;
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildProject (project, build) {
        return build.ref;
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildIsRunning (project, build) {
        return (build.status === 'running' ||
                build.status === 'pending');
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildStartedAt (project, build) {
        return new Date(build.started_at);
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildFinishedAt (project, build) {
        return new Date(build.finished_at);
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildRequestedFor (project, build) {
        return build.commit && build.commit.author_name;
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildStatus (project, build) {
        switch (build.status) {
            case 'pending':
                return '#ffa500';
            case 'running':
                return 'Blue';
            case 'failed':
                return 'Red';
            case 'success':
                return 'Green';
            default:
                return 'Gray';
        }
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildStatusText (project, build) {
        return build.stage + ' ' + build.status;
    }

    //noinspection JSUnusedLocalSymbols
    function getBuildReason (project, build) {
        return build.commit && build.commit.message;

    }

    function getBuildUrl (project, build) {
        var base = self.config.url + '/';
        return base + project.path_with_namespace + '/builds/' + build.id;
    }

    function getBuildMonitorBuild (project, build) {
        return {
            id: getBuildId(project, build),
            number: getBuildNumber(project, build),
            project: getBuildProject(project, build),
            isRunning: getBuildIsRunning(project, build),
            startedAt: getBuildStartedAt(project, build),
            finishedAt: getBuildFinishedAt(project, build),
            requestedFor: getBuildRequestedFor(project, build),
            status: getBuildStatus(project, build),
            statusText: getBuildStatusText(project, build),
            reason: getBuildReason(project, build),
            hasErrors: false,
            hasWarnings: false,
            url: getBuildUrl(project, build)
        };
    }

    function requestFirstPage(getPagedApiUrl, callback) {
        log('Fetching', getPagedApiUrl(1, 100));
        request({
            headers: getRequestHeaders(),
            url: getPagedApiUrl(1, 100),
            json: true
        }, function (err, response, body) {
            if (!err && response.statusCode == 200) {
                process.nextTick(function() {
                    callback(body);
                });
            } else {
                log('Error', body);
                process.nextTick(function() {
                    callback([]);
                });
            }
        });
    }

    function requestAllPages(getPagedApiUrl, callback) {
        log('Fetching', getPagedApiUrl(1, 100));
        request({
            headers: getRequestHeaders(),
            url: getPagedApiUrl(1, 100),
            json: true
        }, function(err, response, body) {
            if (!err && response.statusCode == 200) {
                var urls = [], pages = Math.ceil(
                    parseInt(response.headers['x-total-pages'], 10));
                for (var i = 2; i <= pages; i = i + 1) {
                    urls.push(getPagedApiUrl(i, 100));
                }

                process.nextTick(function() {
                    callback(body);
                });

                async.mapSeries(urls, function(url, pass) {
                    log('Fetching', url);
                    request({
                        headers: getRequestHeaders(),
                        url: url,
                        json: true
                    }, function (err, response, body) {
                        if (!err && response.statusCode == 200) {
                            process.nextTick(function() {
                                callback(body);
                            });
                            process.nextTick(function() {
                                pass(null, body);
                            });
                        } else {
                            log('Error', body);
                            process.nextTick(function() {
                                callback([]);
                            });
                            process.nextTick(function() {
                                pass(null, []);
                            });
                        }
                    });
                });
            } else {
                log('Error', body);
                process.nextTick(function() {
                    callback([]);
                });
            }
        });
    }

    function updateBuild(project, build, callback) {
        log('Fetching', getBuildApiUrl(project, build));
        request({
            headers: getRequestHeaders(),
            url: getBuildApiUrl(project, build),
            json: true
        }, function(err, response, body) {
            if (!err && response.statusCode == 200) {
                body.monitor = getBuildMonitorBuild(project, body);
                body.expires = getBuildExpiration(body);
                project.builds[body.monitor.id] = body;
                if (typeof callback === 'function') {
                    process.nextTick(function() {
                        callback(body);
                    });
                }
            } else {
                log('Error', body);
                if (typeof callback === 'function') {
                    process.nextTick(function() {
                        callback(build);
                    });
                }
            }
        });
    }

    function reduceBuilds(builds, callback) {
        const seen = {};
        let latest = null;

        results = builds
            .filter(build => {
                const key = build.monitor.id;
                if (typeof seen[key] === 'undefined') {
                    seen[key] = build;
                    return true;
                }
                else if (seen[key].monitor.startedAt < build.monitor.startedAt) {
                    seen[key] = build;
                    return true;
                } else {
                    return false;
                }
            })
            .filter(build => {
                if (!latest || build.monitor.startedAt > latest) {
                    latest = build.monitor.startedAt;
                    return true;
                } else {
                    return build.monitor.isRunning || build.status === 'failing';
                }
            });

        if (typeof callback === 'function') {
            process.nextTick(function() {
                callback(results);
            });
        }
    }

    function fetchProjectBuilds(project, callback) {
        requestFirstPage(function (page, per_page) {
            return getProjectBuildsApiUrl(project, page, per_page);
        }, function (results) {
            results.forEach((build, index) => {
                results.find(item => item.id === build.id).monitor = getBuildMonitorBuild(project, build);
                results.find(item => item.id === build.id).expires = getBuildExpiration(build);
            });

            process.nextTick(function() {
                reduceBuilds(results, function(results) {
                    if (results.length) {
                        log(project.name_with_namespace + ' | ' +
                            results.length + ' current builds.');
                    }
                    process.nextTick(function() {
                        callback(results);
                    });
                });
            });
        });
    }

    function updateProject(project, callback) {
        log('Updating project:', project.name_with_namespace);
        if (self.config.slugs.indexOf('*/*') > -1 || self.config.slugs.indexOf(project.path_with_namespace) > -1) {
          if (typeof project.builds === 'undefined') {
              project.builds = {};
          }
          if (project.builds_enabled === true) {
              fetchProjectBuilds(project, function(results) {
                  var i, build, builds = {};
                  for (i = 0; i < results.length; i = i + 1) {
                      build = results[i];
                      builds[build.monitor.id] = build;
                  }
                  if (Object.keys(builds).length) {
                      project.builds = builds;
                  }
                  project.expires = getProjectExpiration(project);
                  self.cache.projects[project.id] = project;
                  if (typeof callback === 'function') {
                      process.nextTick(function() {
                          callback(project);
                      });
                  }
              });
          } else {
              project.builds = {};
              project.expires = getProjectExpiration(project);
              self.cache.projects[project.id] = project;
              if (typeof callback === 'function') {
                  process.nextTick(function() {
                      callback(project);
                  });
              }
          }
        } else {
          if (typeof callback === 'function') {
              process.nextTick(function() {
                  callback(project);
              });
          }
        }
    }

    function fetchNewProjects(callback) {
        self.cache.expires = getDefaultExpiration();

        log('Fetching new projects...');
        requestAllPages(getProjectsApiUrl, function (projects) {
             projects
                .filter(project => project.builds_enabled)
                .forEach(project => {
                    updateProject(project);
                });

            log('Found', projects.length + ' new projects.');
            if (typeof callback === 'function') {
                process.nextTick(function() {
                    callback(projects);
                });
            }
        });
    }

    self.check = function (callback) {
        // Trigger fetch for new projects
        if (now() > self.cache.expires) {
            process.nextTick(fetchNewProjects);
        }

        // Iterate through already cached projects
        async.mapSeries(Object.keys(self.cache.projects),
                        function(key, pass) {
            var project = self.cache.projects[key];

            // Trigger fetch for new builds for projects with expired cache
            if (now() > project.expires) {
                process.nextTick(function () {
                    updateProject(project);
                });
            }

            // Iterate through already cached builds for the project
            async.mapSeries(Object.keys(project.builds),
                            function(key, pass) {
                var build = project.builds[key];

                // Trigger fetch for build with expired cache
                if (now() > build.expires) {
                    process.nextTick(function() {
                        updateBuild(project, build);
                    });
                }

                // Pass along the monitor version of the build info
                process.nextTick(function() {
                    pass(null, build.monitor);
                });
            }, function(err, results) {

                // Pass along all project builds
                process.nextTick(function() {
                    pass(null, results);
                });
            });
        }, function(err, builds) {

            // Reduce builds from all projects into a flat array
            async.reduce(builds, [], function(memo, item, pass) {
                process.nextTick(function() {
                    pass(null, memo.concat(item));
                });
            }, function(err, builds) {
                process.nextTick(function() {
                    callback(err, builds);
                });
            });
        });
    };

    self.configure = function (config) {
        self.config = config;
        if (typeof self.config.intervals === 'undefined') {
            self.config.intervals = {};
        }
        if (typeof self.config.intervals.disabled === 'undefined') {
            self.config.intervals.disabled = 12 * 60 * minute;
        }
        if (typeof self.config.intervals.empty === 'undefined') {
            self.config.intervals.empty = 10 * minute;
        }
        if (typeof self.config.intervals.default === 'undefined') {
            self.config.intervals.default = minute;
        }
        if (typeof self.config.slugs === 'undefined') {
            self.config.slugs = ['*/*'];
        }
        if (typeof process.env.GITLAB_TOKEN !== 'undefined') {
            self.config.token = process.env.GITLAB_TOKEN;
        }
        if (typeof self.config.caPath !== 'undefined') {
            request = request.defaults({
                agentOptions: {
                    ca: require('fs').readFileSync(self.config.caPath).toString().split("\n\n")
                }
            });
        }
        for (var key in self.config) {
          if (key !== 'token') {
            log(key + ':', self.config[key]);
          }
        }
    };
};
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var PointText = this.PointText = TextItem.extend({
	beans: true,

	initialize: function(point) {
		this.base();
		var point = Point.read(arguments);
		this.content = '';
		this._point = LinkedPoint.create(this, 'setPoint', point.x, point.y);
		this._matrix = new Matrix().translate(point);
	},

	clone: function() {
		var copy = this._clone(new PointText(this._point));
		copy.content = this.content;
		// Use Matrix#initialize to easily copy over values.
		copy._matrix.initialize(this._matrix);
		return copy;
	},

	getPoint: function() {
		return this._point;
	},

	setPoint: function(point) {
		this._transform(new Matrix().translate(
				Point.read(arguments).subtract(this._point)));
	},

	// TODO: position should be the center point of the bounds
	// but we currently don't support bounds for PointText.
	getPosition: function() {
		return this._point;
	},

	setPosition: function(point) {
		this.setPoint.apply(this, arguments);
	},

	_transform: function(matrix, flags) {
		this._matrix.preConcatenate(matrix);
		// We need to transform the LinkedPoint, passing true for dontNotify so
		// chaning it won't trigger calls of setPoint(), leading to an endless
		// recursion.
		matrix._transformPoint(this._point, this._point, true);
	},

	draw: function(ctx) {
		if (this.content == null)
			return;
		ctx.save();
		ctx.font = this._characterStyle.fontSize + 'pt ' +
				this._characterStyle.font;
		ctx.textAlign = this._paragraphStyle.justification;
		this._matrix.applyToContext(ctx);

		var fillColor = this.getFillColor();
		var strokeColor = this.getStrokeColor();
		if (!fillColor || !strokeColor)
			ctx.globalAlpha = this.opacity;
		if (fillColor) {
			ctx.fillStyle = fillColor.getCanvasStyle(ctx);
			ctx.fillText(this.content, 0, 0);
		}
		if (strokeColor) {
			ctx.strokeStyle = strokeColor.getCanvasStyle(ctx);
			ctx.strokeText(this.content, 0, 0);
		}
		ctx.restore();
	}
});
<commit_msg>Add PointText documentation.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var PointText = this.PointText = TextItem.extend({
	/** @lends PointText# */

	beans: true,

	/**
	 * Creates a point text item
	 *
	 * @example
	 * var text = new PointText(new Point(50, 100));
	 * text.paragraphStyle.justification = 'center';
	 * text.content = 'The contents of the point text';
	 * text.fillColor = 'black';
	 *
	 * @param {Point} point the position where the text will start
	 *
	 * @constructs PointText
	 *
	 * @class A PointText item represents a piece of typography in your Paper.js
	 * project which starts from a certain point and extends by the amount of
	 * characters contained in it.
	 *
	 * @extends TextItem
	 * @extends Item
	 */
	initialize: function(point) {
		this.base();
		var point = Point.read(arguments);
		this.content = '';
		this._point = LinkedPoint.create(this, 'setPoint', point.x, point.y);
		this._matrix = new Matrix().translate(point);
	},

	clone: function() {
		var copy = this._clone(new PointText(this._point));
		copy.content = this.content;
		// Use Matrix#initialize to easily copy over values.
		copy._matrix.initialize(this._matrix);
		return copy;
	},

	/**
	 * The PointText's anchor point
	 *
	 * @type Point
	 * @bean
	 */
	getPoint: function() {
		return this._point;
	},

	setPoint: function(point) {
		this._transform(new Matrix().translate(
				Point.read(arguments).subtract(this._point)));
	},

	// TODO: position should be the center point of the bounds
	// but we currently don't support bounds for PointText.
	getPosition: function() {
		return this._point;
	},

	setPosition: function(point) {
		this.setPoint.apply(this, arguments);
	},

	_transform: function(matrix, flags) {
		this._matrix.preConcatenate(matrix);
		// We need to transform the LinkedPoint, passing true for dontNotify so
		// chaning it won't trigger calls of setPoint(), leading to an endless
		// recursion.
		matrix._transformPoint(this._point, this._point, true);
	},

	draw: function(ctx) {
		if (this.content == null)
			return;
		ctx.save();
		ctx.font = this._characterStyle.fontSize + 'pt ' +
				this._characterStyle.font;
		ctx.textAlign = this._paragraphStyle.justification;
		this._matrix.applyToContext(ctx);

		var fillColor = this.getFillColor();
		var strokeColor = this.getStrokeColor();
		if (!fillColor || !strokeColor)
			ctx.globalAlpha = this.opacity;
		if (fillColor) {
			ctx.fillStyle = fillColor.getCanvasStyle(ctx);
			ctx.fillText(this.content, 0, 0);
		}
		if (strokeColor) {
			ctx.strokeStyle = strokeColor.getCanvasStyle(ctx);
			ctx.strokeText(this.content, 0, 0);
		}
		ctx.restore();
	}
});
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

/**
 * The ToolEvent object is received by the {@link Tool}'s mouse event handlers
 * {@link Tool#getOnMouseDown()}, {@link Tool#getOnMouseDrag()},
 * {@link Tool#getOnMouseMove()} and {@link Tool#getOnMouseUp()}. The ToolEvent
 * object is the only parameter passed to these functions and contains
 * information about the mouse event.
 *
 * Sample code:
 *
 * function onMouseUp(event) {
 * 	// the position of the mouse when it is released
 * 	print(event.point);
 * }
 *
 *
 * @author lehni
 */
var ToolEvent = this.ToolEvent = Base.extend({
	beans: true,

	initialize: function(tool, type, event) {
		this.tool = tool;
		this.type = type;
		this.event = event;
	},

	/**
	 * Convenience method to allow local overrides of point values.
	 * See application below.
	 */
	_choosePoint: function(point, toolPoint) {
		return point ? point : toolPoint ? toolPoint.clone() : null;
	},

	/**
	 * The position of the mouse in document coordinates when the event was
	 * fired.
	 *
	 * Sample code:
	 *
	 * function onMouseDrag(event) {
	 * 	// the position of the mouse when it is dragged
	 * 	print(event.point);
	 * }
	 *
	 * function onMouseUp(event) {
	 * 	// the position of the mouse when it is released
	 * 	print(event.point);
	 * }
	 *
	 */
	getPoint: function() {
		return this._choosePoint(this._point, this.tool.point);
	},

	setPoint: function(point) {
		this._point = point;
	},

	/**
	 * The position of the mouse in document coordinates when the previous
	 * event was fired.
	 */
	getLastPoint: function() {
		return this._choosePoint(this._lastPoint, this.tool.lastPoint);
	},

	setLastPoint: function(lastPoint) {
		this._lastPoint = lastPoint;
	},

	/**
	 * The position of the mouse in document coordinates when the mouse button
	 * was last clicked.
	 */
	getDownPoint: function() {
		return this._choosePoint(this._downPoint, this.tool.downPoint);
	},

	setDownPoint: function(downPoint) {
		this._downPoint = downPoint;
	},

	/**
	 * The point in the middle between {@link #getLastPoint()} and
	 * {@link #getPoint()}. This is a useful position to use when creating
	 * artwork based on the moving direction of the mouse, as returned by
	 * {@link #getDelta()}.
	 */
	getMiddlePoint: function() {
		// For explanations, see getDelta()
		if (!this._middlePoint && this.tool.lastPoint) {
			// (point + lastPoint) / 2
			return this.tool.point.add(this.tool.lastPoint).divide(2);
		}
		return this.middlePoint;
	},

	setMiddlePoint: function(middlePoint) {
		this._middlePoint = middlePoint;
	},

	/**
	 * The difference between the current position and the last position of the
	 * mouse when the event was fired. In case of the mouseup event, the
	 * difference to the mousedown position is returned.
	 */
	getDelta: function() {
		// Do not put the calculated delta into delta, since this only reserved
		// for overriding event.delta.
		// Instead, keep calculating the delta each time, so the result can be
		// directly modified by the script without changing the internal values.
		// We could cache this and use clone, but this is almost as fast...
		return this._delta && this.tool.lastPoint
		 		? this.tool.point.subtract(this.tool.lastPoint)
				: this._delta;
	},

	setDelta: function(delta) {
		this._delta = delta;
	},

	/**
	 * The number of times the mouse event was fired.
	 *
	 * Sample code:
	 *
	 * function onMouseDrag(event) {
	 * 	// the amount of times the onMouseDrag event was fired
	 * 	// since the last onMouseDown event
	 * 	print(event.count);
	 * }
	 *
	 * function onMouseUp(event) {
	 * 	// the amount of times the onMouseUp event was fired
	 * 	// since the tool was activated
	 * 	print(event.point);
	 * }
	 *
	 */
	getCount: function() {
		// Return downCount for both mouse down and up, since
		// the count is the same.
		return /^mouse(down|up)$/.test(this.type)
			? this.tool.downCount
			: this.tool.count;
	},

	setCount: function(count) {
		this.tool[/^mouse(down|up)$/.test(this.type) ? 'downCount' : 'count']
			= count;
	},

	getModifiers: function() {
		return Key.modifiers;
	},

	// TODO: implement hitTest first
	// getItem: function() {
	// 	if (this.item == null) {
	// 		var result = Document.getActiveDocument().hitTest(this.getPoint());
	// 		if (result != null) {
	// 			this.item = result.getItem();
	// 			// Find group parent
	// 			var parent = item.getParent();
	// 			while (parent instanceof Group || parent instanceof CompoundPath) {
	// 				item = parent;
	// 				parent = parent.getParent();
	// 			}
	// 		}
	// 	}
	// 	return item;
	// }
	//
	// setItem: function(Item item) {
	// 	this.item = item;
	// }

	toString: function() {
		return '{ type: ' + this.type
				+ ', point: ' + this.point
				+ ', count: ' + this.count
				+ ', modifiers: ' + this.getModifiers()
				+ ' }';
	}
});
<commit_msg>Use getters rather than beans.<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

/**
 * The ToolEvent object is received by the {@link Tool}'s mouse event handlers
 * {@link Tool#getOnMouseDown()}, {@link Tool#getOnMouseDrag()},
 * {@link Tool#getOnMouseMove()} and {@link Tool#getOnMouseUp()}. The ToolEvent
 * object is the only parameter passed to these functions and contains
 * information about the mouse event.
 *
 * Sample code:
 *
 * function onMouseUp(event) {
 * 	// the position of the mouse when it is released
 * 	print(event.point);
 * }
 *
 *
 * @author lehni
 */
var ToolEvent = this.ToolEvent = Base.extend({
	beans: true,

	initialize: function(tool, type, event) {
		this.tool = tool;
		this.type = type;
		this.event = event;
	},

	/**
	 * Convenience method to allow local overrides of point values.
	 * See application below.
	 */
	_choosePoint: function(point, toolPoint) {
		return point ? point : toolPoint ? toolPoint.clone() : null;
	},

	/**
	 * The position of the mouse in document coordinates when the event was
	 * fired.
	 *
	 * Sample code:
	 *
	 * function onMouseDrag(event) {
	 * 	// the position of the mouse when it is dragged
	 * 	print(event.point);
	 * }
	 *
	 * function onMouseUp(event) {
	 * 	// the position of the mouse when it is released
	 * 	print(event.point);
	 * }
	 *
	 */
	getPoint: function() {
		return this._choosePoint(this._point, this.tool.point);
	},

	setPoint: function(point) {
		this._point = point;
	},

	/**
	 * The position of the mouse in document coordinates when the previous
	 * event was fired.
	 */
	getLastPoint: function() {
		return this._choosePoint(this._lastPoint, this.tool.lastPoint);
	},

	setLastPoint: function(lastPoint) {
		this._lastPoint = lastPoint;
	},

	/**
	 * The position of the mouse in document coordinates when the mouse button
	 * was last clicked.
	 */
	getDownPoint: function() {
		return this._choosePoint(this._downPoint, this.tool.downPoint);
	},

	setDownPoint: function(downPoint) {
		this._downPoint = downPoint;
	},

	/**
	 * The point in the middle between {@link #getLastPoint()} and
	 * {@link #getPoint()}. This is a useful position to use when creating
	 * artwork based on the moving direction of the mouse, as returned by
	 * {@link #getDelta()}.
	 */
	getMiddlePoint: function() {
		// For explanations, see getDelta()
		if (!this._middlePoint && this.tool.lastPoint) {
			// (point + lastPoint) / 2
			return this.tool.point.add(this.tool.lastPoint).divide(2);
		}
		return this.middlePoint;
	},

	setMiddlePoint: function(middlePoint) {
		this._middlePoint = middlePoint;
	},

	/**
	 * The difference between the current position and the last position of the
	 * mouse when the event was fired. In case of the mouseup event, the
	 * difference to the mousedown position is returned.
	 */
	getDelta: function() {
		// Do not put the calculated delta into delta, since this only reserved
		// for overriding event.delta.
		// Instead, keep calculating the delta each time, so the result can be
		// directly modified by the script without changing the internal values.
		// We could cache this and use clone, but this is almost as fast...
		return this._delta && this.tool.lastPoint
		 		? this.tool.point.subtract(this.tool.lastPoint)
				: this._delta;
	},

	setDelta: function(delta) {
		this._delta = delta;
	},

	/**
	 * The number of times the mouse event was fired.
	 *
	 * Sample code:
	 *
	 * function onMouseDrag(event) {
	 * 	// the amount of times the onMouseDrag event was fired
	 * 	// since the last onMouseDown event
	 * 	print(event.count);
	 * }
	 *
	 * function onMouseUp(event) {
	 * 	// the amount of times the onMouseUp event was fired
	 * 	// since the tool was activated
	 * 	print(event.point);
	 * }
	 *
	 */
	getCount: function() {
		// Return downCount for both mouse down and up, since
		// the count is the same.
		return /^mouse(down|up)$/.test(this.type)
			? this.tool.downCount
			: this.tool.count;
	},

	setCount: function(count) {
		this.tool[/^mouse(down|up)$/.test(this.type) ? 'downCount' : 'count']
			= count;
	},

	getModifiers: function() {
		return Key.modifiers;
	},

	// TODO: implement hitTest first
	// getItem: function() {
	// 	if (this.item == null) {
	// 		var result = Document.getActiveDocument().hitTest(this.getPoint());
	// 		if (result != null) {
	// 			this.item = result.getItem();
	// 			// Find group parent
	// 			var parent = item.getParent();
	// 			while (parent instanceof Group || parent instanceof CompoundPath) {
	// 				item = parent;
	// 				parent = parent.getParent();
	// 			}
	// 		}
	// 	}
	// 	return item;
	// }
	//
	// setItem: function(Item item) {
	// 	this.item = item;
	// }

	toString: function() {
		return '{ type: ' + this.type
				+ ', point: ' + this.getPoint()
				+ ', count: ' + this.getCount()
				+ ', modifiers: ' + this.getModifiers()
				+ ' }';
	}
});
<|endoftext|>


<commit_before>// Copyright (c) Cognitect, Inc.
// All rights reserved.

"use strict";

var caching = require("./caching"),
    h       = require("./handlers"),
    t       = require("./types"),
    d       = require("./delimiters"),
    sb      = require("./stringbuilder");

var JSON_INT_MAX = Math.pow(2, 53);
var JSON_INT_MIN = -JSON_INT_MAX;

function escape(string) {
    if(string.length > 0) {
        var c = string[0];
        if(c === d.RES && string[1] === ESC) {
            return string.substring(1);
        } else if(c === d.ESC || c === d.SUB || c === d.RES) {
            return d.ESC+string;
        } else {
            return string;
        }
    }
    return null;
}

// STATES

/*
var OBJECT = 0,
    ARRAY = 1,
    OBJECT_KEY = 2,
    OBJECT_VALUE = 3,
    OBJECT_FIRST_KEY = 4,
    ARRAY_FIRST_VALUE = 5;
*/

/*
var OBJECT = "object",
    ARRAY = "array",
    OBJECT_KEY = "object_key",
    OBJECT_VALUE = "object_value",
    OBJECT_FIRST_KEY = "object_first_key",
    ARRAY_FIRST_VALUE = "array_first_value";
*/

function JSONMarshaller(stream, options) {
    this.buffer = (options && options.buffer) || sb.stringBuilder();
    this.state = t.queue();
    this.handlers = h.handlers();
    this._prefersStrings = options ? options.prefersString || false : true;
}

JSONMarshaller.prototype = {
    getState: function() {
        return this.state.peek();
    },

    pushState: function(newState) {
        var oldState = this.getState();
        this.state.push(newState);

        // ARRAY
        if(oldState === 1) {
            this.buffer.write(",");
        }

        switch(newState) {
            // ARRAY
        case 1:
            this.state.push(5); // ARRAY_FIRST_VALUE
            this.buffer.write("[");
            break;
            // OBJECT
        case 0:
            this.state.push(4); // OBJECT_FIRST_KEY
            this.buffer.write("{");
            break;
        default:
            var err = new Error("JSONMarshaller: Invalid pushState, " + state);
            err.data = {state: state};
            throw err;
            break;
        }
    },

    popState: function() {
        var state = this.state.pop();

        // while !OBJECT && !ARRAY
        while(state !== 0 && state !== 1) {
            state = this.state.pop();
        }

        switch(state) {
            // ARRAY
        case 1:
            this.buffer.write("]");
            return 1; // ARRAY
            break;
            // OBJECT
        case 0:
            this.buffer.write("}");
            return 0; // OBJECT
            break;
        default:
            var err = new Error("JSONMarshaller: Popped unknown state " + state);
            err.data = {state: state};
            throw err;
            break;
        }
    },

    pushKey: function(obj) {
        var state = this.getState();
        switch(state) {
            // OBJECT_KEY
        case 2:
            this.buffer.write(",");
            // OBJECT_FIRST_KEY
        case 4:
            this.state.pop();
            this.state.push(3); // OBJECT_VALUE
            this.buffer.write(obj);
            break;
        default:
            var err = new Error("JSONMarshaller: Cannot pushKey in state " + state);
            err.data = {state: state};
            throw err;
            break;
        }
        this.buffer.write(":");
    },

    pushValue: function(obj) {
        var state = this.getState();
        switch(state) {
            // ARRAY
        case 1:
            this.buffer.write(",");
            this.buffer.write(obj);
            break;
            // ARRAY_FIRST_VALUE
        case 5:
            this.state.pop();
            this.buffer.write(obj);
            break;
            // OBJECT_VALUE
        case 3:
            this.state.pop();
            this.buffer.write(obj);
            this.state.push(2);
            break;
        default:
            this.buffer.write(obj);
            break;
        }
    },

    handler: function(obj) {
        return this.handlers.get(h.constructor(obj));
    },

    registerHandler: function(ctor, handler) {
        this.handlers.set(ctor, handler);
    },

    writeObject: function(obj, asMapKey) {
        asMapKey = asMapKey || false;
        if(asMapKey) {
            this.pushKey(obj);
        } else {
            this.pushValue(obj);
        }
    },

    emitNil: function(asMapKey, cache) {
        if(asMapKey) {
            this.emitString(d.ESC, "_", "", asMapKey, cache);
        } else {
            this.writeObject("null", false);
        }
    },

    emitString: function(prefix, tag, s, asMapKey, cache) {
        var s = "\""+cache.write(prefix+tag+s, asMapKey)+"\"";
        if(asMapKey) {
            this.writeObject(s, asMapKey);
        } else {
            this.writeObject(s, asMapKey);
        }
    },

    emitBoolean: function(b, asMapKey, cache) {
        var s = b.toString();
        if(asMapKey) {
            this.emitString(d.ESC, "?", s[0], asMapKey, cache);
        } else {
            this.writeObject(s, false);
        }
    },

    emitInteger: function(i, asMapKey, cache) {
        if(asMapKey || (typeof i === "string") || (i > JSON_INT_MAX) || (i < JSON_INT_MIN)) {
            this.emitString(d.ESC, "i", i, asMapKey, cache);
        } else {
            this.writeObject(i);
        }
    },

    emitDouble: function(d, asMapKey, cache) {
        if(asMapKey) {
            this.emitString(d.ESC, "d", d, asMapKey, cache);
        } else {
            this.writeObject(s);
        }
    },

    emitBinary: function(b, asMapKey, cache) {
        this.emitBinary(d.ESC, "b", new Buffer(b).toString("base64"), asMapKey, cache);
    },

    emitArrayStart: function(size) {
        this.pushState(1); // ARRAY
    },

    emitArrayEnd: function() {
        var lastState = this.popState();
        if(lastState !== 1) { // ARRAY
            throw new Error("JSONMarshaller: Invalid array end");
        }
    },

    emitMapStart: function(size) {
        this.pushState(0);
    },

    emitMapEnd: function() {
        var lastState = this.popState();
        if(lastState !== 0) {
            throw new Error("JSONMarshaller: Invalid object end");
        }
    },

    emitQuoted: function(obj, cache) {
        this.emitMapStart();
        this.emitString(d.ESC, "'", "", true, cache);
        marshal(this, obj, false, cache);
        this.emitMapEnd();
    },

    flushBuffer: function(ignore) {
        this.state = t.queue();
        return this.buffer.flush();
    },

    prefersStrings: function() {
        return this._prefersStrings;
    }
};

function emitInts(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        em.emitInt(em, src[i], false, cache);
    }
}

function emitShorts(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        em.emitShort(em, src[i], false, cache);
    }
}

function emitLongs(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        em.emitLong(em, src[i], false, cache);
    }
}

function emitFloats(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        em.emitFloat(em, src[i], false, cache);
    }
}

function emitDouble(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        em.emitDouble(em, src[i], false, cache);
    }
}

function emitChars(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        marshal(em, src[i], false, cache);
    }
}

function emitBooleans(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        em.emitBoolean(em, src[i], false, cache);
    }
}

function emitObjects(em, iterable, cache) {
    if(Array.isArray(iterable)) {
        for(var i = 0; i < iterable.length; i++) {
            marshal(em, iterable[i], false, cache);
        }
    } else {
        iterable.forEach(function(v, i) {
            marshal(em, v, false, cache);
        });
    }
}

function emitArray(em, iterable, skip, cache) {
    em.emitArrayStart();
    if(iterable instanceof Int8Array) {
        emitChars(em, iterable, cache);
    } else if(iterable instanceof Int16Array) {
        emitShorts(em, iterable, cache);
    } else if(iterable instanceof Int32Array) {
        emitInts(em, iterable, cache);
    } else if(iterable instanceof Float32Array) {
        emitFloats(em, iterable, cache);
    } else if(iterable instanceof Float64Array) {
        emitDoubles(em, iterable, cache);
    } else {
        emitObjects(em, iterable, cache);
    }
    em.emitArrayEnd();
}

function emitMap(em, obj, skip, cache) {
    em.emitMapStart();
    var ks = Object.keys(obj);
    for(var i = 0; i < ks.length; i++) {
        marshal(em, ks[i], true, cache);
        marshal(em, obj[ks[i]], false, cache);
    }
    em.emitMapEnd();
}

function emitTaggedMap(em, tag, rep, skip, cache) {
    em.emitMapStart();
    em.emitString(d.ESC_TAG, tag, "", true, cache);
    marshal(em, rep, false, cache);
    em.emitMapEnd();
}

function emitEncoded(em, h, tag, obj, asMapKey, cache) {
    if(tag.length === 1) {
        var rep = h.rep(obj);
        if(typeof rep === "string") {
            em.emitString(d.ESC, tag, rep, asMapKey, cache);
        } else if(asMapKey || em.prefersStrings()) {
            rep = h.stringRep(obj);
            if(typeof rep === "string") {
                em.emitString(d.ESC, tag, rep, asMapKey, cache);
            } else {
                var err = new Error("Cannot be encoded as string");
                err.data = {tag: tag, rep: rep, obj: obj};
                throw err;
            }
        } else {
            emitTaggedMap(em, tag, rep, asMapKey, cache);
        }
    } else if (asMapKey) {
        var err = new Error("Cannot be used as map key");
        err.data = {tag: tag, rep: rep, obj: obj};
        throw err;
    } else {
        emitTaggedMap(em, tag, h.rep(obj), asMapKey, cache);
    }
}

function marshal(em, obj, asMapKey, cache) {
    var h   = em.handler(obj),
        tag = h ? h.tag(obj) : null,
        rep = h ? h.rep(obj) : null;

    if(h && tag) {
        switch(tag) {
        case "_":
            em.emitNil(asMapKey, cache);
            break;
        case "s":
            em.emitString("", "", escape(rep), asMapKey, cache);
            break;
        case "?":
            em.emitBoolean(rep, asMapKey, cache);
            break;
        case "i":
            em.emitInteger(rep, asMapKey, cache);
            break;
        case "d":
            em.emitDouble(rep, asMapKey, cache);
            break;
        case "b":
            em.emitBinary(rep, asMapKey, cache);
            break;
        case "'":
            em.emitQuoted(rep, cache);
            break;
        case "array":
            emitArray(em, rep, asMapKey, cache);
            break;
        case "map":
            emitMap(em, rep, asMapKey, cache);
            break;
        default:
            emitEncoded(em, h, tag, obj, asMapKey, cache);
            break;
        }
    } else {
        var err = new Error("Not supported");
        err.data = {obj: obj, type: h.constructor(obj).name};
        throw err;
    }
}

function maybeQuoted(em, obj) {
    var h = em.handler(obj);

    if(h != null) {
        if(h.tag(obj).length === 1) {
            return t.quoted(obj);
        } else {
            return obj;
        }
    } else {
        var err = new Error("Not supported");
        err.data = {obj: obj, type: h.constructor(obj).name};
        throw err;
    }
}

function marshalTop(em, obj, cache) {
    marshal(em, maybeQuoted(em, obj), false, cache);
}

function Writer(marshaller, stream, options) {
    this.marshaller = marshaller;
    this.stream = stream;
    this.options = options || {};
    this.cache = this.options.cache ? this.options.cache : caching.writeCache();
}

Writer.prototype = {
    write: function(obj) {
        marshalTop(this.marshaller, obj, this.cache)
        this.stream.write(this.marshaller.flushBuffer());
    },

    register: function(type, handler) {
        this.marshaller.registerHandler(type, handler);
    },

    clearCache: function() {
        this.cache = this.options.cache ? new this.options.cache.constructor() : caching.writeCache();
    }
};

function writer(out, type, opts) {
    if(type === "json") {
        var marshaller = new JSONMarshaller(opts);
        return new Writer(marshaller, out, opts);
    } else {
        var err = new Error("Type must be \"json\"");
        err.data = {type: type};
        throw err;
    }
}

module.exports = {
    writer: writer,
    marshal: marshal,
    marshalTop: marshalTop,
    emitTaggedMap: emitTaggedMap,
    JSONMarshaller: JSONMarshaller
};
<commit_msg>remove old comment, formatting<commit_after>// Copyright (c) Cognitect, Inc.
// All rights reserved.

"use strict";

var caching = require("./caching"),
    h       = require("./handlers"),
    t       = require("./types"),
    d       = require("./delimiters"),
    sb      = require("./stringbuilder");

var JSON_INT_MAX = Math.pow(2, 53);
var JSON_INT_MIN = -JSON_INT_MAX;

function escape(string) {
    if(string.length > 0) {
        var c = string[0];
        if(c === d.RES && string[1] === ESC) {
            return string.substring(1);
        } else if(c === d.ESC || c === d.SUB || c === d.RES) {
            return d.ESC+string;
        } else {
            return string;
        }
    }
    return null;
}

// STATES

/*
var OBJECT = 0,
    ARRAY = 1,
    OBJECT_KEY = 2,
    OBJECT_VALUE = 3,
    OBJECT_FIRST_KEY = 4,
    ARRAY_FIRST_VALUE = 5;
*/

function JSONMarshaller(stream, options) {
    this.buffer = (options && options.buffer) || sb.stringBuilder();
    this.state = t.queue();
    this.handlers = h.handlers();
    this._prefersStrings = options ? options.prefersString || false : true;
}

JSONMarshaller.prototype = {
    getState: function() {
        return this.state.peek();
    },

    pushState: function(newState) {
        var oldState = this.getState();
        this.state.push(newState);

        // ARRAY
        if(oldState === 1) {
            this.buffer.write(",");
        }

        switch(newState) {
        // ARRAY
        case 1:
            this.state.push(5); // ARRAY_FIRST_VALUE
            this.buffer.write("[");
            break;
        // OBJECT
        case 0:
            this.state.push(4); // OBJECT_FIRST_KEY
            this.buffer.write("{");
            break;
        default:
            var err = new Error("JSONMarshaller: Invalid pushState, " + state);
            err.data = {state: state};
            throw err;
            break;
        }
    },

    popState: function() {
        var state = this.state.pop();

        // while !OBJECT && !ARRAY
        while(state !== 0 && state !== 1) {
            state = this.state.pop();
        }

        switch(state) {
        // ARRAY
        case 1:
            this.buffer.write("]");
            return 1; // ARRAY
            break;
        // OBJECT
        case 0:
            this.buffer.write("}");
            return 0; // OBJECT
            break;
        default:
            var err = new Error("JSONMarshaller: Popped unknown state " + state);
            err.data = {state: state};
            throw err;
            break;
        }
    },

    pushKey: function(obj) {
        var state = this.getState();
        switch(state) {
        // OBJECT_KEY
        case 2:
            this.buffer.write(",");
        // OBJECT_FIRST_KEY
        case 4:
            this.state.pop();
            this.state.push(3); // OBJECT_VALUE
            this.buffer.write(obj);
            break;
        default:
            var err = new Error("JSONMarshaller: Cannot pushKey in state " + state);
            err.data = {state: state};
            throw err;
            break;
        }
        this.buffer.write(":");
    },

    pushValue: function(obj) {
        var state = this.getState();
        switch(state) {
        // ARRAY
        case 1:
            this.buffer.write(",");
            this.buffer.write(obj);
            break;
        // ARRAY_FIRST_VALUE
        case 5:
            this.state.pop();
            this.buffer.write(obj);
            break;
        // OBJECT_VALUE
        case 3:
            this.state.pop();
            this.buffer.write(obj);
            this.state.push(2);
            break;
        default:
            this.buffer.write(obj);
            break;
        }
    },

    handler: function(obj) {
        return this.handlers.get(h.constructor(obj));
    },

    registerHandler: function(ctor, handler) {
        this.handlers.set(ctor, handler);
    },

    writeObject: function(obj, asMapKey) {
        asMapKey = asMapKey || false;
        if(asMapKey) {
            this.pushKey(obj);
        } else {
            this.pushValue(obj);
        }
    },

    emitNil: function(asMapKey, cache) {
        if(asMapKey) {
            this.emitString(d.ESC, "_", "", asMapKey, cache);
        } else {
            this.writeObject("null", false);
        }
    },

    emitString: function(prefix, tag, s, asMapKey, cache) {
        var s = "\""+cache.write(prefix+tag+s, asMapKey)+"\"";
        if(asMapKey) {
            this.writeObject(s, asMapKey);
        } else {
            this.writeObject(s, asMapKey);
        }
    },

    emitBoolean: function(b, asMapKey, cache) {
        var s = b.toString();
        if(asMapKey) {
            this.emitString(d.ESC, "?", s[0], asMapKey, cache);
        } else {
            this.writeObject(s, false);
        }
    },

    emitInteger: function(i, asMapKey, cache) {
        if(asMapKey || (typeof i === "string") || (i > JSON_INT_MAX) || (i < JSON_INT_MIN)) {
            this.emitString(d.ESC, "i", i, asMapKey, cache);
        } else {
            this.writeObject(i);
        }
    },

    emitDouble: function(d, asMapKey, cache) {
        if(asMapKey) {
            this.emitString(d.ESC, "d", d, asMapKey, cache);
        } else {
            this.writeObject(s);
        }
    },

    emitBinary: function(b, asMapKey, cache) {
        this.emitBinary(d.ESC, "b", new Buffer(b).toString("base64"), asMapKey, cache);
    },

    emitArrayStart: function(size) {
        this.pushState(1); // ARRAY
    },

    emitArrayEnd: function() {
        var lastState = this.popState();
        if(lastState !== 1) { // ARRAY
            throw new Error("JSONMarshaller: Invalid array end");
        }
    },

    emitMapStart: function(size) {
        this.pushState(0);
    },

    emitMapEnd: function() {
        var lastState = this.popState();
        if(lastState !== 0) {
            throw new Error("JSONMarshaller: Invalid object end");
        }
    },

    emitQuoted: function(obj, cache) {
        this.emitMapStart();
        this.emitString(d.ESC, "'", "", true, cache);
        marshal(this, obj, false, cache);
        this.emitMapEnd();
    },

    flushBuffer: function(ignore) {
        this.state = t.queue();
        return this.buffer.flush();
    },

    prefersStrings: function() {
        return this._prefersStrings;
    }
};

function emitInts(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        em.emitInt(em, src[i], false, cache);
    }
}

function emitShorts(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        em.emitShort(em, src[i], false, cache);
    }
}

function emitLongs(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        em.emitLong(em, src[i], false, cache);
    }
}

function emitFloats(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        em.emitFloat(em, src[i], false, cache);
    }
}

function emitDouble(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        em.emitDouble(em, src[i], false, cache);
    }
}

function emitChars(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        marshal(em, src[i], false, cache);
    }
}

function emitBooleans(em, src, cache) {
    for(var i = 0; i < src.length; i++) {
        em.emitBoolean(em, src[i], false, cache);
    }
}

function emitObjects(em, iterable, cache) {
    if(Array.isArray(iterable)) {
        for(var i = 0; i < iterable.length; i++) {
            marshal(em, iterable[i], false, cache);
        }
    } else {
        iterable.forEach(function(v, i) {
            marshal(em, v, false, cache);
        });
    }
}

function emitArray(em, iterable, skip, cache) {
    em.emitArrayStart();
    if(iterable instanceof Int8Array) {
        emitChars(em, iterable, cache);
    } else if(iterable instanceof Int16Array) {
        emitShorts(em, iterable, cache);
    } else if(iterable instanceof Int32Array) {
        emitInts(em, iterable, cache);
    } else if(iterable instanceof Float32Array) {
        emitFloats(em, iterable, cache);
    } else if(iterable instanceof Float64Array) {
        emitDoubles(em, iterable, cache);
    } else {
        emitObjects(em, iterable, cache);
    }
    em.emitArrayEnd();
}

function emitMap(em, obj, skip, cache) {
    em.emitMapStart();
    var ks = Object.keys(obj);
    for(var i = 0; i < ks.length; i++) {
        marshal(em, ks[i], true, cache);
        marshal(em, obj[ks[i]], false, cache);
    }
    em.emitMapEnd();
}

function emitTaggedMap(em, tag, rep, skip, cache) {
    em.emitMapStart();
    em.emitString(d.ESC_TAG, tag, "", true, cache);
    marshal(em, rep, false, cache);
    em.emitMapEnd();
}

function emitEncoded(em, h, tag, obj, asMapKey, cache) {
    if(tag.length === 1) {
        var rep = h.rep(obj);
        if(typeof rep === "string") {
            em.emitString(d.ESC, tag, rep, asMapKey, cache);
        } else if(asMapKey || em.prefersStrings()) {
            rep = h.stringRep(obj);
            if(typeof rep === "string") {
                em.emitString(d.ESC, tag, rep, asMapKey, cache);
            } else {
                var err = new Error("Cannot be encoded as string");
                err.data = {tag: tag, rep: rep, obj: obj};
                throw err;
            }
        } else {
            emitTaggedMap(em, tag, rep, asMapKey, cache);
        }
    } else if (asMapKey) {
        var err = new Error("Cannot be used as map key");
        err.data = {tag: tag, rep: rep, obj: obj};
        throw err;
    } else {
        emitTaggedMap(em, tag, h.rep(obj), asMapKey, cache);
    }
}

function marshal(em, obj, asMapKey, cache) {
    var h   = em.handler(obj),
        tag = h ? h.tag(obj) : null,
        rep = h ? h.rep(obj) : null;

    if(h && tag) {
        switch(tag) {
        case "_":
            em.emitNil(asMapKey, cache);
            break;
        case "s":
            em.emitString("", "", escape(rep), asMapKey, cache);
            break;
        case "?":
            em.emitBoolean(rep, asMapKey, cache);
            break;
        case "i":
            em.emitInteger(rep, asMapKey, cache);
            break;
        case "d":
            em.emitDouble(rep, asMapKey, cache);
            break;
        case "b":
            em.emitBinary(rep, asMapKey, cache);
            break;
        case "'":
            em.emitQuoted(rep, cache);
            break;
        case "array":
            emitArray(em, rep, asMapKey, cache);
            break;
        case "map":
            emitMap(em, rep, asMapKey, cache);
            break;
        default:
            emitEncoded(em, h, tag, obj, asMapKey, cache);
            break;
        }
    } else {
        var err = new Error("Not supported");
        err.data = {obj: obj, type: h.constructor(obj).name};
        throw err;
    }
}

function maybeQuoted(em, obj) {
    var h = em.handler(obj);

    if(h != null) {
        if(h.tag(obj).length === 1) {
            return t.quoted(obj);
        } else {
            return obj;
        }
    } else {
        var err = new Error("Not supported");
        err.data = {obj: obj, type: h.constructor(obj).name};
        throw err;
    }
}

function marshalTop(em, obj, cache) {
    marshal(em, maybeQuoted(em, obj), false, cache);
}

function Writer(marshaller, stream, options) {
    this.marshaller = marshaller;
    this.stream = stream;
    this.options = options || {};
    this.cache = this.options.cache ? this.options.cache : caching.writeCache();
}

Writer.prototype = {
    write: function(obj) {
        marshalTop(this.marshaller, obj, this.cache)
        this.stream.write(this.marshaller.flushBuffer());
    },

    register: function(type, handler) {
        this.marshaller.registerHandler(type, handler);
    },

    clearCache: function() {
        this.cache = this.options.cache ? new this.options.cache.constructor() : caching.writeCache();
    }
};

function writer(out, type, opts) {
    if(type === "json") {
        var marshaller = new JSONMarshaller(opts);
        return new Writer(marshaller, out, opts);
    } else {
        var err = new Error("Type must be \"json\"");
        err.data = {type: type};
        throw err;
    }
}

module.exports = {
    writer: writer,
    marshal: marshal,
    marshalTop: marshalTop,
    emitTaggedMap: emitTaggedMap,
    JSONMarshaller: JSONMarshaller
};
<|endoftext|>


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

  function sequoiaTreeDirective(Tree, BUTTONS, DEFAULT_OPTIONS){

    return {
      restrict: 'AE',
      replace: true,
      templateUrl: 'angular-sequoia.html',
      scope: {
        'treeNodes': '=sequoiaTree',
        'model': '=ngModel',
        'template': '=nodeTemplate',
        'options': '='
      },
      link: function(scope) {
        function init() {
          /* Set the default options*/
          scope.options = _.defaults(scope.options || {}, DEFAULT_OPTIONS);
          scope.canEdit = scope.options.canEdit;
          scope.inline = scope.options.inline;
          scope.allowSelect = scope.options.allowSelect;
          scope.isMultiSelect = scope.options.limit === 1 ? false : true;
          scope.model = scope.isMultiSelect ? _.isArray(scope.model) ? scope.model : [] : _.isString(scope.model) ? scope.model : '';
          scope.breadcrumbs = [];
          scope.tree = new Tree(angular.copy(scope.treeNodes), scope.template);
          scope.buttons = {
            edit: scope.options.buttons.edit ? scope.options.buttons.edit : BUTTONS.edit,
            select: scope.options.buttons.select ? scope.options.buttons.select : BUTTONS.select,
            deselect: scope.options.buttons.deselect ? scope.options.buttons.deselect : BUTTONS.deselect,
            goToSubitems: scope.options.buttons.goToSubitems ? scope.options.buttons.goToSubitems : BUTTONS.goToSubitems,
            addSubitems: scope.options.buttons.addSubitems ? scope.options.buttons.addSubitems : BUTTONS.addSubitems,
            addNode: scope.options.buttons.addNode ? scope.options.buttons.addNode : BUTTONS.addNode,
            remove: scope.options.buttons.remove ? scope.options.buttons.remove : BUTTONS.remove,
            done: scope.options.buttons.done ? scope.options.buttons.done : BUTTONS.done,
            search: scope.options.buttons.search ? scope.options.buttons.search : BUTTONS.search,
            searchClear: scope.options.buttons.searchClear ? scope.options.buttons.searchClear : BUTTONS.searchClear,
            showSelected: scope.options.buttons.showSelected ? scope.options.buttons.showSelected : BUTTONS.showSelected,
            hideSelected: scope.options.buttons.hideSelected ? scope.options.buttons.hideSelected : BUTTONS.hideSelected,
            backToList: scope.options.buttons.backToList ? scope.options.buttons.backToList : BUTTONS.backToList,
            move: scope.options.buttons.move ? scope.options.buttons.move : BUTTONS.move,
            modalSelect: scope.options.buttons.modalSelect ? scope.options.buttons.modalSelect : BUTTONS.modalSelect
          };
        }

        scope.load = function(node) {
          scope.onlySelected = false;
          if(scope.tree.isValidNode(node)) {
            scope.tree.setCurrentNodes(node[scope.tree.template.nodes]);
            scope.breadcrumbs = scope.tree.breadcrumbs(node[scope.tree.template.id]);
          } else {
            scope.tree.setCurrentNodes();
            scope.breadcrumbs = [];
          }
        };

        scope.select = function(node) {
          if(node[scope.tree.template.id]) {
            if(scope.options.limit !== 0 && scope.model.length === scope.options.limit) {
              scope.notification = 'You cannot select more than ' + scope.options.limit + ' items!';
            } else {
              if(scope.isMultiSelect) {
                scope.model.push(node[scope.tree.template.id]);
              } else {
                scope.model = node[scope.tree.template.id];
              }
            }
          }
        };

        scope.deselect = function(node) {
          if(scope.isMultiSelect) {
            var index = node[scope.tree.template.id] ? _.indexOf(scope.model,node[scope.tree.template.id]) : -1;
            if(index !== -1) {
              scope.model.splice(index, 1);
            }
          } else {
            scope.model = '';
          }

        };

        scope.isSelected = function(node) {
          return scope.isMultiSelect ? _.indexOf(scope.model, node[scope.tree.template.id]) !== -1 ? true : false : scope.model === node[scope.tree.template.id];
        };

        scope.toggleSelected = function() {
          if(scope.onlySelected) {
            scope.onlySelected = false;
            scope.tree.setCurrentNodes(scope.tree.getNodesInPath());
          } else {
            scope.onlySelected = true;
            var selected = scope.tree.findSelected(scope.model);
            scope.tree.setNodesInPath(scope.tree.nodes);
            scope.tree.setCurrentNodes(selected);
          }
        };

        init();

        scope.$watch('treeNodes', function(newVal) {
          if(newVal) {
            scope.tree = new Tree(angular.copy(scope.treeNodes), scope.template);
            scope.load();
          }
        }, true);

        if(!scope.inline) {
          scope.load();
        }

        /* Handle Modal */
        scope.showModal = function() {
          scope.load();
          scope.modalShown = true;
        };

        scope.closeModal = function() {
          scope.modalShown = false;
        };

        /* Handle adding and editing nodes */
        scope.toggleEditing = function(form) {
          //handle form validation
          if(scope.isEditing) {
            form.isSubmitted = true;
          }
          if(form && !form.$valid) {
            return;
          }

          scope.treeNodes = angular.copy(scope.tree.tree);

          scope.isEditing = !scope.isEditing;
        };

        scope.addNode = function(node) {
          if(scope.tree.isValidNode(node)) {
            scope.load(node);
          }

          scope.tree.nodes.push(scope.tree.newNode());
          scope.isEditing = true;
        };

        scope.remove = function(node) {
          var index = node ? _.indexOf(scope.tree.nodes, node) : -1;
          if(index !== -1) {
            scope.tree.nodes.splice(index, 1);
          }
        };

        scope.closeNotification = function() {
          scope.notification = '';
        };
      }
    };

  }

  sequoiaTreeDirective.$inject = ['SequoiaTree', 'BUTTONS', 'DEFAULT_OPTIONS'];

  angular.module('ngSequoia')
    .directive('sequoiaTree', sequoiaTreeDirective);

})();<commit_msg>Replace default buttons with lodash _.defaults to extend<commit_after>(function() {
  'use strict';

  function sequoiaTreeDirective(Tree, BUTTONS, DEFAULT_OPTIONS){

    return {
      restrict: 'AE',
      replace: true,
      templateUrl: 'angular-sequoia.html',
      scope: {
        'treeNodes': '=sequoiaTree',
        'model': '=ngModel',
        'template': '=nodeTemplate',
        'options': '='
      },
      link: function(scope) {
        function init() {
          /* Set the default options*/
          scope.options = _.defaults(scope.options || {}, DEFAULT_OPTIONS);
          scope.canEdit = scope.options.canEdit;
          scope.inline = scope.options.inline;
          scope.allowSelect = scope.options.allowSelect;
          scope.isMultiSelect = scope.options.limit === 1 ? false : true;
          scope.model = scope.isMultiSelect ? _.isArray(scope.model) ? scope.model : [] : _.isString(scope.model) ? scope.model : '';
          scope.breadcrumbs = [];
          scope.tree = new Tree(angular.copy(scope.treeNodes), scope.template);
          scope.buttons = _.defaults(scope.options.buttons, BUTTONS);
        }

        scope.load = function(node) {
          scope.onlySelected = false;
          if(scope.tree.isValidNode(node)) {
            scope.tree.setCurrentNodes(node[scope.tree.template.nodes]);
            scope.breadcrumbs = scope.tree.breadcrumbs(node[scope.tree.template.id]);
          } else {
            scope.tree.setCurrentNodes();
            scope.breadcrumbs = [];
          }
        };

        scope.select = function(node) {
          if(node[scope.tree.template.id]) {
            if(scope.options.limit !== 0 && scope.model.length === scope.options.limit) {
              scope.notification = 'You cannot select more than ' + scope.options.limit + ' items!';
            } else {
              if(scope.isMultiSelect) {
                scope.model.push(node[scope.tree.template.id]);
              } else {
                scope.model = node[scope.tree.template.id];
              }
            }
          }
        };

        scope.deselect = function(node) {
          if(scope.isMultiSelect) {
            var index = node[scope.tree.template.id] ? _.indexOf(scope.model,node[scope.tree.template.id]) : -1;
            if(index !== -1) {
              scope.model.splice(index, 1);
            }
          } else {
            scope.model = '';
          }

        };

        scope.isSelected = function(node) {
          return scope.isMultiSelect ? _.indexOf(scope.model, node[scope.tree.template.id]) !== -1 ? true : false : scope.model === node[scope.tree.template.id];
        };

        scope.toggleSelected = function() {
          if(scope.onlySelected) {
            scope.onlySelected = false;
            scope.tree.setCurrentNodes(scope.tree.getNodesInPath());
          } else {
            scope.onlySelected = true;
            var selected = scope.tree.findSelected(scope.model);
            scope.tree.setNodesInPath(scope.tree.nodes);
            scope.tree.setCurrentNodes(selected);
          }
        };

        init();

        scope.$watch('treeNodes', function(newVal) {
          if(newVal) {
            scope.tree = new Tree(angular.copy(scope.treeNodes), scope.template);
            scope.load();
          }
        }, true);

        if(!scope.inline) {
          scope.load();
        }

        /* Handle Modal */
        scope.showModal = function() {
          scope.load();
          scope.modalShown = true;
        };

        scope.closeModal = function() {
          scope.modalShown = false;
        };

        /* Handle adding and editing nodes */
        scope.toggleEditing = function(form) {
          //handle form validation
          if(scope.isEditing) {
            form.isSubmitted = true;
          }
          if(form && !form.$valid) {
            return;
          }

          scope.treeNodes = angular.copy(scope.tree.tree);

          scope.isEditing = !scope.isEditing;
        };

        scope.addNode = function(node) {
          if(scope.tree.isValidNode(node)) {
            scope.load(node);
          }

          scope.tree.nodes.push(scope.tree.newNode());
          scope.isEditing = true;
        };

        scope.remove = function(node) {
          var index = node ? _.indexOf(scope.tree.nodes, node) : -1;
          if(index !== -1) {
            scope.tree.nodes.splice(index, 1);
          }
        };

        scope.closeNotification = function() {
          scope.notification = '';
        };
      }
    };

  }

  sequoiaTreeDirective.$inject = ['SequoiaTree', 'BUTTONS', 'DEFAULT_OPTIONS'];

  angular.module('ngSequoia')
    .directive('sequoiaTree', sequoiaTreeDirective);

})();<|endoftext|>


<commit_before>var K=function(){var e=navigator.userAgent;return{ie:e.match(/MSIE\s([^;]*)/)}}();var Tweetlight={init:function(e){this.url="./tweets.php?username="+e.username+"&count="+e.count+"&api=statuses_userTimeline",this.fetch()},xhr:function(){var e=new XMLHttpRequest;return e},getJSON:function(e,t){var n=this.xhr();e.url=e.url||location.href;e.data=e.data||null;t=t||function(){};n.open("GET",e.url,true);n.send(e.data);n.onreadystatechange=function(){if(n.status==200&&n.readyState==4){t(n.responseText)}}},fetch:function(){var e=this;e.getJSON({url:this.url},function(t){var n=JSON.parse(t);var r=document.getElementById("tweets"),i="";for(var s in n){i+='
'+e.twitterLinks(n[s].text)+' '+e.prettyDate(n[s].created)+"
"}r.innerHTML=i})},prettyDate:function(e){var t=new Date;var n=new Date(e);if(K.ie){n=Date.parse(e.replace(/( \+)/," UTC$1"))}var r=t-n;var i=1e3,s=i*60,o=s*60,u=o*24,a=u*7;if(isNaN(r)||r<0){return""}if(r<i*7){return"just now"}if(r<s){return Math.floor(r/i)+" seconds ago"}if(r<s*2){return"1 minute ago"}if(r<o){return Math.floor(r/s)+" minutes ago"}if(r<o*2){return"1 hour ago"}if(ru&&r<u*2){return"yesterday"}if(r<u*365){return Math.floor(r/u)+" days ago"}else{return"over a year ago"}},twitterLinks:function(e){e=e.replace(/(https?:\/\/)([\w\-:;?&=+.%#\/]+)/gi,'$2').replace(/(^|\W)@(\w+)/g,'$1@$2').replace(/(^|\W)#(\w+)/g,'$1#$2');return e}}<commit_msg>Update minified version<commit_after>var K=function(){var e=navigator.userAgent;return{ie:e.match(/MSIE\s([^;]*)/)}}();var Tweetlight={init:function(e){this.url="./tweets.php?username="+e.username+"&count="+e.count+"&api=statuses_userTimeline";this.container=e.container;this.fetch()},xhr:function(){var e=new XMLHttpRequest;return e},getJSON:function(e,t){var n=this.xhr();e.url=e.url||location.href;e.data=e.data||null;t=t||function(){};n.open("GET",e.url,true);n.send(e.data);n.onreadystatechange=function(){if(n.status==200&&n.readyState==4){t(n.responseText)}}},fetch:function(){var e=this;e.getJSON({url:this.url},function(t){var n=JSON.parse(t);var r=document.querySelector(e.container),i="";for(var s in n){i+='
'+e.twitterLinks(n[s].text)+' '+e.prettyDate(n[s].created)+"
"}r.innerHTML=i})},prettyDate:function(e){var t=new Date;var n=new Date(e);if(K.ie){n=Date.parse(e.replace(/( \+)/," UTC$1"))}var r=t-n;var i=1e3,s=i*60,o=s*60,u=o*24,a=u*7;if(isNaN(r)||r<0){return""}if(r<i*7){return"just now"}if(r<s){return Math.floor(r/i)+" seconds ago"}if(r<s*2){return"1 minute ago"}if(r<o){return Math.floor(r/s)+" minutes ago"}if(r<o*2){return"1 hour ago"}if(ru&&r<u*2){return"yesterday"}if(r<u*365){return Math.floor(r/u)+" days ago"}else{return"over a year ago"}},twitterLinks:function(e){e=e.replace(/(https?:\/\/)([\w\-:;?&=+.%#\/]+)/gi,'$2').replace(/(^|\W)@(\w+)/g,'$1@$2').replace(/(^|\W)#(\w+)/g,'$1#$2');return e}}<|endoftext|>


<commit_before>import _ from 'lodash'

import Uncolored from '../definitions/uncolored'
import ColorValue from '../colorvalue'
import { NotImplemented } from '../errors'

/**
 * @class OperationalTx
 */
export default class OperationalTx {
  /**
   * @constructor
   */
  constructor () {
    this._targets = []
  }

  /**
   * @param {ColorTarget} ctarget
   */
  addTarget (target) {
    this._targets.push(target)
  }

  /**
   * @param {ColorTarget[]} targets
   */
  addTargets (targets) {
    for (let target of targets) {
      this.addTarget(target)
    }
  }

  /**
   * @return {ColorTarget[]}
   */
  getTargets () {
    return this._targets
  }

  /**
   * @return {boolean}
   */
  isMonoColor () {
    let cids = _.invoke(this._targets, 'getColorId')
    return _.uniq(cids).length <= 1
  }

  /**
   * @callback OperationalTx~FeeEstimatorEstimateRequiredFee
   * @param {Object} extra
   * @param {number} [extra.inputs]
   * @param {number} [extra.outputs]
   * @param {number} [extra.bytes]
   * @return {number}
   */

  /**
   * @typedef {Object} OperationalTx~FeeEstimator
   * @property {OperationalTx~FeeEstimatorEstimateRequiredFee} estimateRequiredFee
   */

  /**
   * @typedef {Object} OperationalTx~AbstractRawCoin
   * @property {string} txId
   * @property {number} outIndex
   * @property {number} value
   * @property {string} script
   */

  /**
   * @callback OperationalTx~AbstractCoinToRawCoin
   * @return {OperationalTx~AbstractRawCoin}
   */

  /**
   * @typedef {Object} OperationalTx~AbstractCoin
   * @property {OperationalTx~AbstractCoinToRawCoin} toRawCoin
   */

  /**
   * @typedef OperationalTx~selectCoinsResult
   * @property {OperationalTx~AbstractCoin[]} coins
   * @property {ColorValue} total
   */

  /**
   * Return of object that have
   *  coins -- an array of utxo objects with same color that given color value
   *  total -- sum of coins that at least equal of given color value
   * For uncolored coins sum of values of UTXO objects must also include
   *  a fee (usually it is ComposedTx)
   *
   * @abstract
   * @param {ColorValue} cvalue
   * @param {OperationalTx~FeeEstimator} [feeEstimator]
   * @return {Promise<OperationalTx~selectCoinsResult>}
   */
  async selectCoins () {
    throw new NotImplemented(this.constructor.name + '.selectCoins')
  }

  /**
   * Returns an address which can be used as a change for given color definition
   *
   * @abstract
   * @param {IColorDefinition} cdef
   * @return {Promise<string>}
   */
  async getChangeAddress () {
    throw new NotImplemented(this.constructor.name + '.getChangeAddress')
  }

  /**
   * Returns ColorValue representing the fee for a certain tx size
   *
   * @param {number} txSize Transaction size in bytes
   * @param {number} [feePerKb=10000] Satoshis-per-kilobyte
   * @return {ColorValue}
   */
  getRequiredFee (txSize, feePerKb) {
    // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/main.cpp#L53
    if (feePerKb === undefined) {
      feePerKb = 10000
    }

    let uncolored = new Uncolored()
    let feeValue = Math.ceil(txSize * feePerKb / 1000)

    return new ColorValue(uncolored, feeValue)
  }

  /**
   * Returns ColorValue representing smallest satoshi value
   *  which isn't dust according to current parameters
   *
   * @return {ColorValue}
   */
  getDustThreshold () {
    // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/core.h#L151-L162
    let uncolored = new Uncolored()
    return new ColorValue(uncolored, 546)
  }

  /**
   * @return {ComposedTx}
   */
  makeComposedTx () {
    let ComposedTx = require('./composed')
    return new ComposedTx(this)
  }
}
<commit_msg>add minRelayTxFee to getDustThreshold<commit_after>import _ from 'lodash'

import Uncolored from '../definitions/uncolored'
import ColorValue from '../colorvalue'
import { NotImplemented } from '../errors'

/**
 * @class OperationalTx
 */
export default class OperationalTx {
  /**
   * @constructor
   */
  constructor () {
    this._targets = []
  }

  /**
   * @param {ColorTarget} ctarget
   */
  addTarget (target) {
    this._targets.push(target)
  }

  /**
   * @param {ColorTarget[]} targets
   */
  addTargets (targets) {
    for (let target of targets) {
      this.addTarget(target)
    }
  }

  /**
   * @return {ColorTarget[]}
   */
  getTargets () {
    return this._targets
  }

  /**
   * @return {boolean}
   */
  isMonoColor () {
    let cids = _.invoke(this._targets, 'getColorId')
    return _.uniq(cids).length <= 1
  }

  /**
   * @callback OperationalTx~FeeEstimatorEstimateRequiredFee
   * @param {Object} extra
   * @param {number} [extra.inputs]
   * @param {number} [extra.outputs]
   * @param {number} [extra.bytes]
   * @return {number}
   */

  /**
   * @typedef {Object} OperationalTx~FeeEstimator
   * @property {OperationalTx~FeeEstimatorEstimateRequiredFee} estimateRequiredFee
   */

  /**
   * @typedef {Object} OperationalTx~AbstractRawCoin
   * @property {string} txId
   * @property {number} outIndex
   * @property {number} value
   * @property {string} script
   */

  /**
   * @callback OperationalTx~AbstractCoinToRawCoin
   * @return {OperationalTx~AbstractRawCoin}
   */

  /**
   * @typedef {Object} OperationalTx~AbstractCoin
   * @property {OperationalTx~AbstractCoinToRawCoin} toRawCoin
   */

  /**
   * @typedef OperationalTx~selectCoinsResult
   * @property {OperationalTx~AbstractCoin[]} coins
   * @property {ColorValue} total
   */

  /**
   * Return of object that have
   *  coins -- an array of utxo objects with same color that given color value
   *  total -- sum of coins that at least equal of given color value
   * For uncolored coins sum of values of UTXO objects must also include
   *  a fee (usually it is ComposedTx)
   *
   * @abstract
   * @param {ColorValue} cvalue
   * @param {OperationalTx~FeeEstimator} [feeEstimator]
   * @return {Promise<OperationalTx~selectCoinsResult>}
   */
  async selectCoins () {
    throw new NotImplemented(this.constructor.name + '.selectCoins')
  }

  /**
   * Returns an address which can be used as a change for given color definition
   *
   * @abstract
   * @param {IColorDefinition} cdef
   * @return {Promise<string>}
   */
  async getChangeAddress () {
    throw new NotImplemented(this.constructor.name + '.getChangeAddress')
  }

  /**
   * Returns ColorValue representing the fee for a certain tx size
   *
   * @param {number} txSize Transaction size in bytes
   * @param {number} [feePerKb=10000] Satoshis-per-kilobyte
   * @return {ColorValue}
   */
  getRequiredFee (txSize, feePerKb) {
    // https://github.com/bitcoin/bitcoin/blob/v0.9.2/src/main.cpp#L53
    if (feePerKb === undefined) {
      feePerKb = 10000
    }

    let uncolored = new Uncolored()
    let feeValue = Math.ceil(txSize * feePerKb / 1000)

    return new ColorValue(uncolored, feeValue)
  }

  /**
   * Returns ColorValue representing smallest satoshi value
   *  which isn't dust according to current parameters
   *
   * @param {number} [minRelayTxFee=5000] Satoshis-per-kilobyte
   * @return {ColorValue}
   */
  getDustThreshold (minRelayTxFee) {
    // https://github.com/bitcoin/bitcoin/pull/6793
    if (minRelayTxFee === undefined) {
      minRelayTxFee = 5000
    }

    let uncolored = new Uncolored()
    return new ColorValue(uncolored, Math.ceil(182 * 3 * minRelayTxFee / 1000))
  }

  /**
   * @return {ComposedTx}
   */
  makeComposedTx () {
    let ComposedTx = require('./composed')
    return new ComposedTx(this)
  }
}
<|endoftext|>


<commit_before>// Resolvers
import { TodoList } from "/imports/models/TodoList.js";
import { pubsub } from "/server/pubsub";

export const resolvers = {
    Query: {
        todoList(root, args) {
            return TodoList.find().fetch();
        }
    },
    Mutation: {
        removeTodo(root, args, context) {
            let toRemove = TodoList.findOne({ _id: args._id });
            let result = toRemove.remove();
            if (result) {
                return args;
            }
        },
        createTodo(root, args, context) {
            let todo = new TodoList(args);
            let _id = todo.save({
                simulation: false // Insert only on the server
            });
            pubsub.publish("todoAdded", { todoAdded: { _id: _id } });
            if (_id) {
                return { _id: _id };
            }
        },
        updateTodo(root, args, context) {
            let result = TodoList.update(
                {
                    _id: args._id
                },
                {
                    task: args.task,
                    completed: args.completed
                }
            );
            if (result) {
                return args;
            }
        }
    },
    Subscription: {
        todoList: {
            resolve: (data, args, context, info) => {
                // Manipulate and return the new value
                //console.log("got to todoList resolver");
                //console.log(data);
                //console.log(args);
                //console.log(context);
                //console.log(info);
                return data;
            },
            subscribe: () => pubsub.asyncIterator("todoList")
        }
    }
};
<commit_msg>Minor resolver update for test server<commit_after>// Resolvers
import { TodoList } from "/imports/models/TodoList.js";
import { pubsub } from "/server/pubsub";

export const resolvers = {
    Query: {
        todoList(root, args) {
            return TodoList.find().fetch();
        }
    },
    Mutation: {
        removeTodo(root, args, context) {
            let toRemove = TodoList.findOne({ _id: args._id });
            let result = toRemove.remove();
            if (result) {
                return args;
            }
        },
        createTodo(root, args, context) {
            let todo = new TodoList(args);
            let _id = todo.save({
                simulation: false // Insert only on the server
            });
            let result = Object.assign({_id: _id}, args);
            pubsub.publish("todoAdded", { todoAdded: result });
            return result;
        },
        updateTodo(root, args, context) {
            let result = TodoList.update(
                {
                    _id: args._id
                },
                {
                    task: args.task,
                    completed: args.completed
                }
            );
            if (result) {
                return args;
            }
        }
    },
    Subscription: {
        todoList: {
            resolve: (data, args, context, info) => {
                // Manipulate and return the new value
                //console.log("got to todoList resolver");
                //console.log(data);
                //console.log(args);
                //console.log(context);
                //console.log(info);
                return data;
            },
            subscribe: () => pubsub.asyncIterator("todoList")
        }
    }
};
<|endoftext|>