<commit_before>'use strict';
const _ = require('lodash');
const Twit = require('twit');
const redis = require('redis');

// TODO: when a user deauths, remove from DB
// NOTE: we don't know when a user deauths! but we probably get some errors
// when that happens, so we should test that out manually, catch the error
// message, and delete (though I guess it's possible for someone's auth to just
// run out, too?)

class Stream {
  constructor(profile, secret, app, UNMUTE) {
    let client = app.get('client');
    this.stream = null;
    this.app = app;
    // A stream is a userid and a set of keys
    // This needs to be stored in redis
    // Let's serialize the keys as a JSON blob and then put the
    // the blob in a hash where the key is the... let's do TWITTER ID
    // instead of userid since username can change

    /* In this constructor, we're going to check if
    "HEXISTS supermute-users ${profile.id_str}"
    and if does NOT, then we create a new entry,
    "HSET supermute-users {$profile.id_str} json-blob".

    Either way, we then instantiate local variables and we fire up this stream.
    */

    client.hexists(`supermute-users`, profile.id_str, (err, exists) => {
      let userdata = {
        credentials: {
          access_token: profile.access_token,
          access_token_secret: profile.access_token_secret
        },
        supermutes: []
      };
      this.userid = profile.id_str;
      let creds = userdata.credentials;
      // use the application's consumer stuff but the user's access stuff
      creds.consumer_key = this.app.get('twitterCredentials').consumer_key;
      creds.consumer_secret = this.app.get('twitterCredentials').consumer_secret;
      console.log(creds);
      this.T = new Twit(creds);

      // This user doesn't exist in the DB yet so we create a blank entry
      // and include the new keyword and expiration date
      // mutedUsers and isExpired are empty because we're intializing
      if (!exists) {
        console.log(`writing ${profile.id_str} to database...`);
        // TODO hash our application credentials???? maybe??
        client.hset(`supermute-users`, profile.id_str, JSON.stringify(userdata), redis.print);
        // save our userdata to this stream object
        this.userdata = userdata;
      }
      else {
        // do nothing
      }

      // start the stream
      this.start(UNMUTE);
    });
  }

  start() {
    // if our stream is running, stop it. then start it up again regardless.
    if (this.stream && typeof this.stream.stop === 'function') {
      this.stream.stop();
      console.log('stopping stream...');
    }

    // start listening for mentions of our bot name
    console.log('starting stream...');
    this.stream = this.T.stream('user', { });

    let client = this.app.get('client');
    client.hget(`supermute-users`, this.userid, (err, userdataDb) => {
      this.userdata = JSON.parse(userdataDb);
    });

    this.stream.on('tweet', eventMsg => {
      console.log(eventMsg);
      // get all our different defined keywords
      let activeSupermutes = this.userdata.supermutes.filter(supermute => !supermute.isExpired);
      let keywords = activeSupermutes.map(supermute => supermute.keyword.toLowerCase());
      console.log('active keywords',this.userid, keywords);

      const text = eventMsg.text.toLowerCase();
      let user = eventMsg.user.screen_name.toLowerCase();
      let userid = eventMsg.user.id_str;
      // if this is a retweet, the user is actually the retweeted user
      if (eventMsg.retweeted_status) {
        userid = eventMsg.retweeted_status.user.id_str;
        user = eventMsg.retweeted_status.user.screen_name.toLowerCase();
      }

      // If this is US, do nothing (we don't mute ourselves, though Twitter would throw an error anyway)
      if (userid === this.userid) {
        // do nothing
      }
      // otherwise, we go ahead with our main logic
      else {
        // check if there's a keyword in the tweet that came to us (undefined if nothing)
        const wordFound = _.find(keywords, keyword => text.indexOf(keyword) !== -1);
        if (wordFound) {
          console.log(`Muting now`,user,text);
          this.T.post('mutes/users/create', { screen_name: user }, (err, data) => {
            if (err) {
              console.log('err',err);
            }
            else {
              console.log(err,data);
              if (data.muting) {
                console.log(`not muting ${user} because they are already muted for ${this.userid}`);
              }
              else {
                console.log(`muting ${user} for ${this.userid}!`);
                let supermute = this.userdata.supermutes.filter(mute => mute.keyword.toLowerCase() === wordFound.toLowerCase())[0];
                let mute_list = supermute.mutedUsers;
                // we muted! add the muted user to the database
                const client = this.app.get('client');
                mute_list.push(user);
                mute_list = _.uniq(mute_list);
                supermute.mutedUsers = mute_list;
                console.log('pushing',mute_list.length,'unique people');
                // set the blob with the new value
                client.hset(`supermute-users`, this.userid, JSON.stringify(this.userdata), (err) => {
                  if (err) {
                    console.log('err:', err);
                  }
                  else {
                    console.log(`Updated ${this.userid}!`);
                  }
                });
              }
            }
          });
        } // end if(wordFound)
      }
    }); // end stream.on('tweet')
  } // end start()
} // end Stream

module.exports = {
  Stream
};
<commit_msg>Removing extraneous log<commit_after>'use strict';
const _ = require('lodash');
const Twit = require('twit');
const redis = require('redis');

// TODO: when a user deauths, remove from DB
// NOTE: we don't know when a user deauths! but we probably get some errors
// when that happens, so we should test that out manually, catch the error
// message, and delete (though I guess it's possible for someone's auth to just
// run out, too?)

class Stream {
  constructor(profile, secret, app, UNMUTE) {
    let client = app.get('client');
    this.stream = null;
    this.app = app;
    // A stream is a userid and a set of keys
    // This needs to be stored in redis
    // Let's serialize the keys as a JSON blob and then put the
    // the blob in a hash where the key is the... let's do TWITTER ID
    // instead of userid since username can change

    /* In this constructor, we're going to check if
    "HEXISTS supermute-users ${profile.id_str}"
    and if does NOT, then we create a new entry,
    "HSET supermute-users {$profile.id_str} json-blob".

    Either way, we then instantiate local variables and we fire up this stream.
    */

    client.hexists(`supermute-users`, profile.id_str, (err, exists) => {
      let userdata = {
        credentials: {
          access_token: profile.access_token,
          access_token_secret: profile.access_token_secret
        },
        supermutes: []
      };
      this.userid = profile.id_str;
      let creds = userdata.credentials;
      // use the application's consumer stuff but the user's access stuff
      creds.consumer_key = this.app.get('twitterCredentials').consumer_key;
      creds.consumer_secret = this.app.get('twitterCredentials').consumer_secret;
      console.log(creds);
      this.T = new Twit(creds);

      // This user doesn't exist in the DB yet so we create a blank entry
      // and include the new keyword and expiration date
      // mutedUsers and isExpired are empty because we're intializing
      if (!exists) {
        console.log(`writing ${profile.id_str} to database...`);
        // TODO hash our application credentials???? maybe??
        client.hset(`supermute-users`, profile.id_str, JSON.stringify(userdata), redis.print);
        // save our userdata to this stream object
        this.userdata = userdata;
      }
      else {
        // do nothing
      }

      // start the stream
      this.start(UNMUTE);
    });
  }

  start() {
    // if our stream is running, stop it. then start it up again regardless.
    if (this.stream && typeof this.stream.stop === 'function') {
      this.stream.stop();
      console.log('stopping stream...');
    }

    // start listening for mentions of our bot name
    console.log('starting stream...');
    this.stream = this.T.stream('user', { });

    let client = this.app.get('client');
    client.hget(`supermute-users`, this.userid, (err, userdataDb) => {
      this.userdata = JSON.parse(userdataDb);
    });

    this.stream.on('tweet', eventMsg => {
      // get all our different defined keywords
      let activeSupermutes = this.userdata.supermutes.filter(supermute => !supermute.isExpired);
      let keywords = activeSupermutes.map(supermute => supermute.keyword.toLowerCase());
      console.log('active keywords',this.userid, keywords);

      const text = eventMsg.text.toLowerCase();
      let user = eventMsg.user.screen_name.toLowerCase();
      let userid = eventMsg.user.id_str;
      // if this is a retweet, the user is actually the retweeted user
      if (eventMsg.retweeted_status) {
        userid = eventMsg.retweeted_status.user.id_str;
        user = eventMsg.retweeted_status.user.screen_name.toLowerCase();
      }

      // If this is US, do nothing (we don't mute ourselves, though Twitter would throw an error anyway)
      if (userid === this.userid) {
        // do nothing
      }
      // otherwise, we go ahead with our main logic
      else {
        // check if there's a keyword in the tweet that came to us (undefined if nothing)
        const wordFound = _.find(keywords, keyword => text.indexOf(keyword) !== -1);
        if (wordFound) {
          console.log(`Muting now`,user,text);
          this.T.post('mutes/users/create', { screen_name: user }, (err, data) => {
            if (err) {
              console.log('err',err);
            }
            else {
              console.log(err,data);
              if (data.muting) {
                console.log(`not muting ${user} because they are already muted for ${this.userid}`);
              }
              else {
                console.log(`muting ${user} for ${this.userid}!`);
                let supermute = this.userdata.supermutes.filter(mute => mute.keyword.toLowerCase() === wordFound.toLowerCase())[0];
                let mute_list = supermute.mutedUsers;
                // we muted! add the muted user to the database
                const client = this.app.get('client');
                mute_list.push(user);
                mute_list = _.uniq(mute_list);
                supermute.mutedUsers = mute_list;
                console.log('pushing',mute_list.length,'unique people');
                // set the blob with the new value
                client.hset(`supermute-users`, this.userid, JSON.stringify(this.userdata), (err) => {
                  if (err) {
                    console.log('err:', err);
                  }
                  else {
                    console.log(`Updated ${this.userid}!`);
                  }
                });
              }
            }
          });
        } // end if(wordFound)
      }
    }); // end stream.on('tweet')
  } // end start()
} // end Stream

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


