<commit_before>/**
 * Module that controls the addon node settings. Includes Knockout view-model
 * for syncing data, and HGrid-folderpicker for selecting a folder.
 */
'use strict';

var ko = require('knockout');
require('knockout.punches');
var $ = require('jquery');
var Raven = require('raven-js');
var bootbox = require('bootbox');

var ZeroClipboard = require('zeroclipboard');
ZeroClipboard.config('/static/vendor/bower_components/zeroclipboard/dist/ZeroClipboard.swf');
var $osf = require('js/osfHelpers');
var oop = require('js/oop');
var FolderPickerViewModel = require('js/folderPickerNodeConfig');

ko.punches.enableAll();

/**
 * View model to support instances of AddonNodeConfig (folder picker widget)
 *
 * @class AddonFolderPickerViewModel
 * @param {String} addonName Full display name of the addon
 * @param {String} url API url to initially fetch settings
 * @param {String} selector CSS selector for containing div
 * @param {String} folderPicker CSS selector for folderPicker div
 * @param {Object} opts Optional overrides to the class' default treebeardOptions, in particular onPickFolder
 */
var OauthAddonFolderPickerViewModel = oop.extend(FolderPickerViewModel, {
    constructor: function(addonName, url, selector, folderPicker, opts) {
        var self = this;
        self.super.constructor.call(self, addonName, url, selector, folderPicker);
        // whether the auth token is valid
        self.validCredentials = ko.observable(true);
        // Emails of contributors, can only be populated by activating the share dialog
        self.emails = ko.observableArray([]);
        self.loading = ko.observable(false);
        // Whether the contributor emails have been loaded from the server
        self.loadedEmails = ko.observable(false);
        // externalAccounts
        self.accounts = ko.observableArray();
        // List of contributor emails as a comma-separated values
        self.emailList = ko.pureComputed(function() {
            return self.emails().join([', ']);
        });
        self.selectedFolderType = ko.pureComputed(function() {
            var userHasAuth = self.userHasAuth();
            var selected = self.selected();
            return (userHasAuth && selected) ? selected.type : '';
        });
        self.messages.submitSettingsSuccess =  ko.pureComputed(function() {
            return 'Successfully linked "' + $osf.htmlEscape(self.folder().name) + '". Go to the Files page to view your content.';
        });
        // Overrides
        var defaults = {
            onPickFolder: function(evt, item) {
                evt.preventDefault();
                var name = item.data.path !== '/' ? item.data.path : '/ (Full ' + self.addonName + ')';
                self.selected({
                    name: name,
                    path: item.data.path,
                    id: item.data.id
                });
                return false; // Prevent event propagation
            },
            /**
             * Allows a user to create an access token from the nodeSettings page
             */
            connectAccount: function() {
                var self = this;

                window.oauthComplete = function(res) {
                    // Update view model based on response
                    self.changeMessage(self.messages.connectAccountSuccess(), 'text-success', 3000);
                    self.updateAccounts(function() {
                        $osf.putJSON(
                            self.urls().importAuth, {
                                external_account_id: self.accounts()[0].id
                            }
                        ).done(self.onImportSuccess.bind(self)
                        ).fail(self.onImportError.bind(self));
                    });
                };
                window.open(self.urls().auth);
            }
        };
        // Overrides
        self.options = $.extend({}, defaults, opts);
        // Treebeard config
        self.treebeardOptions = $.extend(
            {},
            FolderPickerViewModel.prototype.treebeardOptions,
            {
                onPickFolder: function(evt, item) {
                    return this.options.onPickFolder.call(this, evt, item);
                }.bind(this),
                resolveLazyloadUrl: function(item) {
                    return item.data.urls.folders;
                }
            }
        );
    },
    toggleShare: function() {
        if (this.currentDisplay() === this.SHARE) {
            this.currentDisplay(null);
        } else {
            // Clear selection
            this.cancelSelection();
            this.currentDisplay(this.SHARE);
            this.activateShare();
        }
    },
    fetchEmailList: function(){
        var self = this;

        var ret = $.Deferred();
        var promise = ret.promise();
        if(!self.loadedEmails()){
            $.ajax({
                url: self.urls().emails,
                type: 'GET',
                dataType: 'json'
            }).done(function(res){
                self.loadedEmails(true);
                ret.resolve(res.results.emails);
            }).fail(function(xhr, status, error){
                Raven.captureMessage('Could not GET ' + self.addonName + ' email list', {
                    url: self.urls().emails,
                    textStatus: status,
                    error: error
                });
                ret.reject(xhr, status, error);
            });
        }
        else{
            ret.resolve(self.emails());
        }
        return promise;
    },
    activateShare: function() {
        var self = this;
        self.fetchEmailList()
            .done(function(emails){
                self.emails(emails);
            });
        var $copyBtn = $(self.selector).find('.copyBtn');
        new ZeroClipboard($copyBtn);
    },
    _updateCustomFields: function(settings){
        this.validCredentials(settings.validCredentials);
    },
     /**
     * Allows a user to create an access token from the nodeSettings page
     */
    connectAccount: function() {
        this.options.connectAccount.call(this);
    },
    importAuth: function(){
        var self = this;

        self.updateAccounts(function() {
            if (self.accounts().length > 1) {
                bootbox.prompt({
                    title: 'Choose ' + self.addonName + ' Access Token to Import',
                    inputType: 'select',
                    inputOptions: ko.utils.arrayMap(
                        self.accounts(),
                        function(item) {
                            return {
                                text: item.name,
                                value: item.id
                            };
                        }
                    ),
                    value: self.accounts()[0].id,
                    callback: (self.connectExistingAccount.bind(self))
                });
            } else {
                bootbox.confirm({
                    title: 'Import ' + self.addonName + ' Access Token?',
                    message: self.messages.confirmAuth(),
                    callback: function(confirmed) {
                        if (confirmed) {
                            self.connectExistingAccount.call(self, (self.accounts()[0].id));
                        }
                    }
                });
            }
        });
    }
});

OauthAddonFolderPickerViewModel.prototype.connectExistingAccount = function(account_id) {
     var self = this;

    $osf.putJSON(
        self.urls().importAuth, {
            external_account_id: account_id
        }
    ).done(self.onImportSuccess.bind(self)
    ).fail(self.onImportError.bind(self));
};

OauthAddonFolderPickerViewModel.prototype.updateAccounts = function(callback) {
    var self = this;
    var request = $.get(self.urls().accounts);
    request.done(function(data) {
        self.accounts(data.accounts.map(function(account) {
            return {
                name: account.display_name,
                id: account.id
            };
        }));
        callback();
    });
    request.fail(function(xhr, textStatus, error) {
        self.changeMessage(self.messages.UPDATE_ACCOUNTS_ERROR(), 'text-warning');
        Raven.captureMessage('Could not GET ' + self.addonName + ' accounts for user', {
            url: self.url,
            textStatus: textStatus,
            error: error
        });
    });
};

// Public API
function OauthAddonNodeConfig(addonName, selector, url, folderPicker, opts) {
    var self = this;
    self.url = url;
    self.folderPicker = folderPicker;
    if (typeof opts === 'undefined') {
        opts = {};
    }
    self.viewModel = new OauthAddonFolderPickerViewModel(addonName, url, selector, folderPicker, opts);
    self.viewModel.updateFromData();
    $osf.applyBindings(self.viewModel, selector);
}

module.exports = {
    OauthAddonNodeConfig: OauthAddonNodeConfig,
    _OauthAddonNodeConfigViewModel: OauthAddonFolderPickerViewModel
};
<commit_msg>Update with promises that work<commit_after>/**
 * Module that controls the addon node settings. Includes Knockout view-model
 * for syncing data, and HGrid-folderpicker for selecting a folder.
 */
'use strict';

var ko = require('knockout');
require('knockout.punches');
var $ = require('jquery');
var Raven = require('raven-js');
var bootbox = require('bootbox');

var $osf = require('js/osfHelpers');
var oop = require('js/oop');
var FolderPickerViewModel = require('js/folderPickerNodeConfig');

ko.punches.enableAll();

/**
 * View model to support instances of AddonNodeConfig (folder picker widget)
 *
 * @class AddonFolderPickerViewModel
 * @param {String} addonName Full display name of the addon
 * @param {String} url API url to initially fetch settings
 * @param {String} selector CSS selector for containing div
 * @param {String} folderPicker CSS selector for folderPicker div
 * @param {Object} opts Optional overrides to the class' default treebeardOptions, in particular onPickFolder
 */
