<commit_before>var https = require('https'),
    querystring = require('querystring'),
    Buffer = require('buffer').Buffer;

var API_SERVER = 'api.twilio.com';
var API_VERSION = '2010-04-01';

function RestClient(sid, authToken) {
    if(!(this instanceof RestClient)) {
        return new RestClient(sid, authToken);
    }

    if(!sid) {
        throw new Error('RestClient must be passed a SID');
    }

    if(!authToken) {
        throw new Error('RestClient must be passed an authToken');
    }

    this.sid = sid;
    this.authToken = authToken;

    this.basicAuth = (new Buffer(sid + ':' + authToken)).toString('base64');
}

module.exports = RestClient;

RestClient.prototype.apiCall = function(method, path, options, suc, err, wholePath) {
    var self = this;

    method = method.toUpperCase();
    options = options || {};

    var params = options.params,
        headers = options.headers || {},
        fullPath = '';

    if(params) {
        if(typeof params != 'string') {
            params = querystring.stringify(params);
        }
    }

    if(wholePath) {
        fullPath = path;
    } else {
        fullPath = '/' + API_VERSION + '/Accounts/' + self.sid;
        if(path.length > 0) {
            if(path[0] != '/') {
                fullPath += '/';
            }
            fullPath += path;
        }
        if(fullPath.substr(fullPath.length - 5) != '.json') {
            fullPath += '.json';
        }
    }

    if(params && method == 'POST') {
        headers['Content-Length'] = params.length;
        headers['Content-Type'] = 'application/x-www-form-urlencoded';
    } else if(params && method == 'GET') {
        fullPath += '?' + params;
    }

    headers.Host = API_SERVER;
    headers.Authorization = "Basic " + self.basicAuth;

    var request = https.request({ host: API_SERVER, port: 443, method: method, path: fullPath, headers: headers }, function(response) {
       var responseChunks = [];
       response.setEncoding('utf8');

       response.on('data', function(chunk) {
           responseChunks.push(chunk);
       });

       response.on('end', function() {
           var body = responseChunks.join('');

           // Try to deserialize if possible
           try {
               body = JSON.parse(body);
           } catch(err) {
               // Do nothing. Probably wasn't JSON. We'll just return the string.
           }
           if(typeof suc == 'function') suc(body);
       });

       if(typeof err == 'function') {
           response.on('error', err);
       }
    });

    if(params && method == 'POST') {
       request.write(params);
    }
    request.end();
};

//-----------------------------------------------------------------------------
//--------------------- Accounts
//-----------------------------------------------------------------------------

/**
 * getAccountInfo: Request your account information
 */
RestClient.prototype.getAccountInfo = function(suc, err) {
    this.apiCall('GET', '', null, suc, err);
};

/**
 * updateAccountInfo: Update your account information
 *
 * @param {Map} params: Map of information to update. Currently, only
 * FriendlyName is supported.
 */
RestClient.prototype.updateAccountInfo = function(params, suc, err) {
    this.apiCall('POST', '', {params: params}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Available Phone Numbers
//-----------------------------------------------------------------------------

// Country can be either 'CA' or 'US' (until Twilio gets more areas serviced)
// Possible filters: AreaCode, Contains, InRegion, InPostalCode, NearLatLong,
// InLata, InRateCenter, Distance
RestClient.prototype.getAvailableLocalNumbers = function(country, filters, suc, err) {
    if(!country) {
        throw new Error('Country argument required');
    }
    this.apiCall('GET', '/AvailablePhoneNumbers/' + country + '/Local',
                 {params: filters}, suc, err);
};

// Country can be either 'CA' or 'US'
// Possible filters: Contains
RestClient.prototype.getAvailableTollFreeNumbers = function(country, filters, suc, err) {
    if(!country) {
        throw new Error('Country argument required');
    }
    this.apiCall('GET', '/AvailablePhoneNumbers/' + country + '/Local',
                 {params: filters}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Outgoing Caller Ids
//-----------------------------------------------------------------------------

RestClient.prototype.getOutgoingCallerId = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Outgoing SID argument required');
    }
    this.apiCall('GET', '/OutgoingCallerIds/' + sid, null, suc, err);
};

RestClient.prototype.updateOutgoingCallerId = function(sid, params, suc, err) {
    if(!sid) {
        throw new Error('Outgoing SID argument required');
    }
    this.apiCall('POST', '/OutgoingCallerIds/' + sid, null, suc, err);
};

RestClient.prototype.deleteOutgoingCallerId = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Outgoing SID argument required');
    }
    this.apiCall('DELETE', '/OutgoingCallerIds/' + sid, null, suc, err);
};

// Possible filters: PhoneNumber, FriendlyName
RestClient.prototype.getOutgoingCallerIdList = function(filters, suc, err) {
    this.apiCall('GET', '/OutgoingCallerIds', {params: filters}, suc, err);
};

// Add an outgoing caller ID. This will cause Twilio to call the specified
// number to verify it. CallDelay specifies a delay (<=60) for the call.
// Possible params: FriendlyName, CallDelay
RestClient.prototype.addOutgoingCallerId = function(num, params, suc, err) {
    if(!num) {
        throw new Error('Phone number argument required');
    }
    params = params || {};
    params.PhoneNumber = num;

    this.apiCall('POST', '/OutgoingCallerIds', {params: params}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Incoming Phone Numbers
//-----------------------------------------------------------------------------

// Possible filters: PhoneNumber, FriendlyName
RestClient.prototype.getIncomingNumbers = function(filters, suc, err) {
    this.apiCall('GET', '/IncomingPhoneNumbers', {params: filters}, suc, err);
};

RestClient.prototype.getIncomingNumber = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }
    this.apiCall('GET', '/IncomingPhoneNumbers/' + sid, null, suc, err);
};

RestClient.prototype.updateIncomingNumber = function(sid, params, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }
    this.apiCall('POST', '/IncomingPhoneNumbers/' + sid, {params: params}, suc, err);
};

RestClient.prototype.deleteIncomingNumber = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }
    this.apiCall('DELETE', '/IncomingPhoneNumbers/' + sid, null, suc, err);
};

// Possible optional params: FriendlyName, VoiceUrl, VoiceMethod, VoiceFallbackUrl,
// StatusCallback, StatusCallbackMethod, SmsUrl, SmsMethod, SmsFallbackUrl,
// SmsFallbackMethod, VoiceCallerIdLookup
RestClient.prototype.provisionIncomingNumber = function(num, areaCode, params, suc, err) {
    params = params || {};
    params.PhoneNumber = num;
    params.AreaCode = areaCode;
    this.apiCall('POST', '/IncomingPhoneNumbers', {params: params}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Calls
//-----------------------------------------------------------------------------

/**
 * getCallList: Request a list of call instance resources
 *
 * @param {Map} filters: An optional map of possible filters. See:
 * http://www.twilio.com/docs/api/2010-04-01/rest/call
 */
RestClient.prototype.getCallList = function(filters, suc, err) {
    this.apiCall('GET', '/Calls', null, suc, err);
};

/**
 * getCallInstance: Request a call instance resource
 *
 * @param {String} sid: The sid of the call to fetch
 */
RestClient.prototype.getCallInstance = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }

    this.apiCall('GET', '/Calls/' + sid, {params: filters}, suc, err);
};

/**
 * makeCall: Place a call
 *
 * @param {String} from: The number the call is originating from. Must be a
 * Twilio number of a valid outgoing caller ID for your account, in E.164
 * format (i.e., +18674451795)
 * @param {String} to: The number of the callee. Same format as from.
 * @param {String} url: The callback URL that Twilio will request when the
 * call is picked up.
 * @param {Map} opts: A map of optional parameters. See:
 * http://www.twilio.com/docs/api/2010-04-01/rest/making_calls
 */
RestClient.prototype.makeOutgoingCall = function(from, to, url, opts, suc, err) {
    if(!from || !to || !url) {
        throw new Error('From, to, and URL arguments required');
    }

    opts = opts || {};
    opts.Url = url;
    opts.From = from;
    opts.To = to;

    this.apiCall('POST', '/Calls', {params: opts}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- SMS
//-----------------------------------------------------------------------------

/**
 * getSmsInstance: Request an SMS instance resource
 *
 * @param {String} sid: The sid of the message to retrieve.
 */
RestClient.prototype.getSmsInstance = function(messageSid, suc, err) {
    this.apiCall('GET', '/SMS/Messages/' + messageSid, null, suc, err);
};

/**
 * getSmsList: Request a list of SMS instance resources
 *
 * @param {Map} filters: An optional map of filters. See:
 * http://www.twilio.com/docs/api/2010-04-01/rest/sms
 */
RestClient.prototype.getSmsList = function(filters, suc, err) {
    this.apiCall('GET', '/SMS/Messages', {params: filters}, suc, err);
};

/**
 * sendSms: Send a new SMS message
 *
 * @param {String} from: The outgoing callerId. Must be a valid twilio/outgoing
 * caller id number, in E.164 format (i.e., +18674451795)
 * @param {String} to: The number of the message target. Same format as from.
 * @param {String} body: The body of the SMS. Must be < 160 chars.
 * @param {String} uri: The optional status callback URI.
 */
RestClient.prototype.sendSms = function(from, to, body, uri, suc, err) {
    if(!from || !to || !body) {
        throw new Error('From, To, and Body argument');
    }
    var params = {
        From: from,
        To: to,
        Body: body
    };

    if(uri) {
        params.StatusCallback = uri;
    }
    this.apiCall('POST', '/SMS/Messages', {params: params}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Recordings
//-----------------------------------------------------------------------------

/**
 * getRecordingUri: Since recording requests always return the actual binary
 * data (either as Wav or MP3), we don't actually handle making this request.
 * That the recording URIs are public (i.e., they require no basic auth), this
 * means that a user can just go and GET the recording themselves, and do what
 * they will with the reply, which is the recording file itself.
 *
 * @param {String} sid: The sid of the recording to fetch.
 * @param {String} encoding: The encoding of the resultant file. May be either
 * 'mp3' or 'wav'. Default is 'mp3'.
 */
RestClient.prototype.getRecordingUri = function(sid, encoding, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }
    return 'https://' + API_SERVER + '/' + API_VERSION + '/' +
        self.sid + '/Recordings/' + sid;
};

/**
 * deleteRecording: Delete a recording.
 *
 * @param {String} sid: The sid of the recording to delete
 */
RestClient.prototype.deleteRecording = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }

    this.apiCall('DELETE', '/Recordings/' + sid, null, suc, err);
};

/**
 * getRecordingList: Request a list of all recordings associated with account
 *
 * @param {Map} filters: An optional map of filters. Possible filters are:
 * CallSid: The sid of the call that originated the recording
 * DateCreated: The date of the call that originated the recording
 * See: http://www.twilio.com/docs/api/2010-04-01/rest/recording
 */
RestClient.prototype.getRecordingList = function(filters, suc, err) {
    this.apiCall('GET', '/Recordings', {params: filters}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Transcriptions
//-----------------------------------------------------------------------------

/**
 * getTranscriptionList: Request a list of all transcriptions
 */
RestClient.prototype.getTranscriptionList = function(suc, err) {
    this.apiCall('GET', '/Transcriptions', null, suc, err);
};

/**
 * getTranscriptionInstance: Request a transcription instance resource
 *
 * @param {String} sid: The transcription sid.
 */
RestClient.prototype.getTranscriptionInstance = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }

    this.apiCall('GET', '/Transcriptions/' + sid, null, suc, err);
};

/**
 * getTranscriptionText: Request only the text of a transcription
 *
 * @param {String} sid: The transcription sid.
 */
RestClient.prototype.getTranscriptionText = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }

    this.apiCall('GET', '/Transcriptions/' + sid + '.txt', null, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Notifications
//-----------------------------------------------------------------------------

/**
 * getNotificationList: Get a list of notifications assicated with this account
 *
 * @param {Map} filters: An optional list of filters.
 * See: http://www.twilio.com/docs/api/2010-04-01/rest/notification
 */
RestClient.prototype.getNotificationList = function(filters, suc, err) {
    this.apiCall('GET', '/Notifications', null, suc, err);
};

/**
 * getNotificationInstance: Get a notification instance resource
 *
 * @param {sid}: The sid of the notification.
 */
RestClient.prototype.getNotificationInstance = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }

    this.apiCall('GET', '/Notifications/' + sid, null, suc, err);
};

