<commit_before>
/**
 * @fileoverview Request Sender
 */

/**
 * @augments JsSIP
 * @class Class creating a request sender.
 * @param {Object} applicant
 * @param {JsSIP.UA} ua
 */

JsSIP.RequestSender = function(applicant, ua) {
  this.ua = ua;
  this.applicant = applicant;
  this.method = applicant.request.method;
  this.request = applicant.request;
  this.credentials = null;
  this.challenged = false;
  this.staled = false;

  // If ua is in closing process or even closed just allow sending Bye and ACK
  if (ua.status === JsSIP.c.UA_STATUS_USER_CLOSED && (this.method !== JsSIP.c.BYE || this.method !== JsSIP.c.ACK)) {
    this.onTransportError();
  }

  this.credentials = ua.getCredentials(this.request);
};

/**
* Create the client transaction and send the message.
*/
JsSIP.RequestSender.prototype = {
  send: function() {
    if (this.credentials) {
      if (this.request.method === JsSIP.c.REGISTER) {
        this.request.setHeader('authorization', this.credentials.authenticate());
      } else {
        this.request.setHeader('proxy-authorization', this.credentials.authenticate());
      }
    }

    switch(this.method) {
      case "INVITE":
        this.clientTransaction = new JsSIP.Transactions.InviteClientTransaction(this, this.request, this.ua.transport);
        break;
      case "ACK":
        this.clientTransaction = new JsSIP.Transactions.AckClientTransaction(this, this.request, this.ua.transport);
        break;
      default:
        this.clientTransaction = new JsSIP.Transactions.NonInviteClientTransaction(this, this.request, this.ua.transport);
    }
    this.clientTransaction.send();
  },

  /**
  * Callback fired when receiving a request timeout error from the client transaction.
  * To be re-defined by the applicant.
  * @event
  */
  onRequestTimeout: function() {
    this.applicant.onRequestTimeout();
  },

  /**
  * Callback fired when receiving a transport error from the client transaction.
  * To be re-defined by the applicant.
  * @event
  */
  onTransportError: function() {
    this.applicant.onTransportError();
  },

  /**
  * Called from client transaction when receiving a correct response to the request.
  * Authenticate request if needed or pass the response back to the applicant.
  * @param {JsSIP.IncomingResponse} response
  */
  receiveResponse: function(response) {
    var cseq, challenge,
      status_code = response.status_code;

    /*
    * Authentication
    * Authenticate once. _challenged_ flag used to avoid infinite authentications.
    */
    if ((status_code === 401 || status_code === 407) && this.ua.configuration.password !== null) {

      if (status_code === 401) {
        challenge = response.s('WWW-Authenticate');
      } else {
        challenge = response.s('Authenticate');
      }

      if ( !this.challenged || (this.challenged && !this.staled && challenge.stale) ) {
        if (!this.credentials) {
          this.credentials = new JsSIP.DigestAuthentication(this.ua, this.request, response);
        }

        if (response.method === JsSIP.c.REGISTER) {
          cseq = this.applicant.cseq += 1;
        } else if (this.request.dialog){
          cseq = this.request.dialog.local_seqnum += 1;
        } else {
          cseq = this.request.headers.CSeq.toString().split(' ')[0];
          cseq = parseInt(cseq,10) +1;
        }

        this.request.setHeader('cseq', cseq +' '+ this.method);
        this.challenged = true;
        this.send();
      }
    } else {
        if (this.challenged && response.status_code >= 200) {
          this.ua.saveCredentials(this.credentials);
        }
        this.applicant.receiveResponse(response);
    }
  }
};<commit_msg>Fix Typo<commit_after>
/**
 * @fileoverview Request Sender
 */

/**
 * @augments JsSIP
 * @class Class creating a request sender.
 * @param {Object} applicant
 * @param {JsSIP.UA} ua
 */

JsSIP.RequestSender = function(applicant, ua) {
  this.ua = ua;
  this.applicant = applicant;
  this.method = applicant.request.method;
  this.request = applicant.request;
  this.credentials = null;
  this.challenged = false;
  this.staled = false;

  // If ua is in closing process or even closed just allow sending Bye and ACK
  if (ua.status === JsSIP.c.UA_STATUS_USER_CLOSED && (this.method !== JsSIP.c.BYE || this.method !== JsSIP.c.ACK)) {
    this.onTransportError();
  }

  this.credentials = ua.getCredentials(this.request);
};

/**
* Create the client transaction and send the message.
*/
JsSIP.RequestSender.prototype = {
  send: function() {
    if (this.credentials) {
      if (this.request.method === JsSIP.c.REGISTER) {
        this.request.setHeader('authorization', this.credentials.authenticate());
      } else {
        this.request.setHeader('proxy-authorization', this.credentials.authenticate());
      }
    }

    switch(this.method) {
      case "INVITE":
        this.clientTransaction = new JsSIP.Transactions.InviteClientTransaction(this, this.request, this.ua.transport);
        break;
      case "ACK":
        this.clientTransaction = new JsSIP.Transactions.AckClientTransaction(this, this.request, this.ua.transport);
        break;
      default:
        this.clientTransaction = new JsSIP.Transactions.NonInviteClientTransaction(this, this.request, this.ua.transport);
    }
    this.clientTransaction.send();
  },

  /**
  * Callback fired when receiving a request timeout error from the client transaction.
  * To be re-defined by the applicant.
  * @event
  */
  onRequestTimeout: function() {
    this.applicant.onRequestTimeout();
  },

  /**
  * Callback fired when receiving a transport error from the client transaction.
  * To be re-defined by the applicant.
  * @event
  */
  onTransportError: function() {
    this.applicant.onTransportError();
  },

  /**
  * Called from client transaction when receiving a correct response to the request.
  * Authenticate request if needed or pass the response back to the applicant.
  * @param {JsSIP.IncomingResponse} response
  */
  receiveResponse: function(response) {
    var cseq, challenge,
      status_code = response.status_code;

    /*
    * Authentication
    * Authenticate once. _challenged_ flag used to avoid infinite authentications.
    */
    if ((status_code === 401 || status_code === 407) && this.ua.configuration.password !== null) {

      if (status_code === 401) {
        challenge = response.s('WWW-Authenticate');
      } else {
        challenge = response.s('Proxy-Authenticate');
      }

      if ( !this.challenged || (this.challenged && !this.staled && challenge.stale) ) {
        if (!this.credentials) {
          this.credentials = new JsSIP.DigestAuthentication(this.ua, this.request, response);
        }

        if (response.method === JsSIP.c.REGISTER) {
          cseq = this.applicant.cseq += 1;
        } else if (this.request.dialog){
          cseq = this.request.dialog.local_seqnum += 1;
        } else {
          cseq = this.request.headers.CSeq.toString().split(' ')[0];
          cseq = parseInt(cseq,10) +1;
        }

        this.request.setHeader('cseq', cseq +' '+ this.method);
        this.challenged = true;
        this.send();
      }
    } else {
        if (this.challenged && response.status_code >= 200) {
          this.ua.saveCredentials(this.credentials);
        }
        this.applicant.receiveResponse(response);
    }
  }
};<|endoftext|>


<commit_before>/**
 * This module handles the dates parsing/formatting processes
 *
 * To format dates and times this scripts use the GNU (C/Python/Ruby) strftime
 * function formatting principles
 *
 *   %a - The abbreviated weekday name (``Sun'')
 *   %A - The  full  weekday  name (``Sunday'')
 *   %b - The abbreviated month name (``Jan'')
 *   %B - The  full  month  name (``January'')
 *   %d - Day of the month (01..31)
 *   %e - Day of the month without leading zero (1..31)
 *   %m - Month of the year (01..12)
 *   %y - Year without a century (00..99)
 *   %Y - Year with century
 *   %H - Hour of the day, 24-hour clock (00..23)
 *   %k - Hour of the day, 24-hour clock without leading zero (0..23)
 *   %I - Hour of the day, 12-hour clock (01..12)
 *   %l - Hour of the day, 12-hour clock without leading zer (0..12)
 *   %p - Meridian indicator (``AM''  or  ``PM'')
 *   %P - Meridian indicator (``pm''  or  ``pm'')
 *   %M - Minute of the hour (00..59)
 *   %S - Second of the minute (00..60)
 *   %% - Literal ``%'' character
 *
 * Copyright (C) 2009-2010 Nikolay V. Nemshilov
 */