<commit_before>module.exports = {
  name: '#field-name',
  statusActive: '[for="field-archived-1"]',
  statusInactive: '[for="field-archived-2"]',
  ukRegion: '#group-field-uk_region',
  usState: '#group-field-us_state',
  ukPostcode: '#field-uk_postcode',
  completedOnAfterTextInput: '#field-completed_on_after',
  country: '#group-field-country',
  sector: '#group-field-sector_descends',
  exportingTo: '#group-field-export_to_countries',
  interestedIn: '#group-field-future_interest_countries',
  firstInteractionDate: '[for="field-interaction_between-1"]',
  leadIta: '#group-field-one_list_group_global_account_manager',
  contacts: {
    sector: '#group-field-company_sector_descends',
    companyName: '#field-company_name',
    country: '#group-field-address_country',
    ukRegion: '#group-field-company_uk_region',
  },
  interaction: {
    myInteractions: '[for="field-dit_participants__adviser-1"]',
  },
  investments: {
    companyName: '#group-field-sector_descends',
    country: '#group-field-investor_company_country',
    ukRegion: '#group-field-uk_region_location',
    sector: '#group-field-sector_descends',
  },
  omis: {
    country: '#group-field-primary_market',
    firstUkRegion: '[for="field-uk_region-1"]',
    sector: '#group-field-sector_descends',
  },
  events: {
    country: '#group-field-address_country',
    ukRegion: '#group-field-uk_region',
  },
  companies: {
    country: '#group-field-address_country',
    sector: '#group-field-company_sector_descends',
  },
  typeahead(id) {
    return {
      fieldset: id,
      placeHolder: `${id} .multiselect__tags`,
      textInput: `${id} .multiselect__input`,
      selectedOption: `${id} .multiselect`,
      addAnotherBtn: `${id} .js-AddItems__add--typeahead`,
      firstOption: `${id} .multiselect__element:nth-child(1)`,
      options: `${id} .multiselect__element`,
    }
  },
}
<commit_msg>Updated selector name to fix cypress test<commit_after>module.exports = {
  name: '#field-name',
  statusActive: '[for="field-archived-1"]',
  statusInactive: '[for="field-archived-2"]',
  ukRegion: '#group-field-uk_region',
  usState: '#group-field-area',
  ukPostcode: '#field-uk_postcode',
  completedOnAfterTextInput: '#field-completed_on_after',
  country: '#group-field-country',
  sector: '#group-field-sector_descends',
  exportingTo: '#group-field-export_to_countries',
  interestedIn: '#group-field-future_interest_countries',
  firstInteractionDate: '[for="field-interaction_between-1"]',
  leadIta: '#group-field-one_list_group_global_account_manager',
  contacts: {
    sector: '#group-field-company_sector_descends',
    companyName: '#field-company_name',
    country: '#group-field-address_country',
    ukRegion: '#group-field-company_uk_region',
  },
  interaction: {
    myInteractions: '[for="field-dit_participants__adviser-1"]',
  },
  investments: {
    companyName: '#group-field-sector_descends',
    country: '#group-field-investor_company_country',
    ukRegion: '#group-field-uk_region_location',
    sector: '#group-field-sector_descends',
  },
  omis: {
    country: '#group-field-primary_market',
    firstUkRegion: '[for="field-uk_region-1"]',
    sector: '#group-field-sector_descends',
  },
  events: {
    country: '#group-field-address_country',
    ukRegion: '#group-field-uk_region',
  },
  companies: {
    country: '#group-field-address_country',
    sector: '#group-field-company_sector_descends',
  },
  typeahead(id) {
    return {
      fieldset: id,
      placeHolder: `${id} .multiselect__tags`,
      textInput: `${id} .multiselect__input`,
      selectedOption: `${id} .multiselect`,
      addAnotherBtn: `${id} .js-AddItems__add--typeahead`,
      firstOption: `${id} .multiselect__element:nth-child(1)`,
      options: `${id} .multiselect__element`,
    }
  },
}
<|endoftext|>


<commit_before>var CloudCmd, Util, DOM, $;
(function(CloudCmd, Util, DOM){
    'use strict';

    CloudCmd.Console = new ConsoleProto(CloudCmd, Util, DOM);

    function ConsoleProto(CloudCmd, Util, DOM){
        var Name    = 'Console',
            Key     = CloudCmd.Key,
            Images  = DOM.Images,
            Console = this;

        this.init                = function(pCallBack){
            Util.loadOnLoad([
                Console.show,
                load,
                CloudCmd.View,
                DOM.jqueryLoad,
            ]);

            DOM.Events.addKey(listener);

            delete Console.init;
        };

        this.show                       = function(){
            var lElement, lViewElement;

            Images.showLoad({top:true});

            lViewElement     = DOM.anyload({
                name        : 'div',
                id          : 'view',
                attribute   : {
                    tabindex : 0
                },
                not_append  : true
            }),

            lElement    = DOM.anyload({
                name        : 'div',
                className   : 'console',
                parent      : lViewElement
            }),

            $(lElement).console({
                promptLabel: '# ',
                commandValidate : function(line){
                    var lRet = line !== "";

                    return lRet;
                },
                commandHandle   : function(line){
                    return line;
                },
                autofocus       : true,
                animateScroll   : true,
                promptHistory   : true,
            });

            CloudCmd.View.show(lViewElement);
        };

        this.hide                       =  function(){
            CloudCmd.View.hide();
        };

        function load(pCallBack){
            Util.time(Name + ' load');

            var lDir    =  CloudCmd.LIBDIRCLIENT + 'terminal/jquery-console/',
                lFiles  = [
                    lDir + 'jquery.console.js',
                    lDir + 'jquery.console.css'
                ];

            DOM.anyLoadInParallel(lFiles, function(){
                console.timeEnd(Name + ' load');

                Util.exec(pCallBack);
            });
        }

        function listener(pEvent){
            var lF10        = Key.F10,
                lESC        = Key.ESC,
                lIsBind     = Key.isBind(),
                lKey        = pEvent.keyCode;

            /* если клавиши можно обрабатывать */
            if (lIsBind)
                switch(lKey){
                    case lF10:
                        Console.show();
                        break;
                    case lESC:
                        Console.hide();
                        break;
                }

        }
    }

})(CloudCmd, Util, DOM);<commit_msg>removed lIsBind from listener<commit_after>var CloudCmd, Util, DOM, $;
(function(CloudCmd, Util, DOM){
    'use strict';

    CloudCmd.Console = new ConsoleProto(CloudCmd, Util, DOM);

    function ConsoleProto(CloudCmd, Util, DOM){
        var Name    = 'Console',
            Key     = CloudCmd.Key,
            Images  = DOM.Images,
            Console = this;

        this.init                = function(pCallBack){
            Util.loadOnLoad([
                Console.show,
                load,
                CloudCmd.View,
                DOM.jqueryLoad,
            ]);

            DOM.Events.addKey(listener);

            delete Console.init;
        };

        this.show                       = function(){
            var lElement, lViewElement;

            Images.showLoad({top:true});

            lViewElement     = DOM.anyload({
                name        : 'div',
                id          : 'view',
                attribute   : {
                    tabindex : 0
                },
                not_append  : true
            }),

            lElement    = DOM.anyload({
                name        : 'div',
                className   : 'console',
                parent      : lViewElement
            }),

            $(lElement).console({
                promptLabel: '# ',
                commandValidate : function(line){
                    var lRet = line !== "";

                    return lRet;
                },
                commandHandle   : function(line){
                    return line;
                },
                autofocus       : true,
                animateScroll   : true,
                promptHistory   : true,
            });

            CloudCmd.View.show(lViewElement);
        };

        this.hide                       =  function(){
            CloudCmd.View.hide();
        };

        function load(pCallBack){
            Util.time(Name + ' load');

            var lDir    =  CloudCmd.LIBDIRCLIENT + 'terminal/jquery-console/',
                lFiles  = [
                    lDir + 'jquery.console.js',
                    lDir + 'jquery.console.css'
                ];

            DOM.anyLoadInParallel(lFiles, function(){
                console.timeEnd(Name + ' load');

                Util.exec(pCallBack);
            });
        }

        function listener(pEvent){
            var lF10        = Key.F10,
                lESC        = Key.ESC,
                lIsBind     = Key.isBind(),
                lKey        = pEvent.keyCode;

            switch(lKey){
                case lF10:
                    Console.show();
                    break;
                case lESC:
                    Console.hide();
                    break;
            }

        }
    }

})(CloudCmd, Util, DOM);<|endoftext|>


<commit_before>var coldstart = true;
var startupTime = new Date();
var startupThreshold = 1000; // ms
var paused = false;

var _atStartup = function() {
  // If we were triggered before resume then its a startup
  if (paused) return true;

  // If startup time is less than startupThreshold ago then lets say this is
  // at startup.
  return (new Date() - startupTime < startupThreshold);
};