/**
 * deleteNotification: Delete a notification associated with this account
 *
 * @param {String} sid: The sid of the notification to delete.
 */
RestClient.prototype.deleteNotification = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }

    this.apiCall('DELETE', '/Notifications/' + sid, null, suc, err);
};
<commit_msg>Added paged resource handling<commit_after>var https = require('https'),
    querystring = require('querystring'),
    Buffer = require('buffer').Buffer;

var API_SERVER = 'api.twilio.com';
var API_VERSION = '2010-04-01';

function RestClient(sid, authToken) {
    if(!(this instanceof RestClient)) {
        return new RestClient(sid, authToken);
    }

    if(!sid) {
        throw new Error('RestClient must be passed a SID');
    }

    if(!authToken) {
        throw new Error('RestClient must be passed an authToken');
    }

    this.sid = sid;
    this.authToken = authToken;

    this.basicAuth = (new Buffer(sid + ':' + authToken)).toString('base64');
}

module.exports = RestClient;

RestClient.prototype.apiCall = function(method, path, options, suc, err, wholePath) {
    var self = this;

    method = method.toUpperCase();
    options = options || {};

    var params = options.params,
        headers = options.headers || {},
        fullPath = '';

    if(params) {
        if(typeof params != 'string') {
            params = querystring.stringify(params);
        }
    }

    if(wholePath) {
        fullPath = path;
    } else {
        fullPath = '/' + API_VERSION + '/Accounts/' + self.sid;
        if(path.length > 0) {
            if(path[0] != '/') {
                fullPath += '/';
            }
            fullPath += path;
        }
        if(fullPath.substr(fullPath.length - 5) != '.json') {
            fullPath += '.json';
        }
    }

    if(params && method == 'POST') {
        headers['Content-Length'] = params.length;
        headers['Content-Type'] = 'application/x-www-form-urlencoded';
    } else if(params && method == 'GET') {
        fullPath += '?' + params;
    }

    headers.Host = API_SERVER;
    headers.Authorization = "Basic " + self.basicAuth;
    var request = https.request({ host: API_SERVER, port: 443, method: method, path: fullPath, headers: headers }, function(response) {
       var responseChunks = [];
       response.setEncoding('utf8');

       response.on('data', function(chunk) {
           responseChunks.push(chunk);
       });

       response.on('end', function() {
           var body = responseChunks.join('');

           // Try to deserialize if possible
           try {
               body = JSON.parse(body);
           } catch(err) {
               // Do nothing. Probably wasn't JSON. We'll just return the string.
           }
           if(typeof suc == 'function') suc(body);
       });

       if(typeof err == 'function') {
           response.on('error', err);
       }
    });

    if(params && method == 'POST') {
       request.write(params);
    }
    request.end();
};

//-----------------------------------------------------------------------------
//--------------------- Accounts
//-----------------------------------------------------------------------------

/**
 * getAccountInfo: Request your account information
 */
RestClient.prototype.getAccountInfo = function(suc, err) {
    this.apiCall('GET', '', null, suc, err);
};

/**
 * updateAccountInfo: Update your account information
 *
 * @param {Map} params: Map of information to update. Currently, only
 * FriendlyName is supported.
 */
RestClient.prototype.updateAccountInfo = function(params, suc, err) {
    this.apiCall('POST', '', {params: params}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Available Phone Numbers
//-----------------------------------------------------------------------------

// Country can be either 'CA' or 'US' (until Twilio gets more areas serviced)
// Possible filters: AreaCode, Contains, InRegion, InPostalCode, NearLatLong,
// InLata, InRateCenter, Distance
RestClient.prototype.getAvailableLocalNumbers = function(country, filters, suc, err) {
    if(!country) {
        throw new Error('Country argument required');
    }
    this.apiCall('GET', '/AvailablePhoneNumbers/' + country + '/Local',
                 {params: filters}, suc, err);
};

// Country can be either 'CA' or 'US'
// Possible filters: Contains
RestClient.prototype.getAvailableTollFreeNumbers = function(country, filters, suc, err) {
    if(!country) {
        throw new Error('Country argument required');
    }
    this.apiCall('GET', '/AvailablePhoneNumbers/' + country + '/Local',
                 {params: filters}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Outgoing Caller Ids
//-----------------------------------------------------------------------------

RestClient.prototype.getOutgoingCallerId = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Outgoing SID argument required');
    }
    this.apiCall('GET', '/OutgoingCallerIds/' + sid, null, suc, err);
};

RestClient.prototype.updateOutgoingCallerId = function(sid, params, suc, err) {
    if(!sid) {
        throw new Error('Outgoing SID argument required');
    }
    this.apiCall('POST', '/OutgoingCallerIds/' + sid, null, suc, err);
};

RestClient.prototype.deleteOutgoingCallerId = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Outgoing SID argument required');
    }
    this.apiCall('DELETE', '/OutgoingCallerIds/' + sid, null, suc, err);
};

// Possible filters: PhoneNumber, FriendlyName
RestClient.prototype.getOutgoingCallerIdList = function(filters, suc, err) {
    this.apiCall('GET', '/OutgoingCallerIds', {params: filters}, suc, err);
};

// Add an outgoing caller ID. This will cause Twilio to call the specified
// number to verify it. CallDelay specifies a delay (<=60) for the call.
// Possible params: FriendlyName, CallDelay
RestClient.prototype.addOutgoingCallerId = function(num, params, suc, err) {
    if(!num) {
        throw new Error('Phone number argument required');
    }
    params = params || {};
    params.PhoneNumber = num;

    this.apiCall('POST', '/OutgoingCallerIds', {params: params}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Incoming Phone Numbers
//-----------------------------------------------------------------------------
RestClient.prototype.getPagedResource = function(startingUri, filter, resourceName, suc, err) {
    var col = [],
        firstRun = true;

    function getRes(uri) {
        this.apiCall('GET', uri, firstRun ? {params: filter} : null,
            (function(res) {
                col = col.concat(res[resourceName]);

                if(res.next_page_uri) {
                    getRes(res.next_page_uri);
                } else {
                    suc(col);
                }
            }).bind(this),
            err, !firstRun
        );
        // Reset this so we use fullPaths.
        firstRun = false;
    }

    // Fire it up
    getRes.bind(this)(startingUri);
};

RestClient.prototype.getAllIncomingNumbers = function(filter, suc, err) {
    this.getPagedResource('/IncomingPhoneNumbers', filter, 'incoming_phone_numbers', suc, err);
};

// Possible filters: PhoneNumber, FriendlyName
RestClient.prototype.getIncomingNumbers = function(filters, suc, err) {
    this.apiCall('GET', '/IncomingPhoneNumbers', {params: filters}, suc, err);
};

RestClient.prototype.getIncomingNumber = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }
    this.apiCall('GET', '/IncomingPhoneNumbers/' + sid, null, suc, err);
};

RestClient.prototype.updateIncomingNumber = function(sid, params, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }
    this.apiCall('POST', '/IncomingPhoneNumbers/' + sid, {params: params}, suc, err);
};

RestClient.prototype.deleteIncomingNumber = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }
    this.apiCall('DELETE', '/IncomingPhoneNumbers/' + sid, null, suc, err);
};

// Possible optional params: FriendlyName, VoiceUrl, VoiceMethod, VoiceFallbackUrl,
// StatusCallback, StatusCallbackMethod, SmsUrl, SmsMethod, SmsFallbackUrl,
// SmsFallbackMethod, VoiceCallerIdLookup
RestClient.prototype.provisionIncomingNumber = function(num, areaCode, params, suc, err) {
    params = params || {};
    params.PhoneNumber = num;
    params.AreaCode = areaCode;
    this.apiCall('POST', '/IncomingPhoneNumbers', {params: params}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Calls
//-----------------------------------------------------------------------------

/**
 * getCallList: Request a list of call instance resources
 *
 * @param {Map} filters: An optional map of possible filters. See:
 * http://www.twilio.com/docs/api/2010-04-01/rest/call
 */
RestClient.prototype.getCallList = function(filters, suc, err) {
    this.apiCall('GET', '/Calls', null, suc, err);
};

/**
 * getCallInstance: Request a call instance resource
 *
 * @param {String} sid: The sid of the call to fetch
 */
RestClient.prototype.getCallInstance = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }

    this.apiCall('GET', '/Calls/' + sid, {params: filters}, suc, err);
};

/**
 * makeCall: Place a call
 *
 * @param {String} from: The number the call is originating from. Must be a
 * Twilio number of a valid outgoing caller ID for your account, in E.164
 * format (i.e., +18674451795)
 * @param {String} to: The number of the callee. Same format as from.
 * @param {String} url: The callback URL that Twilio will request when the
 * call is picked up.
 * @param {Map} opts: A map of optional parameters. See:
 * http://www.twilio.com/docs/api/2010-04-01/rest/making_calls
 */