Calendar.include({

  /**
   * Parses out the given string based on the current date formatting
   *
   * @param String string date
   * @return Date parsed date or null if it wasn't parsed
   */
  parse: function(string) {
    var date;

    if (string instanceof Date || Date.parse(string)) {
      date = new Date(string);

    } else if (isString(string) && string) {
      var tpl = RegExp.escape(this.options.format);
      var holders = tpl.match(/%[a-z]/ig).map('match', /[a-z]$/i).map('first').without('%');
      var re  = new RegExp('^'+tpl.replace(/%p/i, '(pm|PM|am|AM)').replace(/(%[a-z])/ig, '(.+?)')+'$');

      var match = string.trim().match(re);

      if (match) {
        match.shift();

        var year = null, month = null, date = null, hour = null, minute = null, second = null, meridian;

        while (match.length) {
          var value = match.shift();
          var key   = holders.shift();

          if (key.toLowerCase() == 'b') {
            month = this.options.i18n[key=='b' ? 'monthNamesShort' : 'monthNames'].indexOf(value);
          } else if (key.toLowerCase() == 'p') {
            meridian = value.toLowerCase();
          } else {
            value = value.toInt();
            switch(key) {
              case 'd':
              case 'e': date   = value; break;
              case 'm': month  = value-1; break;
              case 'y':
              case 'Y': year   = value; break;
              case 'H':
              case 'k':
              case 'I':
              case 'l': hour   = value; break;
              case 'M': minute = value; break;
              case 'S': second = value; break;
            }
          }
        }

        // converting 1..12am|pm into 0..23 hours marker
        if (meridian) {
          hour = hour == 12 ? 0 : hour;
          hour = (meridian == 'pm' ? hour + 12 : hour);
        }

        date = new Date(year, month, date, hour, minute, second);
      }
    } else {
      date = new Date();
    }

    return isNaN(date.getTime()) ? new Date : date;
  },

  /**
   * Formats the current date into a string depend on the current or given format
   *
   * @param String optional format
   * @return String formatted data
   */
  format: function(format) {
    var i18n   = this.options.i18n;
    var day    = this.date.getDay();
    var month  = this.date.getMonth();
    var date   = this.date.getDate();
    var year   = this.date.getFullYear();
    var hour   = this.date.getHours();
    var minute = this.date.getMinutes();
    var second = this.date.getSeconds();

    var hour_ampm = (hour == 0 ? 12 : hour < 13 ? hour : hour - 12);

    var values    = {
      a: i18n.dayNamesShort[day],
      A: i18n.dayNames[day],
      b: i18n.monthNamesShort[month],
      B: i18n.monthNames[month],
      d: (date < 10 ? '0' : '') + date,
      e: ''+date,
      m: (month < 9 ? '0' : '') + (month+1),
      y: (''+year).substring(2,4),
      Y: ''+year,
      H: (hour < 10 ? '0' : '')+ hour,
      k: '' + hour,
      I: (hour > 0 && (hour < 10 || (hour > 12 && hour < 22)) ? '0' : '') + hour_ampm,
      l: '' + hour_ampm,
      p: hour < 12 ? 'AM' : 'PM',
      P: hour < 12 ? 'am' : 'pm',
      M: (minute < 10 ? '0':'')+minute,
      S: (second < 10 ? '0':'')+second,
      '%': '%'
    };

    var result = format || this.options.format;
    for (var key in values) {
      result = result.replace('%'+key, values[key]);
    }

    return result;
  }
});<commit_msg>Calendar dates parsing fix for FF<commit_after>/**
 * This module handles the dates parsing/formatting processes
 *
 * To format dates and times this scripts use the GNU (C/Python/Ruby) strftime
 * function formatting principles
 *
 *   %a - The abbreviated weekday name (``Sun'')
 *   %A - The  full  weekday  name (``Sunday'')
 *   %b - The abbreviated month name (``Jan'')
 *   %B - The  full  month  name (``January'')
 *   %d - Day of the month (01..31)
 *   %e - Day of the month without leading zero (1..31)
 *   %m - Month of the year (01..12)
 *   %y - Year without a century (00..99)
 *   %Y - Year with century
 *   %H - Hour of the day, 24-hour clock (00..23)
 *   %k - Hour of the day, 24-hour clock without leading zero (0..23)
 *   %I - Hour of the day, 12-hour clock (01..12)
 *   %l - Hour of the day, 12-hour clock without leading zer (0..12)
 *   %p - Meridian indicator (``AM''  or  ``PM'')
 *   %P - Meridian indicator (``pm''  or  ``pm'')
 *   %M - Minute of the hour (00..59)
 *   %S - Second of the minute (00..60)
 *   %% - Literal ``%'' character
 *
 * Copyright (C) 2009-2010 Nikolay V. Nemshilov
 */
Calendar.include({

  /**
   * Parses out the given string based on the current date formatting
   *
   * @param String string date
   * @return Date parsed date or null if it wasn't parsed
   */
  parse: function(string) {
    var date;

    if (isString(string) && string) {
      var tpl = RegExp.escape(this.options.format);
      var holders = tpl.match(/%[a-z]/ig).map('match', /[a-z]$/i).map('first').without('%');
      var re  = new RegExp('^'+tpl.replace(/%p/i, '(pm|PM|am|AM)').replace(/(%[a-z])/ig, '(.+?)')+'$');

      var match = string.trim().match(re);

      if (match) {
        match.shift();

        var year = null, month = null, date = null, hour = null, minute = null, second = null, meridian;

        while (match.length) {
          var value = match.shift();
          var key   = holders.shift();

          if (key.toLowerCase() == 'b') {
            month = this.options.i18n[key=='b' ? 'monthNamesShort' : 'monthNames'].indexOf(value);
          } else if (key.toLowerCase() == 'p') {
            meridian = value.toLowerCase();
          } else {
            value = value.toInt();
            switch(key) {
              case 'd':
              case 'e': date   = value; break;
              case 'm': month  = value-1; break;
              case 'y':
              case 'Y': year   = value; break;
              case 'H':
              case 'k':
              case 'I':
              case 'l': hour   = value; break;
              case 'M': minute = value; break;
              case 'S': second = value; break;
            }
          }
        }

        // converting 1..12am|pm into 0..23 hours marker
        if (meridian) {
          hour = hour == 12 ? 0 : hour;
          hour = (meridian == 'pm' ? hour + 12 : hour);
        }

        date = new Date(year, month, date, hour, minute, second);
      }
    } else if (string instanceof Date || Date.parse(string)) {
      date = new Date(string);
    }

    return (!date || isNaN(date.getTime())) ? new Date : date;
  },

  /**
   * Formats the current date into a string depend on the current or given format
   *
   * @param String optional format
   * @return String formatted data
   */
  format: function(format) {
    var i18n   = this.options.i18n;
    var day    = this.date.getDay();
    var month  = this.date.getMonth();
    var date   = this.date.getDate();
    var year   = this.date.getFullYear();
    var hour   = this.date.getHours();
    var minute = this.date.getMinutes();
    var second = this.date.getSeconds();

    var hour_ampm = (hour == 0 ? 12 : hour < 13 ? hour : hour - 12);

    var values    = {
      a: i18n.dayNamesShort[day],
      A: i18n.dayNames[day],
      b: i18n.monthNamesShort[month],
      B: i18n.monthNames[month],
      d: (date < 10 ? '0' : '') + date,
      e: ''+date,
      m: (month < 9 ? '0' : '') + (month+1),
      y: (''+year).substring(2,4),
      Y: ''+year,
      H: (hour < 10 ? '0' : '')+ hour,
      k: '' + hour,
      I: (hour > 0 && (hour < 10 || (hour > 12 && hour < 22)) ? '0' : '') + hour_ampm,
      l: '' + hour_ampm,
      p: hour < 12 ? 'AM' : 'PM',
      P: hour < 12 ? 'am' : 'pm',
      M: (minute < 10 ? '0':'')+minute,
      S: (second < 10 ? '0':'')+second,
      '%': '%'
    };

    var result = format || this.options.format;
    for (var key in values) {
      result = result.replace('%'+key, values[key]);
    }

    return result;
  }
});<|endoftext|>


<commit_before>'use babel'

export default [
  {
    scopes: ['source.js', 'source.js.jsx', 'source.coffee', 'source.coffee.jsx', 'source.ts', 'source.tsx'],
    prefixes: [
      'import\\s+.*?from\\s+[\'"]', // import foo from './foo'
      'import\\s+[\'"]', // import './foo'
      'require\\([\'"]', // require('./foo')
      'define\\(\\[?[\'"]' // define(['./foo']) or define('./foo')
    ],
    extensions: ['js', 'jsx', 'ts', 'tsx', 'coffee', 'json'],
    relative: true,
    replaceOnInsert: [
      ['\\.jsx?$', ''],
      ['\\.ts$', ''],
      ['\\.coffee$', '']
    ]
  },
  {
    scopes: ['text.html.vue'],
    prefixes: [
      'import\\s+.*?from\\s+[\'"]', // import foo from './foo'
      'import\\s+[\'"]', // import './foo'
      'require\\([\'"]', // require('./foo')
      'define\\(\\[?[\'"]' // define(['./foo']) or define('./foo')
    ],
    extensions: ['js', 'jsx', 'vue', 'ts', 'tsx', 'coffee'],
    relative: true,
    replaceOnInsert: [
      ['\\.jsx?$', ''],
      ['\\.ts$', ''],
      ['\\.coffee$', '']
    ]
  },
  {
    scopes: ['text.html.vue'],
    prefixes: [
      '@import[\\(|\\s+]?[\'"]' // @import 'foo' or @import('foo')
    ],
    extensions: ['css', 'sass', 'scss', 'less', 'styl'],
    relative: true,
    replaceOnInsert: [
      ['(/)?_([^/]*?)$', '$1$2'] // dir1/_dir2/_file.sass => dir1/_dir2/file.sass
    ]
  },
  {
    scopes: ['source.coffee', 'source.coffee.jsx'],
    prefixes: [
      'require\\s+[\'"]', // require './foo'
      'define\\s+\\[?[\'"]' // define(['./foo']) or define('./foo')
    ],
    extensions: ['js', 'jsx', 'ts', 'tsx', 'coffee'],
    relative: true,
    replaceOnInsert: [
      ['\\.jsx?$', ''],
      ['\\.ts$', ''],
      ['\\.coffee$', '']
    ]
  },
  {
    scopes: ['source.php'],
    prefixes: [
      'require_once\\([\'"]', // require_once('foo.php')
      'include\\([\'"]' // include('./foo.php')
    ],
    extensions: ['php'],
    relative: true
  },
  {
    scopes: ['source.sass', 'source.css.scss', 'source.less', 'source.stylus'],
    prefixes: [
      '@import[\\(|\\s+]?[\'"]' // @import 'foo' or @import('foo')
    ],
    extensions: ['sass', 'scss', 'css'],
    relative: true,
    replaceOnInsert: [
      ['(/)?_([^/]*?)$', '$1$2'] // dir1/_dir2/_file.sass => dir1/_dir2/file.sass
    ]
  },
  {
    scopes: ['source.css'],
    prefixes: [
      '@import\\s+[\'"]?', // @import 'foo.css'
      '@import\\s+url\\([\'"]?' // @import url('foo.css')
    ],
    extensions: ['css'],
    relative: true
  },
  {
    scopes: ['source.css', 'source.sass', 'source.less', 'source.css.scss', 'source.stylus'],
    prefixes: [
      'url\\([\'"]?'
    ],
    extensions: ['png', 'gif', 'jpeg', 'jpg', 'woff', 'ttf', 'svg', 'otf'],
    relative: true
  },
  {
    scopes: ['source.c', 'source.cpp'],
    prefixes: [
      '^\\s*#include\\s+[\'"]'
    ],
    extensions: ['h', 'hpp'],
    relative: true,
    includeCurrentDirectory: false
  },
  {
    scopes: ['source.lua'],
    prefixes: [
      'require[\\s+|\\(][\'"]'
    ],
    extensions: ['lua'],
    relative: true,
    includeCurrentDirectory: false,
    replaceOnInsert: [
      ['\\/', '.'],
      ['\\\\', '.'],
      ['\\.lua$', '']
    ]
  },
  {
    scopes: ['source.ruby'],
    prefixes: [
      '^\\s*require[\\s+|\\(][\'"]'
    ],
    extensions: ['rb'],
    relative: true,
    includeCurrentDirectory: false,
    replaceOnInsert: [
      ['\\.rb$', '']
    ]
  },
  {
    scopes: ['source.python'],
    prefixes: [
      '^\\s*from\\s+',
      '^\\s*import\\s+'
    ],
    extensions: ['py'],
    relative: true,
    includeCurrentDirectory: false,
    replaceOnInsert: [
      ['\\/', '.'],
      ['\\\\', '.'],
      ['\\.py$', '']
    ]
  }
]
<commit_msg>:sparkles: Automatically trim `/index.js`<commit_after>'use babel'