var OauthAddonFolderPickerViewModel = oop.extend(FolderPickerViewModel, {
    constructor: function(addonName, url, selector, folderPicker, opts) {
        var self = this;
        self.super.constructor.call(self, addonName, url, selector, folderPicker);
        // externalAccounts
        self.accounts = ko.observableArray();
        self.selectedFolderType = ko.pureComputed(function() {
            var userHasAuth = self.userHasAuth();
            var selected = self.selected();
            return (userHasAuth && selected) ? selected.type : '';
        });
        self.messages.submitSettingsSuccess =  ko.pureComputed(function() {
            return 'Successfully linked "' + $osf.htmlEscape(self.folder().name) + '". Go to the Files page to view your content.';
        });
        var defaults = {
            onPickFolder: function(evt, item) {
                evt.preventDefault();
                var name = item.data.path !== '/' ? item.data.path : '/ (Full ' + self.addonName + ')';
                self.selected({
                    name: name,
                    path: item.data.path,
                    id: item.data.id
                });
                return false; // Prevent event propagation
            },
            /**
             * Allows a user to create an access token from the nodeSettings page
             */
            connectAccount: function() {
                var self = this;

                window.oauthComplete = function(res) {
                    // Update view model based on response
                    self.updateAccounts().then(function() {
                        try{
                            $osf.putJSON(
                                self.urls().importAuth, {
                                    external_account_id: self.accounts()[0].id
                                }
                            ).done(self.onImportSuccess.bind(self)
                            ).fail(self.onImportError.bind(self));

                            self.changeMessage(self.messages.connectAccountSuccess(), 'text-success', 3000);
                        }
                        catch(err){
                            self.changeMessage(self.messages.connectAccountDenied(), 'text-failure', 6000);
                        }
                    });
                };
                window.open(self.urls().auth);
            }
        };
        // Overrides
        self.options = $.extend({}, defaults, opts);
        // Treebeard config
        self.treebeardOptions = $.extend(
            {},
            FolderPickerViewModel.prototype.treebeardOptions,
            {
                onPickFolder: function(evt, item) {
                    return this.options.onPickFolder.call(this, evt, item);
                }.bind(this),
                resolveLazyloadUrl: function(item) {
                    return item.data.urls.folders;
                }
            }
        );
    },
    _updateCustomFields: function(settings){
        this.validCredentials(settings.validCredentials);
    },
     /**
     * Allows a user to create an access token from the nodeSettings page
     */
    connectAccount: function() {
        this.options.connectAccount.call(this);
    },
    /**
    * Imports addon settings from user's account. If multiple addon accounts are connected, allow user to pick between them.
    */
    importAuth: function(){
        var self = this;

        self.updateAccounts().then(function () {
            if (self.accounts().length > 1) {
                bootbox.prompt({
                    title: 'Choose ' + self.addonName + ' Access Token to Import',
                    inputType: 'select',
                    inputOptions: ko.utils.arrayMap(
                        self.accounts(),
                        function(item) {
                            return {
                                text: item.name,
                                value: item.id
                            };
                        }
                    ),
                    value: self.accounts()[0].id,
                    callback: (self.connectExistingAccount.bind(self))
                });
            } else {
                bootbox.confirm({
                    title: 'Import ' + self.addonName + ' Access Token?',
                    message: self.messages.confirmAuth(),
                    callback: function(confirmed) {
                        if (confirmed) {
                            self.connectExistingAccount.call(self, (self.accounts()[0].id));
                        }
                    }
                });
            }
        });
    },
    /**
    * Associates selected external account with this node, or handles error.
    */
    connectExistingAccount: function(account_id) {
        var self = this;

        return $osf.putJSON(
            self.urls().importAuth, {
                external_account_id: account_id
            }
        ).done(self.onImportSuccess.bind(self)
        ).fail(self.onImportError.bind(self));
    },
    updateAccounts: function() {
        var self = this;
        var request = $.get(self.urls().accounts);
        return request.done(function(data) {
            self.accounts(data.accounts.map(function(account) {
                return {
                    name: account.display_name,
                    id: account.id
                };
            }));
        }).fail(function(xhr, textStatus, error) {
            self.changeMessage(self.messages.UPDATE_ACCOUNTS_ERROR(), 'text-warning');
            Raven.captureMessage('Could not GET ' + self.addonName + ' accounts for user', {
                url: self.url,
                textStatus: textStatus,
                error: error
            });
        });
    },
});

// Public API
function OauthAddonNodeConfig(addonName, selector, url, folderPicker, opts) {
    var self = this;
    self.url = url;
    self.folderPicker = folderPicker;
    opts = opts || {};
    self.viewModel = new OauthAddonFolderPickerViewModel(addonName, url, selector, folderPicker, opts);
    self.viewModel.updateFromData();
    $osf.applyBindings(self.viewModel, selector);
}

module.exports = {
    OauthAddonNodeConfig: OauthAddonNodeConfig,
    _OauthAddonNodeConfigViewModel: OauthAddonFolderPickerViewModel
};
<|endoftext|>


<commit_before>const fs = require('fs');
const R = require('ramda');

const {tail, head, toUpper, toLower, compose, juxt, join} = R;

const upperCase = compose(
  join(''),
  juxt([compose(toUpper, head), tail])
);

const lowerCase = compose(
  join(''),
  juxt([compose(toLower, head), tail])
);

const folder = __dirname;
const parent = __dirname.split('/');
const filename = parent[parent.length - 1];

const htmlFileName = filename + '.html';
const stylFileName = filename + '.styl';
const controllerFileName = filename + '-controller';
const componentFileName = filename + '-component';
const moduleFileName = filename;

const html = folder + '/' + htmlFileName;
const styl = folder + '/' + stylFileName;
const controller = folder + '/' + controllerFileName;
const component = folder + '/' + componentFileName;
const angularModule = folder + '/' + moduleFileName;
const spec = folder + '/' + filename + '.spec.js';
const integration = folder + '/' + filename + '.integration.spec.js';

const controllerName = filename.split('-').reduce((acc, segment) => {
  return acc + upperCase(segment);
}, '') + 'Controller';

const componentName = lowerCase(filename.split('-').reduce((acc, segment) => {
  return acc + upperCase(segment);
}, '') + 'Component');

const moduleName = lowerCase(filename.split('-').reduce((acc, segment) => {
  return acc + upperCase(segment);
}, ''));