RestClient.prototype.makeOutgoingCall = function(from, to, url, opts, suc, err) {
    if(!from || !to || !url) {
        throw new Error('From, to, and URL arguments required');
    }

    opts = opts || {};
    opts.Url = url;
    opts.From = from;
    opts.To = to;

    this.apiCall('POST', '/Calls', {params: opts}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- SMS
//-----------------------------------------------------------------------------

/**
 * getSmsInstance: Request an SMS instance resource
 *
 * @param {String} sid: The sid of the message to retrieve.
 */
RestClient.prototype.getSmsInstance = function(messageSid, suc, err) {
    this.apiCall('GET', '/SMS/Messages/' + messageSid, null, suc, err);
};

/**
 * getSmsList: Request a list of SMS instance resources
 *
 * @param {Map} filters: An optional map of filters. See:
 * http://www.twilio.com/docs/api/2010-04-01/rest/sms
 */
RestClient.prototype.getSmsList = function(filters, suc, err) {
    this.apiCall('GET', '/SMS/Messages', {params: filters}, suc, err);
};

/**
 * sendSms: Send a new SMS message
 *
 * @param {String} from: The outgoing callerId. Must be a valid twilio/outgoing
 * caller id number, in E.164 format (i.e., +18674451795)
 * @param {String} to: The number of the message target. Same format as from.
 * @param {String} body: The body of the SMS. Must be < 160 chars.
 * @param {String} uri: The optional status callback URI.
 */
RestClient.prototype.sendSms = function(from, to, body, uri, suc, err) {
    if(!from || !to || !body) {
        throw new Error('From, To, and Body argument');
    }
    var params = {
        From: from,
        To: to,
        Body: body
    };

    if(uri) {
        params.StatusCallback = uri;
    }
    this.apiCall('POST', '/SMS/Messages', {params: params}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Recordings
//-----------------------------------------------------------------------------

/**
 * getRecordingUri: Since recording requests always return the actual binary
 * data (either as Wav or MP3), we don't actually handle making this request.
 * That the recording URIs are public (i.e., they require no basic auth), this
 * means that a user can just go and GET the recording themselves, and do what
 * they will with the reply, which is the recording file itself.
 *
 * @param {String} sid: The sid of the recording to fetch.
 * @param {String} encoding: The encoding of the resultant file. May be either
 * 'mp3' or 'wav'. Default is 'mp3'.
 */
RestClient.prototype.getRecordingUri = function(sid, encoding, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }
    return 'https://' + API_SERVER + '/' + API_VERSION + '/' +
        self.sid + '/Recordings/' + sid;
};

/**
 * deleteRecording: Delete a recording.
 *
 * @param {String} sid: The sid of the recording to delete
 */
RestClient.prototype.deleteRecording = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }

    this.apiCall('DELETE', '/Recordings/' + sid, null, suc, err);
};

/**
 * getRecordingList: Request a list of all recordings associated with account
 *
 * @param {Map} filters: An optional map of filters. Possible filters are:
 * CallSid: The sid of the call that originated the recording
 * DateCreated: The date of the call that originated the recording
 * See: http://www.twilio.com/docs/api/2010-04-01/rest/recording
 */
RestClient.prototype.getRecordingList = function(filters, suc, err) {
    this.apiCall('GET', '/Recordings', {params: filters}, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Transcriptions
//-----------------------------------------------------------------------------

/**
 * getTranscriptionList: Request a list of all transcriptions
 */
RestClient.prototype.getTranscriptionList = function(suc, err) {
    this.apiCall('GET', '/Transcriptions', null, suc, err);
};

/**
 * getTranscriptionInstance: Request a transcription instance resource
 *
 * @param {String} sid: The transcription sid.
 */
RestClient.prototype.getTranscriptionInstance = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }

    this.apiCall('GET', '/Transcriptions/' + sid, null, suc, err);
};

/**
 * getTranscriptionText: Request only the text of a transcription
 *
 * @param {String} sid: The transcription sid.
 */
RestClient.prototype.getTranscriptionText = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }

    this.apiCall('GET', '/Transcriptions/' + sid + '.txt', null, suc, err);
};

//-----------------------------------------------------------------------------
//--------------------- Notifications
//-----------------------------------------------------------------------------

/**
 * getNotificationList: Get a list of notifications assicated with this account
 *
 * @param {Map} filters: An optional list of filters.
 * See: http://www.twilio.com/docs/api/2010-04-01/rest/notification
 */
RestClient.prototype.getNotificationList = function(filters, suc, err) {
    this.apiCall('GET', '/Notifications', null, suc, err);
};

/**
 * getNotificationInstance: Get a notification instance resource
 *
 * @param {sid}: The sid of the notification.
 */
RestClient.prototype.getNotificationInstance = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }

    this.apiCall('GET', '/Notifications/' + sid, null, suc, err);
};

/**
 * deleteNotification: Delete a notification associated with this account
 *
 * @param {String} sid: The sid of the notification to delete.
 */
RestClient.prototype.deleteNotification = function(sid, suc, err) {
    if(!sid) {
        throw new Error('Sid argument required');
    }

    this.apiCall('DELETE', '/Notifications/' + sid, null, suc, err);
};
<|endoftext|>


<commit_before>const fs = require('fs');
const path = require('path');

const fileHelpers = require('./file-helpers');
const isDirectory = fileHelpers.isDirectory;
const getFileContents = fileHelpers.getFileContents;
const splitBasename = fileHelpers.splitBasename;

// Allows you to use short words for Roblox Script classes.
//
// Adding '.module' or '.local' between a Lua file's name and extension defines
// it as a ModuleScript or LocalScript, respectively.
//
// word : str
//  This can either be 'module' for ModuleScript, 'local' for LocalScript, or
//  nothing for a plain Script.
function getScriptClassFromWord(word) {
  if (word === 'module') {
    return 'ModuleScript';
  } else if (word === 'local') {
    return 'LocalScript';
  } else {
    return 'Script';
  }
}

// Gets properties of a folder.
//
// Usage:
//
//   getFolderProperties('./Folder/')
//   { Name: 'Folder', ClassName: 'Folder', Children: [ Object... ] }
function getFolderProperties(filePath) {
  const name = path.basename(filePath);

  return {
    Name: name,
    ClassName: 'Folder',
    Children: constructHierarchy(filePath)
  };
}

// Gets properties of a Lua script.
//
// The `ClassName` property varies based on the class identifier (the part after
// the filename). You can see how this works below.
//
// Usage:
//
//   getLuaFileProperties('Server.lua');
//   { Name: 'Server', ClassName: 'Script', Source: '...'}
//
//   getLuaFileProperties('Client.local.lua');
//   { Name: 'Client', ClassName: 'LocalScript', Source: '...'}
//
//   getLuaFileProperties('Helper.module.lua');
//   { Name: 'Helper', ClassName: 'ModuleScript', Source: '...'}
function getLuaFileProperties(filePath) {
  const parts = splitBasename(filePath);

  return {
    Name: parts.name,
    ClassName: getScriptClassFromWord(parts.classIdentifier),
    Source: getFileContents(filePath)
  };
}

// Gets properties for other instances using JSON.
//
// This function allows you to create just about any Roblox instance using JSON
// files. Simply add in-game properties of the instance you're creating and
// they'll appear in-game.
//
// Requirements:
//
// - All properties need to be written in UpperCamelCase.
// - A ClassName property needs to be defined. This lets us know which instance
//   to create.
//
// Usage:
//
//   getJsonFileProperties('/path/to/file.json')
function getJsonFileProperties(filePath) {
  const name = path.basename(filePath, '.json');
  const properties = JSON.parse(getFileContents(filePath));

  properties.Name = name;

  if (!properties.ClassName) {
    console.error('Could not sync ' + filePath + ' (missing ClassName property)');
  };

  return properties;
}

// Simply routes files to the appropriate function for retrieveing properties.
function getFileProperties(filePath) {
  const ext = path.extname(filePath);

  if (ext === '.lua') {
    return getLuaFileProperties(filePath);
  } else if (ext === '.json') {
    return getJsonFileProperties(filePath);
  };
}

// Gets the Roblox properties of a file or folder.
//
// The returned object's keys are in UpperCamelCase, matching Roblox's naming
// convention. This makes it easy to work with the properties when the object is
// passed off to the plugin.
//
// Usage:
//
//   getProperties('./path/to/folder/');
//   { Name: 'folder', ClassName: 'Folder', Children: [ [Object]... ] }
//
//   getProperties('./path/to/file.local.lua');
//   { Name: 'file', ClassName: 'LocalScript', Source: '...'}
function getProperties(filePath) {
  if (isDirectory(filePath)) {
    return getFolderProperties(filePath);
  } else {
    return getFileProperties(filePath);
  };
}

// Gets children and converts them to their appropriate Object.
//
// This is the primary interface to constructing the Object hierarchy. When
// supplied with a folder, it will recursively gather all of that folder's
// children, converting them to their appropriate Object.
//
// When supplied with a file, this just works like getObjectFromFile() or
// newScript().
function constructHierarchy(filePath) {
  const children = [];

  for (const child of fs.readdirSync(filePath)) {
    const childPath = path.join(filePath, child);
    const object = getProperties(childPath);

    if (object) {
      children.push(object);
    };
  };

  return children;
}

module.exports = constructHierarchy
<commit_msg>Refactor how we get the ClassName for a file<commit_after>const fs = require('fs');
const path = require('path');

const fileHelpers = require('./file-helpers');
const isDirectory = fileHelpers.isDirectory;
const getFileContents = fileHelpers.getFileContents;

// Allows you to use short words for Roblox Script classes.
//
// Adding '.module' or '.local' between a Lua file's name and extension defines
// it as a ModuleScript or LocalScript, respectively.
//
// word : str
//  This can either be 'module' for ModuleScript, 'local' for LocalScript, or
//  nothing for a plain Script.
function getClassNameFromKeyword(word) {
  if (word === 'module') {
    return 'ModuleScript';
  } else if (word === 'local') {
    return 'LocalScript';
  } else if (word === 'script') {
    return 'Script';
  } else {
    return null;
  }
}

function getName(filePath) {
  const base = path.basename(filePath);
  const parts = base.split('.');
  return parts[0];
}

function getClassKeyword(filePath) {
  const base = path.basename(filePath);
  const keyword = base.split('.').slice(-2, -1)[0];

  if (keyword != getName(filePath)) {
    return keyword;
  } else {
    return 'script';
  }
}