export default [
  {
    scopes: ['source.js', 'source.js.jsx', 'source.coffee', 'source.coffee.jsx', 'source.ts', 'source.tsx'],
    prefixes: [
      'import\\s+.*?from\\s+[\'"]', // import foo from './foo'
      'import\\s+[\'"]', // import './foo'
      'require\\([\'"]', // require('./foo')
      'define\\(\\[?[\'"]' // define(['./foo']) or define('./foo')
    ],
    extensions: ['js', 'jsx', 'ts', 'tsx', 'coffee', 'json'],
    relative: true,
    replaceOnInsert: [
      ['([\\/]?index)?\\.jsx?$', ''],
      ['([\\/]?index)?\\.ts$', ''],
      ['([\\/]?index)?\\.coffee$', '']
    ]
  },
  {
    scopes: ['text.html.vue'],
    prefixes: [
      'import\\s+.*?from\\s+[\'"]', // import foo from './foo'
      'import\\s+[\'"]', // import './foo'
      'require\\([\'"]', // require('./foo')
      'define\\(\\[?[\'"]' // define(['./foo']) or define('./foo')
    ],
    extensions: ['js', 'jsx', 'vue', 'ts', 'tsx', 'coffee'],
    relative: true,
    replaceOnInsert: [
      ['\\.jsx?$', ''],
      ['\\.ts$', ''],
      ['\\.coffee$', '']
    ]
  },
  {
    scopes: ['text.html.vue'],
    prefixes: [
      '@import[\\(|\\s+]?[\'"]' // @import 'foo' or @import('foo')
    ],
    extensions: ['css', 'sass', 'scss', 'less', 'styl'],
    relative: true,
    replaceOnInsert: [
      ['(/)?_([^/]*?)$', '$1$2'] // dir1/_dir2/_file.sass => dir1/_dir2/file.sass
    ]
  },
  {
    scopes: ['source.coffee', 'source.coffee.jsx'],
    prefixes: [
      'require\\s+[\'"]', // require './foo'
      'define\\s+\\[?[\'"]' // define(['./foo']) or define('./foo')
    ],
    extensions: ['js', 'jsx', 'ts', 'tsx', 'coffee'],
    relative: true,
    replaceOnInsert: [
      ['\\.jsx?$', ''],
      ['\\.ts$', ''],
      ['\\.coffee$', '']
    ]
  },
  {
    scopes: ['source.php'],
    prefixes: [
      'require_once\\([\'"]', // require_once('foo.php')
      'include\\([\'"]' // include('./foo.php')
    ],
    extensions: ['php'],
    relative: true
  },
  {
    scopes: ['source.sass', 'source.css.scss', 'source.less', 'source.stylus'],
    prefixes: [
      '@import[\\(|\\s+]?[\'"]' // @import 'foo' or @import('foo')
    ],
    extensions: ['sass', 'scss', 'css'],
    relative: true,
    replaceOnInsert: [
      ['(/)?_([^/]*?)$', '$1$2'] // dir1/_dir2/_file.sass => dir1/_dir2/file.sass
    ]
  },
  {
    scopes: ['source.css'],
    prefixes: [
      '@import\\s+[\'"]?', // @import 'foo.css'
      '@import\\s+url\\([\'"]?' // @import url('foo.css')
    ],
    extensions: ['css'],
    relative: true
  },
  {
    scopes: ['source.css', 'source.sass', 'source.less', 'source.css.scss', 'source.stylus'],
    prefixes: [
      'url\\([\'"]?'
    ],
    extensions: ['png', 'gif', 'jpeg', 'jpg', 'woff', 'ttf', 'svg', 'otf'],
    relative: true
  },
  {
    scopes: ['source.c', 'source.cpp'],
    prefixes: [
      '^\\s*#include\\s+[\'"]'
    ],
    extensions: ['h', 'hpp'],
    relative: true,
    includeCurrentDirectory: false
  },
  {
    scopes: ['source.lua'],
    prefixes: [
      'require[\\s+|\\(][\'"]'
    ],
    extensions: ['lua'],
    relative: true,
    includeCurrentDirectory: false,
    replaceOnInsert: [
      ['\\/', '.'],
      ['\\\\', '.'],
      ['\\.lua$', '']
    ]
  },
  {
    scopes: ['source.ruby'],
    prefixes: [
      '^\\s*require[\\s+|\\(][\'"]'
    ],
    extensions: ['rb'],
    relative: true,
    includeCurrentDirectory: false,
    replaceOnInsert: [
      ['\\.rb$', '']
    ]
  },
  {
    scopes: ['source.python'],
    prefixes: [
      '^\\s*from\\s+',
      '^\\s*import\\s+'
    ],
    extensions: ['py'],
    relative: true,
    includeCurrentDirectory: false,
    replaceOnInsert: [
      ['\\/', '.'],
      ['\\\\', '.'],
      ['\\.py$', '']
    ]
  }
]
<|endoftext|>


<commit_before>module.exports = {
  isMobile : function (req) {
    if(!req) return;

    // detectmobilebrowsers.com
    var ua = req.headers['user-agent'].toLowerCase();
    if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(ua)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(ua.substr(0,4))) {
      return true;
    }

    return false;
  }
};
<commit_msg>Fix bug with no user-agent present<commit_after>module.exports = {
  isMobile : function (req) {
    if(!req || !req.headers['user-agent']) return false;

    // detectmobilebrowsers.com
    var ua = req.headers['user-agent'].toLowerCase();
    if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(ua)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(ua.substr(0,4))) {
      return true;
    }

    return false;
  }
};
<|endoftext|>


<commit_before>import utils from 'osg/utils';
import InputSource from 'osgViewer/input/source/InputSource';

/**
 * Standard Keyboard Event handled directly on the canvas.
 * @param canvas
 * @constructor
 */
var InputSourceKeyboard = function(canvas) {
    InputSource.call(this, canvas);
    this._supportedEvents = ['keydown', 'keyup', 'keypress'];
};
utils.createPrototypeObject(
    InputSourceKeyboard,
    utils.objectInherit(InputSource.prototype, {
        getName: function() {
            return 'Keyboard';
        },

        setEnable: function(name, callback, enable) {
            if (enable) {
                this._target.addEventListener(name, callback);
            } else {
                this._target.removeEventListener(name, callback);
            }
        },

        populateEvent: function(ev, customEvent) {
            customEvent.key = ev.key;
            customEvent.keyCode = ev.keyCode;
            customEvent.code = ev.code;
            customEvent.location = ev.location;
            customEvent.repeat = ev.repeat;

            // modifiers
            customEvent.ctrlKey = ev.ctrlKey;
            customEvent.shiftKey = ev.shiftKey;
            customEvent.altKey = ev.altKey;
            customEvent.metaKey = ev.metaKey;
        },

        isEventRegistered: function(nativeEvent, parsedEvent) {
            if (!parsedEvent.action) {
                return true;
            }

            if (!nativeEvent.key || typeof nativeEvent.key !== 'string') {
                // Throw Errors when nativeEvent key undefined.
                // so that we can investigate those errors.
                var str = '';
                for (var k in nativeEvent) {
                    if (k !== undefined && nativeEvent[k] !== undefined) {
                        str += k + ':' + nativeEvent[k] + ',\n';
                    }
                }
                var error = new Error('Invalid keyboard event: ' + str);
                throw error;
                return false;
            }
            if (nativeEvent.key.toLowerCase() !== parsedEvent.action) {
                if (nativeEvent.code.toLowerCase() !== parsedEvent.action) {
                    return false;
                }
            }
            if (parsedEvent.ctrl !== undefined && nativeEvent.ctrlKey !== parsedEvent.ctrl) {
                return false;
            }
            if (parsedEvent.shift !== undefined && nativeEvent.shiftKey !== parsedEvent.shift) {
                return false;
            }
            if (parsedEvent.alt !== undefined && nativeEvent.altKey !== parsedEvent.alt) {
                return false;
            }
            if (parsedEvent.meta !== undefined && nativeEvent.metaKey !== parsedEvent.meta) {
                return false;
            }

            return true;
        }
    }),
    'osgViewer',
    'InputSourceKeyboard'
);

export default InputSourceKeyboard;
<commit_msg>Fixes IE11 missing key on event when hitting shift<commit_after>import utils from 'osg/utils';
import InputSource from 'osgViewer/input/source/InputSource';

/**
 * Standard Keyboard Event handled directly on the canvas.
 * @param canvas
 * @constructor
 */
var InputSourceKeyboard = function(canvas) {
    InputSource.call(this, canvas);
    this._supportedEvents = ['keydown', 'keyup', 'keypress'];
};
utils.createPrototypeObject(
    InputSourceKeyboard,
    utils.objectInherit(InputSource.prototype, {
        getName: function() {
            return 'Keyboard';
        },

        setEnable: function(name, callback, enable) {
            if (enable) {
                this._target.addEventListener(name, callback);
            } else {
                this._target.removeEventListener(name, callback);
            }
        },

        populateEvent: function(ev, customEvent) {
            customEvent.key = ev.key;
            customEvent.keyCode = ev.keyCode;
            customEvent.code = ev.code;
            customEvent.location = ev.location;
            customEvent.repeat = ev.repeat;

            // modifiers
            customEvent.ctrlKey = ev.ctrlKey;
            customEvent.shiftKey = ev.shiftKey;
            customEvent.altKey = ev.altKey;
            customEvent.metaKey = ev.metaKey;
        },

        isEventRegistered: function(nativeEvent, parsedEvent) {
            if (!parsedEvent.action) {
                return true;
            }

            // IE11 has no nativeEvent.key when hitting "modifer" (shift)
            if (nativeEvent.key && nativeEvent.key.toLowerCase() !== parsedEvent.action) {
                if (nativeEvent.code.toLowerCase() !== parsedEvent.action) {
                    return false;
                }
            }
            if (parsedEvent.ctrl !== undefined && nativeEvent.ctrlKey !== parsedEvent.ctrl) {
                return false;
            }
            if (parsedEvent.shift !== undefined && nativeEvent.shiftKey !== parsedEvent.shift) {
                return false;
            }
            if (parsedEvent.alt !== undefined && nativeEvent.altKey !== parsedEvent.alt) {
                return false;
            }
            if (parsedEvent.meta !== undefined && nativeEvent.metaKey !== parsedEvent.meta) {
                return false;
            }

            return true;
        }
    }),
    'osgViewer',
    'InputSourceKeyboard'
);