fs.writeFileSync(html, '

\n');
fs.writeFileSync(styl, '');

fs.writeFileSync(controller + '.js',
  'function ' + controllerName + '() {\n' +
  '  const vm = this;\n' +
  '  console.log(vm);\n' +
  '}\n\n' +
  '//noinspection JSValidateTypes\n' +
  controllerName + '.$inject = [];\n\n' +
  'export {' + controllerName + '};\n'
);

fs.writeFileSync(component + '.js',
  'import \'./' + stylFileName + '\';\n' +
  'import template from \'./' + htmlFileName + '\';\n' +
  'import {' + controllerName + ' as controller} from \'./' + controllerFileName + '\';\n' +
  '\n' +
  'export const ' + componentName + ' = () => {\n' +
  '  return {\n' +
  '    template,\n' +
  '    restrict: \'E\',\n' +
  '    replace: true,\n' +
  '    scope: {},\n' +
  '    controller,\n' +
  '    controllerAs: \'vm\'\n' +
  '  };\n' +
  '};\n'
);

fs.writeFileSync(angularModule + '.js',
`import angular from 'angular';
import uiRouter from 'angular-ui-router';
import ngAnimate from 'angular-animate';
import ngAria from 'angular-aria';
import ngMaterial from 'angular-material';

import {` + componentName + '} from \'./' + componentFileName + `';

export const ` + moduleName + ' = angular.angularModule(\'' + moduleName + `', [
  uiRouter,
  ngAnimate,
  ngAria,
  ngMaterial
])
.directive('` + moduleName + '\', ' + componentName + `);
`
);

fs.writeFileSync(spec,
`
import 'script!jquery/dist/jquery';
import angular from 'angular';

import {` + componentName + '} from \'./' + componentFileName + `';

describe('the ` + filename + `', () => {
  const $ = window.$;
  let element, $scope;

  let buildTemplate = () => {
    return angular.element('<` + filename + '></' + filename + `>');
  };

  beforeEach(window.module('ui.router'));
  beforeEach(window.module(` + componentName + `.name));

  beforeEach(window.inject(($rootScope, $compile) => {
    $scope = $rootScope.$new();
    element = $compile(buildTemplate())($scope);
    $scope.$digest();
  }));

  describe('shows the product', () => {
    it.skip('name: RF-97 Autograph', () => {
      $scope.product = {title: 'RF-97 Autograph'};
      $scope.$digest();
      ($(element).find('span[rel=' + '"product-title"' + ']').text())
          .should.equal('RF-97 Autograph');
    });
  });
});
`);

fs.writeFileSync(integration,
`
/*eslint no-undef: "off"*/

import 'script!jquery/dist/jquery';
import angular from 'angular';

import {` + componentName + '} from \'./' + componentFileName + `';

describe('the ` + filename + `', () => {
  const $ = window.$;
  let element, $scope, $location, $state, $timeout;

  let buildTemplate = () => {
    return angular.element('<` + filename + ' products="products"></' + filename + `>');
  };

  beforeEach(window.module('ui.router'));
  beforeEach(window.module(` + componentName + `.name));
  beforeEach(angular.mock.http.init);
  afterEach(angular.mock.http.reset);

  beforeEach(window.inject(($rootScope, $compile, _$state_, _$location_,
  _$timeout_, $httpBackend) => {

    $scope = $rootScope.$new();
    $state = _$state_;
    $location = _$location_;
    $timeout = _$timeout_;
    $httpBackend.whenGET(/.*/).passThrough();

    element = $compile(buildTemplate())($scope);
    $scope.$digest();
  }));

  describe('shows', () => {
    it.skip('/#products in the url', () => {
      $location.path('/products');
      $scope.$apply();

      ($state.current.url).should.equal('/products');
      ($state.current.name).should.equal('products');
    });

    it.skip('a title', () => {
      $(element).find('h1[rel=' + '"products-title"' + ']').text().should.equal('Products');
    });

    it.skip('products', (done) => {
      $timeout(function() {

        $(element).find('span[rel=product-title]').length.should.equal(27);
        done();

      }, 1000);
    });
  });
});
`
);

const componentBuilder = {
  html: html,
  styl: styl,
  controller: controller + '.js',
  component: component + '.js',
  module: angularModule + '.js',
  spec: spec,
  integration: integration,
  folder: folder,
  filename: filename
};

module.exports = componentBuilder;

<commit_msg>squash bug in make-component.js<commit_after>const fs = require('fs');
const R = require('ramda');

const {tail, head, toUpper, toLower, compose, juxt, join} = R;

const upperCase = compose(
  join(''),
  juxt([compose(toUpper, head), tail])
);

const lowerCase = compose(
  join(''),
  juxt([compose(toLower, head), tail])
);

const folder = __dirname;
const parent = __dirname.split('/');
const filename = parent[parent.length - 1];

const htmlFileName = filename + '.html';
const stylFileName = filename + '.styl';
const controllerFileName = filename + '-controller';
const componentFileName = filename + '-component';
const moduleFileName = filename;

const html = folder + '/' + htmlFileName;
const styl = folder + '/' + stylFileName;
const controller = folder + '/' + controllerFileName;
const component = folder + '/' + componentFileName;
const angularModule = folder + '/' + moduleFileName;
const spec = folder + '/' + filename + '.spec.js';
const integration = folder + '/' + filename + '.integration.spec.js';

const controllerName = filename.split('-').reduce((acc, segment) => {
  return acc + upperCase(segment);
}, '') + 'Controller';

const componentName = lowerCase(filename.split('-').reduce((acc, segment) => {
  return acc + upperCase(segment);
}, '') + 'Component');

const moduleName = lowerCase(filename.split('-').reduce((acc, segment) => {
  return acc + upperCase(segment);
}, ''));

fs.writeFileSync(html, '

\n');
fs.writeFileSync(styl, '');

fs.writeFileSync(controller + '.js',
  'function ' + controllerName + '() {\n' +
  '  const vm = this;\n' +
  '  console.log(vm);\n' +
  '}\n\n' +
  '//noinspection JSValidateTypes\n' +
  controllerName + '.$inject = [];\n\n' +
  'export {' + controllerName + '};\n'
);

fs.writeFileSync(component + '.js',
  'import \'./' + stylFileName + '\';\n' +
  'import template from \'./' + htmlFileName + '\';\n' +
  'import {' + controllerName + ' as controller} from \'./' + controllerFileName + '\';\n' +
  '\n' +
  'export const ' + componentName + ' = () => {\n' +
  '  return {\n' +
  '    template,\n' +
  '    restrict: \'E\',\n' +
  '    replace: true,\n' +
  '    scope: {},\n' +
  '    controller,\n' +
  '    controllerAs: \'vm\'\n' +
  '  };\n' +
  '};\n'
);

fs.writeFileSync(angularModule + '.js',
`import angular from 'angular';
import uiRouter from 'angular-ui-router';
import ngAnimate from 'angular-animate';
import ngAria from 'angular-aria';
import ngMaterial from 'angular-material';

import {` + componentName + '} from \'./' + componentFileName + `';

export const ` + moduleName + ' = angular.module(\'' + moduleName + `', [
  uiRouter,
  ngAnimate,
  ngAria,
  ngMaterial
])
.directive('` + moduleName + '\', ' + componentName + `);
`
);

fs.writeFileSync(spec,
`
import 'script!jquery/dist/jquery';
import angular from 'angular';

import {` + componentName + '} from \'./' + componentFileName + `';

describe('the ` + filename + `', () => {
  const $ = window.$;
  let element, $scope;

  let buildTemplate = () => {
    return angular.element('<` + filename + '></' + filename + `>');
  };

  beforeEach(window.module('ui.router'));
  beforeEach(window.module(` + componentName + `.name));

  beforeEach(window.inject(($rootScope, $compile) => {
    $scope = $rootScope.$new();
    element = $compile(buildTemplate())($scope);
    $scope.$digest();
  }));

  describe('shows the product', () => {
    it.skip('name: RF-97 Autograph', () => {
      $scope.product = {title: 'RF-97 Autograph'};
      $scope.$digest();
      ($(element).find('span[rel=' + '"product-title"' + ']').text())
          .should.equal('RF-97 Autograph');
    });
  });
});
`);

fs.writeFileSync(integration,
`
/*eslint no-undef: "off"*/

import 'script!jquery/dist/jquery';
import angular from 'angular';

import {` + componentName + '} from \'./' + componentFileName + `';

describe('the ` + filename + `', () => {
  const $ = window.$;
  let element, $scope, $location, $state, $timeout;

  let buildTemplate = () => {
    return angular.element('<` + filename + ' products="products"></' + filename + `>');
  };

  beforeEach(window.module('ui.router'));
  beforeEach(window.module(` + componentName + `.name));
  beforeEach(angular.mock.http.init);
  afterEach(angular.mock.http.reset);

  beforeEach(window.inject(($rootScope, $compile, _$state_, _$location_,
  _$timeout_, $httpBackend) => {

    $scope = $rootScope.$new();
    $state = _$state_;
    $location = _$location_;
    $timeout = _$timeout_;
    $httpBackend.whenGET(/.*/).passThrough();

    element = $compile(buildTemplate())($scope);
    $scope.$digest();
  }));

  describe('shows', () => {
    it.skip('/#products in the url', () => {
      $location.path('/products');
      $scope.$apply();

      ($state.current.url).should.equal('/products');
      ($state.current.name).should.equal('products');
    });

    it.skip('a title', () => {
      $(element).find('h1[rel=' + '"products-title"' + ']').text().should.equal('Products');
    });

    it.skip('products', (done) => {
      $timeout(function() {

        $(element).find('span[rel=product-title]').length.should.equal(27);
        done();

      }, 1000);
    });
  });
});
`
);

const componentBuilder = {
  html: html,
  styl: styl,
  controller: controller + '.js',
  component: component + '.js',
  module: angularModule + '.js',
  spec: spec,
  integration: integration,
  folder: folder,
  filename: filename
};

module.exports = componentBuilder;

<|endoftext|>


<commit_before>/**
 * Class that adds a parse channel to all instalation of an App
 */

//Class Variables
var winston = require('winston');
var Parse = require('parse').Parse;
var async = require('async');

/**
 * Initialize logger
 * @param  {[type]} winston.Logger [description]
 * @return {[type]}                [description]
 */
var logger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)({ level: 'debug' }),
    new (winston.transports.File)({ filename: 'userLog.log' },{ level: 'debug' })
  ]
});

/**
 * Initialize Parse with keys
 */
Parse.initialize("gj2TfaLUgtmIrBNovNrVYCtsGGGJS3UV2RqsPTpe", "lXGNArrpLeY7p9OP0sJZQzU2iLZaSoMF7I1H2cja","FmwsZHYjTcUMqNCcELfw45w5eZaw3fJ8UMhD4urP");

//Getting users
updateInstalations();

/**
 * Update instalations
 * @return void
 */
function updateInstalations()
{
  logger.debug('Connecting to parse');

  logger.debug('Getting instalations');

  Parse.Cloud.useMasterKey();

  var changedObjects = [];
  var channelName = "costarica";

  var query = new Parse.Query(Parse.Installation);
  query.find({
    success: function(installations) {
      logger.debug("Successfully retrieved " + installations.length + " instalations.");

      logger.debug("Updating instalation and adding channel of " + channelName);
      for (var i = 0; i < installations.length; i++){
        // Add the channel to all the installations for this user
        installations[i].addUnique("channels", channelName); //Add the channel to the installation
        changedObjects.push(installations[i]); //Add the installation to be saved later on!
      }

      //Saving all the installations
      Parse.Object.saveAll(changedObjects, {
        success: function(installations) {
          //All installation saved
          logger.debug("Updated all instalations objects");

        },
        error: function(error) {
          // An error occurred while saving one of the objects.
          logger.error("Error saving installations "+ error);
        }
      });

    },
    error: function(error) {
      logger.error("Error: " + error.code + " " + error.message);
    }
  });
}
<commit_msg>Update script so it iterates over all the responces and updates one by one<commit_after>/**
 * Class that adds a parse channel to all instalation of an App
 * Due to the parse request limit you may have to run the script several times to get all instalation to update
 */