function getClassName(filePath) {
  const keyword = getClassKeyword(filePath);
  return getClassNameFromKeyword(keyword);
}

// Gets properties of a folder.
//
// Usage:
//
//   getFolderProperties('./Folder/')
//   { Name: 'Folder', ClassName: 'Folder', Children: [ Object... ] }
function getFolderProperties(filePath) {
  const name = path.basename(filePath);

  return {
    Name: name,
    ClassName: 'Folder',
    Children: constructHierarchy(filePath)
  };
}

// Gets properties of a Lua script.
//
// The `ClassName` property varies based on the class identifier (the part after
// the filename). You can see how this works below.
//
// Usage:
//
//   getLuaFileProperties('Server.lua');
//   { Name: 'Server', ClassName: 'Script', Source: '...'}
//
//   getLuaFileProperties('Client.local.lua');
//   { Name: 'Client', ClassName: 'LocalScript', Source: '...'}
//
//   getLuaFileProperties('Helper.module.lua');
//   { Name: 'Helper', ClassName: 'ModuleScript', Source: '...'}
function getLuaFileProperties(filePath) {
  return {
    Name: getName(filePath),
    ClassName: getClassName(filePath),
    Source: getFileContents(filePath)
  };
}

// Gets properties for other instances using JSON.
//
// This function allows you to create just about any Roblox instance using JSON
// files. Simply add in-game properties of the instance you're creating and
// they'll appear in-game.
//
// Requirements:
//
// - All properties need to be written in UpperCamelCase.
// - A ClassName property needs to be defined. This lets us know which instance
//   to create.
//
// Usage:
//
//   getJsonFileProperties('/path/to/file.json')
function getJsonFileProperties(filePath) {
  const name = path.basename(filePath, '.json');
  const properties = JSON.parse(getFileContents(filePath));

  properties.Name = name;

  if (!properties.ClassName) {
    console.error('Could not sync ' + filePath + ' (missing ClassName property)');
  };

  return properties;
}

// Simply routes files to the appropriate function for retrieveing properties.
function getFileProperties(filePath) {
  const ext = path.extname(filePath);

  if (ext === '.lua') {
    return getLuaFileProperties(filePath);
  } else if (ext === '.json') {
    return getJsonFileProperties(filePath);
  };
}

// Gets the Roblox properties of a file or folder.
//
// The returned object's keys are in UpperCamelCase, matching Roblox's naming
// convention. This makes it easy to work with the properties when the object is
// passed off to the plugin.
//
// Usage:
//
//   getProperties('./path/to/folder/');
//   { Name: 'folder', ClassName: 'Folder', Children: [ [Object]... ] }
//
//   getProperties('./path/to/file.local.lua');
//   { Name: 'file', ClassName: 'LocalScript', Source: '...'}
function getProperties(filePath) {
  if (isDirectory(filePath)) {
    return getFolderProperties(filePath);
  } else {
    return getFileProperties(filePath);
  };
}

// Gets children and converts them to their appropriate Object.
//
// This is the primary interface to constructing the Object hierarchy. When
// supplied with a folder, it will recursively gather all of that folder's
// children, converting them to their appropriate Object.
//
// When supplied with a file, this just works like getObjectFromFile() or
// newScript().
function constructHierarchy(filePath) {
  const children = [];

  for (const child of fs.readdirSync(filePath)) {
    const childPath = path.join(filePath, child);
    const object = getProperties(childPath);

    if (object) {
      children.push(object);
    };
  };

  return children;
}

module.exports = constructHierarchy
<|endoftext|>


<commit_before>const Router = require('express').Router;
const router = Router();
const User = require('../models/user');
const tokenService = require('../auth/token-service');
const ensureAuth = require('../auth/ensure-auth')();
const analyze = require('../utils/analyze');
const superagent = require('superagent');

function hasEmailAndPassword(req, res, next) {
    console.log('you send this to post', req.body);
    const { email, password } = req.body;
    if (!email || !password) {
        return next({
            code: 400,
            error: 'both email and password are required'
        });
    }
    next();
}

function analyzeVerify(email, ip) {
    return 'okay';
}

function checkUser(req, res, next) {
    console.log('you send this to post', req.body);

    return superagent
        .get('https://api.ipify.org?format=json')
        .then(res => analyzeVerify(req.body.email, res.body.ip))
        .then(result => {
            if (result === 'terminate') {
                return next({
                    code: 401,
                    error: 'Access Denied'
                });
            }
            next();
        });
}

router
    .get('/verify', ensureAuth, (req, res) => {
        res.send({ valid: true });
    })

    .post('/signup', hasEmailAndPassword, checkUser, (req, res, next) => {
        const { email, password, name, role, status } = req.body;

        delete req.body.password;

        User.exists({ email })
            .then(exists => {
                if (exists) {
                    throw next({
                        code: 400,
                        error: 'the email provided is already in use'
                    });
                }

                const user = new User({ email, name, role, status });
                user.generateHash(password);
                return user.save();
            })
            .then(user => tokenService.sign(user))
            .then(token => res.send({ token }))
            .catch(next);
    })

    .post('/signin', hasEmailAndPassword, checkUser, (req, res, next) => {
        const { email, password } = req.body;
        delete req.body.password;

        User.findOne({ email })
            .then(user => {
                if (!user || !user.comparePassword(password)) {
                    throw next({
                        code: 401,
                        error: 'Invalid Login'
                    });
                }
                return user;
            })
            .then(user => tokenService.sign(user))
            .then(token => {
                //saveEvent(...)
                res.send({ token });
            })
            .catch(next);
    });

module.exports = router;<commit_msg>removed console logs<commit_after>const Router = require('express').Router;
const router = Router();
const User = require('../models/user');
const tokenService = require('../auth/token-service');
const ensureAuth = require('../auth/ensure-auth')();
const analyze = require('../utils/analyze');
const superagent = require('superagent');

function hasEmailAndPassword(req, res, next) {
    const { email, password } = req.body;
    if (!email || !password) {
        return next({
            code: 400,
            error: 'both email and password are required'
        });
    }
    next();
}

function analyzeVerify(email, ip) {
    return 'okay';
}

function checkUser(req, res, next) {
    return superagent
        .get('https://api.ipify.org?format=json')
        .then(res => analyzeVerify(req.body.email, res.body.ip))
        .then(result => {
            if (result === 'terminate') {
                return next({
                    code: 401,
                    error: 'Access Denied'
                });
            }
            next();
        });
}

router
    .get('/verify', ensureAuth, (req, res) => {
        res.send({ valid: true });
    })

    .post('/signup', hasEmailAndPassword, checkUser, (req, res, next) => {
        const { email, password, name, role, status } = req.body;

        delete req.body.password;

        User.exists({ email })
            .then(exists => {
                if (exists) {
                    throw next({
                        code: 400,
                        error: 'the email provided is already in use'
                    });
                }

                const user = new User({ email, name, role, status });
                user.generateHash(password);
                return user.save();
            })
            .then(user => tokenService.sign(user))
            .then(token => res.send({ token }))
            .catch(next);
    })

    .post('/signin', hasEmailAndPassword, checkUser, (req, res, next) => {
        const { email, password } = req.body;
        delete req.body.password;

        User.findOne({ email })
            .then(user => {
                if (!user || !user.comparePassword(password)) {
                    throw next({
                        code: 401,
                        error: 'Invalid Login'
                    });
                }
                return user;
            })
            .then(user => tokenService.sign(user))
            .then(token => {
                //saveEvent(...)
                res.send({ token });
            })
            .catch(next);
    });

module.exports = router;<|endoftext|>


<commit_before>var _ = require('lodash');
var kramed = require('kramed');

// Render a section using our custom renderer
function render(section) {
    // Copy section
    var links = section.links || {};
    section = _.toArray(section);
    section.links = links;

    return kramed.parser(section);
}

function quizQuestion(node) {
    if (node.text) {
        node.text = node.text.replace(/^([\[(])x([\])])/, "$1 $2");
    } else {
        return node.replace(/^([\[(])x([\])])/, "$1 $2");
    }
}

function section2obj(section) {
    var quiz = [], question, foundFeedback = false;
    var nonQuizNodes = section[0].type === 'paragraph' && section[1].type !== 'list_start' ? [section[0]] : [];
    var quizNodes = section.slice(0);
    quizNodes.splice(0, nonQuizNodes.length);

    for (var i = 0; i < quizNodes.length; i++) {
        var node = quizNodes[i];

        if (question && (((node.type === 'list_end' || node.type === 'blockquote_end') && i === quizNodes.length - 1)
                         || node.type === 'table' || (node.type === 'paragraph' && !foundFeedback))) {
            quiz.push({
                base: render(question.questionNodes),
                solution: render(question.solutionNodes),
                feedback: render(question.feedbackNodes)
            });
        }

        if (node.type === 'table' || (node.type === 'paragraph' && !foundFeedback)) {
            question = { questionNodes: [], solutionNodes: [], feedbackNodes: [] };
        }

        if (node.type === 'blockquote_start') {
            foundFeedback = true;
        } else if (node.type === 'blockquote_end') {
            foundFeedback = false;
        }

        if (node.type === 'table') {
            question.solutionNodes.push(_.cloneDeep(node));
            node.cells = node.cells.map(function(row) {
                return row.map(quizQuestion);
            });
            question.questionNodes.push(node);
        } else if (!/blockquote/.test(node.type)) {
            if (foundFeedback) {
                question.feedbackNodes.push(node);
            } else if (node.type === 'paragraph' || node.type === 'text'){
                question.solutionNodes.push(_.cloneDeep(node));
                quizQuestion(node);
                question.questionNodes.push(node);
            } else {
                question.solutionNodes.push(node);
                question.questionNodes.push(node);
            }
        }
    }

    return {
        content: render(nonQuizNodes),
        quiz: quiz
    };
}

module.exports = section2obj;
<commit_msg>Clarify return of section2obj<commit_after>var _ = require('lodash');
var kramed = require('kramed');

// Render a section using our custom renderer
function render(section) {
    // Copy section
    var links = section.links || {};
    section = _.toArray(section);
    section.links = links;

    return kramed.parser(section);
}

function quizQuestion(node) {
    if (node.text) {
        node.text = node.text.replace(/^([\[(])x([\])])/, "$1 $2");
    } else {
        return node.replace(/^([\[(])x([\])])/, "$1 $2");
    }
}