export default InputSourceKeyboard;
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import SelectList from './select-list.component';
import Textbox from '../textbox';
import Pill from '../../../components/pill';
import Events from '../../../utils/helpers/events';
import tagComponent from '../../../utils/helpers/tags';
import StyledSelectPillContainer from './select.style';

/**
 * Basic example:
 *
 *   <Select>
 *     <Option text='Approve' />
 *     <Option text='Configure' />
 *     <Option text='Deny' />
 *   </Select>
 *
 * Custom JSX:
 *
 *   <Select>
 *     <Option text='Approve'><Icon type='tick' /></Option>
 *     <Option text='Configure'><Icon type='settings' /></Option>
 *     <Option text='Deny'><Icon type='cross' /></Option>
 *   </Select>
 */

class Select extends React.Component {
  state = {
    filter: undefined,
    open: false
  }

  blurBlocked = false // stops the blur callback from triggering (closing the list) when we don't want it to

  input = {} // this will store a reference to the input html element

  assignInput = (input) => { this.input = input; }

  blockBlur() {
    this.blurBlocked = true;
  }

  unblockBlur() {
    this.blurBlocked = false;
  }

  handleBlur = (ev) => {
    if (this.blurBlocked) return;
    this.setState({ filter: undefined, open: false });
    if (this.props.onBlur) this.props.onBlur(ev);
  }

  // opens the dropdown and ensures the input has focus
  // (this fixes a bug in which rapidly clicking the label or dropdown icon would break the list open state)
  handleFocus = (ev) => {
    this.openList();
    if (this.props.onFocus) this.props.onFocus(ev);
  }

  handleMouseEnter = () => this.blockBlur()

  handleMouseLeave = () => this.unblockBlur()

  handleClick = () => this.openList()

  handleChange = (newValue) => {
    let updatedValue = newValue;
    // if the component is multi value then we need to push the new value into the array of values
    if (this.isMultiValue(this.props.value)) {
      // do not allow the same value twice
      if (this.props.value.find(item => item.value === newValue.value)) return;
      const value = this.props.value.slice();
      value.push(newValue);
      updatedValue = value;
    }
    this.triggerChange(updatedValue);
  }

  handleFilter = (ev) => {
    const { value: filter } = ev.target;
    this.setState({ filter });

    if (this.props.onFilter) this.props.onFilter(filter);
  }

  handleKeyDown = (ev) => {
    // order of event checking is important here!

    // if tab key then allow normal behaviour
    if (Events.isTabKey(ev)) {
      this.unblockBlur();
      return;
    }
    // if the dropdown is not open then block regular activity and open it
    if (!this.state.open) {
      ev.preventDefault();
      this.openList();
      return;
    }
    // if esc key then close the dropdown
    if (Events.isEscKey(ev)) {
      this.setState({ open: false });
      return;
    }
    // if backspace key and multi value and no filter, remove the last item in the array
    if (Events.isBackspaceKey(ev)) {
      if (!this.isMultiValue(this.props.value) || this.state.filter || !this.props.value.length) return;
      this.removeItem(this.props.value.length - 1);
    }

    if (!this.props.filterable) ev.preventDefault();
  }

  openWhenTypeAhead(typeAhead, value) {
    if (!this.props.filterable) return false;

    return typeAhead && value && value.length >= 3;
  }

  openList() {
    if (this.state.open) return;

    this.setState({ open: true });
    if (this.props.onOpen) this.props.onOpen();
  }

  triggerChange(value) {
    const newState = {};
    if (!this.isMultiValue(value)) {
      // only closes the dropdown if not multi-value
      newState.open = false;
      this.unblockBlur();
    }

    newState.filter = undefined;
    this.setState(newState);

    if (this.props.onChange) this.props.onChange({ target: { value } });
  }

  removeItem(index) {
    const newValue = this.props.value.slice(); // copies the array first to not mutate original value
    newValue.splice(index, 1);
    this.triggerChange(newValue);
  }

  // returns the human readable value for the user
  formattedValue(filterValue, value) {
    let visibleValue = '';
    // if not multi-value then fetch the text key on the value
    if (!this.isMultiValue(value) && value) visibleValue = value.text;
    // if there is a filter then return that over the selected visible value
    return (typeof filterValue === 'string') ? filterValue : visibleValue;
  }

  // returns the correct value to feed into the textbox component
  value(value) {
    if (!this.props.filterable) return undefined;
    if (this.isMultiValue(value)) {
      return value; // if multi value the returns the full array
    }
    if (value) return value.value; // if single value then returns the id/value

    return undefined; // otherwise return undefined
  }

  renderMultiValues(values) {
    const canDelete = !this.props.disabled && !this.props.readOnly;

    return (
      values.map((value, index) => (
        <StyledSelectPillContainer key={ value.value }>
          <Pill
            onDelete={ canDelete ? () => this.removeItem(index) : undefined }
            title={ value.text }
          >
            { value.text }
          </Pill>
        </StyledSelectPillContainer>
      ))
    );
  }

  isMultiValue(value) { return Array.isArray(value); }

  placeholder(placeholder, value) {
    let displayedPlaceHolder = this.props.typeAhead ? 'Type to Search...' : 'Please Select...';

    if (placeholder) displayedPlaceHolder = placeholder;
    if (this.isMultiValue(value)) {
      // if multi-value then only show placeholder if nothing is currently selected
      return value.length ? null : displayedPlaceHolder;
    }
    return displayedPlaceHolder;
  }

  // data attributes used for automation
  dataAttributes() {
    return tagComponent(this.props['data-component'], this.props);
  }

  inputIcon(typeAhead, value) {
    if (this.openWhenTypeAhead(typeAhead, this.state.filter)) return 'cross';
    if (typeAhead) return 'search';
    return this.isMultiValue(value) ? undefined : 'dropdown';
  }

  eventProps() {
    let events = {};

    if (!this.props.disabled && !this.props.readOnly) {
      events = {
        onBlur: this.handleBlur,
        onFocus: this.handleFocus,
        onKeyDown: this.handleKeyDown,
        onClick: this.handleClick,
        onChange: this.handleFilter
      };
    }
    return events;
  }

  textboxProps() {
    const {
      typeAhead,
      value,
      placeholder
    } = this.props;

    const props = {
      'data-component': 'carbon-select',
      inputIcon: this.inputIcon(typeAhead, value),
      inputRef: this.assignInput,
      placeholder: this.placeholder(placeholder, value),
      leftChildren: this.isMultiValue(value) && this.renderMultiValues(value),
      value: this.value(value),
      formattedValue: this.formattedValue(this.state.filter, value)
    };

    return props;
  }

  listDisplayable(isTypeAhead) {
    const { filter, open } = this.state;
    return (this.openWhenTypeAhead((isTypeAhead), filter) || !isTypeAhead) ? open : false;
  }

  render() {
    const {
      children,
      customFilter,
      placeholder,
      value,
      onLazyLoad,
      onFilter,
      onOpen,
      typeAhead,
      filterable,
      ...props
    } = this.props;

    const { filter, open } = this.state;

    const allowTypeAhead = filterable ? typeAhead : false;
    return (
      <>
        <Textbox
          { ...props } // this needs to send all of the original props
          { ...this.dataAttributes() }
          { ...this.textboxProps() }
          { ...this.eventProps() }
          role='combobox'
          aria-haspopup='listbox'
          aria-expanded={ open }
        >
          { this.listDisplayable(allowTypeAhead, filter, open) && (
            <SelectList
              alwaysHighlight={ !!filter } // always ensure something is highlighted only if there's a filter
              customFilter={ customFilter }
              filterValue={ filter }
              onLazyLoad={ onLazyLoad }
              onMouseEnter={ this.handleMouseEnter }
              onMouseLeave={ this.handleMouseLeave }
              onSelect={ this.handleChange }
              open={ open }
              target={ this.input.current && this.input.current.parentElement }
              role='listbox'
            >
              { children }
            </SelectList>
          ) }
        </Textbox>
      </>
    );
  }
}

const optionShape = PropTypes.shape({
  value: PropTypes.string.isRequired,
  text: PropTypes.string.isRequired
});

Select.propTypes = {
  children: PropTypes.node,
  className: PropTypes.string,
  customFilter: PropTypes.func,
  disabled: PropTypes.bool,
  label: PropTypes.string,
  onBlur: PropTypes.func,
  onChange: PropTypes.func,
  onFocus: PropTypes.func,
  onOpen: PropTypes.func,
  onLazyLoad: PropTypes.func,
  onFilter: PropTypes.func,
  placeholder: PropTypes.string,
  readOnly: PropTypes.bool,
  value: PropTypes.oneOfType([
    optionShape,
    PropTypes.arrayOf(optionShape)
  ]),
  'data-component': PropTypes.string,
  typeAhead: PropTypes.bool,
  filterable: PropTypes.bool
};

Select.defaultProps = {
  filterable: true,
  typeAhead: false
};

export default Select;
<commit_msg>(FE-1420) Fix a11y: "Required ARIA child role not present: textbox"<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import SelectList from './select-list.component';
import Textbox from '../textbox';
import Pill from '../../../components/pill';
import Events from '../../../utils/helpers/events';
import tagComponent from '../../../utils/helpers/tags';
import StyledSelectPillContainer from './select.style';