//Class Variables
var winston = require('winston');
var Parse = require('parse').Parse;
var async = require('async');

/**
 * Initialize logger
 * @param  {[type]} winston.Logger [description]
 * @return {[type]}                [description]
 */
var logger = new (winston.Logger)({
  transports: [
    new (winston.transports.Console)({ level: 'debug' }),
    new (winston.transports.File)({ filename: 'userLog.log' },{ level: 'debug' })
  ]
});

/**
 * Initialize Parse with keys
 */
Parse.initialize("WXYWaxFqpJWUq0Sc1RSF4T5pEcRa9hzd0L5WCdfy", "ViL8y0PTQ8kXXbAJZsHySeuyNluw3GRIe4KOZNZb","lyZ1SyItcofFzyzvg8eCzD5y78lJNJrbsN0dz99k");

//Getting users
updateInstalations();

/**
 * Update instalations
 * @return void
 */
function updateInstalations()
{
  logger.debug('Connecting to parse');

  logger.debug('Getting instalations');

  Parse.Cloud.useMasterKey();

  var changedObjects = [];
  var channelName = "costarica";

  var query = new Parse.Query(Parse.Installation);
  query.notContainedIn("channels", [channelName]);

  query.each(function(installation) {
    console.log("Updating instalation: " + installation.id);

    installation.addUnique("channels", channelName); //Add the channel to the installation

    installation.save();

  });
}
<|endoftext|>


<commit_before>var cdb = require('cartodb.js');
var BaseDialog = require('../../views/base_dialog/view');

/**
 * Scratch modal
 */
module.exports = BaseDialog.extend({

  events: {
    "click .js-option" : "_onOptionClick",
    "click .js-skip"   : "close"
  },

  initialize: function() {
    this.elder('initialize');

    if (!this.options.table) {
      throw new TypeError('table is required');
    }

    this.table = this.options.table;
    this._template = cdb.templates.getTemplate('common/dialogs/map/scratch_view_template');

  },

  // implements cdb.ui.common.Dialog.prototype.render
  render: function() {
    this.clearSubViews();
    BaseDialog.prototype.render.call(this);
    return this;
  },

  // implements cdb.ui.common.Dialog.prototype.render
  render_content: function() {
    return this._template({
      name: this.table.get("name")
    });
  },

  _onOptionClick: function(e) {
    this.killEvent(e);
    this.close();
    this.trigger("newGeometry", $(e.target).closest("button").data("type"));
  },

  _ok: function() {
    this.close();
  }

});
<commit_msg>Simplifies events<commit_after>var cdb = require('cartodb.js');
var BaseDialog = require('../../views/base_dialog/view');

/**
 * Scratch modal
 */
module.exports = BaseDialog.extend({

  events: {
    "click .js-option" : "_onOptionClick",
    "click .js-skip"   : "_ok"
  },

  initialize: function() {
    this.elder('initialize');

    if (!this.options.table) {
      throw new TypeError('table is required');
    }

    this.table = this.options.table;
    this._template = cdb.templates.getTemplate('common/dialogs/map/scratch_view_template');

  },

  // implements cdb.ui.common.Dialog.prototype.render
  render: function() {
    this.clearSubViews();
    BaseDialog.prototype.render.call(this);
    return this;
  },

  // implements cdb.ui.common.Dialog.prototype.render
  render_content: function() {
    return this._template({
      name: this.table.get("name")
    });
  },

  _onOptionClick: function(e) {
    this.killEvent(e);
    this.close();
    this.trigger("newGeometry", $(e.target).data("type"));
  }

});
<|endoftext|>


<commit_before>
  /**
   *  Import error pane
   *
   *  Displays error messages if import went bad :(
   *
   *  - It needs a model to know what happened with the import.
   *
   *  new cdb.admin.ImportErrorPane({ model: state_model });
   *
  */

  cdb.admin.ImportErrorPane = cdb.core.View.extend({

    className: 'create-error',

    _TEXTS: {
      what_about: _t('Sorry, something went wrong and we\'re not sure what. Contact us at \
                    contact@cartodb.com.'),
    },

    initialize: function() {
      this.template = cdb.templates.getTemplate(this.options.template || 'common/views/import/import_error');

      this._initBinds();
      this.render();
    },

    render: function() {
      var d = {
        item_queue_id:  this.model.get('upload') && this.model.get('upload').item_queue_id || '',
        what_about:     this.model.get('error') && this.model.get('error').what_about || this._TEXTS.what_about
      };

      this.$el.html(this.template(d));

      return this;
    },

    _initBinds: function() {
      this.model.bind('change', this.render, this);
    }

  });<commit_msg>import pane: error: fix typo, close #1320<commit_after>
  /**
   *  Import error pane
   *
   *  Displays error messages if import went bad :(
   *
   *  - It needs a model to know what happened with the import.
   *
   *  new cdb.admin.ImportErrorPane({ model: state_model });
   *
  */

  cdb.admin.ImportErrorPane = cdb.core.View.extend({

    className: 'create-error',

    _TEXTS: {
      what_about: _t('Sorry, something went wrong and we\'re not sure what. Contact us at \
                    support@cartodb.com.'),
    },

    initialize: function() {
      this.template = cdb.templates.getTemplate(this.options.template || 'common/views/import/import_error');

      this._initBinds();
      this.render();
    },

    render: function() {
      var d = {
        item_queue_id:  this.model.get('upload') && this.model.get('upload').item_queue_id || '',
        what_about:     this.model.get('error') && this.model.get('error').what_about || this._TEXTS.what_about
      };

      this.$el.html(this.template(d));

      return this;
    },

    _initBinds: function() {
      this.model.bind('change', this.render, this);
    }

  });<|endoftext|>


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

'use strict';

// MODULES //

var logger = require( 'debug' );
var defineProperty = require( '@stdlib/utils/define-property' );
var objectKeys = require( '@stdlib/utils/keys' );
var isArrayLike = require( '@stdlib/assert/is-array-like' );
var mergeFcn = require( '@stdlib/utils/merge' ).factory;
var pick = require( '@stdlib/utils/pick' );
var inherit = require( '@stdlib/utils/inherit' );
var Sparkline = require( '@stdlib/plot/sparklines/base/ctor' );
var defaults = require( './defaults.js' );

// VARIABLES //

var debug = logger( 'sparkline:line-chart:unicode:main' );

var merge = mergeFcn({
	'extend': false
});

// List of private properties (note: keep in alphabetical order):
var PRIVATE_PROPS = [
	'_infinities',
	'_yMax',
	'_yMin'
];

// List of options properties (note: keep in alphabetical order):
var OPTIONS_PROPS = [
	'infinities',
	'yMax',
	'yMin'
];

// MAIN //

/**
* Unicode sparkline line chart constructor.
*
* @constructor
* @param {(ArrayLike|ndarrayLike)} [data] - chart data
* @param {Options} [options] - chart options
* @param {boolean} [options.autoRender=false] - indicates whether to re-render on a `change` event
* @param {(PositiveInteger|null)} [options.bufferSize] - data buffer size
* @param {(ArrayLikeObject|ndarrayLike)} [options.data] - data
* @param {string} [options.description=''] - chart description
* @param {boolean} [options.infinities=false] - boolean indicating whether to encode infinite values
* @param {Function} [options.isDefined] - accessor indicating whether a datum is defined
* @param {string} [options.label] - data label
* @param {(FiniteNumber|null)} [options.yMax] - maximum value of the y-axis domain
* @param {(FiniteNumber|null)} [options.yMin] - minimum value of the y-axis domain
* @throws {TypeError} must provide valid options
* @returns {LineChart} chart instance
*
* @example
* var data = [ 1.0, 5.0, 3.0, 2.0, 4.0, 4.0, 3.0 ];
*
* var chart = new LineChart( data );
*
* var str = chart.render();
* // returns '⡈⠑⠢⠔⠒⠒⠒'
*
* @example
* var data = [ 1.0, 5.0, 3.0, 2.0, 4.0, 4.0, 3.0 ];
* var opts = {
*     'data': data
* };
* var chart = new LineChart( opts );
*
* var str = chart.render();
* // returns '⡈⠑⠢⠔⠒⠒⠒'
*/
function LineChart() {
	var options;
	var nargs;
	var opts;
	var keys;
	var key;
	var i;

	nargs = arguments.length;
	if ( !(this instanceof LineChart) ) {
		if ( nargs === 0 ) {
			return new LineChart();
		}
		if ( nargs === 1 ) {
			return new LineChart( arguments[ 0 ] );
		}
		return new LineChart( arguments[ 0 ], arguments[ 1 ] );
	}
	// Invoke parent constructor...
	if ( nargs === 0 ) {
		Sparkline.call( this );
	} else if ( nargs === 1 ) {
		Sparkline.call( this, arguments[ 0 ] );
	} else {
		Sparkline.call( this, arguments[ 0 ], arguments[ 1 ] );
	}
	// Extract chart-specific options...
	opts = defaults();
	if ( nargs === 1 && !isArrayLike( arguments[ 0 ] ) ) {
		options = arguments[ 0 ];
	} else if ( nargs === 2 ) {
		options = arguments[ 1 ];
	} else {
		options = {};
	}
	opts = merge( opts, pick( options, OPTIONS_PROPS ) );

	debug( 'Creating an instance with the following configuration: %s.', JSON.stringify( options ) );

	// Initialize private chart-specific properties...
	for ( i = 0; i < PRIVATE_PROPS.length; i++ ) {
		defineProperty( this, PRIVATE_PROPS[i], {
			'configurable': false,
			'enumerable': false,
			'writable': true,
			'value': null
		});
	}

	// Set chart-specific properties...
	keys = objectKeys( opts );
	for ( i = 0; i < keys.length; i++ ) {
		key = keys[ i ];
		this[ key ] = opts[ key ];
	}
	return this;
}