Push.setBadge = function(count) {
  document.addEventListener('deviceready', function() {
    // Helper
    var pushNotification = window.plugins.pushNotification;

    // If the set application badge is available
    if (typeof pushNotification.setApplicationIconBadgeNumber == 'function') {
      // Set the badge
      pushNotification.setApplicationIconBadgeNumber(function(result) {
        // Success callback
      }, function(err) {
        // Error callback
        Push.emit('error', { type: 'badge', error: err });
      }, count);

    }
  });
};

_parsePayload = function(value) {
  // Android actually parses payload into an object - this is not the case with
  // iOS (here is it just a string)
  if (value !== ''+value) value = JSON.stringify(value);

  // Run the string through ejson
  try {
    return EJSON.parse(value);
  } catch(err) {
    return { error: err };
  }
};

var onNotification = function(notification) {
  // alert('onNotification' + JSON.stringify(notification));

  // Emit alert event - this requires the app to be in forground
  if (notification.message && notification.foreground)
    Push.emit('alert', notification);

  // Emit sound event
  if (notification.sound) Push.emit('sound', notification);

  // Emit badge event
  if (notification.badge) Push.emit('badge', notification);

  // If within thres
  if (notification.open) {
    Push.emit('startup', notification);
  } else {
    Push.emit('message', notification);
  }
};

// handle APNS notifications for iOS
onNotificationAPN = function(e) {
  // alert('onNotificationAPN ' + JSON.stringify(e));

  var sound = e.sound;

  // Only prefix sound if actual text found
  if (sound && sound.length) sound = 'application/' + sound;

  // XXX: Investigate if we need more defaults
  var unifiedMessage = {
    message: e.alert,
    sound: sound,
    badge: e.badge,
    coldstart: coldstart,
    background: !e.foreground,
    foreground: !!e.foreground,
    open: _atStartup(),
    type: 'apn.cordova'
  };

  // E.ejson should be a string - we send it directly to payload
  if (e.ejson) unifiedMessage.payload = _parsePayload(e.ejson);

  // Trigger notification
  onNotification(unifiedMessage);
};

// handle GCM notifications for Android and Fire OS
onNotificationGCM = function(e) {
  // alert('onNotificationGCM ' + JSON.stringify(e));

  switch( e.event ) {
    case 'registered':
      if ( e.regid.length > 0 ) {
        Push.emit('token', { gcm: ''+e.regid } );
      }
    break;

    case 'message':

      var sound = e.soundname || e.payload.sound;

      // Only prefix sound if actual text found
      if (sound && sound.length) sound = '/android_asset/www/application/' + sound;

      // XXX: Investigate if we need more defaults
      var unifiedMessage = {
        message: e.payload.message || e.msg || '',
        sound: sound,
        badge: e.payload.msgcnt,
        // Coldstart on android is a bit inconsistent - its only set when the
        // notification opens the app
        coldstart: (e.coldstart === !!e.coldstart) ? e.coldstart : coldstart,
        background: !e.foreground,
        foreground: !!e.foreground,
        // open: _atStartup(),  // This is the iOS implementation
        open: (e.coldstart === !!e.coldstart), // If set true / false its an open event
        type: 'gcm.cordova'
      };

      // If payload.ejson this is an object - we hand it over to parsePayload,
      // parsePayload will do the convertion for us
      if (e.payload.ejson) unifiedMessage.payload = _parsePayload(e.payload.ejson);

      // Trigger notification
      onNotification(unifiedMessage);
    break;

    case 'error':
      // e.msg
      Push.emit('error', { type: 'gcm.cordova', error: e });
    break;
  }
};

var rigDefaultEventListeners = function(options) {
  // alert('RIG: ' + JSON.stringify(options));

  // Set default badge behaviour
  if (options.badge === true) Push.addListener('badge', function(notification) {
    Push.setBadge(notification.badge);
  });

  // Set default sound behaviour
  if (options.sound === true) Push.addListener('sound', function(notification) {
    if (notification.sound && notification.sound.length) {
      var snd = new Media(notification.sound);
      snd.play();
    }
  });

  // Set default alert behaviour
  if (options.alert === true) Push.addListener('alert', function(notification) {

    // if (navigator && navigator.notification && navigator.notification.alert) {
    //   // If native notifications installed
    //   navigator.notification.alert(notification.message);
    // } else {
    //   // Use regular notification
    //   alert(notification.message);
    // }
  });

  // We add a vibrate listener
  if (options.vibrate === true) Push.addListener('message', function(notification) {
    // Vibrate if possible
    if (navigator && navigator.notification && navigator.notification.vibrate) {
      // If vibrate installed
      navigator.notification.vibrate(500);
    }
  });
};

var isConfigured = false;

Push.Configure = function(options) {
  var self = this;

  // Block multiple calls
  if (isConfigured)
    throw new Error('Push.Configure should not be called more than once!');

  isConfigured = true;

  // Clean up options, make sure the projectNumber
  if (options.gcm && !options.gcm.projectNumber)
    throw new Error('Push.Configure gcm got no projectNumber');

  // Client-side security warnings
  checkClientSecurity(options);

  // Set default options - these are needed for apn?
  options = _.extend({
    badge: (options.badge === true),
    sound: (options.sound === true),
    alert: (options.alert === true),
    vibrate: (options.vibrate === true)
  }, options);

  // Rig default event listeners for badge/sound/alert/vibrate
  rigDefaultEventListeners(options);

  // Add debug info
  if (Push.debug) console.log('Push.Configure', options);

  // Start token updates
  initPushUpdates(options.appName);

    // Initialize on ready
  Meteor.startup(function() {

    document.addEventListener('deviceready', function() {

      // At initial startup set startup time
      startupTime = new Date();

      // Update flag if app coldstart
      document.addEventListener("pause", function() {
        paused = true;
        coldstart = false;
      }, false);

      document.addEventListener('resume', function() {
        paused = false;
        // Reset startup time at resume
        startupTime = new Date();
      });

      var pushNotification = window.plugins.pushNotification;

      if (device.platform == 'android' || device.platform == 'Android') {
        // alert('Rig GCM');
        try {

          if (options.gcm && options.gcm.projectNumber) {
            pushNotification.register(function(result) {
              // Emit registered
              self.emit('register', result);
            }, function(error) {
              // Emit error
              self.emit('error', { type: 'gcm.cordova', error: error });
            }, {
              'senderID': ''+options.gcm.projectNumber,
              'ecb': 'onNotificationGCM'
            });
          } else {
            // throw new Error('senderID not set in options, required on android');
            console.warn('WARNING: Push.init, No gcm.projectNumber set on android');
          }

        } catch(err) {
          // console.log('There was an error starting up push');
          // console.log('Error description: ' + err.message);
          self.emit('error', { type: 'gcm.cordova', error: err.message });
        }
      } else {
        // alert('Rig APN');

        try {

          pushNotification.register(function(token) {
            // Got apn / ios token
            self.emit('token', { apn: token });
          }, function(error) {
            // Emit error
            self.emit('error', { type: 'apn.cordova', error: error });
          }, {
            'badge': ''+options.badge,
            'sound': ''+options.sound,
            'alert': ''+options.alert,
            'ecb': 'onNotificationAPN'
          }); // required!
        } catch(err) {
          // console.log('There was an error starting up push');
          // console.log('Error description: ' + err.message);
          self.emit('error', { type: 'apn.cordova', error: err.message });
        }
      }

    }, false);

  });

}; // EO Push
<commit_msg>Respect resume - if paused wait until resume before triggering start up events<commit_after>var coldstart = true;
var startupTime = new Date();
var startupThreshold = 1000; // ms
var paused = false;
var waitingMessage = null;

var _atStartup = function() {
  // If we were triggered before resume then its a startup
  if (paused) return true;

  // If startup time is less than startupThreshold ago then lets say this is
  // at startup.
  return (new Date() - startupTime < startupThreshold);
};

Push.setBadge = function(count) {
  document.addEventListener('deviceready', function() {
    // Helper
    var pushNotification = window.plugins.pushNotification;

    // If the set application badge is available
    if (typeof pushNotification.setApplicationIconBadgeNumber == 'function') {
      // Set the badge
      pushNotification.setApplicationIconBadgeNumber(function(result) {
        // Success callback
      }, function(err) {
        // Error callback
        Push.emit('error', { type: 'badge', error: err });
      }, count);

    }
  });
};

_parsePayload = function(value) {
  // Android actually parses payload into an object - this is not the case with
  // iOS (here is it just a string)
  if (value !== ''+value) value = JSON.stringify(value);

  // Run the string through ejson
  try {
    return EJSON.parse(value);
  } catch(err) {
    return { error: err };
  }
};

var onNotification = function(notification) {
  // alert('onNotification' + JSON.stringify(notification));

  // Emit alert event - this requires the app to be in forground
  if (notification.message && notification.foreground)
    Push.emit('alert', notification);

  // Emit sound event
  if (notification.sound) Push.emit('sound', notification);

  // Emit badge event
  if (notification.badge) Push.emit('badge', notification);

  // If within thres
  if (notification.open) {
    Push.emit('startup', notification);
  } else {
    Push.emit('message', notification);
  }
};