function section2obj(section) {
    var quiz = [], question, foundFeedback = false;
    var nonQuizNodes = section[0].type === 'paragraph' && section[1].type !== 'list_start' ? [section[0]] : [];
    var quizNodes = section.slice(0);
    quizNodes.splice(0, nonQuizNodes.length);

    for (var i = 0; i < quizNodes.length; i++) {
        var node = quizNodes[i];

        if (question && (((node.type === 'list_end' || node.type === 'blockquote_end') && i === quizNodes.length - 1)
                         || node.type === 'table' || (node.type === 'paragraph' && !foundFeedback))) {
            quiz.push({
                base: render(question.questionNodes),
                solution: render(question.solutionNodes),
                feedback: render(question.feedbackNodes)
            });
        }

        if (node.type === 'table' || (node.type === 'paragraph' && !foundFeedback)) {
            question = { questionNodes: [], solutionNodes: [], feedbackNodes: [] };
        }

        if (node.type === 'blockquote_start') {
            foundFeedback = true;
        } else if (node.type === 'blockquote_end') {
            foundFeedback = false;
        }

        if (node.type === 'table') {
            question.solutionNodes.push(_.cloneDeep(node));
            node.cells = node.cells.map(function(row) {
                return row.map(quizQuestion);
            });
            question.questionNodes.push(node);
        } else if (!/blockquote/.test(node.type)) {
            if (foundFeedback) {
                question.feedbackNodes.push(node);
            } else if (node.type === 'paragraph' || node.type === 'text'){
                question.solutionNodes.push(_.cloneDeep(node));
                quizQuestion(node);
                question.questionNodes.push(node);
            } else {
                question.solutionNodes.push(node);
                question.questionNodes.push(node);
            }
        }
    }

    return {
        content: render(nonQuizNodes),
        questions: quiz
    };
}

module.exports = section2obj;
<|endoftext|>


<commit_before>var j_forms = require('j-forms');
    models = require('../models');
    async = require('async');
module.exports = j_forms.forms.AdminForm.extend({
    render_ready:function(callback) {
        var self = this;
        this._super(function(err) {

            var instance = self.instance;
            self.char_count = instance.getCharCount();

            async.waterfall([
                function(cbk){
                    models.Discussion.findById(instance.discussion_id, cbk);
                },

                function(discussion_obj, cbk){
                    self.discussion_thresh = Number(discussion_obj.admin_threshold_for_accepting_change_suggestions) || discussion_obj.threshold_for_accepting_change_suggestions;
                    self.num_of_graders = discussion_obj.evaluate_counter;
                    self.grade = discussion_obj.grade;
                    cbk();
                }
            ], function(err, result){

                callback(err);
            });
        });

    },
    render:function(res,options) {
        var self = this;
        this._super(res,options);
        res.write(
                "
number of graders = " + self.num_of_graders + "
" +
                    "
avg grade = " + self.grade + "
" +
                    "
char counter = " + self.char_count + "
" +
                    "
discussion threshold = " + self.discussion_thresh + "
"
        );
    }
});<commit_msg>suggestion theresholf for admin<commit_after>var j_forms = require('j-forms');
    models = require('../models');
    async = require('async');