/*
* Inherit from the `Sparkline` prototype.
*/
inherit( LineChart, Sparkline );

/**
* Boolean indicating whether to encode infinite values.
*
* @name infinities
* @memberof LineChart.prototype
* @type {boolean}
* @throws {TypeError} must be a boolean primitive
* @default false
*
* @example
* var chart = new LineChart();
* chart.infinities = true;
*
* @example
* var chart = new LineChart({
*     'infinities': true
* });
* var bool = chart.infinities;
* // returns true
*/
defineProperty( LineChart.prototype, 'infinities', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/infinities/set.js' ),
	'get': require( './props/infinities/get.js' )
});

/**
* Maximum value of the y-axis domain.
*
* @name yMax
* @memberof LineChart.prototype
* @type {(FiniteNumber|null)}
* @throws {TypeError} must be a finite number primitive or null
*
* @example
* var chart = new LineChart();
* chart.yMax = 100.0;
*
* @example
* var chart = new LineChart({
*     'yMax': 314.0
* });
* var ymax = chart.yMax;
* // returns 314.0
*/
defineProperty( LineChart.prototype, 'yMax', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/y-max/set.js' ),
	'get': require( './props/y-max/get.js' )
});

/**
* Minimum value of the y-axis domain.
*
* @name yMin
* @memberof LineChart.prototype
* @type {(FiniteNumber|null)}
* @throws {TypeError} must be a finite number primitive or null
*
* @example
* var chart = new LineChart();
* chart.yMin = -100.0;
*
* @example
* var chart = new LineChart({
*     'yMin': 3.14
* });
* var ymin = chart.yMin;
* // returns 3.14
*/
defineProperty( LineChart.prototype, 'yMin', {
	'configurable': false,
	'enumerable': true,
	'set': require( './props/y-min/set.js' ),
	'get': require( './props/y-min/get.js' )
});

/**
* Renders a sparkline line chart.
*
* @private
* @name _render
* @memberof LineChart.prototype
* @type {Function}
* @returns {string} rendered sparkline line chart
*
* @example
* var data = [ 1.0, 5.0, 3.0, 2.0, 4.0, 4.0, 3.0 ];
*
* var chart = new LineChart( data );
*
* var str = chart.render();
* // returns '⡈⠑⠢⠔⠒⠒⠒'
*/
LineChart.prototype._render = require( './render.js' ); // eslint-disable-line no-underscore-dangle

// EXPORTS //

module.exports = LineChart;
<commit_msg>Move require expressions<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2018 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var logger = require( 'debug' );
var defineProperty = require( '@stdlib/utils/define-property' );
var objectKeys = require( '@stdlib/utils/keys' );
var isArrayLike = require( '@stdlib/assert/is-array-like' );
var mergeFcn = require( '@stdlib/utils/merge' ).factory;
var pick = require( '@stdlib/utils/pick' );
var inherit = require( '@stdlib/utils/inherit' );
var Sparkline = require( '@stdlib/plot/sparklines/base/ctor' );
var defaults = require( './defaults.js' );
var setInfinities = require( './props/infinities/set.js' );
var getInfinities = require( './props/infinities/get.js' );
var setYMax = require( './props/y-max/set.js' );
var getYMax = require( './props/y-max/get.js' );
var setYMin = require( './props/y-min/set.js' );
var getYMin = require( './props/y-min/get.js' );
var render = require( './render.js' );

// VARIABLES //

var debug = logger( 'sparkline:line-chart:unicode:main' );

var merge = mergeFcn({
	'extend': false
});

// List of private properties (note: keep in alphabetical order):
var PRIVATE_PROPS = [
	'_infinities',
	'_yMax',
	'_yMin'
];

// List of options properties (note: keep in alphabetical order):
var OPTIONS_PROPS = [
	'infinities',
	'yMax',
	'yMin'
];

// MAIN //

/**
* Unicode sparkline line chart constructor.
*
* @constructor
* @param {(ArrayLike|ndarrayLike)} [data] - chart data
* @param {Options} [options] - chart options
* @param {boolean} [options.autoRender=false] - indicates whether to re-render on a `change` event
* @param {(PositiveInteger|null)} [options.bufferSize] - data buffer size
* @param {(ArrayLikeObject|ndarrayLike)} [options.data] - data
* @param {string} [options.description=''] - chart description
* @param {boolean} [options.infinities=false] - boolean indicating whether to encode infinite values
* @param {Function} [options.isDefined] - accessor indicating whether a datum is defined
* @param {string} [options.label] - data label
* @param {(FiniteNumber|null)} [options.yMax] - maximum value of the y-axis domain
* @param {(FiniteNumber|null)} [options.yMin] - minimum value of the y-axis domain
* @throws {TypeError} must provide valid options
* @returns {LineChart} chart instance
*
* @example
* var data = [ 1.0, 5.0, 3.0, 2.0, 4.0, 4.0, 3.0 ];
*
* var chart = new LineChart( data );
*
* var str = chart.render();
* // returns '⡈⠑⠢⠔⠒⠒⠒'
*
* @example
* var data = [ 1.0, 5.0, 3.0, 2.0, 4.0, 4.0, 3.0 ];
* var opts = {
*     'data': data
* };
* var chart = new LineChart( opts );
*
* var str = chart.render();
* // returns '⡈⠑⠢⠔⠒⠒⠒'
*/
function LineChart() {
	var options;
	var nargs;
	var opts;
	var keys;
	var key;
	var i;

	nargs = arguments.length;
	if ( !(this instanceof LineChart) ) {
		if ( nargs === 0 ) {
			return new LineChart();
		}
		if ( nargs === 1 ) {
			return new LineChart( arguments[ 0 ] );
		}
		return new LineChart( arguments[ 0 ], arguments[ 1 ] );
	}
	// Invoke parent constructor...
	if ( nargs === 0 ) {
		Sparkline.call( this );
	} else if ( nargs === 1 ) {
		Sparkline.call( this, arguments[ 0 ] );
	} else {
		Sparkline.call( this, arguments[ 0 ], arguments[ 1 ] );
	}
	// Extract chart-specific options...
	opts = defaults();
	if ( nargs === 1 && !isArrayLike( arguments[ 0 ] ) ) {
		options = arguments[ 0 ];
	} else if ( nargs === 2 ) {
		options = arguments[ 1 ];
	} else {
		options = {};
	}
	opts = merge( opts, pick( options, OPTIONS_PROPS ) );

	debug( 'Creating an instance with the following configuration: %s.', JSON.stringify( options ) );

	// Initialize private chart-specific properties...
	for ( i = 0; i < PRIVATE_PROPS.length; i++ ) {
		defineProperty( this, PRIVATE_PROPS[i], {
			'configurable': false,
			'enumerable': false,
			'writable': true,
			'value': null
		});
	}

	// Set chart-specific properties...
	keys = objectKeys( opts );
	for ( i = 0; i < keys.length; i++ ) {
		key = keys[ i ];
		this[ key ] = opts[ key ];
	}
	return this;
}

/*
* Inherit from the `Sparkline` prototype.
*/
inherit( LineChart, Sparkline );

/**
* Boolean indicating whether to encode infinite values.
*
* @name infinities
* @memberof LineChart.prototype
* @type {boolean}
* @throws {TypeError} must be a boolean primitive
* @default false
*
* @example
* var chart = new LineChart();
* chart.infinities = true;
*
* @example
* var chart = new LineChart({
*     'infinities': true
* });
* var bool = chart.infinities;
* // returns true
*/
defineProperty( LineChart.prototype, 'infinities', {
	'configurable': false,
	'enumerable': true,
	'set': setInfinities,
	'get': getInfinities
});

/**
* Maximum value of the y-axis domain.
*
* @name yMax
* @memberof LineChart.prototype
* @type {(FiniteNumber|null)}
* @throws {TypeError} must be a finite number primitive or null
*
* @example
* var chart = new LineChart();
* chart.yMax = 100.0;
*
* @example
* var chart = new LineChart({
*     'yMax': 314.0
* });
* var ymax = chart.yMax;
* // returns 314.0
*/
defineProperty( LineChart.prototype, 'yMax', {
	'configurable': false,
	'enumerable': true,
	'set': setYMax,
	'get': getYMax
});