// handle APNS notifications for iOS
onNotificationAPN = function(e) {
  // alert('onNotificationAPN ' + JSON.stringify(e));

  var sound = e.sound;

  // Only prefix sound if actual text found
  if (sound && sound.length) sound = 'application/' + sound;

  // XXX: Investigate if we need more defaults
  var unifiedMessage = {
    message: e.alert,
    sound: sound,
    badge: e.badge,
    coldstart: coldstart,
    background: !e.foreground,
    foreground: !!e.foreground,
    open: _atStartup(),
    type: 'apn.cordova'
  };

  // E.ejson should be a string - we send it directly to payload
  if (e.ejson) unifiedMessage.payload = _parsePayload(e.ejson);

  if (paused) {
    waitingMessage = unifiedMessage;
  } else {
    // Trigger notification
    onNotification(unifiedMessage);
  }
};

// handle GCM notifications for Android and Fire OS
onNotificationGCM = function(e) {
  // alert('onNotificationGCM ' + JSON.stringify(e));

  switch( e.event ) {
    case 'registered':
      if ( e.regid.length > 0 ) {
        Push.emit('token', { gcm: ''+e.regid } );
      }
    break;

    case 'message':

      var sound = e.soundname || e.payload.sound;

      // Only prefix sound if actual text found
      if (sound && sound.length) sound = '/android_asset/www/application/' + sound;

      // XXX: Investigate if we need more defaults
      var unifiedMessage = {
        message: e.payload.message || e.msg || '',
        sound: sound,
        badge: e.payload.msgcnt,
        // Coldstart on android is a bit inconsistent - its only set when the
        // notification opens the app
        coldstart: (e.coldstart === !!e.coldstart) ? e.coldstart : coldstart,
        background: !e.foreground,
        foreground: !!e.foreground,
        // open: _atStartup(),  // This is the iOS implementation
        open: (e.coldstart === !!e.coldstart), // If set true / false its an open event
        type: 'gcm.cordova'
      };

      // If payload.ejson this is an object - we hand it over to parsePayload,
      // parsePayload will do the convertion for us
      if (e.payload.ejson) unifiedMessage.payload = _parsePayload(e.payload.ejson);

      if (paused) {
        waitingMessage = unifiedMessage;
      } else {
        // Trigger notification
        onNotification(unifiedMessage);
      }
    break;

    case 'error':
      // e.msg
      Push.emit('error', { type: 'gcm.cordova', error: e });
    break;
  }
};

var rigDefaultEventListeners = function(options) {
  // alert('RIG: ' + JSON.stringify(options));

  // Set default badge behaviour
  if (options.badge === true) Push.addListener('badge', function(notification) {
    Push.setBadge(notification.badge);
  });

  // Set default sound behaviour
  if (options.sound === true) Push.addListener('sound', function(notification) {
    if (notification.sound && notification.sound.length) {
      var snd = new Media(notification.sound);
      snd.play();
    }
  });

  // Set default alert behaviour
  if (options.alert === true) Push.addListener('alert', function(notification) {

    // if (navigator && navigator.notification && navigator.notification.alert) {
    //   // If native notifications installed
    //   navigator.notification.alert(notification.message);
    // } else {
    //   // Use regular notification
    //   alert(notification.message);
    // }
  });

  // We add a vibrate listener
  if (options.vibrate === true) Push.addListener('message', function(notification) {
    // Vibrate if possible
    if (navigator && navigator.notification && navigator.notification.vibrate) {
      // If vibrate installed
      navigator.notification.vibrate(500);
    }
  });
};

var isConfigured = false;

Push.Configure = function(options) {
  var self = this;

  // Block multiple calls
  if (isConfigured)
    throw new Error('Push.Configure should not be called more than once!');

  isConfigured = true;

  // Clean up options, make sure the projectNumber
  if (options.gcm && !options.gcm.projectNumber)
    throw new Error('Push.Configure gcm got no projectNumber');

  // Client-side security warnings
  checkClientSecurity(options);

  // Set default options - these are needed for apn?
  options = _.extend({
    badge: (options.badge === true),
    sound: (options.sound === true),
    alert: (options.alert === true),
    vibrate: (options.vibrate === true)
  }, options);

  // Rig default event listeners for badge/sound/alert/vibrate
  rigDefaultEventListeners(options);

  // Add debug info
  if (Push.debug) console.log('Push.Configure', options);

  // Start token updates
  initPushUpdates(options.appName);

    // Initialize on ready
  Meteor.startup(function() {

    document.addEventListener('deviceready', function() {

      // At initial startup set startup time
      startupTime = new Date();

      // Update flag if app coldstart
      document.addEventListener("pause", function() {
        paused = true;
        coldstart = false;
      }, false);

      document.addEventListener('resume', function() {
        paused = false;
        // Reset startup time at resume
        startupTime = new Date();

        if (waitingMessage) {
          // Trigger notification
          onNotification(waitingMessage);

          // Reset waiting message
          waitingMessage = null;
        }
      });

      var pushNotification = window.plugins.pushNotification;

      if (device.platform == 'android' || device.platform == 'Android') {
        // alert('Rig GCM');
        try {

          if (options.gcm && options.gcm.projectNumber) {
            pushNotification.register(function(result) {
              // Emit registered
              self.emit('register', result);
            }, function(error) {
              // Emit error
              self.emit('error', { type: 'gcm.cordova', error: error });
            }, {
              'senderID': ''+options.gcm.projectNumber,
              'ecb': 'onNotificationGCM'
            });
          } else {
            // throw new Error('senderID not set in options, required on android');
            console.warn('WARNING: Push.init, No gcm.projectNumber set on android');
          }

        } catch(err) {
          // console.log('There was an error starting up push');
          // console.log('Error description: ' + err.message);
          self.emit('error', { type: 'gcm.cordova', error: err.message });
        }
      } else {
        // alert('Rig APN');

        try {

          pushNotification.register(function(token) {
            // Got apn / ios token
            self.emit('token', { apn: token });
          }, function(error) {
            // Emit error
            self.emit('error', { type: 'apn.cordova', error: error });
          }, {
            'badge': ''+options.badge,
            'sound': ''+options.sound,
            'alert': ''+options.alert,
            'ecb': 'onNotificationAPN'
          }); // required!
        } catch(err) {
          // console.log('There was an error starting up push');
          // console.log('Error description: ' + err.message);
          self.emit('error', { type: 'apn.cordova', error: err.message });
        }
      }

    }, false);

  });

}; // EO Push
<|endoftext|>


<commit_before>var coldstart = true;

Push.setBadge = function(count) {
  // Helper
  var pushNotification = window.plugins.pushNotification;

  // If the set application badge is available
  if (typeof pushNotification.setApplicationIconBadgeNumber == 'function') {
    // Set the badge
    pushNotification.setApplicationIconBadgeNumber(function(result) {
      // Success callback
    }, function(err) {
      // Error callback
      Push.emit('error', { type: 'badge', error: err });
    }, count);

  }
};

_stripPayload = function(payload) {
  // Strip data already used in message
  return _.omit(payload, 'title', 'sound', 'badge', 'alert', 'message', 'msgcnt', 'foreground', 'messageFrom');
};

onNotification = function(notification) {
  // alert(JSON.stringify(notification));

  // Emit alert event - this requires the app to be in forground
  if (notification.message && notification.foreground)
    Push.emit('alert', notification);

  // Emit sound event
  if (notification.sound) Push.emit('sound', notification);

  // Emit badge event
  if (notification.badge) Push.emit('badge', notification);

  // If within thres
  if (notification.background) {
    Push.emit('startup', notification);
  } else {
    Push.emit('message', notification);
  }
};

// handle APNS notifications for iOS
onNotificationAPN = function(e) {
  // alert(JSON.stringify(e));

  var sound = e.sound;

  // Only prefix sound if actual text found
  if (sound && sound.length) sound = 'application/' + sound;

  // XXX: Investigate if we need more defaults
  var unifiedMessage = {
    message: e.alert,
    sound: sound,
    badge: e.badge,
    coldstart: coldstart,
    background: !e.foreground,
    foreground: !!e.foreground,
    type: 'apn.cordova',
    payload: _stripPayload(e)
  };

  // Trigger notification
  onNotification(unifiedMessage);
};

// handle GCM notifications for Android and Fire OS
onNotificationGCM = function(e) {
  // alert(JSON.stringify(e));

  switch( e.event ) {
    case 'registered':
      if ( e.regid.length > 0 ) {
        Push.emit('token', { gcm: ''+e.regid } );
      }
    break;

    case 'message':

      var sound = e.soundname || e.payload.sound;

      // Only prefix sound if actual text found
      if (sound && sound.length) sound = '/android_asset/www/application/' + sound;

      // XXX: Investigate if we need more defaults
      var unifiedMessage = {
        message: e.payload.message || e.msg || '',
        sound: sound,
        badge: e.payload.msgcnt,
        coldstart: e.coldstart,
        background: !e.foreground,
        foreground: !!e.foreground,
        type: 'gcm.cordova',
        payload: _stripPayload(e.payload)
      };

      // Trigger notification
      onNotification(unifiedMessage);
    break;

    case 'error':
      // e.msg
      Push.emit('error', { type: 'gcm.cordova', error: e });
    break;
  }
};