module.exports = j_forms.forms.AdminForm.extend({
    render_ready:function(callback) {
        var self = this;
        this._super(function(err) {

            var instance = self.instance;
            self.char_count = instance.getCharCount();

            async.waterfall([
                function(cbk){
                    models.Discussion.findById(instance.discussion_id, cbk);
                },

                function(discussion_obj, cbk){
                    self.discussion_thresh = Number(discussion_obj.admin_threshold_for_accepting_change_suggestions) || discussion_obj.threshold_for_accepting_change_suggestions;
                    self.num_of_graders = discussion_obj.evaluate_counter;
                    self.grade = discussion_obj.grade;
                    cbk();
                }
            ], function(err, result){

                callback(err);
            });
        });

    },
    render:function(res,options) {
        var self = this;
        this._super(res,options);
        res.write(
                "
number of graders = " + self.num_of_graders + "
" +
                    "
avg grade = " + self.grade + "
" +
                    "
char counter = " + self.char_count + "
" +
                    "
suggestion threshold= " + self.instance.threshold_for_accepting_the_suggestion + "
" +
                    "
discussion threshold = " + self.discussion_thresh + "
"
        );
    }
});<|endoftext|>


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

    /* Global var accessible from any loaded module */
    global.cloudcmd     = {};

    var DIR, LIBDIR, SRVDIR, JSONDIR, HTMLDIR,
        Util,
        UTIL = 'util',

        SLASH,
        ISWIN32,
        ext,
        path, fs, zlib, url, pipe, CloudFunc, diffPatch, querystring,

        OK, FILE_NOT_FOUND, MOVED_PERMANENTLY,
        REQUEST, RESPONSE,

        Config = {
            server  : true,
            socket  : true,
            port    : 80
        };

    /* Consts */

    exports.OK                  = OK                = 200;
                                  MOVED_PERMANENTLY = 301;
    exports.FILE_NOT_FOUND      = FILE_NOT_FOUND    = 404;

    exports.REQUEST     = REQUEST           = 'request';
    exports.RESPONSE    = RESPONSE          = 'response';

    /* Native Modules*/
    exports.crypto                          = require('crypto'),
    exports.child_process                   = require('child_process'),
    exports.fs          = fs                = require('fs'),
    exports.http                            = require('http'),
    exports.https                           = require('https'),
    exports.path        = path              = require('path'),
    exports.url         = url               = require('url'),
    exports.querystring = querystring       = require('querystring'),

    /* Constants */
    /* current dir + 2 levels up */
    exports.WIN32       = ISWIN32           = isWin32();
    exports.SLASH       = SLASH             = '/',

    exports.SRVDIR      = SRVDIR            = __dirname + SLASH,
    exports.LIBDIR      = LIBDIR            = path.normalize(SRVDIR + '../'),
    exports.DIR         = DIR               = path.normalize(LIBDIR + '../'),
    exports.HTMLDIR     = HTMLDIR           = DIR + 'html' + SLASH,
    exports.JSONDIR     = JSONDIR           = DIR + 'json' + SLASH,

    /* Functions */
    exports.require                         = mrequire,
    exports.librequire                      = librequire,
    exports.srvrequire                      = srvrequire,
    exports.rootrequire                     = rootrequire,
    exports.quietrequire                    = quietrequire,

    exports.generateHeaders                 = generateHeaders,
    exports.getQuery                        = getQuery,
    exports.getPathName                     = getPathName,
    exports.isGZIP                          = isGZIP,
    exports.mainSetHeader                   = mainSetHeader,

    exports.sendFile                        = sendFile,
    exports.sendResponse                    = sendResponse,
    exports.sendError                       = sendError,
    exports.redirect                        = redirect,

    exports.checkParams                     = checkParams,
    exports.checkCallBackParams             = checkCallBackParams,

    /* compitability with old versions of node */
    exports.fs.exists                       = exports.fs.exists || exports.path.exists,

    /* Needed Modules */

    /* we can not use librequare here */
    exports.util        = Util              = require(LIBDIR + UTIL),

    exports.zlib        = zlib              = mrequire('zlib'),

    /* Main Information */
    exports.modules                         = jsonrequire('modules');
    exports.ext         = ext               = jsonrequire('ext');
    exports.mainpackage                     = rootrequire('package');
    /* base configuration */
    exports.config                          = Config,

    /*
     * Any of loaded below modules could work with global var so
     * it should be initialized first. Becouse of almost any of
     * moudles do not depends on each other all needed information
     * for all modules is initialized hear.
     */
    global.cloudcmd.main                    = exports;

    exports.VOLUMES                         = getVolumes(),

    /* Additional Modules */
    exports.cloudfunc   = CloudFunc         = librequire('cloudfunc'),
    exports.pipe        = pipe              = srvrequire('pipe'),
    exports.socket                          = srvrequire('socket'),
    exports.console                         = srvrequire('console'),
    exports.terminal                        = srvrequire('terminal'),
    exports.express                         = srvrequire('express'),
    exports.auth                            = srvrequire('auth').auth,
    exports.appcache                        = srvrequire('appcache'),
    exports.dir                             = srvrequire('dir'),
    exports.hash                            = srvrequire('hash'),
    diffPatch                               = librequire('diff/diff-match-patch').diff_match_patch,
    exports.diff                            = new (librequire('diff').DiffProto)(diffPatch),
    exports.time                            = srvrequire('time');
    exports.users                           = srvrequire('users');
    exports.rest                            = srvrequire('rest').api,
    exports.update                          = srvrequire('update'),
    exports.ischanged                       = srvrequire('ischanged');
    exports.commander                       = srvrequire('commander');
    exports.files                           = srvrequire('files');

    exports.minify                          = srvrequire('minify').Minify;

    /* second initializing after all modules load, so global var is   *
     * totally filled of all information that should know all modules */
    global.cloudcmd.main            = exports;

    /**
     * function do safe require of needed module
     * @param {Strin} src
     */
    function mrequire(src) {
        var module, msg,
            error = Util.tryCatch(function() {
                module = require(src);
            });

        if (error)
            if (error.code === 'MODULE_NOT_FOUND')
                msg = CloudFunc.formatMsg('require', src, 'no');
            else
                Util.log(error);

        Util.log(msg);

        return module;
    }

    function quietrequire(src) {
        var module;

        Util.tryCatch(function() {
            module = require(src);
        });

        return module;
    }

    function rootrequire(src) { return mrequire(DIR + src); }

    function librequire(src) { return mrequire(LIBDIR + src); }

    function srvrequire(src) { return mrequire(SRVDIR + src); }

    function jsonrequire(src) { return mrequire(JSONDIR + src);}

    /**
     * function check is current platform is win32
     */
    function isWin32() { return process.platform === 'win32'; }

    /**
     * get volumes if win32 or get nothing if nix
     */
    function getVolumes() {
        var lRet = ISWIN32 ? [] : '/';

        if (ISWIN32)
            srvrequire('win').getVolumes(function(pVolumes) {
                Util.log(pVolumes);
                exports.VOLUMES = pVolumes;
            });

        return lRet;
    }

    /**
     * Функция создаёт заголовки файлов
     * в зависимости от расширения файла
     * перед отправкой их клиенту
     * @param pParams
     *  name - имя файла
     * gzip - данные сжаты gzip'ом
     * query
     * https://developers.google.com/speed/docs/best-practices/caching?hl=ru#LeverageProxyCaching
     */
    function generateHeaders(params) {
        var header, p, extension, type, encoding, isContain, cmp;

        if (params.name) {
            p               = params,
            extension       = Util.getExtension(p.name),
            type            = ext[extension] || 'text/plain',
            encoding        = '';

            /* if type of file any, but img - then we shoud specify charset */
            isContain       = Util.isContainStr(type, ['img', 'image']);
            if (!isContain)
                encoding    = '; charset=UTF-8';

            isContain        = Util.isContainStr(p.query, 'download');
            if (isContain)
                type        = 'application/octet-stream';

            header          = {
                'Access-Control-Allow-Origin'   : '*',
                'Content-Type'                  : type  + encoding,
                'last-modified'                 : ''    + new Date(),
                'Vary'                          : 'Accept-Encoding'
            };

            cmp             = Util.strCmp(ext, '.appcache');
            if (!cmp && p.cache)
                header['cache-control']     = 'max-age=' + 31337 * 21;

            if (p.gzip)
                header['content-encoding']  = 'gzip';
        }

        return header;
    }

    function mainSetHeader(pParams) {
        var p, header, lGzip,
            lRet = checkParams(pParams);

        if (lRet) {
            p       = pParams;
            lGzip   = isGZIP(p.request) && p.gzip;

            header  = generateHeaders({
                name    : p.name,
                cache   : p.cache,
                gzip    : lGzip,
                query   : getQuery(p.request)
            });

            setHeader(header, p.response);
            p.response.statusCode = p.status || OK;
        }
    }

    /**
     * send file to client thru pipe
     * and gzip it if client support
     *
     * @param pName - имя файла
     * @param pGzip - данные сжаты gzip'ом
     */
    function sendFile(params) {
        var isGzip, header,
            p   = params,
            ret = checkParams(params);

        if (ret) {
            isGzip  = isGZIP(p.request) && p.gzip;

            mainSetHeader(params);

            pipe.create({
                from    : p.name,
                write   : p.response,
                gzip    : isGzip,
                callback: function(error) {
                    if (error)
                        sendError(params, error);
                }
            });
        }

        return ret;
    }

    /**
     * Функция высылает ответ серверу
     * @param pHead     - заголовок
     * @param Data      - данные
     * @param pName     - имя отсылаемого файла
     */
    function sendResponse(params, data, notLog) {
        var p, query, isGzip, head,
            ret = checkParams(params);

        if (ret) {
            p           = params;
            data        = p.data || data;
            isGzip      = isGZIP(p.request);

            head        = generateHeaders({
                name    : p.name,
                cache   : p.cache,
                gzip    : isGzip,
                query   : query
            });

            setHeader(head, p.response);

            if (!notLog)
                Util.log(data);

            /* если браузер поддерживает gzip-сжатие - сжимаем данные*/
            Util.ifExec(!isGzip,
                function(params) {
                    var ret = Util.checkObj(params, ['data']);

                    if (ret) {
                        p.status    = params.status || p.status;
                        p.data      = params.data;
                    }

                    p.response.statusCode = p.status || OK;
                    p.response.end(p.data);
                },

                function(callback) {
                    zlib.gzip (data, function(error, data) {
                        if (!error)
                            p.data = data;
                        else {
                            p.status    = FILE_NOT_FOUND;
                            p.data      = error.toString();
                        }

                        Util.exec(callback, p);
                    });
                });
        }
    }

    /**
     * redirect to another URL
     */
    function redirect(pParams) {
        var p, header,
            lRet    = Util.checkObjTrue(pParams, [RESPONSE]);

        if (lRet) {
            p       = pParams;

            header  = {
                'Location': p.url
            };

            setHeader(header, p.response);
            p.response.statusCode = MOVED_PERMANENTLY;
            p.response.end();
        }
    }

    /**
     * send error response
     */
    function sendError(params, error) {
        var p, ret     = checkParams(params);

        if (ret) {
            p           = params;
            p.status    = FILE_NOT_FOUND;

            if (!p.data && error)
              p.data    = error.toString();

            sendResponse(p);
        }
    }

    function checkCallBackParams(pParams) {
        return Util.checkObj(pParams, ['error', 'data', 'params']);
    }

    function checkParams(params, additional) {
        var ret = Util.checkObjTrue(params, ['name', REQUEST, RESPONSE]);

        if (ret && additional)
            ret = Util.checkObjTrue(params, additional);

        return ret;
    }

    function getQuery(req) {
        var query, parsed;

        if (req) {
            parsed  = url.parse(req.url);
            query   = parsed.query;
        }

        return query;
    }

    function getPathName(req) {
        var pathname, parsed;

        if (req) {
            parsed      = url.parse(req.url);
            pathname    = parsed.pathname;
            /* supporting of Russian language in directory names */
            pathname    = querystring.unescape(pathname);
        }

        return pathname;
    }

    function isGZIP(pReq) {
        var lEnc, lGZIP;
        if (pReq) {
            lEnc        = pReq.headers['accept-encoding'] || '';
            lGZIP       = lEnc.match(/\bgzip\b/);
        }

        return lGZIP;
    }

    function setHeader(header, response) {
        var name;

        if (!response.headersSent && Util.isObject(header))
            for (name in header)
                response.setHeader(name, header[name]);
    }

})();
<commit_msg>chore(main) generateHeaders<commit_after>(function() {
    'use strict';

    /* Global var accessible from any loaded module */
    global.cloudcmd     = {};

    var DIR, LIBDIR, SRVDIR, JSONDIR, HTMLDIR,
        Util,
        UTIL = 'util',

        SLASH,
        ISWIN32,
        ext,
        path, fs, zlib, url, pipe, CloudFunc, diffPatch, querystring,

        OK, FILE_NOT_FOUND, MOVED_PERMANENTLY,
        REQUEST, RESPONSE,

        Config = {
            server  : true,
            socket  : true,
            port    : 80
        };

    /* Consts */

    exports.OK                  = OK                = 200;
                                  MOVED_PERMANENTLY = 301;
    exports.FILE_NOT_FOUND      = FILE_NOT_FOUND    = 404;

    exports.REQUEST     = REQUEST           = 'request';
    exports.RESPONSE    = RESPONSE          = 'response';

    /* Native Modules*/
    exports.crypto                          = require('crypto'),
    exports.child_process                   = require('child_process'),
    exports.fs          = fs                = require('fs'),
    exports.http                            = require('http'),
    exports.https                           = require('https'),
    exports.path        = path              = require('path'),
    exports.url         = url               = require('url'),
    exports.querystring = querystring       = require('querystring'),

    /* Constants */
    /* current dir + 2 levels up */
    exports.WIN32       = ISWIN32           = isWin32();
    exports.SLASH       = SLASH             = '/',

    exports.SRVDIR      = SRVDIR            = __dirname + SLASH,
    exports.LIBDIR      = LIBDIR            = path.normalize(SRVDIR + '../'),
    exports.DIR         = DIR               = path.normalize(LIBDIR + '../'),
    exports.HTMLDIR     = HTMLDIR           = DIR + 'html' + SLASH,
    exports.JSONDIR     = JSONDIR           = DIR + 'json' + SLASH,

    /* Functions */
    exports.require                         = mrequire,
    exports.librequire                      = librequire,
    exports.srvrequire                      = srvrequire,
    exports.rootrequire                     = rootrequire,
    exports.quietrequire                    = quietrequire,

    exports.generateHeaders                 = generateHeaders,
    exports.getQuery                        = getQuery,
    exports.getPathName                     = getPathName,
    exports.isGZIP                          = isGZIP,
    exports.mainSetHeader                   = mainSetHeader,

    exports.sendFile                        = sendFile,
    exports.sendResponse                    = sendResponse,
    exports.sendError                       = sendError,
    exports.redirect                        = redirect,

    exports.checkParams                     = checkParams,
    exports.checkCallBackParams             = checkCallBackParams,

    /* compitability with old versions of node */
    exports.fs.exists                       = exports.fs.exists || exports.path.exists,

    /* Needed Modules */

    /* we can not use librequare here */
    exports.util        = Util              = require(LIBDIR + UTIL),

    exports.zlib        = zlib              = mrequire('zlib'),

    /* Main Information */
    exports.modules                         = jsonrequire('modules');
    exports.ext         = ext               = jsonrequire('ext');
    exports.mainpackage                     = rootrequire('package');
    /* base configuration */
    exports.config                          = Config,

    /*
     * Any of loaded below modules could work with global var so
     * it should be initialized first. Becouse of almost any of
     * moudles do not depends on each other all needed information
     * for all modules is initialized hear.
     */
    global.cloudcmd.main                    = exports;

    exports.VOLUMES                         = getVolumes(),

    /* Additional Modules */
    exports.cloudfunc   = CloudFunc         = librequire('cloudfunc'),
    exports.pipe        = pipe              = srvrequire('pipe'),
    exports.socket                          = srvrequire('socket'),
    exports.console                         = srvrequire('console'),
    exports.terminal                        = srvrequire('terminal'),
    exports.express                         = srvrequire('express'),
    exports.auth                            = srvrequire('auth').auth,
    exports.appcache                        = srvrequire('appcache'),
    exports.dir                             = srvrequire('dir'),
    exports.hash                            = srvrequire('hash'),
    diffPatch                               = librequire('diff/diff-match-patch').diff_match_patch,
    exports.diff                            = new (librequire('diff').DiffProto)(diffPatch),
    exports.time                            = srvrequire('time');
    exports.users                           = srvrequire('users');
    exports.rest                            = srvrequire('rest').api,
    exports.update                          = srvrequire('update'),
    exports.ischanged                       = srvrequire('ischanged');
    exports.commander                       = srvrequire('commander');
    exports.files                           = srvrequire('files');

    exports.minify                          = srvrequire('minify').Minify;

    /* second initializing after all modules load, so global var is   *
     * totally filled of all information that should know all modules */
    global.cloudcmd.main            = exports;

    /**
     * function do safe require of needed module
     * @param {Strin} src
     */
    function mrequire(src) {
        var module, msg,
            error = Util.tryCatch(function() {
                module = require(src);
            });

        if (error)
            if (error.code === 'MODULE_NOT_FOUND')
                msg = CloudFunc.formatMsg('require', src, 'no');
            else
                Util.log(error);

        Util.log(msg);

        return module;
    }

    function quietrequire(src) {
        var module;

        Util.tryCatch(function() {
            module = require(src);
        });

        return module;
    }

    function rootrequire(src) { return mrequire(DIR + src); }

    function librequire(src) { return mrequire(LIBDIR + src); }

    function srvrequire(src) { return mrequire(SRVDIR + src); }

    function jsonrequire(src) { return mrequire(JSONDIR + src);}

    /**
     * function check is current platform is win32
     */
    function isWin32() { return process.platform === 'win32'; }

    /**
     * get volumes if win32 or get nothing if nix
     */
    function getVolumes() {
        var lRet = ISWIN32 ? [] : '/';

        if (ISWIN32)
            srvrequire('win').getVolumes(function(pVolumes) {
                Util.log(pVolumes);
                exports.VOLUMES = pVolumes;
            });

        return lRet;
    }

    /**
     * Функция создаёт заголовки файлов
     * в зависимости от расширения файла
     * перед отправкой их клиенту
     * @param pParams
     *  name - имя файла
     * gzip - данные сжаты gzip'ом
     * query
     * https://developers.google.com/speed/docs/best-practices/caching?hl=ru#LeverageProxyCaching
     */
    function generateHeaders(params) {
        var header, p, extension, type, encoding, isContain, cmp;

        if (params.name) {
            p               = params,
            extension       = Util.getExtension(p.name),
            type            = ext[extension] || 'text/plain',
            encoding        = '';

            /* if type of file any, but img - then we shoud specify charset */
            isContain       = Util.isContainStr(type, ['img', 'image']);
            if (!isContain)
                encoding    = '; charset=UTF-8';

            isContain        = Util.isContainStr(p.query, 'download');
            if (isContain)
                type        = 'application/octet-stream';

            header          = {
                'Access-Control-Allow-Origin'   : '*',
                'Content-Type'                  : type  + encoding,
                'Last-Modified'                 : ''    + new Date(),
                'Vary'                          : 'Accept-Encoding'
            };

            cmp             = Util.strCmp(ext, '.appcache');
            if (!cmp && p.cache)
                header['Cache-Control']     = 'max-age=' + 31337 * 21;

            if (p.gzip)
                header['Content-Encoding']  = 'gzip';
        }

        return header;
    }

    function mainSetHeader(pParams) {
        var p, header, lGzip,
            lRet = checkParams(pParams);

        if (lRet) {
            p       = pParams;
            lGzip   = isGZIP(p.request) && p.gzip;

            header  = generateHeaders({
                name    : p.name,
                cache   : p.cache,
                gzip    : lGzip,
                query   : getQuery(p.request)
            });

            setHeader(header, p.response);
            p.response.statusCode = p.status || OK;
        }
    }

    /**
     * send file to client thru pipe
     * and gzip it if client support
     *
     * @param pName - имя файла
     * @param pGzip - данные сжаты gzip'ом
     */
    function sendFile(params) {
        var isGzip, header,
            p   = params,
            ret = checkParams(params);

        if (ret) {
            isGzip  = isGZIP(p.request) && p.gzip;

            mainSetHeader(params);

            pipe.create({
                from    : p.name,
                write   : p.response,
                gzip    : isGzip,
                callback: function(error) {
                    if (error)
                        sendError(params, error);
                }
            });
        }

        return ret;
    }

    /**
     * Функция высылает ответ серверу
     * @param pHead     - заголовок
     * @param Data      - данные
     * @param pName     - имя отсылаемого файла
     */
    function sendResponse(params, data, notLog) {
        var p, query, isGzip, head,
            ret = checkParams(params);

        if (ret) {
            p           = params;
            data        = p.data || data;
            isGzip      = isGZIP(p.request);

            head        = generateHeaders({
                name    : p.name,
                cache   : p.cache,
                gzip    : isGzip,
                query   : query
            });

            setHeader(head, p.response);

            if (!notLog)
                Util.log(data);

            /* если браузер поддерживает gzip-сжатие - сжимаем данные*/
            Util.ifExec(!isGzip,
                function(params) {
                    var ret = Util.checkObj(params, ['data']);

                    if (ret) {
                        p.status    = params.status || p.status;
                        p.data      = params.data;
                    }

                    p.response.statusCode = p.status || OK;
                    p.response.end(p.data);
                },

                function(callback) {
                    zlib.gzip (data, function(error, data) {
                        if (!error)
                            p.data = data;
                        else {
                            p.status    = FILE_NOT_FOUND;
                            p.data      = error.toString();
                        }

                        Util.exec(callback, p);
                    });
                });
        }
    }

    /**
     * redirect to another URL
     */
    function redirect(pParams) {
        var p, header,
            lRet    = Util.checkObjTrue(pParams, [RESPONSE]);

        if (lRet) {
            p       = pParams;

            header  = {
                'Location': p.url
            };

            setHeader(header, p.response);
            p.response.statusCode = MOVED_PERMANENTLY;
            p.response.end();
        }
    }

    /**
     * send error response
     */
    function sendError(params, error) {
        var p, ret     = checkParams(params);

        if (ret) {
            p           = params;
            p.status    = FILE_NOT_FOUND;

            if (!p.data && error)
              p.data    = error.toString();

            sendResponse(p);
        }
    }

    function checkCallBackParams(pParams) {
        return Util.checkObj(pParams, ['error', 'data', 'params']);
    }

    function checkParams(params, additional) {
        var ret = Util.checkObjTrue(params, ['name', REQUEST, RESPONSE]);

        if (ret && additional)
            ret = Util.checkObjTrue(params, additional);

        return ret;
    }

    function getQuery(req) {
        var query, parsed;

        if (req) {
            parsed  = url.parse(req.url);
            query   = parsed.query;
        }

        return query;
    }

    function getPathName(req) {
        var pathname, parsed;

        if (req) {
            parsed      = url.parse(req.url);
            pathname    = parsed.pathname;
            /* supporting of Russian language in directory names */
            pathname    = querystring.unescape(pathname);
        }

        return pathname;
    }

    function isGZIP(pReq) {
        var lEnc, lGZIP;
        if (pReq) {
            lEnc        = pReq.headers['accept-encoding'] || '';
            lGZIP       = lEnc.match(/\bgzip\b/);
        }

        return lGZIP;
    }

    function setHeader(header, response) {
        var name;

        if (!response.headersSent && Util.isObject(header))
            for (name in header)
                response.setHeader(name, header[name]);
    }

})();
<|endoftext|>