/**
 * Basic example:
 *
 *   <Select>
 *     <Option text='Approve' />
 *     <Option text='Configure' />
 *     <Option text='Deny' />
 *   </Select>
 *
 * Custom JSX:
 *
 *   <Select>
 *     <Option text='Approve'><Icon type='tick' /></Option>
 *     <Option text='Configure'><Icon type='settings' /></Option>
 *     <Option text='Deny'><Icon type='cross' /></Option>
 *   </Select>
 */

class Select extends React.Component {
  state = {
    filter: undefined,
    open: false
  }

  blurBlocked = false // stops the blur callback from triggering (closing the list) when we don't want it to

  input = {} // this will store a reference to the input html element

  assignInput = (input) => { this.input = input; }

  blockBlur() {
    this.blurBlocked = true;
  }

  unblockBlur() {
    this.blurBlocked = false;
  }

  handleBlur = (ev) => {
    if (this.blurBlocked) return;
    this.setState({ filter: undefined, open: false });
    if (this.props.onBlur) this.props.onBlur(ev);
  }

  // opens the dropdown and ensures the input has focus
  // (this fixes a bug in which rapidly clicking the label or dropdown icon would break the list open state)
  handleFocus = (ev) => {
    this.openList();
    if (this.props.onFocus) this.props.onFocus(ev);
  }

  handleMouseEnter = () => this.blockBlur()

  handleMouseLeave = () => this.unblockBlur()

  handleClick = () => this.openList()

  handleChange = (newValue) => {
    let updatedValue = newValue;
    // if the component is multi value then we need to push the new value into the array of values
    if (this.isMultiValue(this.props.value)) {
      // do not allow the same value twice
      if (this.props.value.find(item => item.value === newValue.value)) return;
      const value = this.props.value.slice();
      value.push(newValue);
      updatedValue = value;
    }
    this.triggerChange(updatedValue);
  }

  handleFilter = (ev) => {
    const { value: filter } = ev.target;
    this.setState({ filter });

    if (this.props.onFilter) this.props.onFilter(filter);
  }

  handleKeyDown = (ev) => {
    // order of event checking is important here!

    // if tab key then allow normal behaviour
    if (Events.isTabKey(ev)) {
      this.unblockBlur();
      return;
    }
    // if the dropdown is not open then block regular activity and open it
    if (!this.state.open) {
      ev.preventDefault();
      this.openList();
      return;
    }
    // if esc key then close the dropdown
    if (Events.isEscKey(ev)) {
      this.setState({ open: false });
      return;
    }
    // if backspace key and multi value and no filter, remove the last item in the array
    if (Events.isBackspaceKey(ev)) {
      if (!this.isMultiValue(this.props.value) || this.state.filter || !this.props.value.length) return;
      this.removeItem(this.props.value.length - 1);
    }

    if (!this.props.filterable) ev.preventDefault();
  }

  openWhenTypeAhead(typeAhead, value) {
    if (!this.props.filterable) return false;

    return typeAhead && value && value.length >= 3;
  }

  openList() {
    if (this.state.open) return;

    this.setState({ open: true });
    if (this.props.onOpen) this.props.onOpen();
  }

  triggerChange(value) {
    const newState = {};
    if (!this.isMultiValue(value)) {
      // only closes the dropdown if not multi-value
      newState.open = false;
      this.unblockBlur();
    }

    newState.filter = undefined;
    this.setState(newState);

    if (this.props.onChange) this.props.onChange({ target: { value } });
  }

  removeItem(index) {
    const newValue = this.props.value.slice(); // copies the array first to not mutate original value
    newValue.splice(index, 1);
    this.triggerChange(newValue);
  }

  // returns the human readable value for the user
  formattedValue(filterValue, value) {
    let visibleValue = '';
    // if not multi-value then fetch the text key on the value
    if (!this.isMultiValue(value) && value) visibleValue = value.text;
    // if there is a filter then return that over the selected visible value
    return (typeof filterValue === 'string') ? filterValue : visibleValue;
  }

  // returns the correct value to feed into the textbox component
  value(value) {
    if (!this.props.filterable) return undefined;
    if (this.isMultiValue(value)) {
      return value; // if multi value the returns the full array
    }
    if (value) return value.value; // if single value then returns the id/value

    return undefined; // otherwise return undefined
  }

  renderMultiValues(values) {
    const canDelete = !this.props.disabled && !this.props.readOnly;

    return (
      values.map((value, index) => (
        <StyledSelectPillContainer key={ value.value }>
          <Pill
            onDelete={ canDelete ? () => this.removeItem(index) : undefined }
            title={ value.text }
          >
            { value.text }
          </Pill>
        </StyledSelectPillContainer>
      ))
    );
  }

  isMultiValue(value) { return Array.isArray(value); }

  placeholder(placeholder, value) {
    let displayedPlaceHolder = this.props.typeAhead ? 'Type to Search...' : 'Please Select...';

    if (placeholder) displayedPlaceHolder = placeholder;
    if (this.isMultiValue(value)) {
      // if multi-value then only show placeholder if nothing is currently selected
      return value.length ? null : displayedPlaceHolder;
    }
    return displayedPlaceHolder;
  }

  // data attributes used for automation
  dataAttributes() {
    return tagComponent(this.props['data-component'], this.props);
  }

  inputIcon(typeAhead, value) {
    if (this.openWhenTypeAhead(typeAhead, this.state.filter)) return 'cross';
    if (typeAhead) return 'search';
    return this.isMultiValue(value) ? undefined : 'dropdown';
  }

  eventProps() {
    let events = {};

    if (!this.props.disabled && !this.props.readOnly) {
      events = {
        onBlur: this.handleBlur,
        onFocus: this.handleFocus,
        onKeyDown: this.handleKeyDown,
        onClick: this.handleClick,
        onChange: this.handleFilter
      };
    }
    return events;
  }

  textboxProps() {
    const {
      typeAhead,
      value,
      placeholder
    } = this.props;

    const props = {
      'data-component': 'carbon-select',
      inputIcon: this.inputIcon(typeAhead, value),
      inputRef: this.assignInput,
      placeholder: this.placeholder(placeholder, value),
      leftChildren: this.isMultiValue(value) && this.renderMultiValues(value),
      value: this.value(value),
      formattedValue: this.formattedValue(this.state.filter, value)
    };

    return props;
  }

  listDisplayable(isTypeAhead) {
    const { filter, open } = this.state;
    return (this.openWhenTypeAhead((isTypeAhead), filter) || !isTypeAhead) ? open : false;
  }

  render() {
    const {
      children,
      customFilter,
      placeholder,
      value,
      onLazyLoad,
      onFilter,
      onOpen,
      typeAhead,
      filterable,
      ...props
    } = this.props;

    const { filter, open } = this.state;

    const allowTypeAhead = filterable ? typeAhead : false;
    return (
      <div
        role='combobox'
        aria-haspopup='listbox'
        aria-expanded={ open }
      >
        <Textbox
          { ...props } // this needs to send all of the original props
          { ...this.dataAttributes() }
          { ...this.textboxProps() }
          { ...this.eventProps() }
        >
          { this.listDisplayable(allowTypeAhead, filter, open) && (
            <SelectList
              alwaysHighlight={ !!filter } // always ensure something is highlighted only if there's a filter
              customFilter={ customFilter }
              filterValue={ filter }
              onLazyLoad={ onLazyLoad }
              onMouseEnter={ this.handleMouseEnter }
              onMouseLeave={ this.handleMouseLeave }
              onSelect={ this.handleChange }
              open={ open }
              target={ this.input.current && this.input.current.parentElement }
              role='listbox'
            >
              { children }
            </SelectList>
          ) }
        </Textbox>
      </div>
    );
  }
}

const optionShape = PropTypes.shape({
  value: PropTypes.string.isRequired,
  text: PropTypes.string.isRequired
});

Select.propTypes = {
  children: PropTypes.node,
  className: PropTypes.string,
  customFilter: PropTypes.func,
  disabled: PropTypes.bool,
  label: PropTypes.string,
  onBlur: PropTypes.func,
  onChange: PropTypes.func,
  onFocus: PropTypes.func,
  onOpen: PropTypes.func,
  onLazyLoad: PropTypes.func,
  onFilter: PropTypes.func,
  placeholder: PropTypes.string,
  readOnly: PropTypes.bool,
  value: PropTypes.oneOfType([
    optionShape,
    PropTypes.arrayOf(optionShape)
  ]),
  'data-component': PropTypes.string,
  typeAhead: PropTypes.bool,
  filterable: PropTypes.bool
};

Select.defaultProps = {
  filterable: true,
  typeAhead: false
};

export default Select;
<|endoftext|>


<commit_before>function SessionManager(options, serializeUser) {
  if (typeof options == 'function') {
    serializeUser = options;
    options = undefined;
  }
  options = options || {};

  this._key = options.key || 'passport';
  this._serializeUser = serializeUser;
}

SessionManager.prototype.logIn = function(req, user, cb) {
  console.log('SM: logIn');

  var self = this;

  // regenerate the session, which is good practice to help
  // guard against forms of session fixation
  req.session.regenerate(function(err) {
    if (err) {
      return cb(err);
    }

    self._serializeUser(user, req, function(err, obj) {
      if (err) {
        return cb(err);
      }
      // TODO: Error if session isn't available here.
      if (!req.session) {
        req.session = {};
      }
      if (!req.session[self._key]) {
        req.session[self._key] = {};
      }
      // store user information in session, typically a user id
      req.session[self._key].user = obj;
      // save the session before redirection to ensure page
      // load does not happen before session is saved
      req.session.save(function(err) {
        if (err) {
          return cb(err);
        }
        cb();
      });
    });
  });
}

SessionManager.prototype.logOut = function(req, cb) {
  console.log('SM: logOut');

  var self = this;
  req.session.regenerate(function(err) {
    if (err) {
      return cb(err);
    }

    if (req.session && req.session[self._key]) {
      delete req.session[self._key].user;
    }
    cb && cb();
  });
}

module.exports = SessionManager;
<commit_msg>Clear user from old session on logout.<commit_after>function SessionManager(options, serializeUser) {
  if (typeof options == 'function') {
    serializeUser = options;
    options = undefined;
  }
  options = options || {};

  this._key = options.key || 'passport';
  this._serializeUser = serializeUser;
}