var rigDefaultEventListeners = function(options) {
  // Set default badge behaviour
  if (options.badge === true) Push.addListener('badge', function(notification) {
    Push.setBadge(notification.badge);
  });

  // Set default sound behaviour
  if (options.sound === true) Push.addListener('sound', function(notification) {
    if (notification.sound && notification.sound.length) {
      var snd = new Media(notification.sound);
      snd.play();
    }
  });

  // Set default alert behaviour
  if (options.alert === true) Push.addListener('alert', function(notification) {

    if (navigator && navigator.notification && navigator.notification.alert) {
      // If native notifications installed
      navigator.notification.alert(notification.message);
    } else {
      // Use regular notification
      alert(notification.message);
    }
  });

  // We add a vibrate listener
  if (options.vibrate === true) Push.addListener('message', function(notification) {
    // Vibrate if possible
    if (navigator && navigator.notification && navigator.notification.vibrate) {
      // If vibrate installed
      navigator.notification.vibrate(500);
    }
  });
};

var isConfigured = false;

Push.Configure = function(options) {
  var self = this;

  // Block multiple calls
  if (isConfigured)
    throw new Error('Push.Configure should not be called more than once!');

  isConfigured = true;

  // Clean up options, make sure the projectNumber
  if (options.gcm && !options.gcm.projectNumber)
    throw new Error('Push.Configure gcm got no projectNumber');

  // Client-side security warnings
  checkClientSecurity(options);

  // Set default options - these are needed for apn?
  options = _.extend({
    badge: (options.badge === true),
    sound: (options.sound === true),
    alert: (options.alert === true),
    vibrate: (options.vibrate === true)
  }, options);

  // Rig default event listeners for badge/sound/alert/vibrate
  rigDefaultEventListeners(options);

  // Add debug info
  if (Push.debug) console.log('Push.Configure', options);

  // Start token updates
  initPushUpdates(options.appName);

    // Initialize on ready
  Meteor.startup(function() {

    // Update flag if app coldstart
    document.addEventListener("pause", function() {
      coldstart = false;
    }, false);

    var pushNotification = window.plugins.pushNotification;

    if (device.platform == 'android' || device.platform == 'Android') {
      try {

        if (options.gcm && options.gcm.projectNumber) {
          pushNotification.register(function(result) {
            // Emit registered
            self.emit('register', result);
          }, function(error) {
            // Emit error
            self.emit('error', { type: 'gcm.cordova', error: error });
          }, {
            'senderID': ''+options.gcm.projectNumber,
            'ecb': 'onNotificationGCM'
          });
        } else {
          // throw new Error('senderID not set in options, required on android');
          console.warn('WARNING: Push.init, No gcm.projectNumber set on android');
        }

      } catch(err) {
        // console.log('There was an error starting up push');
        // console.log('Error description: ' + err.message);
        self.emit('error', { type: 'gcm.cordova', error: err.message });
      }
    } else {

      try {

        pushNotification.register(function(token) {
          // Got apn / ios token
          self.emit('token', { apn: token });
        }, function(error) {
          // Emit error
          self.emit('error', { type: 'apn.cordova', error: error });
        }, {
          'badge': ''+options.badge,
          'sound': ''+options.sound,
          'alert': ''+options.alert,
          'ecb': 'onNotificationAPN'
        }); // required!
      } catch(err) {
        // console.log('There was an error starting up push');
        // console.log('Error description: ' + err.message);
        self.emit('error', { type: 'apn.cordova', error: err.message });
      }
    }

  }, true);

}; // EO Push
<commit_msg>exclude aps from the payload<commit_after>var coldstart = true;

Push.setBadge = function(count) {
  // Helper
  var pushNotification = window.plugins.pushNotification;

  // If the set application badge is available
  if (typeof pushNotification.setApplicationIconBadgeNumber == 'function') {
    // Set the badge
    pushNotification.setApplicationIconBadgeNumber(function(result) {
      // Success callback
    }, function(err) {
      // Error callback
      Push.emit('error', { type: 'badge', error: err });
    }, count);

  }
};

_stripPayload = function(payload) {
  // Strip data already used in message
  return _.omit(payload, 'title', 'sound', 'badge', 'alert', 'message', 'msgcnt', 'foreground', 'messageFrom', 'aps');
};

onNotification = function(notification) {
  // alert(JSON.stringify(notification));

  // Emit alert event - this requires the app to be in forground
  if (notification.message && notification.foreground)
    Push.emit('alert', notification);

  // Emit sound event
  if (notification.sound) Push.emit('sound', notification);

  // Emit badge event
  if (notification.badge) Push.emit('badge', notification);

  // If within thres
  if (notification.background) {
    Push.emit('startup', notification);
  } else {
    Push.emit('message', notification);
  }
};

// handle APNS notifications for iOS
onNotificationAPN = function(e) {
  // alert(JSON.stringify(e));

  var sound = e.sound;

  // Only prefix sound if actual text found
  if (sound && sound.length) sound = 'application/' + sound;

  // XXX: Investigate if we need more defaults
  var unifiedMessage = {
    message: e.alert,
    sound: sound,
    badge: e.badge,
    coldstart: coldstart,
    background: !e.foreground,
    foreground: !!e.foreground,
    type: 'apn.cordova',
    payload: _stripPayload(e)
  };

  // Trigger notification
  onNotification(unifiedMessage);
};

// handle GCM notifications for Android and Fire OS
onNotificationGCM = function(e) {
  // alert(JSON.stringify(e));

  switch( e.event ) {
    case 'registered':
      if ( e.regid.length > 0 ) {
        Push.emit('token', { gcm: ''+e.regid } );
      }
    break;

    case 'message':

      var sound = e.soundname || e.payload.sound;

      // Only prefix sound if actual text found
      if (sound && sound.length) sound = '/android_asset/www/application/' + sound;

      // XXX: Investigate if we need more defaults
      var unifiedMessage = {
        message: e.payload.message || e.msg || '',
        sound: sound,
        badge: e.payload.msgcnt,
        coldstart: e.coldstart,
        background: !e.foreground,
        foreground: !!e.foreground,
        type: 'gcm.cordova',
        payload: _stripPayload(e.payload)
      };

      // Trigger notification
      onNotification(unifiedMessage);
    break;

    case 'error':
      // e.msg
      Push.emit('error', { type: 'gcm.cordova', error: e });
    break;
  }
};

var rigDefaultEventListeners = function(options) {
  // Set default badge behaviour
  if (options.badge === true) Push.addListener('badge', function(notification) {
    Push.setBadge(notification.badge);
  });

  // Set default sound behaviour
  if (options.sound === true) Push.addListener('sound', function(notification) {
    if (notification.sound && notification.sound.length) {
      var snd = new Media(notification.sound);
      snd.play();
    }
  });

  // Set default alert behaviour
  if (options.alert === true) Push.addListener('alert', function(notification) {

    if (navigator && navigator.notification && navigator.notification.alert) {
      // If native notifications installed
      navigator.notification.alert(notification.message);
    } else {
      // Use regular notification
      alert(notification.message);
    }
  });

  // We add a vibrate listener
  if (options.vibrate === true) Push.addListener('message', function(notification) {
    // Vibrate if possible
    if (navigator && navigator.notification && navigator.notification.vibrate) {
      // If vibrate installed
      navigator.notification.vibrate(500);
    }
  });
};

var isConfigured = false;

Push.Configure = function(options) {
  var self = this;

  // Block multiple calls
  if (isConfigured)
    throw new Error('Push.Configure should not be called more than once!');

  isConfigured = true;

  // Clean up options, make sure the projectNumber
  if (options.gcm && !options.gcm.projectNumber)
    throw new Error('Push.Configure gcm got no projectNumber');

  // Client-side security warnings
  checkClientSecurity(options);

  // Set default options - these are needed for apn?
  options = _.extend({
    badge: (options.badge === true),
    sound: (options.sound === true),
    alert: (options.alert === true),
    vibrate: (options.vibrate === true)
  }, options);

  // Rig default event listeners for badge/sound/alert/vibrate
  rigDefaultEventListeners(options);

  // Add debug info
  if (Push.debug) console.log('Push.Configure', options);

  // Start token updates
  initPushUpdates(options.appName);

    // Initialize on ready
  Meteor.startup(function() {

    // Update flag if app coldstart
    document.addEventListener("pause", function() {
      coldstart = false;
    }, false);

    var pushNotification = window.plugins.pushNotification;

    if (device.platform == 'android' || device.platform == 'Android') {
      try {

        if (options.gcm && options.gcm.projectNumber) {
          pushNotification.register(function(result) {
            // Emit registered
            self.emit('register', result);
          }, function(error) {
            // Emit error
            self.emit('error', { type: 'gcm.cordova', error: error });
          }, {
            'senderID': ''+options.gcm.projectNumber,
            'ecb': 'onNotificationGCM'
          });
        } else {
          // throw new Error('senderID not set in options, required on android');
          console.warn('WARNING: Push.init, No gcm.projectNumber set on android');
        }

      } catch(err) {
        // console.log('There was an error starting up push');
        // console.log('Error description: ' + err.message);
        self.emit('error', { type: 'gcm.cordova', error: err.message });
      }
    } else {

      try {

        pushNotification.register(function(token) {
          // Got apn / ios token
          self.emit('token', { apn: token });
        }, function(error) {
          // Emit error
          self.emit('error', { type: 'apn.cordova', error: error });
        }, {
          'badge': ''+options.badge,
          'sound': ''+options.sound,
          'alert': ''+options.alert,
          'ecb': 'onNotificationAPN'
        }); // required!
      } catch(err) {
        // console.log('There was an error starting up push');
        // console.log('Error description: ' + err.message);
        self.emit('error', { type: 'apn.cordova', error: err.message });
      }
    }

  }, true);

}; // EO Push
<|endoftext|>