<commit_before>phoxy.click =
{
  _: {},
};

phoxy._.click =
{
  InitClickHook: function()
    {
      document.querySelector('body').addEventListener('click', function click_hook(event)
      {
        var target = event.target;
        while (true)
        {
          if (target === null)
            return;
          if (target.nodeName === 'A')
            break; // only click on A is triggered
          target = target.parentElement;
        }

        var url = target.getAttribute('href');

        if (url === undefined || target.hasAttribute('not-phoxy'))
          return;

        if (phoxy._.click.OnClick(url, false))
          return;

        event.preventDefault()
      }, true);

      window.onpopstate = phoxy._.click.OnPopState;
    }
  ,
  OnClick: function (url, not_push)
    {
      // Element without url
      if (url === undefined)
        return true;

      if (url.indexOf('#') !== -1)
        return true;

      if (url[0] === '/')
        url = url.substring(1);

      if (not_push)
        phoxy.ApiRequest(url);
      else
        phoxy.MenuCall(url);
      return false;
    }
  ,
  OnPopState: function(e)
    {
      var path = e.target.location.pathname;
      var hash = e.target.location.hash;

      phoxy._.click.OnClick(path, true);
    }
};<commit_msg>Fix annoying issue with url click hook<commit_after>phoxy.click =
{
  _: {},
};

phoxy._.click =
{
  InitClickHook: function()
    {
      document.querySelector('body').addEventListener('click', function click_hook(event)
      {
        var target = event.target;
        while (true)
        {
          if (target === null)
            return;
          if (target.nodeName === 'A')
            break; // only click on A is triggered
          target = target.parentElement;
        }

        var url = target.getAttribute('href');

        if (url === undefined || target.hasAttribute('not-phoxy'))
          return;

        if (phoxy._.click.OnClick(url, false))
          return;

        event.preventDefault()
      }, true);

      window.onpopstate = phoxy._.click.OnPopState;
    }
  ,
  OnClick: function (url, not_push)
    {
      // Element without url
      if (!url)
        return true;

      if (url.indexOf('#') !== -1)
        return true;

      if (url[0] === '/')
        url = url.substring(1);

      if (not_push)
        phoxy.ApiRequest(url);
      else
        phoxy.MenuCall(url);
      return false;
    }
  ,
  OnPopState: function(e)
    {
      var path = e.target.location.pathname;
      var hash = e.target.location.hash;

      phoxy._.click.OnClick(path, true);
    }
};<|endoftext|>


<commit_before>import React, {PropTypes} from 'react'
import QuestionMarkTooltip from 'src/shared/components/QuestionMarkTooltip'
import {HIPCHAT_TOKEN_TIP} from 'src/kapacitor/copy'

const {
  bool,
  func,
  shape,
  string,
} = PropTypes

const HipchatConfig = React.createClass({
  propTypes: {
    config: shape({
      options: shape({
        room: string.isRequired,
        token: bool.isRequired,
        url: string.isRequired,
      }).isRequired,
    }).isRequired,
    onSave: func.isRequired,
  },

  handleSaveAlert(e) {
    e.preventDefault()

    const properties = {
      room: this.room.value,
      url: this.url.value,
      token: this.token.value,
    }

    this.props.onSave(properties)
  },

  render() {
    const {options} = this.props.config
    const {url, room, token} = options

    return (

HipChat Alert

Send alert messages to HipChat.

        <form onSubmit={this.handleSaveAlert}>

            HipChat URL
            <input
              className="form-control"
              id="url"
              type="text"
              placeholder="https://your-subdomain.hipchat.com/v2/room"
              ref={(r) => this.url = r}
              defaultValue={url || ''}
            />

            Room
            <input
              className="form-control"
              id="room"
              type="text"
              placeholder="your-hipchat-token"
              ref={(r) => this.room = r}
              defaultValue={room || ''}
            />

              Token
              <QuestionMarkTooltip
                tipID="token"
                tipContent={HIPCHAT_TOKEN_TIP}
              />

            <input
              className="form-control"
              id="token"
              type="text"
              placeholder="your-hipchat-token"
              ref={(r) => this.token = r}
              defaultValue={token || ''}
            />
            Note: a value of true indicates the HipChat token has been set

            <button className="btn btn-block btn-primary" type="submit">Save</button>

        </form>

    )
  },
})

export default HipchatConfig
<commit_msg>Template HipChat subdomain into URL. Pull subdomain out when loading Kapacitor sections into UI.<commit_after>import React, {PropTypes} from 'react'
import QuestionMarkTooltip from 'src/shared/components/QuestionMarkTooltip'
import {HIPCHAT_TOKEN_TIP} from 'src/kapacitor/copy'