/**
* Minimum value of the y-axis domain.
*
* @name yMin
* @memberof LineChart.prototype
* @type {(FiniteNumber|null)}
* @throws {TypeError} must be a finite number primitive or null
*
* @example
* var chart = new LineChart();
* chart.yMin = -100.0;
*
* @example
* var chart = new LineChart({
*     'yMin': 3.14
* });
* var ymin = chart.yMin;
* // returns 3.14
*/
defineProperty( LineChart.prototype, 'yMin', {
	'configurable': false,
	'enumerable': true,
	'set': setYMin,
	'get': getYMin
});

/**
* Renders a sparkline line chart.
*
* @private
* @name _render
* @memberof LineChart.prototype
* @type {Function}
* @returns {string} rendered sparkline line chart
*
* @example
* var data = [ 1.0, 5.0, 3.0, 2.0, 4.0, 4.0, 3.0 ];
*
* var chart = new LineChart( data );
*
* var str = chart.render();
* // returns '⡈⠑⠢⠔⠒⠒⠒'
*/
LineChart.prototype._render = render; // eslint-disable-line no-underscore-dangle

// EXPORTS //

module.exports = LineChart;
<|endoftext|>


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

'use strict';

// MODULES //

var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
var nextGraphemeClusterBreak = require( '@stdlib/string/next-grapheme-cluster-break' );
var format = require( '@stdlib/string/format' );

// MAIN //

/**
* Returns the number of grapheme clusters in a string.
*
* @param {string} str - input string
* @throws {TypeError} must provide a string primitive
* @returns {NonNegative} number of grapheme clusters
*
* @example
* var out = numGraphemeClusters( 'last man standing' );
* // returns 17
*
* @example
* var out = numGraphemeClusters( 'presidential election' );
* // returns 21
*
* @example
* var out = numGraphemeClusters( 'अनुच्छेद' );
* // returns 5
*
* @example
* var out = numGraphemeClusters( '🌷' );
* // returns 1
*/
function numGraphemeClusters( str ) {
	var count;
	var idx;
	var brk;

	if ( !isString( str ) ) {
		throw new TypeError( format( 'invalid argument. Must provide a string. Value: `%s`.', str ) );
	}
	count = 0;
	idx = 0;

	brk = nextGraphemeClusterBreak( str, idx );
	while ( brk !== -1 ) {
		count += 1;
		idx = brk;
		brk = nextGraphemeClusterBreak( str, idx );
	}
	if ( idx < str.length ) {
		count += 1;
	}
	return count;
}

// EXPORTS //

module.exports = numGraphemeClusters;
<commit_msg>Fix type annotation<commit_after>/**
* @license Apache-2.0
*
* Copyright (c) 2020 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var isString = require( '@stdlib/assert/is-string' ).isPrimitive;
var nextGraphemeClusterBreak = require( '@stdlib/string/next-grapheme-cluster-break' );
var format = require( '@stdlib/string/format' );

// MAIN //

/**
* Returns the number of grapheme clusters in a string.
*
* @param {string} str - input string
* @throws {TypeError} must provide a string primitive
* @returns {NonNegativeInteger} number of grapheme clusters
*
* @example
* var out = numGraphemeClusters( 'last man standing' );
* // returns 17
*
* @example
* var out = numGraphemeClusters( 'presidential election' );
* // returns 21
*
* @example
* var out = numGraphemeClusters( 'अनुच्छेद' );
* // returns 5
*
* @example
* var out = numGraphemeClusters( '🌷' );
* // returns 1
*/
function numGraphemeClusters( str ) {
	var count;
	var idx;
	var brk;

	if ( !isString( str ) ) {
		throw new TypeError( format( 'invalid argument. Must provide a string. Value: `%s`.', str ) );
	}
	count = 0;
	idx = 0;

	brk = nextGraphemeClusterBreak( str, idx );
	while ( brk !== -1 ) {
		count += 1;
		idx = brk;
		brk = nextGraphemeClusterBreak( str, idx );
	}
	if ( idx < str.length ) {
		count += 1;
	}
	return count;
}

// EXPORTS //

module.exports = numGraphemeClusters;
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var teep = require('teep');

function loadListeners(eventName) {
  var listeners = [];
  fs.readdirSync(__dirname + '/listeners/' + eventName + '/').forEach(function(file) {
    if (/^[^\.].*.js$/.test(file)) {
      var path = './listeners/' + eventName + '/' + file;
      listeners.push(require(path));
    }
  });
  return listeners;
}

var dbFile = process.env.HOME + '/.sectery.json';

function getDb() {
  if (fs.existsSync(dbFile)) {
    return JSON.parse(fs.readFileSync(dbFile));
  } else {
    return {};
  }
}

function saveDb(db) {
  fs.writeFileSync(dbFile, JSON.stringify(db, null, 2));
}

function sectery(client) {

  var db = getDb();

  var sendReply = teep.fn.throttle(5, 10000, 250, function (reply) {
    if (reply && reply.to && reply.message) {
      client.say(reply.to, reply.message);
    }
  });

  client.addListener('join', function (channel, nick, message) {
    function run(joinListener) {
      joinListener(db, channel, nick, message, sendReply);
    }
    loadListeners('join').forEach(run);
  });

  client.addListener('part', function(channel, nick, reason, message) {
    function run(partListener) {
      partListener(db, channel, nick, reason, message, sendReply);
    }
    loadListeners('part').forEach(run);
  });

  client.addListener('names', function(channel, names) {
    function run(namesListener) {
      namesListener(db, channel, names, sendReply);
    }
    loadListeners('names').forEach(run);
  });

  client.addListener('message', function(from, to, message) {
    function run(messageListener) {
      try {
        messageListener(db, from, to, message, sendReply);
      } catch (e) {
        console.error('running message listener', e);
      }
    }
    loadListeners('message').forEach(run);
  });

  client.addListener('pm', function (from, message) {
    function run(pmListener) {
      pmListener(db, from, message, sendReply);
    }
    loadListeners('pm').forEach(run);
  });

}

module.exports = sectery;
<commit_msg>Restore lost db writes<commit_after>'use strict';

var fs = require('fs');
var teep = require('teep');

function loadListeners(eventName) {
  var listeners = [];
  fs.readdirSync(__dirname + '/listeners/' + eventName + '/').forEach(function(file) {
    if (/^[^\.].*.js$/.test(file)) {
      var path = './listeners/' + eventName + '/' + file;
      listeners.push(require(path));
    }
  });
  return listeners;
}

var dbFile = process.env.HOME + '/.sectery.json';

function getDb() {
  if (fs.existsSync(dbFile)) {
    return JSON.parse(fs.readFileSync(dbFile));
  } else {
    return {};
  }
}

function saveDb(db) {
  fs.writeFileSync(dbFile, JSON.stringify(db, null, 2));
}

function sectery(client) {

  var db = getDb();

  var sendReply = teep.fn.throttle(5, 10000, 250, function (reply) {
    if (reply && reply.to && reply.message) {
      client.say(reply.to, reply.message);
    }
  });

  client.addListener('join', function (channel, nick, message) {
    function run(joinListener) {
      joinListener(db, channel, nick, message, sendReply);
      saveDb(db);
    }
    loadListeners('join').forEach(run);
  });

  client.addListener('part', function(channel, nick, reason, message) {
    function run(partListener) {
      partListener(db, channel, nick, reason, message, sendReply);
      saveDb(db);
    }
    loadListeners('part').forEach(run);
  });

  client.addListener('names', function(channel, names) {
    function run(namesListener) {
      namesListener(db, channel, names, sendReply);
      saveDb(db);
    }
    loadListeners('names').forEach(run);
  });

  client.addListener('message', function(from, to, message) {
    function run(messageListener) {
      try {
        messageListener(db, from, to, message, sendReply);
      } catch (e) {
        console.error('running message listener', e);
      }
      saveDb(db);
    }
    loadListeners('message').forEach(run);
  });

  client.addListener('pm', function (from, message) {
    function run(pmListener) {
      pmListener(db, from, message, sendReply);
      saveDb(db);
    }
    loadListeners('pm').forEach(run);
  });

}

module.exports = sectery;
<|endoftext|>


<commit_before>/**
 * config:session配置
 * config.lock 用户进程锁, 默认:false(关闭),格式:[num,ms,reload],
 * config.lock = [10,500,1]
 * 仅当在session存放用户cache时才有必要将reload设置为 true
 *
 */

exports = module.exports = function(config) {
    return function (req, res, next) {
        Object.defineProperty(req, "session", { value : new session(req, res, config),  writable : false, configurable : false, enumerable : false  });
        next();
    }
}