<commit_before>//tickets.js: Client for the zendesk API.

var util        = require('util'),
    Client      = require('./client').Client,
    defaultUser = require('./helpers').defaultUser;

var Tickets = exports.Tickets = function (options) {
  this.jsonAPIName = 'tickets';
  this.jsonAPIName2 = 'ticket';
  Client.call(this, options);
};

// Inherit from Client base object
util.inherits(Tickets, Client);

// ######################################################## Tickets
// ====================================== Listing Tickets
Tickets.prototype.list = function (cb) {
  this.requestAll('GET', ['tickets'], cb);//all
};

Tickets.prototype.listByOrganization = function (orgID, cb) {
  this.requestAll('GET', ['organizations', orgID, 'tickets'], cb);//all
};

Tickets.prototype.listByUserRequested = function (userID, cb) {
  this.requestAll('GET', ['users', userID, 'tickets', 'requested'], cb);//all
};

Tickets.prototype.listByUserCCD = function (userID, cb) {
  this.requestAll('GET', ['users', userID, 'tickets', 'ccd'], cb);//all
};

Tickets.prototype.listRecent = function (cb) {
  this.requestAll('GET', ['tickets', 'recent'], cb);//all?
};

Tickets.prototype.listCollaborators = function (ticketID, cb) {
  this.requestAll('GET', ['tickets', ticketID, 'collaborators'],  cb);//all?
};

Tickets.prototype.listIncidents = function (ticketID, cb) {
  this.requestAll('GET', ['tickets', ticketID, 'incidents'],  cb);//all
};

// ====================================== Viewing Tickets
Tickets.prototype.show = function (ticketID, cb) {
  this.request('GET', ['tickets', ticketID], cb);
};

// ====================================== Creating Tickets
Tickets.prototype.create = function (ticket, cb) {
  this.request('POST', ['tickets'], ticket,  cb);
};

// ====================================== Updating Tickets
Tickets.prototype.update = function (ticketID, ticket, cb) {
  this.request('PUT', ['tickets', ticketID], ticket,  cb);
};

Tickets.prototype.updateMany = function (ticket_ids, ticket, cb) {
  this.request('PUT', ['tickets', 'update_many', '?ids=' + ticket_ids.toString()], ticket,  cb);
};

// ====================================== Deleting Tickets
Tickets.prototype.delete = function (ticketID, cb) {
  this.request('DELETE', ['tickets', ticketID],  cb);
};

// ######################################################## Ticket export (max 1000 tickets per request in 5 min intrvals)
// ====================================== Ticket Export
Tickets.prototype.export = function (startTime, cb) {
  this.request('GET', ['exports', 'tickets', {start_time: startTime}],  cb);
};

// ====================================== Ticket Export Sample (max 50 tickets per request)
Tickets.prototype.exportSample = function (startTime, cb) {
  this.request('GET', ['exports', 'tickets', 'sample', {start_time: startTime}],  cb);
};

// ====================================== Listing Ticket Comments
Tickets.prototype.getComments = function (ticketID, cb) {
	this.requestAll('GET', ['tickets', ticketID, 'comments'],  cb);
};

// ######################################################## Ticket Audits

// ====================================== Listing Audits
Tickets.prototype.exportAudit = function (ticketID, cb) {
  this.request('GET', ['tickets', ticketID, 'audits'],  cb);
};

<commit_msg>Added deleteMany to mass delete tickets from Zendesk.<commit_after>//tickets.js: Client for the zendesk API.

var util        = require('util'),
    Client      = require('./client').Client,
    defaultUser = require('./helpers').defaultUser;

var Tickets = exports.Tickets = function (options) {
  this.jsonAPIName = 'tickets';
  this.jsonAPIName2 = 'ticket';
  Client.call(this, options);
};

// Inherit from Client base object
util.inherits(Tickets, Client);

// ######################################################## Tickets
// ====================================== Listing Tickets
Tickets.prototype.list = function (cb) {
  this.requestAll('GET', ['tickets'], cb);//all
};

Tickets.prototype.listByOrganization = function (orgID, cb) {
  this.requestAll('GET', ['organizations', orgID, 'tickets'], cb);//all
};

Tickets.prototype.listByUserRequested = function (userID, cb) {
  this.requestAll('GET', ['users', userID, 'tickets', 'requested'], cb);//all
};

Tickets.prototype.listByUserCCD = function (userID, cb) {
  this.requestAll('GET', ['users', userID, 'tickets', 'ccd'], cb);//all
};

Tickets.prototype.listRecent = function (cb) {
  this.requestAll('GET', ['tickets', 'recent'], cb);//all?
};

Tickets.prototype.listCollaborators = function (ticketID, cb) {
  this.requestAll('GET', ['tickets', ticketID, 'collaborators'],  cb);//all?
};

Tickets.prototype.listIncidents = function (ticketID, cb) {
  this.requestAll('GET', ['tickets', ticketID, 'incidents'],  cb);//all
};

// ====================================== Viewing Tickets
Tickets.prototype.show = function (ticketID, cb) {
  this.request('GET', ['tickets', ticketID], cb);
};

// ====================================== Creating Tickets
Tickets.prototype.create = function (ticket, cb) {
  this.request('POST', ['tickets'], ticket,  cb);
};

// ====================================== Updating Tickets
Tickets.prototype.update = function (ticketID, ticket, cb) {
  this.request('PUT', ['tickets', ticketID], ticket,  cb);
};

Tickets.prototype.updateMany = function (ticket_ids, ticket, cb) {
  this.request('PUT', ['tickets', 'update_many', '?ids=' + ticket_ids.toString()], ticket,  cb);
};

// ====================================== Deleting Tickets
Tickets.prototype.delete = function (ticketID, cb) {
  this.request('DELETE', ['tickets', ticketID],  cb);
};

Tickets.prototype.deleteMany = function (ticket_ids, cb) {
  this.request('DELETE', ['tickets', 'destroy_many', '?ids=' + ticket_ids.toString()],  cb);
};

// ######################################################## Ticket export (max 1000 tickets per request in 5 min intrvals)
// ====================================== Ticket Export
Tickets.prototype.export = function (startTime, cb) {
  this.request('GET', ['exports', 'tickets', {start_time: startTime}],  cb);
};

// ====================================== Ticket Export Sample (max 50 tickets per request)
Tickets.prototype.exportSample = function (startTime, cb) {
  this.request('GET', ['exports', 'tickets', 'sample', {start_time: startTime}],  cb);
};

// ====================================== Listing Ticket Comments
Tickets.prototype.getComments = function (ticketID, cb) {
	this.requestAll('GET', ['tickets', ticketID, 'comments'],  cb);
};

// ######################################################## Ticket Audits

// ====================================== Listing Audits
Tickets.prototype.exportAudit = function (ticketID, cb) {
  this.request('GET', ['tickets', ticketID, 'audits'],  cb);
};

<|endoftext|>


<commit_before>const CommandContext = require('./command-context');
const ParsedCommand = require('./parsed-command');

COMMAND_PREFIX = '!';

class CommandReader {
  constructor () {
    this._commands = {};
  }

  get commands () {
    return this._commands;
  }

  addCommand(command) {
    console.log("adding command", command.name);
    this.commands[command.name] = command;
  }

  msgIsCommand(message) {
    if (!message.content.startsWith(COMMAND_PREFIX)) {
      return false;
    }

    let commandName = message.content.split(' ')[0].slice(1);
    return typeof this.commands[commandName] !== 'undefined';
  }

  parse(message, nix) {
    let commandData = this._parseMessage(message);

    let command = commandData.command;
    let inputs = commandData.inputs;

    let argIndex = 0;

    let argsObject = {};
    let flagsObject = {};

    //Filter out flags from the inputs
    for(let i = 0; i < inputs.length; i += 1) {
      let input = inputs[i];

      let flagMatch = input.match(/--(\w+)|-(\w)/);

      if (flagMatch) {
        let flagName = flagMatch[1];
        let shortAlias = flagMatch[2];
        let flag;

        if (flagName) {
          flag = command.flags.find((flag) => flag.name === flagName);
        } else if (shortAlias) {
          flag = command.flags.find((flag) => flag.shortAlias === shortAlias);
        }

        if (flag.type === "boolean") {
          flagsObject[flag.name] = true;
        } else {
          i += 1; //increment so that the next value isn't mistaken for an argument
          flagsObject[flag.name] = inputs[i];
        }
      } else {
        let arg = command.args[argIndex];
        argsObject[arg.name] = input;
      }
    }

    command.args.forEach((arg) => {
      if (typeof argsObject[arg.name] === "undefined" && typeof arg.default !== "undefined") {
        argsObject[arg.name] = arg.default;
      }
    });

    command.flags.forEach((flag) => {
      if (typeof flagsObject[flag.name] === "undefined" && typeof flag.default !== "undefined") {
        flagsObject[flag.name] = flag.default;
      }
    });

    let context = new CommandContext(message, argsObject, flagsObject, nix);
    return new ParsedCommand(command, context);
  }

  _parseMessage(message) {
    let msgParts = message.content.split(/ (.+)/); //split into name and input parts

    let name = msgParts[0].slice(COMMAND_PREFIX.length); //slice to strip the command prefix
    let command = this.commands[name];

    let inputs = [];

    if (typeof msgParts[1] !== "undefined") {
      let values = msgParts[1].match(/\{.*\}|"[^"]*"|'[^']*'|\S+/g);
      if (values) {
        inputs = values;
      }
    }

    return {
      command: command,
      inputs: inputs,
    };
  }
}