const {
  bool,
  func,
  shape,
  string,
} = PropTypes

const HipchatConfig = React.createClass({
  propTypes: {
    config: shape({
      options: shape({
        room: string.isRequired,
        token: bool.isRequired,
        url: string.isRequired,
      }).isRequired,
    }).isRequired,
    onSave: func.isRequired,
  },

  handleSaveAlert(e) {
    e.preventDefault()

    const properties = {
      room: this.room.value,
      url: `https://${this.url.value}.hipchat.com/v2/room`,
      token: this.token.value,
    }

    this.props.onSave(properties)
  },

  render() {
    const {options} = this.props.config
    const {url, room, token} = options

    const subdomain = url.replace('https://', '').replace('.hipchat.com/v2/room', '')

    return (

HipChat Alert

Send alert messages to HipChat.

        <form onSubmit={this.handleSaveAlert}>

            Subdomain
            <input
              className="form-control"
              id="url"
              type="text"
              placeholder="your-subdomain"
              ref={(r) => this.url = r}
              defaultValue={subdomain && subdomain.length ? subdomain : ''}
            />

            Room
            <input
              className="form-control"
              id="room"
              type="text"
              placeholder="your-hipchat-token"
              ref={(r) => this.room = r}
              defaultValue={room || ''}
            />

              Token
              <QuestionMarkTooltip
                tipID="token"
                tipContent={HIPCHAT_TOKEN_TIP}
              />

            <input
              className="form-control"
              id="token"
              type="text"
              placeholder="your-hipchat-token"
              ref={(r) => this.token = r}
              defaultValue={token || ''}
            />
            Note: a value of true indicates the HipChat token has been set

            <button className="btn btn-block btn-primary" type="submit">Save</button>

        </form>

    )
  },
})

export default HipchatConfig
<|endoftext|>


<commit_before>function YouTubeClip() {
    var youtube_id = youtube_parser( document.getElementById("startURL").value );
    var startsec = document.getElementById("
}

// Function taken from the following stackoverflow comment
// http://stackoverflow.com/a/8260383/3161979
function youtube_parser(url){
    var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
    var match = url.match(regExp);
    return (match&&match[7].length==11)? match[7] : false;
}

<commit_msg>Adding conditions and validation on form input<commit_after>function YouTubeClip() {
    // Multiple condition testing style taken from the following stackoverflow comment
    // http://stackoverflow.com/a/19478159/3161979
    //
    // condition0: URL has a valid YouTube video ID
    // condition1: startsec is valid second value
    // condition2: startmin is valid minute value
    // condition3: endsec is valid second value
    // condition4: endmin is valid minute value
    // condition5: end time is greater than start time
    // condition6: URL is valid YouTube URL
    var a = 0;
    var b = 0;
    var condition0 = youtube_parser(document.getElementById("startURL").value);
    var condition1 = validator.isInt(document.getElementById("startsec").value, {min: 0, max:59 });
    var condition2 = validator.isInt(document.getElementById("startmin").value, {min: 0, max:59 });
    var condition3 = validator.isInt(document.getElementById("endsec").value, {min: 0, max:59 });
    var condition4 = validator.isInt(document.getElementById("endmin").value, {min: 0, max:59 });
    var condition5 = document.getElementById("endmin").value * 60 + document.getElementById("endsec").value > document.getElementById("startmin").value * 60 + document.getElementById("startsec").value;
    var condition6 = validator.isURL(document.getElementById("startURL").value, {protocols: ['http','https'], host_whitelist: ["www.youtube.com", "youtube.com", "www.youtu.be", "youtu.be"]});
    a += (condition0)? 1 : 0; b += 1;
    a += (condition1)? 1 : 0; b += 1;
    a += (condition2)? 1 : 0; b += 1;
    a += (condition3)? 1 : 0; b += 1;
    a += (condition4)? 1 : 0; b += 1;
    a += (condition5)? 1 : 0; b += 1;
    a += (condition6)? 1 : 0; b += 1;
    console.log(condition0);
    console.log(condition1);
    console.log(condition2);
    console.log(condition3);
    console.log(condition4);
    console.log(condition5);
    console.log(condition6);

    if (a == b) {
        var youtube_id = youtube_parser(document.getElementById("startURL").value);
        var startsec = document.getElementById("startsec").value;
        var startmin = document.getElementById("startmin").value;
        var endsec = document.getElementById("endsec").value;
        var endmin = document.getElementById("endmin").value;
    }
}

// Function taken from the following stackoverflow comment
// http://stackoverflow.com/a/8260383/3161979
function youtube_parser(url){
    var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/;
    var match = url.match(regExp);
    return (match&&match[7].length==11)? match[7] : false;
}

<|endoftext|>


<commit_before>/*
 * Copyright 2012 VirtuOz Inc.  All rights reserved.
 */

/**
 *
 * @author ccauchois
 * @created 2012-10-24
 */

require('jsclass');
JS.require('JS.Class');
var EventEmitter = require('events').EventEmitter;
var Io = require('socket.io');
var Amqp = require('amqp');

var SmartRouter = new JS.Class(EventEmitter, {
  initialize: function () {
    EventEmitter.call(this);
    this.io = {};
    this.amqp = {};
    this.config = {};
  },

  /**
   * start method: starts the SmartRouter
   *
   */
  start: function (config) {
    console.log('starting...');
    this.config = config;
    this.io = Io.listen(config.port);
    this.amqp = Amqp.createConnection(config.amqp);
    this.amqp.on('error', function (err) {
      console.log('error connecting to RabbitMQ: ' + err);
    });

    this.registerEndpoints();

    this.emit('started');
  },

  /**
   * registerEndpoints: register bindings for the endpoints.
   *
   */
  registerEndpoints: function () {
    var self = this;
    self.config.endpoints.forEach(function (endpoint) {
      console.log('registering endpoint ' + endpoint.name);
      if (endpoint.ids.length === 0) {
        var socket = self.io.of('/' + endpoint.name);
        self.registerRoutes(endpoint.name, '', socket);
      } else {
        endpoint.ids.forEach(function (id) {
          var socket = self.io.of('/' + endpoint.name + '/' + id);
          self.registerRoutes(endpoint.name, id, socket);
        });
      }
    });
  },

  /**
   * registerRoutes
   */
  registerRoutes: function (name, id, socket) {
    var self = this;
    socket.on('connection', function (sock) {
      socket.emit('whoareyou');
    });
    socket.on('iam', function (actorid) {
      console.log('call from ' + actorid);
      socket.set('actorid', actorid, function () {
        console.log('hello actor ' + actorid);
        socket.emit('hello');
      });
      self.amqp.queue(actorid, function (q) {
        q.bind(name + id, actorid);
        q.subscribe(function (message, headers, deliveryInfo) {
          socket.emit(message.data.type, message.data);
        });
      });
    });
    self.config.routes.forEach( function (route) {
      if (route.name === name) {
        socket.on(route.message, function (data) {
          if (self.check(socket, route.message, data)) {
            route.action(data, self);
          }
        });
      }
    });
  },

  /**
   * check: performs some checks on the message received.
   *
   */
  check: function (socket, type, message) {
    var actorid;
    socket.get('actorid', function (err, id) {
      if (err) {
        actorid = undefined;
        return;
      } else {
        actorid = id;
        return;
      }
    });
    if (!actorid) {
      var data = {};
      data.type = type;
      data.message = message;
      socket.emit('whoareyou', data);
      return false;
    }
    return true;
  }
});

exports.instance = new SmartRouter();
<commit_msg>correcting event binding<commit_after>/*
 * Copyright 2012 VirtuOz Inc.  All rights reserved.
 */

/**
 *
 * @author ccauchois
 * @created 2012-10-24
 */

require('jsclass');
JS.require('JS.Class');
var EventEmitter = require('events').EventEmitter;
var Io = require('socket.io');
var Amqp = require('amqp');

var SmartRouter = new JS.Class(EventEmitter, {
  initialize: function () {
    EventEmitter.call(this);
    this.io = {};
    this.amqp = {};
    this.config = {};
  },

  /**
   * start method: starts the SmartRouter
   *
   */
  start: function (config) {
    console.log('starting...');
    this.config = config;
    this.io = Io.listen(config.port);
    this.amqp = Amqp.createConnection(config.amqp);
    this.amqp.on('error', function (err) {
      console.log('error connecting to RabbitMQ: ' + err);
    });

    this.registerEndpoints();

    this.emit('started');
  },

  /**
   * registerEndpoints: register bindings for the endpoints.
   *
   */
  registerEndpoints: function () {
    var self = this;
    self.config.endpoints.forEach(function (endpoint) {
      console.log('registering endpoint ' + endpoint.name);
      if (endpoint.ids.length === 0) {
        var socket = self.io.of('/' + endpoint.name);
        self.registerRoutes(endpoint.name, '', socket);
      } else {
        endpoint.ids.forEach(function (id) {
          var socketendpoint = self.io.of('/' + endpoint.name + '/' + id);
          self.registerRoutes(endpoint.name, id, socketendpoint);
        });
      }
    });
  },

  /**
   * registerRoutes
   */
  registerRoutes: function (name, id, socketep) {
    var self = this;
    socketep.on('connection', function (socket) {
      socket.emit('whoareyou');
      socket.on('iam', function (actorid) {
        console.log('call from ' + actorid);
        socket.set('actorid', actorid, function () {
          console.log('hello actor ' + actorid);
          socket.emit('hello');
        });
        self.amqp.queue(actorid, function (q) {
          q.bind(name + id, actorid);
          q.subscribe(function (message, headers, deliveryInfo) {
            socket.emit(message.data.type, message.data);
          });
        });
      });
      self.config.routes.forEach( function (route) {
        if (route.name === name) {
          socket.on(route.message, function (data) {
            if (self.check(socket, route.message, data)) {
              route.action(data, self);
            }
          });
        }
      });
    });
  },

  /**
   * check: performs some checks on the message received.
   *
   */
  check: function (socket, type, message) {
    var actorid;
    socket.get('actorid', function (err, id) {
      if (err) {
        actorid = undefined;
        return;
      } else {
        actorid = id;
        return;
      }
    });
    if (!actorid) {
      var data = {};
      data.type = type;
      data.message = message;
      socket.emit('whoareyou', data);
      return false;
    }
    return true;
  }
});

exports.instance = new SmartRouter();
<|endoftext|>