var session = function ( req, res, option) {
    var self = this,
        _id,_key,_store,_crypto,_start = false,
        _delayNum = 0,_isLock = false,_isClose = false;
    var sess_key  = '_sess_key';
    var sess_lock = '_sess_lock';
    var config = Object.extend({ id:"sessid",key:"cookies",lock:false,store:null,secret:"cosjs",prefix:"session",expire:0 },option);
    this.config = function(key,val){
        if(arguments.length==2){
            config[key] = val;
        }
        else{
            return config[key] || null;
        }
    }

    //写入数据，不会修改session,可用于临时缓存
    this.set = function (key,val,callback) {
        var hash = self.key();
        if(!hash){
            return callback('logout','session id empty');
        }
        var store = self.store();
        store.set(hash,key,val,callback);
    }
    //获取一个或者多个在session中缓存的信息
    this.get = function (keys,callback) {
        var hash = self.key();
        if(!hash){
            return callback('logout','session id empty');
        }
        var store = self.store();
        if(_start){
            store.get(hash,keys,callback);
        }
        else{
            start(store,hash,keys,callback);
        }
    }
    //删除一个或者多个在session中缓存的信息，keys==null,删除所有信息，退出登录
    this.del = function(keys,callback){
        var hash = self.key();
        if(!hash){
            return callback('logout','session id empty');
        }
        var store = self.store();
        store.del(hash,keys,callback);
    }
    //创建session
    this.create = function (key,data,callback) {
        var crypto = self.crypto();
        var id = crypto.encode(key);
        if(!id){
            return callback('error','create session id error');
        }
        _id = id;
        var store = self.store();
        var newData = Object.clone(data);
        newData[sess_key] = id;
        newData[sess_lock] = 0;
        store.set(key,newData,function(err,ret){
            if(err){
                return callback(err,ret);
            }
            //自动创建cookie
            if(config['key']=='cookies'){
                res.cookie(config['id'], id, { maxAge: config['expire'] * 1000, httpOnly: true });
            }
            return callback(null,id);
        });
    }

    //获取并检查数据有效性
    this.id = function () {
        if(_id || _id===null){
            return _id;
        }
       return _id = params(config['id'],config['key']);
    }

    this.key = function(){
        if(_key){
            return _key;
        }
        var id = self.id();
        if(!id){
            return null;
        }
        var crypto = self.crypto();
        _key = crypto.decode(id);
        return _key;
    }

    this.store = function () {
        if(_store){
            return _store;
        }
        var store = config['store'];
        if(!store){
            throw new Error('session config[store] empty');
        }
        if(typeof store == 'function'){
            _store = store(req,res);
        }
        else if(typeof store == 'object'){
            _store = store;
        }
        else{
            _store = require('./redis').hash(store,config['prefix']);
        }
        return _store;
    }

    this.crypto = function(){
        if(_crypto){
            return _crypto;
        }
        _crypto = new session_crypto(config['secret']);
        return _crypto;
    }

    var params = function(key,querykey){
        var getVal = function(k){
            if(!req[k]){
                return null;
            }
            else{
                return req[k][key] || null;
            }
        }

        if(!querykey){
            return null;
        }
        if(!Array.isArray(querykey)){
            querykey = [querykey];
        }

        for(var i in querykey){
            var v = getVal(querykey[i]);
            if(v !== null){
                return v;
            }
        }
        return null;
    }
    //解锁session
    var unlock = function(){
        if(!_isLock){
            return false;
        }
        _isLock = false;
        var hash = self.key();
        if(!hash){
            return callback('logout','session id empty');
        }
        var store = self.store();
        store.set(hash,sess_lock,0,function(err,ret){});
    }
    //启动并验证SESSION
    var start = function(store,hash,keys,callback){

        res.on('close',function(){  _isClose = true; unlock(); });
        res.on('finish',unlock);

        var data;
        var usr_sess_id = self.id();
        if(!usr_sess_id){
            return callback('logout','session id empty');
        }
        var Check = function(){
            store.incr(hash, sess_lock, 1, function (err, ret) {
                if (err) {
                    callback(err, ret);
                }
                else if (ret > 1) {
                    Delay();
                }
                else {
                    _isLock = true;
                    _isClose ? unlock() : Result();
                }
            });
        }

        var Delay = function(){
            _delayNum ++;
            if( _delayNum >= config['lock'][0] ){
                callback("locked",_delayNum);
            }
            else{
                setTimeout(Check,config['lock'][1]);
            }
        }

        var Result = function(){
            var expire = config['expire'];
            if(expire){
                store.expire(hash,expire,function(){});
            }
            if( _delayNum > 0 && config['lock'][2] ){
                start(store,hash,keys,callback);   //数据失去时效,其他程序已经修改过session和cache,重新获取数据[仅cache和session放在一起时使用]
            }
            else if(keys && !Array.isArray(keys)){
                callback(null, data[keys]||null );
            }
            else{
                callback(null, data);
            }
        }

        var RealKeys = function(keys) {
            if (!keys) {
                return null;
            }
            var realKey = [sess_key,sess_lock];
            if(Array.isArray(keys)) {
                realKey = realKey.concat(keys);
            }
            else {
                realKey.push(keys);
            }
            return realKey;
        }

        store.get(hash, RealKeys(keys), function (err, ret) {
            if (err) {
                return callback(err, ret);
            }
            else if (!ret) {
                return callback('logout', 'session not exist');
            }

            var ret_sess_id = ret[sess_key]||'';
            var ret_sess_locked = ret[sess_lock]||0;
            delete ret[sess_key];
            delete ret[sess_lock];
            data = ret;

            if ( !ret_sess_id || ret_sess_id != usr_sess_id) {
                return callback("logout", "session id illegal");
            }
            _start = true;  //已经验证用户SESSION有效
            if(!config['lock']){
                return Result();
            }

            if (ret_sess_locked > 0) {
                Delay();
            }
            else{
                Check();
            }
        });
    }

}

var session_crypto = function(secret){
    var codestr = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    var codearr = {};
    var codelen = codestr.length;
    var secrlen = 4;

    for(var i=0;i<codelen;i++){
        var k = codestr[i];
        codearr[k] = i;
    }

    this.key = '';

    this.secret = secret||'';

    this.encode = function(str) {
        if( isSafe(str) ){
            this.key = str;
        }
        else{
            this.key = String.md5(str);
        }
        var code = String.md5( parseInt(Math.random()* 1000).toString()).substr(0,secrlen);
        var skey = String.md5(code + this.secret);

        var arr = [];
        var len = this.key.length;
        for(var i =0;i<len;i++){
            var s1 = this.key[i];
            var m = i % secrlen;
            var s2 = skey[m];
            var n = codearr[s1] + codearr[s2];
            if(n >= codelen){
                n -= codelen;
            }
            arr.push(codestr[n]);
        }
        return code + arr.join('');
    }

    this.decode = function(str) {
        if(!isSafe(str)){
            return false;
        }
        var code  = str.substr(0,secrlen);
        var skey  = String.md5(code + this.secret);
        var secr  = str.substr(secrlen);

        var arr = [];
        var len = secr.length;
        for(var i =0;i<len;i++){
            var s1 = secr[i];
            var m = i % secrlen;
            var s2 = skey[m];
            var n = codearr[s1] - codearr[s2];
            if(n < 0){
                n += codelen;
            }
            arr.push(codestr[n]);
        }
        this.key = arr.join('');
        return this.key;
    }

    var isSafe = function(str){
        var len = str.length;
        for(var i=0;i<len;i++){
            var s = str[i];
            if(codearr[s] === undefined){
                return false;
            }
        }
        return true;
    }
}

<commit_msg>session<commit_after>/**
 * config:session配置
 * config.lock 用户进程锁, 默认:false(关闭),格式:[num,ms,reload],
 * config.lock = [10,500,1]
 * 仅当在session存放用户cache时才有必要将reload设置为 true
 *
 */

exports = module.exports = function(options) {
    return function (req, res, next) {
        Object.defineProperty(req, "session", { value : new session(req, res, options),  writable : false, configurable : false, enumerable :true  });
        next();
    }
}