module.exports = CommandReader;
<commit_msg>fix error with multiple arguments<commit_after>const CommandContext = require('./command-context');
const ParsedCommand = require('./parsed-command');

COMMAND_PREFIX = '!';

class CommandReader {
  constructor () {
    this._commands = {};
  }

  get commands () {
    return this._commands;
  }

  addCommand(command) {
    console.log("adding command", command.name);
    this.commands[command.name] = command;
  }

  msgIsCommand(message) {
    if (!message.content.startsWith(COMMAND_PREFIX)) {
      return false;
    }

    let commandName = message.content.split(' ')[0].slice(1);
    return typeof this.commands[commandName] !== 'undefined';
  }

  parse(message, nix) {
    let commandData = this._parseMessage(message);

    let command = commandData.command;
    let inputs = commandData.inputs;

    let argIndex = 0;

    let argsObject = {};
    let flagsObject = {};

    //Filter out flags from the inputs
    for(let i = 0; i < inputs.length; i += 1) {
      let input = inputs[i];

      let flagMatch = input.match(/--(\w+)|-(\w)/);

      if (flagMatch) {
        let flagName = flagMatch[1];
        let shortAlias = flagMatch[2];
        let flag;

        if (flagName) {
          flag = command.flags.find((flag) => flag.name === flagName);
        } else if (shortAlias) {
          flag = command.flags.find((flag) => flag.shortAlias === shortAlias);
        }

        if (flag.type === "boolean") {
          flagsObject[flag.name] = true;
        } else {
          i += 1; //increment so that the next value isn't mistaken for an argument
          flagsObject[flag.name] = inputs[i];
        }
      } else {
        let arg = command.args[argIndex];
        argsObject[arg.name] = input;
        argIndex += 1;
      }
    }

    command.args.forEach((arg) => {
      if (typeof argsObject[arg.name] === "undefined" && typeof arg.default !== "undefined") {
        argsObject[arg.name] = arg.default;
      }
    });

    command.flags.forEach((flag) => {
      if (typeof flagsObject[flag.name] === "undefined" && typeof flag.default !== "undefined") {
        flagsObject[flag.name] = flag.default;
      }
    });

    let context = new CommandContext(message, argsObject, flagsObject, nix);
    return new ParsedCommand(command, context);
  }

  _parseMessage(message) {
    let msgParts = message.content.split(/ (.+)/); //split into name and input parts

    let name = msgParts[0].slice(COMMAND_PREFIX.length); //slice to strip the command prefix
    let command = this.commands[name];

    let inputs = [];

    if (typeof msgParts[1] !== "undefined") {
      let values = msgParts[1].match(/\{.*\}|"[^"]*"|'[^']*'|\S+/g);
      if (values) {
        inputs = values;
      }
    }

    return {
      command: command,
      inputs: inputs,
    };
  }
}

module.exports = CommandReader;
<|endoftext|>


<commit_before>var myPath = require('../path'),
    Tech = require('../tech').Tech,
    Level = require('../level').Level,
    Context = require('../context').Context;

exports.OptParse = function() {
    return this
        .title('Сборка файлов.').helpful()
        .opt()
            .name('declaration').short('d').long('decl')
            .title('имя файла декларации использования, обязательный параметр')
            .validate(function (d) { return require(myPath.absolute(d)) })
            .required()
            .end()
        .opt()
            .name('level').short('l').long('level')
            .title('уровень переопределения, может использоваться несколько раз')
            .validate(function (l) { return typeof l == 'string'? new Level(l) : l })
            .push()
            .end()
        .opt()
            .name('tech').short('t').long('tech')
            .title('создавать файлы заданной технологии, может использоваться несколько раз')
            .push()
            .end()
        .opt()
            .name('outputDir').short('o').long('output-dir')
            .title('директория для записи результата, по умолчанию текущая')
            .def(process.cwd())
            .validate(function (d) { return myPath.join(d, '/') })
            .end()
        .opt()
            .name('outputName').short('n').long('output-name')
            .title('имя для записи результата')
            .end()
        .act(function (opts, args) {
            var context = new Context(opts.level, opts);

            // для каждой технологии
            context.getTechs().forEach(function (techIdent) {
                var tech = context.getTech(techIdent),
                    prefixes = [],
                    eachLevel = function (getter, args) {
                            // для каждого уровня переопределения
                            context.getLevels().forEach(function (level) {
                                // получить префикс файла
                                prefixes.push(level.get(getter, args));
                            });
                        },
                    forItemWithMods = function (block, elem) {
                            var item = elem || block,
                                type = elem? 'elem' : 'block',
                                args = elem? [block.name, elem.name] : [block.name];

                            // для самого блока или элемента
                            eachLevel(type, args);

                            // для каждого модификатора
                            item.mods && item.mods.forEach(function (mod) {

                                // для самого модификатора
                                eachLevel(type + '-mod', args.concat(mod.name));

                                // для каждого значения модификатора
                                mod.vals && mod.vals.forEach(function (val) {
                                    eachLevel(type + '-mod-val', args.concat(mod.name, val.name || val));
                                });

                            });
                        };

                // для каждого блока в декларации
                opts.declaration.blocks.forEach(function (block) {

                    // для самого блока
                    forItemWithMods(block);

                    // для каждого элемента в блоке
                    block.elems && block.elems.forEach(function (elem) {
                        forItemWithMods(block, elem);
                    });

                });

                // сериализовать контейнер префиксов файлов технологии согласно параметрам вывода
                tech.bemBuild(prefixes, opts.outputDir, opts.outputName);

            });
        });
};
<commit_msg>Устанавливаем глобальный контекст для технологий в bem build<commit_after>var myPath = require('../path'),
    Tech = require('../tech').Tech,
    Level = require('../level').Level,
    Context = require('../context').Context;

exports.OptParse = function() {
    return this
        .title('Сборка файлов.').helpful()
        .opt()
            .name('declaration').short('d').long('decl')
            .title('имя файла декларации использования, обязательный параметр')
            .validate(function (d) { return require(myPath.absolute(d)) })
            .required()
            .end()
        .opt()
            .name('level').short('l').long('level')
            .title('уровень переопределения, может использоваться несколько раз')
            .validate(function (l) { return typeof l == 'string'? new Level(l) : l })
            .push()
            .end()
        .opt()
            .name('tech').short('t').long('tech')
            .title('создавать файлы заданной технологии, может использоваться несколько раз')
            .push()
            .end()
        .opt()
            .name('outputDir').short('o').long('output-dir')
            .title('директория для записи результата, по умолчанию текущая')
            .def(process.cwd())
            .validate(function (d) { return myPath.join(d, '/') })
            .end()
        .opt()
            .name('outputName').short('n').long('output-name')
            .title('имя для записи результата')
            .end()
        .act(function (opts, args) {
            var context = new Context(opts.level, opts);

            // FIXME: унести на уровень выше, например в обработку опций
            Tech.setContext(context);

            // для каждой технологии
            context.getTechs().forEach(function (techIdent) {
                var tech = context.getTech(techIdent),
                    prefixes = [],
                    eachLevel = function (getter, args) {
                            // для каждого уровня переопределения
                            context.getLevels().forEach(function (level) {
                                // получить префикс файла
                                prefixes.push(level.get(getter, args));
                            });
                        },
                    forItemWithMods = function (block, elem) {
                            var item = elem || block,
                                type = elem? 'elem' : 'block',
                                args = elem? [block.name, elem.name] : [block.name];

                            // для самого блока или элемента
                            eachLevel(type, args);

                            // для каждого модификатора
                            item.mods && item.mods.forEach(function (mod) {

                                // для самого модификатора
                                eachLevel(type + '-mod', args.concat(mod.name));

                                // для каждого значения модификатора
                                mod.vals && mod.vals.forEach(function (val) {
                                    eachLevel(type + '-mod-val', args.concat(mod.name, val.name || val));
                                });

                            });
                        };

                // для каждого блока в декларации
                opts.declaration.blocks.forEach(function (block) {

                    // для самого блока
                    forItemWithMods(block);

                    // для каждого элемента в блоке
                    block.elems && block.elems.forEach(function (elem) {
                        forItemWithMods(block, elem);
                    });

                });

                // сериализовать контейнер префиксов файлов технологии согласно параметрам вывода
                tech.bemBuild(prefixes, opts.outputDir, opts.outputName);

            });
        });
};
<|endoftext|>


<commit_before>'use strict';

var cli = require('commander');
var read = require('read');

var Config = require('../config').Config;
var $28 = Config.getAPIClient();

//Login Command
cli
.command('login <email>')
.description('Sign-in into 28.io.')
.action(function(email) {

    if(!email) {
        console.log('Need email to authenticate: 28 -h for more infos');
        return;
    }

    read({ prompt: 'Password: ', silent: true, replace: '*' }, function(er, password) {
        console.log('Authenticating...');
        $28.login(email, password)
        .then(function(response){
            response.body.email = email;
            Config.save(response.body);
            console.log('API tokens have been saved.'.green);
        })
        .catch(Config.handleAPIError);
    });
});