SessionManager.prototype.logIn = function(req, user, cb) {
  console.log('SM: logIn');

  var self = this;

  // regenerate the session, which is good practice to help
  // guard against forms of session fixation
  req.session.regenerate(function(err) {
    if (err) {
      return cb(err);
    }

    self._serializeUser(user, req, function(err, obj) {
      if (err) {
        return cb(err);
      }
      // TODO: Error if session isn't available here.
      if (!req.session) {
        req.session = {};
      }
      if (!req.session[self._key]) {
        req.session[self._key] = {};
      }
      // store user information in session, typically a user id
      req.session[self._key].user = obj;
      // save the session before redirection to ensure page
      // load does not happen before session is saved
      req.session.save(function(err) {
        if (err) {
          return cb(err);
        }
        cb();
      });
    });
  });
}

SessionManager.prototype.logOut = function(req, cb) {
  console.log('SM: logOut');

  var self = this;

  // clear the user from the session object and save.
  // this will ensure that re-using the old session id
  // does not have a logged in user
  if (req.session && req.session[this._key]) {
    delete req.session[this._key].user;
  }

  req.session.save(function(err) {
    if (err) {
      return cb(err)
    }

    // regenerate the session, which is good practice to help
    // guard against forms of session fixation
    req.session.regenerate(function(err) {
      if (err) {
        return cb(err);
      }
      cb && cb();
    });
  });
}

module.exports = SessionManager;
<|endoftext|>


<commit_before>import Ember from 'ember';
import Stream from 'ember-format/utils/stream';
import { scanArray, scanHash, readArray, readHash, subscribe } from 'ember-format/utils/stream';

var get = Ember.get;

var _format = function _format(format, input, options) {
  var formatter = this.container.lookup('formatter:' + format);

  return formatter.format(input, options);
};

export default function format(params, hash, options, env) {
  var view = this;
  var numParams = params.length;
  var param, prop;

  Ember.assert("makeBoundHelper generated helpers do not support use with blocks", !options.template);

  function valueFn() {
    var _params = readArray(params);
    return _format.call(view, _params[0], _params[1], readHash(hash));
  }

  var hasStream = scanArray(params) || scanHash(hash);

  var localeStream = get(this, 'locale.stream');
  var lazyValue = new Stream(valueFn);

  localeStream.subscribe(lazyValue.notify, lazyValue);

  if (hasStream) {
    for (var i = 0; i < numParams; i++) {
      param = params[i];
      subscribe(param, lazyValue.notify, lazyValue);
    }

    for (prop in hash) {
      param = hash[prop];
      subscribe(param, lazyValue.notify, lazyValue);
    }
  }

  return lazyValue;
}
<commit_msg>Assert if formatter does not exist<commit_after>import Ember from 'ember';
import Stream from 'ember-format/utils/stream';
import { scanArray, scanHash, readArray, readHash, subscribe } from 'ember-format/utils/stream';

var get = Ember.get;

var _format = function _format(format, input, options) {
  var formatter = this.container.lookup('formatter:' + format);

  Ember.assert('You specified `' + format +  '` in your template, but a formatter for `' + format + '` could not be found.', !!formatter);

  return formatter.format(input, options);
};

export default function format(params, hash, options, env) {
  var view = this;
  var numParams = params.length;
  var param, prop;

  Ember.assert("makeBoundHelper generated helpers do not support use with blocks", !options.template);

  function valueFn() {
    var _params = readArray(params);
    return _format.call(view, _params[0], _params[1], readHash(hash));
  }

  var hasStream = scanArray(params) || scanHash(hash);

  var localeStream = get(this, 'locale.stream');
  var lazyValue = new Stream(valueFn);

  localeStream.subscribe(lazyValue.notify, lazyValue);

  if (hasStream) {
    for (var i = 0; i < numParams; i++) {
      param = params[i];
      subscribe(param, lazyValue.notify, lazyValue);
    }

    for (prop in hash) {
      param = hash[prop];
      subscribe(param, lazyValue.notify, lazyValue);
    }
  }

  return lazyValue;
}
<|endoftext|>