var session = function ( req, res, options) {
    "use strict"
    var self = this,
        _sid,_uid,_store,_crypto,_delayNum = 0,
        _isStart = false,_isLock = false,_isClose = false;

    var config = Object.extend({
        id:"sessid",
        type:"cookies",   //session id 获取方式
        lock:false,
        store:null,
        fields:null,         //获取SESSION时默认获取的字段
        secret:"cosjs",
        prefix:"session",
        SKey:'_sessKey',
        LKey:'_lockKey',
        expire:0
    },options);

    this.config = function(key,val){
        if(arguments.length==2){
            config[key] = val;
        }
        else{
            return config[key] || null;
        }
    }

    this.lock = function(val){
        config['lock'] = val;
    }
    //写入数据，不会修改session,可用于临时缓存
    this.set = function (key,val,callback) {
        var uid = self.uid();
        if(!uid){
            return callback('logout','session id empty');
        }
        var store = self.store();
        store.set(uid,key,val,callback);
    }
    //获取一个或者多个在session中缓存的信息
    this.get = function (keys,callback) {
        if(arguments.length==1){
            var fields = config['fields'];
            callback = arguments[0];
        }
        else{
            var fields = Array.isArray(keys) ? keys : [keys];
            if(config['fields']){
                fields = fields.concat(config['fields']);
            }
        }

        var uid = self.uid();
        if(!uid){
            return callback('logout','session id empty');
        }

        var store = self.store();
        if(_isStart){
            store.get(uid,fields,callback);
        }
        else{
            start(store,uid,fields,callback);
        }
    }
    //删除一个或者多个在session中缓存的信息，keys==null,删除所有信息，退出登录
    this.del = function(keys,callback){
        var hash = self.key();
        if(!hash){
            return callback('logout','session id empty');
        }
        var store = self.store();
        store.del(hash,keys,callback);
    }
    //创建session
    this.create = function (uid,data,callback) {
        var crypto = self.crypto();
        var id = crypto.encode(uid);
        if(!id){
            return callback('error','create session id error');
        }
        _sid = id;
        _uid = uid;
        var store = self.store();
        var newData = Object.clone(data);
        newData[config['SKey']] = id;
        newData[config['LKey']] = 0;
        store.set(uid,newData,function(err,ret){
            if(err){
                return callback(err,ret);
            }
            //自动创建cookie
            if(config['type']=='cookies'){
                res.cookie(config['id'], id, { maxAge: config['expire'] * 1000, httpOnly: true });
            }
            _isStart = true;
            return callback(null,id);
        });
    }

    //获取并检查session id
    this.sid = function () {
        if(_sid || _sid===null){
            return _sid;
        }
       return _sid = params(config['id'],config['type']);
    }
    //获取uid
    this.uid = function(){
        if(_uid){
            return _uid;
        }
        var sid = self.sid();
        if(!sid){
            return null;
        }
        var crypto = self.crypto();
        _uid = crypto.decode(sid);
        return _uid;
    }

    this.store = function () {
        if(_store){
            return _store;
        }
        var store = config['store'];
        if(!store){
            throw new Error('session config[store] empty');
        }
        if(typeof store == 'function'){
            _store = store(req,res);
        }
        else if(typeof store == 'object'){
            _store = store;
        }
        else{
            _store = require('./redis').hash(store,config['prefix']);
        }
        return _store;
    }

    this.crypto = function(){
        if(_crypto){
            return _crypto;
        }
        _crypto = new session_crypto(config['secret']);
        return _crypto;
    }

    var params = function(key,querykey){
        var getVal = function(k){
            if(!req[k]){
                return null;
            }
            else{
                return req[k][key] || null;
            }
        }

        if(!querykey){
            return null;
        }
        if(!Array.isArray(querykey)){
            querykey = [querykey];
        }

        for(var i in querykey){
            var v = getVal(querykey[i]);
            if(v !== null){
                return v;
            }
        }
        return null;
    }
    //解锁session
    var unlock = function(){
        if(!_isLock){
            return false;
        }
        _isLock = false;
        var uid = self.uid();
        if(!uid){
            return false;
        }
        var store = self.store();
        store.set(uid,config['LKey'],0,function(){});
    }
    //启动并验证SESSION
    var start = function(store,uid,keys,callback){

        res.on('close',function(){  _isClose = true; unlock(); });
        res.on('finish',unlock);

        var data;
        var sid = self.sid();
        if(!sid){
            return callback('logout','session id empty');
        }
        var Check = function(){
            store.incr(uid, config['LKey'], 1, function (err, ret) {
                if (err) {
                    callback(err, ret);
                }
                else if (ret > 1) {
                    Delay();
                }
                else {
                    _isLock = true;
                    _isClose ? unlock() : Result();
                }
            });
        }

        var Delay = function(){
            _delayNum ++;
            if( _delayNum >= config['lock'][0] ){
                callback("locked",_delayNum);
            }
            else{
                setTimeout(Check,config['lock'][1]);
            }
        }

        var Result = function(){
            if( _delayNum > 0 && config['lock'][2] ){
                start(store,uid,keys,callback);   //数据失去时效,其他程序已经修改过session和cache,重新获取数据[仅cache和session放在一起时使用]
            }
            else{
                callback(null, data);
                if(config['expire']){
                    store.expire(uid,config['expire'],function(){});
                }
            }
        }

        keys.push(config['SKey']);
        keys.push(config['LKey']);
        store.get(uid, keys, function (err, ret) {
            if (err) {
                return callback(err, ret);
            }
            else if (!ret) {
                return callback('logout', 'session not exist');
            }

            var ret_SVal = ret[config['SKey']]||'';
            var ret_LVal = ret[config['LKey']]||0;
            delete ret[config['SKey']];
            delete ret[config['LKey']];
            data = ret;
            if ( !ret_SVal || sid != ret_SVal) {
                return callback("logout", "session id illegal");
            }
            _isStart = true;  //已经验证用户SESSION有效
            if(!config['lock']){
                return Result();
            }

            if (ret_LVal > 0) {
                Delay();
            }
            else{
                Check();
            }
        });
    }

}

var session_crypto = function(secret){
    var codestr = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    var codearr = {};
    var codelen = codestr.length;
    var secrlen = 4;

    for(var i=0;i<codelen;i++){
        var k = codestr[i];
        codearr[k] = i;
    }

    this.key = '';

    this.secret = secret||'';

    this.encode = function(str) {
        if( isSafe(str) ){
            this.key = str;
        }
        else{
            this.key = String.md5(str);
        }
        var code = String.md5( parseInt(Math.random()* 1000).toString()).substr(0,secrlen);
        var skey = String.md5(code + this.secret);

        var arr = [];
        var len = this.key.length;
        for(var i =0;i<len;i++){
            var s1 = this.key[i];
            var m = i % secrlen;
            var s2 = skey[m];
            var n = codearr[s1] + codearr[s2];
            if(n >= codelen){
                n -= codelen;
            }
            arr.push(codestr[n]);
        }
        return code + arr.join('');
    }

    this.decode = function(str) {
        if(!isSafe(str)){
            return false;
        }
        var code  = str.substr(0,secrlen);
        var skey  = String.md5(code + this.secret);
        var secr  = str.substr(secrlen);

        var arr = [];
        var len = secr.length;
        for(var i =0;i<len;i++){
            var s1 = secr[i];
            var m = i % secrlen;
            var s2 = skey[m];
            var n = codearr[s1] - codearr[s2];
            if(n < 0){
                n += codelen;
            }
            arr.push(codestr[n]);
        }
        this.key = arr.join('');
        return this.key;
    }

    var isSafe = function(str){
        var len = str.length;
        for(var i=0;i<len;i++){
            var s = str[i];
            if(codearr[s] === undefined){
                return false;
            }
        }
        return true;
    }
}

<|endoftext|>


<commit_before>var EE = require('./event_stream_emitter');
var inherits = require('inherits');
var uuid = require('uuid');

function Session(dataOrId) {
    switch (typeof dataOrId) {
        case 'object':
            this.setData(dataOrId);
            break;
        default:
            this.id = dataOrId || uuid.v4();
            this.results = [];
    }
}

inherits(Session, EE);

Session.prototype.getData = function() {
    return {
        id: this.id,
        results: this.results
    };
};

Session.prototype.setData = function(data) {
    if (this.id !== undefined && data.id !== this.id) throw new Error('session data id mismatch');
    this.results = data.results;
    this.emit('change');
};

Session.prototype.addResult = function(result) {
    this.results.push(result);
    this.emit('resultAdd', result);
    this.emit('change');
};

module.exports = Session;
<commit_msg>session: set id on load if none<commit_after>var EE = require('./event_stream_emitter');
var inherits = require('inherits');
var uuid = require('uuid');

function Session(dataOrId) {
    switch (typeof dataOrId) {
        case 'object':
            this.setData(dataOrId);
            break;
        default:
            this.id = dataOrId || uuid.v4();
            this.results = [];
    }
}

inherits(Session, EE);

Session.prototype.getData = function() {
    return {
        id: this.id,
        results: this.results
    };
};

Session.prototype.setData = function(data) {
    if (this.id !== undefined && data.id !== this.id) throw new Error('session data id mismatch');
    if (this.id === undefined) this.id = data.id;
    this.results = data.results;
    this.emit('change');
};

Session.prototype.addResult = function(result) {
    this.results.push(result);
    this.emit('resultAdd', result);
    this.emit('change');
};

module.exports = Session;
<|endoftext|>


<commit_before>/**
 * Short description of
 * Version: $Id$
 * Author: Goran Miskovic <goran.miskovic at orchard-software.net>
 */
<commit_msg>added sockets lib skeleton.<commit_after>/**
 * Short description of
 * Version: $Id$
 * Author: Goran Miskovic <goran.miskovic at orchard-software.net>
 */
"use strict";

exports.init = function (server, conncet, config) {
    var io = require('socket.io'),
        onConnection,
        onRequests,
        authorization,
        listener;

    onConnection = function (client) {
        console.info('connection created.');
    };
    onRequests = function () {
        console.info('request event');
    };
    authorization = function () {
        console.info('handle connection');
    };

    listener = io.listent(server);

    listener.sockets.on('connection', onConnection);
    listener.set('request', onRequests);
    listener.set('authorization', authorization);
};<|endoftext|>