//Reset password Command
cli
.command('reset-password <email>')
.description('Reset 28.io password.')
.action(function(email){
        if(!email) {
            console.log('Need email to reset password: 28 -h for more infos');
            return;
        }

        read({ prompt: 'New password: ', silent: true, replace: '*' }, function(er, password) {
            read({ prompt: 'New password (confirmation):', silent: true, replace: '*' }, function(er, passwordConfirmation){
                if(password !== passwordConfirmation) {
                    throw new Error('Passwords don\'t match');
                }
                $28.resetPassword(email, password, Config.getAccessToken())
                .then(function(){
                    console.log('Password changed'.green);
                })
                .catch(Config.handleAPIError);
            });
        });
});<commit_msg>Update login.js<commit_after>'use strict';

var cli = require('commander');
var read = require('read');

var Config = require('../config').Config;
var $28 = Config.getAPIClient();

//Login Command
cli
.command('login <email>')
.description('Sign-in into 28.io.')
.action(function(email) {

    if(!email) {
        console.log('Need email to authenticate: 28 -h for more infos');
        return;
    }

    read({ prompt: 'Password: ', silent: true, replace: '*' }, function(er, password) {
        console.log('Authenticating...');
        $28.login(email, password)
        .then(function(response){
            response.body.email = email;
            Config.save(response.body);
            console.log('API tokens have been saved.'.green);
        })
        .catch(Config.handleAPIError);
    });
});

//Reset password Command
cli
.command('change-password <email>')
.description('Reset 28.io password.')
.action(function(email){
        if(!email) {
            console.log('Need email to reset password: 28 -h for more infos');
            return;
        }

        read({ prompt: 'New password: ', silent: true, replace: '*' }, function(er, password) {
            read({ prompt: 'New password (confirmation):', silent: true, replace: '*' }, function(er, passwordConfirmation){
                if(password !== passwordConfirmation) {
                    throw new Error('Passwords don\'t match');
                }
                $28.resetPassword(email, password, Config.getAccessToken())
                .then(function(){
                    console.log('Password changed'.green);
                })
                .catch(Config.handleAPIError);
            });
        });
});
<|endoftext|>


<commit_before>'use strict';
var UglifyJS = require('uglify-js');
var util = require('./util');

/**
 * Parses doctest examples from a string.
 *
 * @param {String} input
 * @return {Array} examples
 */

exports.run = function commentParser$run(input) {
  return exports.parseExamples(exports.parseComments(input));
};

/**
 * Parses comments and code from a string. Heavily inspired by the code in @tj's
 * `dox` module
 *
 * @param {String} input
 * @return {Array} parsed
 */

exports.parseComments = function commentParser$parseComments(input) {
  input = input.replace(/\r\n/gm, '\n');
  var nodes = [];

  var insideSinglelineComment = false;
  var insideMultilineComment  = false;

  var currentNode = { type: 'code', string: '', };

  for(var i = 0, len = input.length; i < len; i += 1) {
    if(insideMultilineComment) {
      if(input[i] === '*' && input[i + 1] === '/') {
        flush();
        insideMultilineComment = false;
        i += 1;
        continue;
      }
    }
    else if(insideSinglelineComment) {
      if(input[i] === '\n') {
        flush();
        insideSinglelineComment = false;
        continue;
      }
    }
    else if(input[i] === '/') {
      if(input[i + 1] === '*') {
        flush();
        currentNode.type = 'comment';
        insideMultilineComment = true;
        i += 1;
        continue;
      }
      else if(input[i + 1] === '/') {
        flush();
        currentNode.type = 'comment';
        insideSinglelineComment = true;
        i += 1;
        continue;
      }
    }

    currentNode.string += input[i];
  }

  flush();
  return nodes;

  function flush() {
    currentNode.string = util.trimString(currentNode.string);
    nodes.push(currentNode);
    currentNode = { type: 'code', string: '', };
  }
};

/**
 * Parses `jsdoc` "examples" for our doctests out of the parsed comments.
 *
 * @param {Array} parsedComments Parsed output from `parseComments`
 * @return {Array} parsedExamples
 */

exports.parseExamples = function commentParser$parseExamples(parsedComments) {
  var examples = [];
  var currentExample = { expectedResult: '', };
  var caption;
  var currentCaption;

  for(var i = 0, len = parsedComments.length; i < len; i++) {
    if(parsedComments[i].type === 'code') {
      if(currentExample.testCase) flush();

      currentExample.testCase = parsedComments[i].string
        //.replace(/\n/g, ';')
        .replace(/^<caption>.+<\/caption>\s*/, '')
        .replace(/;$/, '');
      currentExample.displayTestCase = parsedComments[i].string
        .replace(/\n/g, ';')
        .replace(/^<caption>.+<\/caption>\s*/, '')
        .replace(/;$/, '');

      currentCaption = parsedComments[i].string
        .match(/^<caption>(.+)<\/caption>/);
      if (currentCaption && currentCaption[1]) {
        caption = currentCaption[1];
      }

      if (caption) {
        currentExample.label =
          currentExample.testCase + ' - ' + caption;
      }
    } else if(parsedComments[i].type === 'comment' && currentExample.testCase) {
      if(parsedComments[i].string.indexOf('=>') === 0) {
        currentExample.expectedResult += parsedComments[i].string.slice(3);
      } else if(parsedComments[i].string.indexOf('async =>') === 0) {
        currentExample.expectedResult += parsedComments[i].string.slice(9);
        currentExample.isAsync = true;
      }
    }

    if (!caption)
      currentExample.label =
          currentExample.testCase + ' => ' + currentExample.expectedResult;
  }

  flush();

  return examples;

  function flush() {
    if(currentExample.expectedResult) {
      examples.push(currentExample);
    }

    currentExample = { expectedResult: '', };
  }
};
<commit_msg>Add example's expectedResult to it's label (auto caption)<commit_after>'use strict';
var UglifyJS = require('uglify-js');
var util = require('./util');

/**
 * Parses doctest examples from a string.
 *
 * @param {String} input
 * @return {Array} examples
 */

exports.run = function commentParser$run(input) {
  return exports.parseExamples(exports.parseComments(input));
};

/**
 * Parses comments and code from a string. Heavily inspired by the code in @tj's
 * `dox` module
 *
 * @param {String} input
 * @return {Array} parsed
 */

exports.parseComments = function commentParser$parseComments(input) {
  input = input.replace(/\r\n/gm, '\n');
  var nodes = [];

  var insideSinglelineComment = false;
  var insideMultilineComment  = false;

  var currentNode = { type: 'code', string: '', };

  for(var i = 0, len = input.length; i < len; i += 1) {
    if(insideMultilineComment) {
      if(input[i] === '*' && input[i + 1] === '/') {
        flush();
        insideMultilineComment = false;
        i += 1;
        continue;
      }
    }
    else if(insideSinglelineComment) {
      if(input[i] === '\n') {
        flush();
        insideSinglelineComment = false;
        continue;
      }
    }
    else if(input[i] === '/') {
      if(input[i + 1] === '*') {
        flush();
        currentNode.type = 'comment';
        insideMultilineComment = true;
        i += 1;
        continue;
      }
      else if(input[i + 1] === '/') {
        flush();
        currentNode.type = 'comment';
        insideSinglelineComment = true;
        i += 1;
        continue;
      }
    }

    currentNode.string += input[i];
  }

  flush();
  return nodes;

  function flush() {
    currentNode.string = util.trimString(currentNode.string);
    nodes.push(currentNode);
    currentNode = { type: 'code', string: '', };
  }
};

/**
 * Parses `jsdoc` "examples" for our doctests out of the parsed comments.
 *
 * @param {Array} parsedComments Parsed output from `parseComments`
 * @return {Array} parsedExamples
 */

exports.parseExamples = function commentParser$parseExamples(parsedComments) {
  var examples = [];
  var currentExample = { expectedResult: '', };
  var caption;
  var currentCaption;

  for(var i = 0, len = parsedComments.length; i < len; i++) {
    if(parsedComments[i].type === 'code') {
      if(currentExample.testCase) flush();

      currentExample.testCase = parsedComments[i].string
        //.replace(/\n/g, ';')
        .replace(/^<caption>.+<\/caption>\s*/, '')
        .replace(/;$/, '');
      currentExample.displayTestCase = parsedComments[i].string
        .replace(/\n/g, ';')
        .replace(/^<caption>.+<\/caption>\s*/, '')
        .replace(/;$/, '');

      currentCaption = parsedComments[i].string
        .match(/^<caption>(.+)<\/caption>/);
      if (currentCaption && currentCaption[1]) {
        caption = currentCaption[1];
      }

      if (caption) {
        currentExample.label =
          currentExample.testCase + ' - ' + caption;
      }
    } else if(parsedComments[i].type === 'comment' && currentExample.testCase) {
      if(parsedComments[i].string.indexOf('=>') === 0) {
        currentExample.expectedResult += parsedComments[i].string.slice(3);
      } else if(parsedComments[i].string.indexOf('async =>') === 0) {
        currentExample.expectedResult += parsedComments[i].string.slice(9);
        currentExample.isAsync = true;
      }
    }

    if (!caption) {
      currentExample.label =
          currentExample.testCase + ' => ' + currentExample.expectedResult;
    }
  }

  flush();

  return examples;

  function flush() {
    if(currentExample.expectedResult) {
      examples.push(currentExample);
    }

    currentExample = { expectedResult: '', };
  }
};
<|endoftext|>