<commit_before>window.FoodTruckLocator = function() {
  function buildIconUrl(letter) {
    return "http://www.google.com/mapfiles/marker" + letter + ".png"
  }

  function distanceSort(a, b) {
    if (typeof a.distance == "undefined" || a.distance == null) {
      return 0;
    }
    return a.distance > b.distance ? 1 : ((a.distance == b.distance) ? 0 : -1);
  }

  function buildMarker(objectOnMap, letter, bounds, map) {
    objectOnMap.marker = new google.maps.Marker({
      map: map,
      icon: buildIconUrl(letter),
      position: objectOnMap.position.latLng
    });
    bounds.extend(objectOnMap.position.latLng);
  }

  function removeChicago(location) {
    if (/, Chicago, IL$/i.test(location)) {
      location = location.substring(0, location.length - 13);
    }
    return location;
  }

  var TruckGroup = function(location) {
    var self = this;
    self.trucks = [];
    self.position = location;
    self.addTruck = function(truck) {
      self.trucks.push(truck);
    }
  };

  var Trucks = Backbone.Model.extend({
    url : function() {
      return '/service/schedule';
    },
    getTrucks : function() {
      var self = this;
      if (typeof(this.trucks) != "undefined") {
        return this.trucks;
      }
      var payload = this.get("payload");
      self.trucks = {};
      $.each(payload.trucks, function(idx, truck) {
        self.trucks[truck.id] = truck;
      });
      return self.trucks;
    },
    linkLocations : function(payload) {
      var locations = payload.locations;
      $.each(payload.stops, function(idx, stop) {
        stop.location = locations[stop.location - 1];
      });
    },
    getGroups : function(time) {
      var self = this, groups = [],groupMap = {};
      var payload = this.get("payload");
      var trucks = self.getTrucks();
      var center = this.get("center");
      $.each(payload.stops, function(idx, stop) {
        if (time >= stop.startMillis && time < stop.endMillis) {
          var truckGroup = groupMap[stop.location.name];
          if (typeof(truckGroup) == "undefined") {
            var latlng = new google.maps.LatLng(stop.location.latitude,
                stop.location.longitude);
            truckGroup = new TruckGroup({name: stop.location.name, latLng : latlng });
            if (center) {
              distance = google.maps.geometry.spherical.computeDistanceBetween(center,
                  truckGroup.position.latLng, 3959);
              truckGroup.distance = Math.round(distance * 100) / 100;
            }
            groupMap[stop.location.name] = truckGroup;
            groups.push(truckGroup);
          }
          truckGroup.addTruck(trucks[stop.truckId]);
        }
      });
      return groups;
    }
  });

  var MapView = Backbone.View.extend({
    initialize : function() {
      this.showControlsForMap();
      this.fitMapToView();
      this.groups = [];
      this.map = new google.maps.Map(document.getElementById("map_canvas"), {
        zoom: 13,
        center: this.options.center,
        maxZoom : 15,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      });
      var self = this;
      var TimeSlider = function(initialTime) {
        var sliderValue = (initialTime.getHours() * 60) +
            (Math.floor(initialTime.getMinutes() / 5) * 5);

        function computeTime(value, twelveHour) {
          // yuck - cleanup
          var val = value / 60;
          var hour = Math.floor(val);
          var min = Math.round((val - hour) * 60);
          if (hour > 12 && twelveHour) {
            hour = hour - 12;
          }
          hour = (hour < 10) ? "0" + hour : "" + hour;
          min = (min < 10) ? "0" + min : "" + min;
          return [hour, min];
        }

        function displayTime(value) {
          var time = computeTime(value, true);
          $("#sliderTime").empty().append(time.join(":"));
        }

        displayTime(sliderValue);
        $("#slider").slider({
          min: 0,  max: 1440, value : sliderValue, step: 5,
          slide : function(event, ui) {
            displayTime(ui.value);
          },
          change: function(event, ui) {
            var time = computeTime(ui.value, false);
            self.currentTime.setHours(time[0]);
            self.currentTime.setMinutes(time[1]);
            self.render();
          }
        });

        this.value = function(hour, min) {
          var val = (hour * 60) + min;
          displayTime(val);
          $("#slider").slider("option", "value", val);
        };
      };
      self.currentTime = self.model.get("initialTime");
      self.slider = new TimeSlider(self.currentTime);
      return this;
    },
    showControlsForMap : function() {
      $(".sliderContainer").css("display", "block");
      $("hr").css("display", "block");
    },
    fitMapToView :function() {
      $("#right").css("display", "block");
      if (Modernizr.touch) {
        $("#left").css("overflow-y", "visible");
        $("#left").width(250);
        $("#map_wrapper").css("margin-left", "250px");
        $("#map_canvas").width($(window).width() - 250);
      } else {
        $("#right").width($("#map_canvas").width() - $("#left").width());
        $("#left").css("margin-left", "-" + $("#map_canvas").width() + "px");
        $("#map_canvas").height($(window).height() - $("header").height());
        $("#right").height($("#map_canvas").height());
        $("#left").height($("#right").height());
        $("#foodTruckList").height($("#left").height() - $("#sliderContainer").height() -
            $("header").height() - 75);
        $("#body").height($("#body").height() - $("header").height());
      }
    },
    removeAllMarkers : function() {
      var groups = this.groups || [];
      $.each(groups, function(idx, group) {
        if (group.marker) {
          group.marker.setMap(null);
          group.marker = null;
        }
      });
      this.groups = [];
    },
    render: function() {
      var self = this;
      self.removeAllMarkers();
      var groups = self.groups = this.model.getGroups(self.currentTime);
      var bounds = new google.maps.LatLngBounds();
      bounds.extend(this.options.center);
      var menuSection = $("#foodTruckList");
      menuSection.empty();
      function buildGroupInfo(group, idx, letter) {
        group.index = idx;
        menuSection.append("
");
        var section = $('#group' + idx);
        var markerText = " ";
        markerText =
            "";
        section.append("
" + markerText + "
");
        section.append("

");
        var div = $('#location' + idx + 'Section');
        div.append("<address class='locationName'>" + removeChicago(group.position.name) +
            "</address>");
        if (group.distance && self.showDistance) {
          div.append("" + group.distance + " miles away

")
        }
        return div;
      }

      function buildIconForTruck(truck, contentDiv) {
        contentDiv.append("
");
        var section = $('#truck' + truck.id);
        section.append("

");
        section.append("

");
        var div = $('#truck' + truck.id + 'Section');
        div.append("" + truck.name +
            "
");
        var infoRow = "
";

        $(".truckLink" + truck.id).click(function(evt) {
          evt.preventDefault();
          buildTruckInfoDialog(truck);
        });
        if (truck.twitterHandle) {
          infoRow += " ";
        }
        if (truck.facebook) {
          infoRow += " ";
        }
        infoRow += '
';
        div.append(infoRow);
      }

      function buildInfoWindow(group) {
        var contentString = "
<address class='locaitonName'>" +
            group.position.name + "</address>";
        contentString = contentString + "
"
        $.each(group.trucks, function(truckIdx, truck) {
          contentString +=
              "
" +
                  truck.name + "
"
        });
        contentString = contentString + "

";
        var infowindow = new google.maps.InfoWindow({
          content: contentString
        });

        google.maps.event.addListener(group.marker, 'click', function() {
          infowindow.open(self.map, group.marker);
        });
        group.infowindow = infowindow;
      }

      if (groups.length == 0) {
        menuSection
            .append("
Presently, there are no food trucks on the road. Most food trucks come on the streets at 11:30 or so.
");
        $("#advanceTime").live("click", function(e) {
          e.preventDefault();
          self.slider.value(11, 30);
        });
        return;
      }
      var sorted = groups.sort(function (a, b) {
        if (typeof a.distance == "undefined" || a.distance == null) {
          return 0;
        }
        return a.distance > b.distance ? 1 : ((a.distance == b.distance) ? 0 : -1);
      });
      $.each(sorted, function(groupIndex, group) {
        var letter = String.fromCharCode(65 + groupIndex);
        buildMarker(group, letter, bounds, self.map);
        var contentDiv = buildGroupInfo(group, groupIndex, letter);
        $.each(group.trucks, function(idx, truck) {
          buildIconForTruck(truck, contentDiv);
        });
        buildInfoWindow(group);
        $("#markerIcon" + groupIndex).click(function() {
          $.each(sorted, function(gIndex, g) {
            g.infowindow.close();
            $(".menuSection").removeClass("hilightedSection");
          });
          group.infowindow.open(self.map, group.marker);
          $("#group" + groupIndex).addClass("hilightedSection");
        });
      });
      self.map.fitBounds(bounds);
      return this;
    }
  });

  function loadWithoutGeo(view, date, center) {
    view.showDistance = false;
    var truckObj = new Trucks(view, center);
    truckObj.loadTrucks(date, null);
  }

  function loadAllTrucks(view, date, center) {
    // this isn't very practical on the desktop and takes a while on firefox
    if (Modernizr.geolocation && Modernizr.touch) {
      navigator.geolocation.getCurrentPosition(function(position) {
        var currentLocation = new google.maps.LatLng(position.coords.latitude,
            position.coords.longitude);
        var truckObj = new Trucks(view, currentLocation);
        truckObj.loadTrucks(date);
      }, function() {
        loadWithoutGeo(view, date, center)
      });
    } else {
      loadWithoutGeo(view, date, center);
    }
  }

  function showControlsForNoMap() {
    $("#right").css("display", "none");
    $("#left").css("overflow-y", "visible");
    $("header h1").css("float", "none");
    $("#buttonSection").css("float", "none");
    $("#body").css("clear", "none");
    $("#left").css("margin-left", "0");
    $("#left").css("overflow-y", "visible");
    $(".sliderContainer").css("display", "none");
    $(".timeSelect").css("display", "block");
  }

  function displayTime(time) {
    $("#timeValue").css("display", "inline");
    var minutes = (time.getMinutes() < 10) ? ("0" + time.getMinutes()) : time.getMinutes();
    $("#timeValue").append("at " + time.getHours() + ":" + minutes);
  }

  return {
    isTouchScreenLandscape : function() {
      return Modernizr.touch && window.innerWidth > window.innerHeight;
    },
    isTouchScreenPortrait : function() {
      return Modernizr.touch && window.innerHeight > window.innerWidth;
    },
    run : function(mobile, center, time, modelPayload) {
      if (this.isTouchScreenPortrait() || mobile) {
        this.loadTrucksWithoutMap(center, time, modelPayload);
      } else {
        this.loadTrucksWithMap(center, time, modelPayload);
      }
    },
    loadTrucksWithoutMap : function(center, time, mobilePayload) {
      showControlsForNoMap();
      displayTime(time);
    },
    loadTrucksWithMap : function(center, time, mobilePayload) {
      var trucks = new Trucks({initialTime: time, center: center});
      var view = new MapView({ center : center, model : trucks, el : "map_canvas"});
      trucks.bind('change:payload', function(model, payload) {
        model.linkLocations(payload);
        view.render();
      });
      trucks.set({ payload : mobilePayload });
    }
  };
}();

<commit_msg>Added back list view and geolocation<commit_after>window.FoodTruckLocator = function() {
  function buildIconUrl(letter) {
    return "http://www.google.com/mapfiles/marker" + letter + ".png"
  }

  function distanceSort(a, b) {
    if (typeof a.distance == "undefined" || a.distance == null) {
      return 0;
    }
    return a.distance > b.distance ? 1 : ((a.distance == b.distance) ? 0 : -1);
  }

  function buildMarker(objectOnMap, letter, bounds, map) {
    objectOnMap.marker = new google.maps.Marker({
      map: map,
      icon: buildIconUrl(letter),
      position: objectOnMap.position.latLng
    });
    bounds.extend(objectOnMap.position.latLng);
  }

  function removeChicago(location) {
    if (/, Chicago, IL$/i.test(location)) {
      location = location.substring(0, location.length - 13);
    }
    return location;
  }

  var TruckGroup = function(location) {
    var self = this;
    self.trucks = [];
    self.position = location;
    self.addTruck = function(truck) {
      self.trucks.push(truck);
    }
  };

  var Trucks = Backbone.Model.extend({
    url : function() {
      return '/service/schedule';
    },
    getTrucks : function() {
      var self = this;
      if (typeof(this.trucks) != "undefined") {
        return this.trucks;
      }
      var payload = this.get("payload");
      self.trucks = {};
      $.each(payload.trucks, function(idx, truck) {
        self.trucks[truck.id] = truck;
      });
      return self.trucks;
    },
    linkLocations : function(payload) {
      var locations = payload.locations;
      $.each(payload.stops, function(idx, stop) {
        stop.location = locations[stop.location - 1];
      });
    },
    getGroups : function(time) {
      var self = this, groups = [],groupMap = {};
      var payload = this.get("payload");
      var trucks = self.getTrucks();
      var center = this.get("center");
      $.each(payload.stops, function(idx, stop) {
        if (time >= stop.startMillis && time < stop.endMillis) {
          var truckGroup = groupMap[stop.location.name];
          if (typeof(truckGroup) == "undefined") {
            var latlng = new google.maps.LatLng(stop.location.latitude,
                stop.location.longitude);
            truckGroup = new TruckGroup({name: stop.location.name, latLng : latlng });
            if (center) {
              distance = google.maps.geometry.spherical.computeDistanceBetween(center,
                  truckGroup.position.latLng, 3959);
              truckGroup.distance = Math.round(distance * 100) / 100;
            }
            groupMap[stop.location.name] = truckGroup;
            groups.push(truckGroup);
          }
          truckGroup.addTruck(trucks[stop.truckId]);
        }
      });
      return groups;
    }
  });

  var ListView = Backbone.View.extend({
    initialize : function() {
      var self = this;
      self.showControls();
      self.currentTime = self.model.get("initialTime");
      self.displayTime(self.currentTime);
      self.setupTimeSelector();
    },
    showControls : function() {
      $("#right").css("display", "none");
      $("#left").css("overflow-y", "visible");
      $("header h1").css("float", "none");
      $("#buttonSection").css("float", "none");
      $("#body").css("clear", "none");
      $("#left").css("margin-left", "0");
      $("#left").css("overflow-y", "visible");
      $(".sliderContainer").css("display", "none");
      $(".timeSelect").css("display", "block");
    },
    displayTime : function(time) {
      $("#timeValue").css("display", "inline");
      var minutes = (time.getMinutes() < 10) ? ("0" + time.getMinutes()) : time.getMinutes();
      $("#timeValue").append("at " + time.getHours() + ":" + minutes);
    },
    render : function() {
      var self = this;
      var groups = self.groups = this.model.getGroups(self.currentTime);
      var menuSection = $("#foodTruckList");
      menuSection.empty();
      if (groups.length == 0) {
        menuSection
            .append("
There are presently no food trucks on the road.  Most are on the road around 11:30.
");
        return;
      }
      var sorted = groups.sort(distanceSort);
      $.each(sorted, function(groupIndex, group) {
        menuSection.append("

");
        var section = $("#group" + groupIndex);
        section.append("

");
        var div = $('#location' + groupIndex + 'Section');
        div.append("<address class='locationName mobile'>" + group.position.name + "</address>");
        if (group.distance) {
          div.append("" + group.distance + " miles away
")
        }
        div
            .append(" view map

")
        $.each(group.trucks, function(idx, truck) {
          div.append("

");
          var truckDiv = $('#truck' + truck.id);
          truckDiv.append("

");
          truckDiv.append("

");
          var truckLeft = $("#truckLeft" + truck.id);

          truckLeft.append("" + truck.name + "
");
          var infoRow = "
";

          if (truck.twitterHandle) {
            infoRow += " ";
          }
          if (truck.facebook) {
            infoRow += " ";
          }
          if (truck.foursquare) {
            infoRow += "";
          }
          infoRow += '
';
          truckLeft.append(infoRow);
        });
      });
      $(".locationContent").css("margin", "0");

    },
    setupTimeSelector : function() {
      var self = this, ampm = "am";
      var hours = self.currentTime.getHours();
      if (hours > 12) {
        hours = hours - 12;
        ampm = "pm";
      }
      var minutes = Math.floor(self.currentTime.getMinutes() / 15) * 15;
      $("#hourSelect").val(hours);
      $("#minSelect").val(minutes);
      $("#ampmSelect").val(ampm);
      $("#timeGoButton").live("click", function() {
        var selectedHour = parseInt($("#hourSelect").val());
        var selectedMin = parseInt($("#minSelect").val());
        var selectedAmPm = $("#ampmSelect").val();
        if (selectedAmPm == "pm" && parseInt(selectedHour) != 12) {
          selectedHour = parseInt(selectedHour) + 12;
        }
        self.currentTime.setHours(selectedHour);
        self.currentTime.setMinutes(selectedMin);
        self.render();
      });
    }

  });

  var MapView = Backbone.View.extend({
    initialize : function() {
      this.showControlsForMap();
      this.fitMapToView();
      this.groups = [];
      this.map = new google.maps.Map(document.getElementById("map_canvas"), {
        zoom: 13,
        center: this.options.center,
        maxZoom : 15,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      });
      var self = this;
      var TimeSlider = function(initialTime) {
        var sliderValue = (initialTime.getHours() * 60) +
            (Math.floor(initialTime.getMinutes() / 5) * 5);

        function computeTime(value, twelveHour) {
          // yuck - cleanup
          var val = value / 60;
          var hour = Math.floor(val);
          var min = Math.round((val - hour) * 60);
          if (hour > 12 && twelveHour) {
            hour = hour - 12;
          }
          hour = (hour < 10) ? "0" + hour : "" + hour;
          min = (min < 10) ? "0" + min : "" + min;
          return [hour, min];
        }

        function displayTime(value) {
          var time = computeTime(value, true);
          $("#sliderTime").empty().append(time.join(":"));
        }

        displayTime(sliderValue);
        $("#slider").slider({
          min: 0,  max: 1440, value : sliderValue, step: 5,
          slide : function(event, ui) {
            displayTime(ui.value);
          },
          change: function(event, ui) {
            var time = computeTime(ui.value, false);
            self.currentTime.setHours(time[0]);
            self.currentTime.setMinutes(time[1]);
            self.render();
          }
        });

        this.value = function(hour, min) {
          var val = (hour * 60) + min;
          displayTime(val);
          $("#slider").slider("option", "value", val);
        };
      };
      self.currentTime = self.model.get("initialTime");
      self.slider = new TimeSlider(self.currentTime);
      return this;
    },
    showControlsForMap : function() {
      $(".sliderContainer").css("display", "block");
      $("hr").css("display", "block");
    },
    fitMapToView :function() {
      $("#right").css("display", "block");
      if (Modernizr.touch) {
        $("#left").css("overflow-y", "visible");
        $("#left").width(250);
        $("#map_wrapper").css("margin-left", "250px");
        $("#map_canvas").width($(window).width() - 250);
      } else {
        $("#right").width($("#map_canvas").width() - $("#left").width());
        $("#left").css("margin-left", "-" + $("#map_canvas").width() + "px");
        $("#map_canvas").height($(window).height() - $("header").height());
        $("#right").height($("#map_canvas").height());
        $("#left").height($("#right").height());
        $("#foodTruckList").height($("#left").height() - $("#sliderContainer").height() -
            $("header").height() - 75);
        $("#body").height($("#body").height() - $("header").height());
      }
    },
    removeAllMarkers : function() {
      var groups = this.groups || [];
      $.each(groups, function(idx, group) {
        if (group.marker) {
          group.marker.setMap(null);
          group.marker = null;
        }
      });
      this.groups = [];
    },
    render: function() {
      var self = this;
      self.removeAllMarkers();
      var groups = self.groups = this.model.getGroups(self.currentTime);
      var bounds = new google.maps.LatLngBounds();
      bounds.extend(this.options.center);
      var menuSection = $("#foodTruckList");
      menuSection.empty();
      function buildGroupInfo(group, idx, letter) {
        group.index = idx;
        menuSection.append("
");
        var section = $('#group' + idx);
        var markerText = " ";
        markerText =
            "";
        section.append("
" + markerText + "
");
        section.append("

");
        var div = $('#location' + idx + 'Section');
        div.append("<address class='locationName'>" + removeChicago(group.position.name) +
            "</address>");
        if (group.distance && self.showDistance) {
          div.append("" + group.distance + " miles away

")
        }
        return div;
      }

      function buildIconForTruck(truck, contentDiv) {
        contentDiv.append("
");
        var section = $('#truck' + truck.id);
        section.append("

");
        section.append("

");
        var div = $('#truck' + truck.id + 'Section');
        div.append("" + truck.name +
            "
");
        var infoRow = "
";

        $(".truckLink" + truck.id).click(function(evt) {
          evt.preventDefault();
          buildTruckInfoDialog(truck);
        });
        if (truck.twitterHandle) {
          infoRow += " ";
        }
        if (truck.facebook) {
          infoRow += " ";
        }
        infoRow += '
';
        div.append(infoRow);
      }

      function buildInfoWindow(group) {
        var contentString = "
<address class='locaitonName'>" +
            group.position.name + "</address>";
        contentString = contentString + "
"
        $.each(group.trucks, function(truckIdx, truck) {
          contentString +=
              "
" +
                  truck.name + "
"
        });
        contentString = contentString + "

";
        var infowindow = new google.maps.InfoWindow({
          content: contentString
        });

        google.maps.event.addListener(group.marker, 'click', function() {
          infowindow.open(self.map, group.marker);
        });
        group.infowindow = infowindow;
      }

      if (groups.length == 0) {
        menuSection
            .append("
Presently, there are no food trucks on the road. Most food trucks come on the streets at 11:30 or so.
");
        $("#advanceTime").live("click", function(e) {
          e.preventDefault();
          self.slider.value(11, 30);
        });
        return;
      }
      var sorted = groups.sort(function (a, b) {
        if (typeof a.distance == "undefined" || a.distance == null) {
          return 0;
        }
        return a.distance > b.distance ? 1 : ((a.distance == b.distance) ? 0 : -1);
      });
      $.each(sorted, function(groupIndex, group) {
        var letter = String.fromCharCode(65 + groupIndex);
        buildMarker(group, letter, bounds, self.map);
        var contentDiv = buildGroupInfo(group, groupIndex, letter);
        $.each(group.trucks, function(idx, truck) {
          buildIconForTruck(truck, contentDiv);
        });
        buildInfoWindow(group);
        $("#markerIcon" + groupIndex).click(function() {
          $.each(sorted, function(gIndex, g) {
            g.infowindow.close();
            $(".menuSection").removeClass("hilightedSection");
          });
          group.infowindow.open(self.map, group.marker);
          $("#group" + groupIndex).addClass("hilightedSection");
        });
      });
      self.map.fitBounds(bounds);
      return this;
    }
  });

  return {
    isTouchScreenLandscape : function() {
      return Modernizr.touch && window.innerWidth > window.innerHeight;
    },
    isTouchScreenPortrait : function() {
      return Modernizr.touch && window.innerHeight > window.innerWidth;
    },
    load : function(mobile, center, time, modelPayload) {
      var view, trucks = new Trucks({initialTime: time, center: center});
      if (this.isTouchScreenPortrait() || mobile) {
        view = new ListView({center : center, model : trucks, el: "foodTruckList"});
      } else {
        view = new MapView({ center : center, model : trucks, el : "map_canvas"});
      }
      trucks.bind('change:payload', function(model, payload) {
        model.linkLocations(payload);
        view.render();
      });
      trucks.set({ payload : modelPayload });

    },
    run : function(mobile, center, time, modelPayload) {
      var self = this;
      if (Modernizr.geolocation && Modernizr.touch) {
        navigator.geolocation.getCurrentPosition(function(position) {
          var currentLocation = new google.maps.LatLng(position.coords.latitude,
              position.coords.longitude);
          self.load(mobile, currentLocation, time, modelPayload);
        }, function() {
          self.load(mobile, center, time, modelPayload);
        });
      } else {
        self.load(mobile, center, time, modelPayload);
      }
    }
  };
}();

<|endoftext|>


<commit_before>var Flash = function (session) {
  this.session = session;
};

Flash.prototype = new (function () {

  this.init = function () {
    if (!this.session.get('flashMessages')) {
      this.session.set('flashMessages',{
        error:[],
        info:[],
        success:[]
      });
    }
  };

  this.get = function (type) {
    this.init();

    var messages = this.session.get('flashMessages');

    var _messages;
    if (typeof messages[type] == "object") {
      _messages = messages[type];
      messages[type] = [];
      this.session.set('flashMessages',messages);
      return _messages;
    }
    return [];
  };

  this.add = function (message, t) {
    this.init();

    var type = t || 'info';

    var messages = this.session.get('flashMessages');

    // convert non strings to strings
    if (typeof message != 'string') {
      if (typeof message.toString == 'function') {
        message = message.toString();
      }
    }
    if (typeof messages[type] == "undefined") {
      messages[type] = [];
    }
    messages[type].push(message);
    this.session.set('flashMessages',messages);
  };

  this.has = function () {
    this.init();

    var messages = this.session.get('flashMessages');

    for(var type in messages) {
      if (messages[type].length > 0) {
        return true;
      }
    }

    return false;
  };
})();

exports.Flash = Flash;
<commit_msg>JS idiom, added some fallbacks for message stringification<commit_after>var Flash = function (session) {
  this.session = session;
};

Flash.prototype = new (function () {

  this.init = function () {
    if (!this.session.get('flashMessages')) {
      this.session.set('flashMessages',{
        error:[],
        info:[],
        success:[]
      });
    }
  };

  this.get = function (type) {
    this.init();

    var messages = this.session.get('flashMessages');

    var _messages;
    if (typeof messages[type] == "object") {
      _messages = messages[type];
      messages[type] = [];
      this.session.set('flashMessages',messages);
      return _messages;
    }
    return [];
  };

  this.add = function (message, t) {
    this.init();

    var type = t || 'info';

    var messages = this.session.get('flashMessages');

    // convert non strings to strings
    if (typeof message != 'string') {
      if (typeof message.toString == 'function') {
        message = message.toString();
        if (message == "[object Object]") {
          message = JSON.stringify(message);
        }
      }
      else {
        message = JSON.stringify(message);
      }
    }
    messages[type] = mesages[type] || [];
    messages[type].push(message);
    this.session.set('flashMessages',messages);
  };

  this.has = function () {
    this.init();

    var messages = this.session.get('flashMessages');

    for(var type in messages) {
      if (messages[type].length) {
        return true;
      }
    }

    return false;
  };
})();

exports.Flash = Flash;
<|endoftext|>