<commit_before>var vumigo = require('vumigo_v02');
var App = vumigo.App;
var Choice = vumigo.states.Choice;
var ChoiceState = vumigo.states.ChoiceState;
var EndState = vumigo.states.EndState;
var InteractionMachine = vumigo.InteractionMachine;
var MenuState = vumigo.states.MenuState;
var FreeText = vumigo.states.FreeText;
var JsonApi = vumigo.http.api.JsonApi;

var GoDiApp = App.extend(function(self) {
    App.call(self, 'states:start');
    var $ = self.$;

    self.get_date = function() {
        return new Date().toISOString();
    };

    self.init = function() {
        self.http = new JsonApi(self.im);
        return self.im.contacts.for_user().then(function(user_contact) {
           self.contact = user_contact;
        });
    };

    self.states.add('states:start',function(name) {
        if ( typeof self.contact.extra.is_registered === 'undefined' || self.contact.extra.is_registered === "false") {
            return self.states.create('states:register');
        } else {
            return self.states.create('states:address');
        }
    });

    self.states.add('states:register', function(name) {
        return new ChoiceState(name, {
            question: $('Welcome to Voting is Power! Start by choosing your language:'),
            choices: [
                new Choice('en',$('English')),
                new Choice('af',$('Afrikaans')),
                new Choice('zu',$('Zulu')),
                new Choice('xh',$('Xhosa')),
                new Choice('so',$('Sotho'))
            ],
            next: function(choice) {
                return self.im.user.set_lang(choice.value).then(function() {
                    return 'states:registration:engagement';
                });
            }
        });
    });

    self.states.add('states:registration:engagement', function(name) {
       return new ChoiceState(name, {
           question: $('Are you excited about the election?'),
           choices: [
               new Choice('yes',$('Yes')),
               new Choice('no',$('No'))
           ],
           next: function(choice) {
               self.contact.extra.engagement_question = choice.value;
               self.contact.extra.it_engagement_question = self.get_date();

               return self.im.contacts.save(self.contact).then(function() {
                   return 'states:registration:tandc';
               });
           }
       });
    });

    self.states.add('states:registration:tandc', function(name) {
        return new ChoiceState(name, {
            question: $("Please accept the terms and conditions to get started."),
            choices: [ new Choice('accept','Accept & Join'),
                        new Choice('read','Read t&c'),
                        new Choice('quit','Quit')],
            next: function(choice) {
                return {
                    accept: 'states:registration:accept',
                    read: 'states:registration:read',
                    quit: 'states:registration:end'
                } [choice.value];
            }
        });
    });

    self.states.add('states:registration:accept',function(name){
        self.contact.extra.is_registered = 'true';
        return self.im.contacts.save(self.contact).then(function() {
            return new EndState(name, {
                text: $('Thanks for volunteering to be a citizen reporter for the 2014 elections! Get started by answering questions to earn airtime!'),
                next: 'states:start'
            });
        });
    });

    self.states.add('states:registration:read',function(name){
        self.contact.extra.is_registered = 'false';
        return self.im.contacts.save(self.contact).then(function() {
            return new EndState(name, {
                text: $("Terms and Conditions"),
                next: 'states:start'
            });
        });
    });

    self.states.add('states:registration:end',function(name){
        self.contact.extra.is_registered = 'false';
        return self.im.contacts.save(self.contact).then(function() {
           return new EndState(name,{
               text: $('Thank you for your time. Remember, you can always reconsider becoming a citizen reporter.'),
               next: 'states:start'
           }) ;
        });
    });

    self.states.add('states:address',function(name){
        var error = $("Oops! Something went wrong! Please try again.");
        var response;

        return new FreeText(name,{
            question: $("Please enter your home address. i.e. 9 Dover Street"),
            check: function(content) {
                return self
                    .http.get('http://wards.code4sa.org/?address',{
                        params: {address: encodeURI(content)}
                    })
                    .then(function(resp) {
                        response = resp;

                        if (typeof resp.data.error  !== 'undefined') {
                            return error;
                        } else {
                            self.contact.extra.ward = resp.data.ward;
                            return self.im.contacts.save(self.contact);
                        }
                    });
            },
            next: function(resp) {
                return 'states:menu';
            }
        }) ;
    });

    self.states.add('states:address:accepted',function(name){
        var error = $("Oops! Something went wrong! Please try again.");
        var response;

        return new FreeText(name,{
            question: $("Please enter your home address. i.e. 9 Dover Street"),
            check: function(content) {
                var address = encodeURI(content);
                var url ='http://wards.code4sa.org/?address=' + address;

                return self
                    .http.get(url)
                    .then(function(resp) {
                        response = resp;

                        if (typeof resp.data.error  !== 'undefined') {
                            return error;
                        }
                    });
            },
            next: function(resp) {
                console.log(resp);
                self.contact.extra.ward = resp.data.ward;
                return self.im.contacts.save(self.contact).then(function() {
                    return 'states:menu';
                });
            }
        }) ;
    });

    self.states.add('states:menu',function(name) {
        return new MenuState(name, {
            question: $('Welcome to the Campaign'),
            choices:[
                new Choice('states:quiz:tier2:question1',$('Take the quiz & win!')),
                new Choice('states:report',$('Report an Election Activity')),
                new Choice('states:results',$('View the results...')),
                new Choice('states:about',$('About')),
                new Choice('states:end',$('End'))
            ]
        });
    });

    self.states.add('states:quiz:tier2:question1',function(name) {
        return new ChoiceState(name, {
           question: $('Are you registered to vote?'),
           choices: [
                new Choice('yes',$('Yes')),
                new Choice('no',$('No')),
                new Choice('u18',$('I am u18 and not able to register yet'))
            ],
            next: function(content) {
                self.contact.extra.question1 = content.value;
                self.contact.extra.it_question1 = self.get_date();
                return self.im
                    .contacts.save(self.contact)
                    .then(function() {
                        return 'states:quiz:tier2:question2';
                    });
            }
        });
    });

    self.states.add('states:quiz:tier2:question2',function(name) {
        return new ChoiceState(name, {
            question: $('How old are you?'),
            choices: [
                new Choice('u18',$('under 18')),
                new Choice('19-20',$('19-20')),
                new Choice('21-30',$('21-30')),
                new Choice('31-40',$('31-40')),
                new Choice('41-50',$('41-50')),
                new Choice('51-60',$('51-60')),
                new Choice('61-70',$('61-70')),
                new Choice('71-80',$('71-80')),
                new Choice('81-90',$('81-90')),
                new Choice('90+',$('90+'))
            ],
            next: function(content) {
                self.contact.extra.question2 = content.value;
                self.contact.extra.it_question2 = self.get_date();

                return self.im
                    .contacts.save(self.contact)
                    .then(function() {
                        return 'states:quiz:tier2:question3';
                    });
            }
        });
    });

    self.states.add('states:quiz:tier2:question3',function(name) {
        return new ChoiceState(name, {
            question: $('How likely is it that you will vote in the upcoming election?'),
            choices: [
                new Choice('highly_likely',$('highly likely')),
                new Choice('likely',$('likely')),
                new Choice('not_likely',$('not likely')),
                new Choice('highly_unlikely',$('highly unlikely'))
            ],
            next: function(content) {
                self.contact.extra.question3 = content.value;
                self.contact.extra.it_question3 = self.get_date();

                return self.im
                    .contacts.save(self.contact)
                    .then(function() {
                        return 'states:quiz:tier2:question4';
                    });
            }
        });
    });

    self.states.add('states:quiz:tier2:question4',function(name) {
        return new ChoiceState(name,{
            question: $('What education level do you have?'),
            choices: [
                new Choice('less_than_matric',$('Less than a matric')),
                new Choice('matric',$('matric')),
                new Choice('diploma',$('diploma')),
                new Choice('degree',$('degree')),
                new Choice('postgrad',$('post-grad degree/diploma'))
            ],
            next: function(content) {
                self.contact.extra.question4 = content.value;
                self.contact.extra.it_question4 = self.get_date();

                return self.im
                    .contacts.save(self.contact)
                    .then(function() {
                        return 'states:menu';
                    });
            }
        });
    });

    self.states.add('states:report',function(name) {
        return new EndState(name, {
            text: $('To be continued'),
            next: 'states:start'
        });
    });
    self.states.add('states:results',function(name) {
        return new EndState(name, {
            text: $('To be continued'),
            next: 'states:start'
        });
    });
    self.states.add('states:about',function(name) {
        return new EndState(name, {
            text: $('To be continued'),
            next: 'states:start'
        });
    });

    self.states.add('states:end',function(name) {
        return new EndState(name, {
            text: $('Bye.'),
            next: 'states:start'
        });
    });

});

// if we have the real api, this is not a test, start the interaction machine
if (typeof api != 'undefined') {
    new InteractionMachine(api, new GoDiApp());
}

this.GoDiApp = GoDiApp;
<commit_msg>Fixed up address url<commit_after>var vumigo = require('vumigo_v02');
var App = vumigo.App;
var Choice = vumigo.states.Choice;
var ChoiceState = vumigo.states.ChoiceState;
var EndState = vumigo.states.EndState;
var InteractionMachine = vumigo.InteractionMachine;
var MenuState = vumigo.states.MenuState;
var FreeText = vumigo.states.FreeText;
var JsonApi = vumigo.http.api.JsonApi;

var GoDiApp = App.extend(function(self) {
    App.call(self, 'states:start');
    var $ = self.$;

    self.get_date = function() {
        return new Date().toISOString();
    };

    self.init = function() {
        self.http = new JsonApi(self.im);
        return self.im.contacts.for_user().then(function(user_contact) {
           self.contact = user_contact;
        });
    };

    self.states.add('states:start',function(name) {
        if ( typeof self.contact.extra.is_registered === 'undefined' || self.contact.extra.is_registered === "false") {
            return self.states.create('states:register');
        } else {
            return self.states.create('states:address');
        }
    });

    self.states.add('states:register', function(name) {
        return new ChoiceState(name, {
            question: $('Welcome to Voting is Power! Start by choosing your language:'),
            choices: [
                new Choice('en',$('English')),
                new Choice('af',$('Afrikaans')),
                new Choice('zu',$('Zulu')),
                new Choice('xh',$('Xhosa')),
                new Choice('so',$('Sotho'))
            ],
            next: function(choice) {
                return self.im.user.set_lang(choice.value).then(function() {
                    return 'states:registration:engagement';
                });
            }
        });
    });

    self.states.add('states:registration:engagement', function(name) {
       return new ChoiceState(name, {
           question: $('Are you excited about the election?'),
           choices: [
               new Choice('yes',$('Yes')),
               new Choice('no',$('No'))
           ],
           next: function(choice) {
               self.contact.extra.engagement_question = choice.value;
               self.contact.extra.it_engagement_question = self.get_date();

               return self.im.contacts.save(self.contact).then(function() {
                   return 'states:registration:tandc';
               });
           }
       });
    });

    self.states.add('states:registration:tandc', function(name) {
        return new ChoiceState(name, {
            question: $("Please accept the terms and conditions to get started."),
            choices: [ new Choice('accept','Accept & Join'),
                        new Choice('read','Read t&c'),
                        new Choice('quit','Quit')],
            next: function(choice) {
                return {
                    accept: 'states:registration:accept',
                    read: 'states:registration:read',
                    quit: 'states:registration:end'
                } [choice.value];
            }
        });
    });

    self.states.add('states:registration:accept',function(name){
        self.contact.extra.is_registered = 'true';
        return self.im.contacts.save(self.contact).then(function() {
            return new EndState(name, {
                text: $('Thanks for volunteering to be a citizen reporter for the 2014 elections! Get started by answering questions to earn airtime!'),
                next: 'states:start'
            });
        });
    });

    self.states.add('states:registration:read',function(name){
        self.contact.extra.is_registered = 'false';
        return self.im.contacts.save(self.contact).then(function() {
            return new EndState(name, {
                text: $("Terms and Conditions"),
                next: 'states:start'
            });
        });
    });

    self.states.add('states:registration:end',function(name){
        self.contact.extra.is_registered = 'false';
        return self.im.contacts.save(self.contact).then(function() {
           return new EndState(name,{
               text: $('Thank you for your time. Remember, you can always reconsider becoming a citizen reporter.'),
               next: 'states:start'
           }) ;
        });
    });

    self.states.add('states:address',function(name){
        var error = $("Oops! Something went wrong! Please try again.");
        var response;

        return new FreeText(name,{
            question: $("Please enter your home address. i.e. 9 Dover Street"),
            check: function(content) {
                return self
                    .http.get('http://wards.code4sa.org/',{
                        params: {address: encodeURI(content)}
                    })
                    .then(function(resp) {
                        response = resp;

                        if (typeof resp.data.error  !== 'undefined') {
                            return error;
                        } else {
                            self.contact.extra.ward = resp.data.ward;
                            return self.im.contacts.save(self.contact);
                        }
                    });
            },
            next: function(resp) {
                return 'states:menu';
            }
        }) ;
    });

    self.states.add('states:address:accepted',function(name){
        var error = $("Oops! Something went wrong! Please try again.");
        var response;

        return new FreeText(name,{
            question: $("Please enter your home address. i.e. 9 Dover Street"),
            check: function(content) {
                var address = encodeURI(content);
                var url ='http://wards.code4sa.org/?address=' + address;

                return self
                    .http.get(url)
                    .then(function(resp) {
                        response = resp;

                        if (typeof resp.data.error  !== 'undefined') {
                            return error;
                        }
                    });
            },
            next: function(resp) {
                console.log(resp);
                self.contact.extra.ward = resp.data.ward;
                return self.im.contacts.save(self.contact).then(function() {
                    return 'states:menu';
                });
            }
        }) ;
    });

    self.states.add('states:menu',function(name) {
        return new MenuState(name, {
            question: $('Welcome to the Campaign'),
            choices:[
                new Choice('states:quiz:tier2:question1',$('Take the quiz & win!')),
                new Choice('states:report',$('Report an Election Activity')),
                new Choice('states:results',$('View the results...')),
                new Choice('states:about',$('About')),
                new Choice('states:end',$('End'))
            ]
        });
    });

    self.states.add('states:quiz:tier2:question1',function(name) {
        return new ChoiceState(name, {
           question: $('Are you registered to vote?'),
           choices: [
                new Choice('yes',$('Yes')),
                new Choice('no',$('No')),
                new Choice('u18',$('I am u18 and not able to register yet'))
            ],
            next: function(content) {
                self.contact.extra.question1 = content.value;
                self.contact.extra.it_question1 = self.get_date();
                return self.im
                    .contacts.save(self.contact)
                    .then(function() {
                        return 'states:quiz:tier2:question2';
                    });
            }
        });
    });

    self.states.add('states:quiz:tier2:question2',function(name) {
        return new ChoiceState(name, {
            question: $('How old are you?'),
            choices: [
                new Choice('u18',$('under 18')),
                new Choice('19-20',$('19-20')),
                new Choice('21-30',$('21-30')),
                new Choice('31-40',$('31-40')),
                new Choice('41-50',$('41-50')),
                new Choice('51-60',$('51-60')),
                new Choice('61-70',$('61-70')),
                new Choice('71-80',$('71-80')),
                new Choice('81-90',$('81-90')),
                new Choice('90+',$('90+'))
            ],
            next: function(content) {
                self.contact.extra.question2 = content.value;
                self.contact.extra.it_question2 = self.get_date();

                return self.im
                    .contacts.save(self.contact)
                    .then(function() {
                        return 'states:quiz:tier2:question3';
                    });
            }
        });
    });

    self.states.add('states:quiz:tier2:question3',function(name) {
        return new ChoiceState(name, {
            question: $('How likely is it that you will vote in the upcoming election?'),
            choices: [
                new Choice('highly_likely',$('highly likely')),
                new Choice('likely',$('likely')),
                new Choice('not_likely',$('not likely')),
                new Choice('highly_unlikely',$('highly unlikely'))
            ],
            next: function(content) {
                self.contact.extra.question3 = content.value;
                self.contact.extra.it_question3 = self.get_date();

                return self.im
                    .contacts.save(self.contact)
                    .then(function() {
                        return 'states:quiz:tier2:question4';
                    });
            }
        });
    });

    self.states.add('states:quiz:tier2:question4',function(name) {
        return new ChoiceState(name,{
            question: $('What education level do you have?'),
            choices: [
                new Choice('less_than_matric',$('Less than a matric')),
                new Choice('matric',$('matric')),
                new Choice('diploma',$('diploma')),
                new Choice('degree',$('degree')),
                new Choice('postgrad',$('post-grad degree/diploma'))
            ],
            next: function(content) {
                self.contact.extra.question4 = content.value;
                self.contact.extra.it_question4 = self.get_date();

                return self.im
                    .contacts.save(self.contact)
                    .then(function() {
                        return 'states:menu';
                    });
            }
        });
    });

    self.states.add('states:report',function(name) {
        return new EndState(name, {
            text: $('To be continued'),
            next: 'states:start'
        });
    });
    self.states.add('states:results',function(name) {
        return new EndState(name, {
            text: $('To be continued'),
            next: 'states:start'
        });
    });
    self.states.add('states:about',function(name) {
        return new EndState(name, {
            text: $('To be continued'),
            next: 'states:start'
        });
    });

    self.states.add('states:end',function(name) {
        return new EndState(name, {
            text: $('Bye.'),
            next: 'states:start'
        });
    });

});

// if we have the real api, this is not a test, start the interaction machine
if (typeof api != 'undefined') {
    new InteractionMachine(api, new GoDiApp());
}

this.GoDiApp = GoDiApp;
<|endoftext|>


<commit_before>var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

;(function (exports) {
	'use strict';

  var Arr = (typeof Uint8Array !== 'undefined')
    ? Uint8Array
    : Array

	var PLUS   = '+'.charCodeAt(0)
	var SLASH  = '/'.charCodeAt(0)
	var NUMBER = '0'.charCodeAt(0)
	var LOWER  = 'a'.charCodeAt(0)
	var UPPER  = 'A'.charCodeAt(0)

	function decode (elt) {
		var code = elt.charCodeAt(0)
		if (code === PLUS)
			return 62 // '+'
		if (code === SLASH)
			return 63 // '/'
		if (code < NUMBER)
			return -1 //no match
		if (code < NUMBER + 10)
			return code - NUMBER + 26 + 26
		if (code < UPPER + 26)
			return code - UPPER
		if (code < LOWER + 26)
			return code - LOWER + 26
	}

	function b64ToByteArray (b64) {
		var i, j, l, tmp, placeHolders, arr

		if (b64.length % 4 > 0) {
			throw new Error('Invalid string. Length must be a multiple of 4')
		}

		// the number of equal signs (place holders)
		// if there are two placeholders, than the two characters before it
		// represent one byte
		// if there is only one, then the three characters before it represent 2 bytes
		// this is just a cheap hack to not do indexOf twice
		var len = b64.length
		placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0

		// base64 is 4/3 + up to two characters of the original data
		arr = new Arr(b64.length * 3 / 4 - placeHolders)

		// if there are placeholders, only get up to the last complete 4 chars
		l = placeHolders > 0 ? b64.length - 4 : b64.length

		var L = 0

		function push (v) {
			arr[L++] = v
		}

		for (i = 0, j = 0; i < l; i += 4, j += 3) {
			tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
			push((tmp & 0xFF0000) >> 16)
			push((tmp & 0xFF00) >> 8)
			push(tmp & 0xFF)
		}

		if (placeHolders === 2) {
			tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
			push(tmp & 0xFF)
		} else if (placeHolders === 1) {
			tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
			push((tmp >> 8) & 0xFF)
			push(tmp & 0xFF)
		}

		return arr
	}

	function uint8ToBase64 (uint8) {
		var i,
			extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
			output = "",
			temp, length

		function encode (num) {
			return lookup.charAt(num)
		}

		function tripletToBase64 (num) {
			return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
		}

		// go through the array every three bytes, we'll deal with trailing stuff later
		for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
			temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
			output += tripletToBase64(temp)
		}

		// pad the end with zeros, but make sure to not forget the extra bytes
		switch (extraBytes) {
			case 1:
				temp = uint8[uint8.length - 1]
				output += encode(temp >> 2)
				output += encode((temp << 4) & 0x3F)
				output += '=='
				break
			case 2:
				temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
				output += encode(temp >> 10)
				output += encode((temp >> 4) & 0x3F)
				output += encode((temp << 2) & 0x3F)
				output += '='
				break
		}

		return output
	}

	exports.toByteArray = b64ToByteArray
	exports.fromByteArray = uint8ToBase64
}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))
<commit_msg>decode url-safe style base64<commit_after>var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

;(function (exports) {
	'use strict';

  var Arr = (typeof Uint8Array !== 'undefined')
    ? Uint8Array
    : Array

	var PLUS   = '+'.charCodeAt(0)
	var SLASH  = '/'.charCodeAt(0)
	var NUMBER = '0'.charCodeAt(0)
	var LOWER  = 'a'.charCodeAt(0)
	var UPPER  = 'A'.charCodeAt(0)
	var PLUS_URL_SAFE = '-'.charCodeAt(0)
	var SLASH_URL_SAFE = '_'.charCodeAt(0)

	function decode (elt) {
		var code = elt.charCodeAt(0)
		if (code === PLUS ||
		    code === PLUS_URL_SAFE)
			return 62 // '+'
		if (code === SLASH ||
		    code === SLASH_URL_SAFE)
			return 63 // '/'
		if (code < NUMBER)
			return -1 //no match
		if (code < NUMBER + 10)
			return code - NUMBER + 26 + 26
		if (code < UPPER + 26)
			return code - UPPER
		if (code < LOWER + 26)
			return code - LOWER + 26
	}

	function b64ToByteArray (b64) {
		var i, j, l, tmp, placeHolders, arr

		if (b64.length % 4 > 0) {
			throw new Error('Invalid string. Length must be a multiple of 4')
		}

		// the number of equal signs (place holders)
		// if there are two placeholders, than the two characters before it
		// represent one byte
		// if there is only one, then the three characters before it represent 2 bytes
		// this is just a cheap hack to not do indexOf twice
		var len = b64.length
		placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0

		// base64 is 4/3 + up to two characters of the original data
		arr = new Arr(b64.length * 3 / 4 - placeHolders)

		// if there are placeholders, only get up to the last complete 4 chars
		l = placeHolders > 0 ? b64.length - 4 : b64.length

		var L = 0

		function push (v) {
			arr[L++] = v
		}

		for (i = 0, j = 0; i < l; i += 4, j += 3) {
			tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
			push((tmp & 0xFF0000) >> 16)
			push((tmp & 0xFF00) >> 8)
			push(tmp & 0xFF)
		}

		if (placeHolders === 2) {
			tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
			push(tmp & 0xFF)
		} else if (placeHolders === 1) {
			tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
			push((tmp >> 8) & 0xFF)
			push(tmp & 0xFF)
		}

		return arr
	}

	function uint8ToBase64 (uint8) {
		var i,
			extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
			output = "",
			temp, length

		function encode (num) {
			return lookup.charAt(num)
		}

		function tripletToBase64 (num) {
			return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
		}

		// go through the array every three bytes, we'll deal with trailing stuff later
		for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
			temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
			output += tripletToBase64(temp)
		}

		// pad the end with zeros, but make sure to not forget the extra bytes
		switch (extraBytes) {
			case 1:
				temp = uint8[uint8.length - 1]
				output += encode(temp >> 2)
				output += encode((temp << 4) & 0x3F)
				output += '=='
				break
			case 2:
				temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
				output += encode(temp >> 10)
				output += encode((temp >> 4) & 0x3F)
				output += encode((temp << 2) & 0x3F)
				output += '='
				break
		}

		return output
	}

	exports.toByteArray = b64ToByteArray
	exports.fromByteArray = uint8ToBase64
}(typeof exports === 'undefined' ? (this.base64js = {}) : exports))
<|endoftext|>


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

var config = require("../config");
var TGAPI = require("./tgapi");
var api = new TGAPI(config.token)

var spawn = child_process.spawn;

var botInfo = null;

var runnerList = [];

(function () {
    fs.readdir('./docker_image/test', function (err, files) {
        if (err) {
            console.error(err.stack || err.toString());
            process.exit(-1)
        }
        runnerList = files
        .filter(function (name) {
            return !!name.match(/\.json$/i);
        })
        .map(function (name) {
            return require(path.resolve('./docker_image/test', name));
        })
        runnerList.forEach(function (data) {
            console.log(data.type + ' - run ' + data.type + ' snippet');
            console.log(data.type + '_debug - run ' + data.type + ' snippet with debug output');
            console.log(data.type + '_hello - run ' + data.type + '\'s Hello, World! program.');
        })
    })
} ());

api.getMe(function(err, data)
{
    if (err) console.error(err);
    console.log(data);
    botInfo = data;
    api.startPolling(40);
});

function guidGenerator() {
    var S4 = function() {
       return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
    };
    return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
}
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "<")
         .replace(/>/g, ">");
}

api.on('message', function(message) {
    // message is the parsed JSON data from telegram message
    // query is the parsed JSON data from telegram inline query
    console.log('got message');
    console.log(message);

    // message.text is the text user sent (if there is)
    var text = message.text;

    if (message.text != undefined && message.text.match(/\/start(@[^\s]+)?$/)) {

        var additionOptions = {
            reply_to_message_id: message.message_id
        }
        api.sendMessage(message.chat.id, `
Hello, I am ${botInfo.first_name}
You could run some code snippet with /[you favorite language]
Or run it with /[you favorite language]_debug to see debug message
Or run /[you favorite language]_hello to view hello world example
        `, 0, additionOptions);
    }

    if (message.text != undefined && message.text.match(/\/[a-z0-9_]+(@[^\s]+)?/)) {

        var additionOptions = {
            reply_to_message_id: message.message_id
        }

        var language = (/\/([a-z0-9_]+)(?:@[^\s]+)?(?: |\r|\n|$)/).exec(message.text)
        if (!language) return api.sendMessage(message.chat.id, 'something went wrong', 0, additionOptions);
        language = language[1];

        console.log(language);

        var isSilent = !language.match(/_d(ebug)?$/);
        language = language.replace(/_d(ebug)?$/, '');

        var isHelloWorld = !!language.match(/_h(ello)?$/);
        language = language.replace(/_h(ello)?$/, '');

        if (runnerList.filter(function (info) {
            return info.type === language
        }).length === 0) {
            return
        }

        var text = message.text.replace(/\/[a-z0-9_]+(@[^\s]+)?\s?/, '');
        if (isHelloWorld) {
            text = runnerList.filter(function (info) {
                return info.type === language
            })[0].program;
        }
        if (text.match(/^[\s\r\n]*$/)) {
            api.sendMessage(message.chat.id, 'you must provide something for me to run!', 0, additionOptions);
            return;
        }

        if (!isSilent || isHelloWorld) api.sendMessage(message.chat.id, 'running... \n
' + escapeHtml(text) + '
', 0, {
            parse_mode: 'HTML',
            reply_to_message_id: message.message_id
        });

        var bot_id = 'runner-' + guidGenerator()

        var p = spawn('docker', [
            'run',
            '-i',
            '--rm',
            '--net=none',
            '-m=50M',
            '--memory-swap=50M',
            '--pids-limit=32',
            '--cpuset-cpus=1',
            '-u=ubuntu',
            '-h=localhost',
            '--name=' + bot_id,
            config.image_name,
            'nodejs',
            'executer.js'
        ]);
        p.stdin.write(JSON.stringify({
            type: language,
            program: text
        }) + '\n')
        p.stdin.end();

        const rl = readline.createInterface({
          input: p.stdout,
          output: fs.createWriteStream('/dev/null')
        });

        var hasOutput = false;

        var stdoutWaitId = null;
        var stdoutBuffer = "";
        var stderrWaitId = null;
        var stderrBuffer = "";
        p.stderr.pipe(process.stderr, {end: false})
        p.stderr.on('end', function (argument) {
            p.stderr.unpipe(process.stderr)
        })
        rl.on('line', (cmd) => {
            try {
                cmd = JSON.parse(cmd);
                // console.log(cmd);
                if (cmd.type === 'stdout') {
                    hasOutput = true;
                    // console.log(stdoutWaitId, stdoutBuffer)
                    stdoutBuffer += cmd.text;

                    while (stdoutBuffer.length > 1333) {
                        var part = stdoutBuffer.slice(0, 1333);
                        stdoutBuffer = stdoutBuffer.slice(1333);
                        api.sendMessage(message.chat.id, '
' + escapeHtml(part) + '
', 0, {
                            parse_mode: 'HTML',
                            reply_to_message_id: message.message_id
                        });
                    }

                    clearTimeout(stdoutWaitId);
                    stdoutWaitId = setTimeout(function() {
                        // console.log('output stdout', stdoutBuffer)
                        api.sendMessage(message.chat.id, '
' + escapeHtml(stdoutBuffer) + '
', 0, {
                            parse_mode: 'HTML',
                            reply_to_message_id: message.message_id
                        });
                        stdoutBuffer = "";
                    }, 500)
                }
                if (cmd.type === 'log' && !isSilent) {
                    api.sendMessage(message.chat.id, cmd.text, 0, additionOptions);
                }
                if (cmd.type === 'stderr') {
                    hasOutput = true;
                    // console.log(stdoutWaitId, stdoutBuffer)
                    stderrBuffer += cmd.text;

                    while (stdoutBuffer.length > 1333) {
                        var part = stderrBuffer.slice(0, 1333);
                        stderrBuffer = stderrBuffer.slice(1333);
                        api.sendMessage(message.chat.id, 'stderr:
' + escapeHtml(part) + '
', 0, {
                            parse_mode: 'HTML',
                            reply_to_message_id: message.message_id
                        });
                    }

                    clearTimeout(stderrWaitId);
                    stderrWaitId = setTimeout(function() {
                        // console.log('output stderr', stdoutBuffer)
                        api.sendMessage(message.chat.id, 'stderr:
' + escapeHtml(stderrBuffer) + '
', 0, {
                            parse_mode: 'HTML',
                            reply_to_message_id: message.message_id
                        });
                        stderrBuffer = "";
                    }, 500)
                }
                if (cmd.type === 'throw' || cmd.type === 'error') {
                    api.sendMessage(message.chat.id, 'error: ' + cmd.text, 0, additionOptions);
                }
                if (cmd.type === 'status') {
                    if (cmd.text !== 'exited') {
                        api.sendChatAction(message.chat.id, 'typing');
                    }
                    console.log('status change: ' + cmd.text)
                }
                if (cmd.type === 'exit') {
                    try {
                        var res = JSON.parse(cmd.text);
                        if ((res.code !== 0 || res.signal != null) && isSilent) {
                            api.sendMessage(
                                message.chat.id,
                                'program ended with code ' + res.code + ' and signal ' + res.signal,
                                0,
                                additionOptions);
                        } else if (!hasOutput) {
                            api.sendMessage(
                                message.chat.id,
                                'program ended with code ' + res.code + ' and signal ' + res.signal + ' but doesn\'t has any output at all',
                                0,
                                additionOptions);
                        }
                    } catch (e) {
                        console.error(e);
                    }
                }
            } catch (e) {
                console.error(e)
            }
        });

        p.on('exit', function () {
            p.exited = true;
            // ensure cleared
            child_process.execFile('docker', ['rm', '-f', bot_id], function (err ,stdout, stderr) {
                // console.log(err ,stdout, stderr)
            })
        })

        setTimeout(function () {
            if (!p.exited) {
                console.log('force killing conatner ' + bot_id);
                api.sendMessage(message.chat.id, 'killed due to timeout', 0, additionOptions);
                p.kill('SIGTERM');
                child_process.execFile('docker', ['rm', '-f', bot_id], function (err ,stdout, stderr) {
                    console.log(err ,stdout, stderr)
                })
            }
        }, 10000)
    }

})<commit_msg>increse memory limit a little to run vb compiler<commit_after>const fs = require("fs");
const path = require("path");
const readline = require('readline');
const child_process = require("child_process");

var config = require("../config");
var TGAPI = require("./tgapi");
var api = new TGAPI(config.token)

var spawn = child_process.spawn;

var botInfo = null;

var runnerList = [];

(function () {
    fs.readdir('./docker_image/test', function (err, files) {
        if (err) {
            console.error(err.stack || err.toString());
            process.exit(-1)
        }
        runnerList = files
        .filter(function (name) {
            return !!name.match(/\.json$/i);
        })
        .map(function (name) {
            return require(path.resolve('./docker_image/test', name));
        })
        runnerList.forEach(function (data) {
            console.log(data.type + ' - run ' + data.type + ' snippet');
            console.log(data.type + '_debug - run ' + data.type + ' snippet with debug output');
            console.log(data.type + '_hello - run ' + data.type + '\'s Hello, World! program.');
        })
    })
} ());

api.getMe(function(err, data)
{
    if (err) console.error(err);
    console.log(data);
    botInfo = data;
    api.startPolling(40);
});

function guidGenerator() {
    var S4 = function() {
       return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
    };
    return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
}
function escapeHtml(unsafe) {
    return unsafe
         .replace(/&/g, "&")
         .replace(/</g, "<")
         .replace(/>/g, ">");
}

api.on('message', function(message) {
    // message is the parsed JSON data from telegram message
    // query is the parsed JSON data from telegram inline query
    console.log('got message');
    console.log(message);

    // message.text is the text user sent (if there is)
    var text = message.text;

    if (message.text != undefined && message.text.match(/\/start(@[^\s]+)?$/)) {

        var additionOptions = {
            reply_to_message_id: message.message_id
        }
        api.sendMessage(message.chat.id, `
Hello, I am ${botInfo.first_name}
You could run some code snippet with /[you favorite language]
Or run it with /[you favorite language]_debug to see debug message
Or run /[you favorite language]_hello to view hello world example
        `, 0, additionOptions);
    }

    if (message.text != undefined && message.text.match(/\/[a-z0-9_]+(@[^\s]+)?/)) {

        var additionOptions = {
            reply_to_message_id: message.message_id
        }

        var language = (/\/([a-z0-9_]+)(?:@[^\s]+)?(?: |\r|\n|$)/).exec(message.text)
        if (!language) return api.sendMessage(message.chat.id, 'something went wrong', 0, additionOptions);
        language = language[1];

        console.log(language);

        var isSilent = !language.match(/_d(ebug)?$/);
        language = language.replace(/_d(ebug)?$/, '');

        var isHelloWorld = !!language.match(/_h(ello)?$/);
        language = language.replace(/_h(ello)?$/, '');

        if (runnerList.filter(function (info) {
            return info.type === language
        }).length === 0) {
            return
        }

        var text = message.text.replace(/\/[a-z0-9_]+(@[^\s]+)?\s?/, '');
        if (isHelloWorld) {
            text = runnerList.filter(function (info) {
                return info.type === language
            })[0].program;
        }
        if (text.match(/^[\s\r\n]*$/)) {
            api.sendMessage(message.chat.id, 'you must provide something for me to run!', 0, additionOptions);
            return;
        }

        if (!isSilent || isHelloWorld) api.sendMessage(message.chat.id, 'running... \n
' + escapeHtml(text) + '
', 0, {
            parse_mode: 'HTML',
            reply_to_message_id: message.message_id
        });

        var bot_id = 'runner-' + guidGenerator()

        var p = spawn('docker', [
            'run',
            '-i',
            '--rm',
            '--net=none',
            '-m=64M',
            '--memory-swap=64M',
            '--pids-limit=32',
            '--cpuset-cpus=1',
            '-u=ubuntu',
            '-h=localhost',
            '--name=' + bot_id,
            config.image_name,
            'nodejs',
            'executer.js'
        ]);
        p.stdin.write(JSON.stringify({
            type: language,
            program: text
        }) + '\n')
        p.stdin.end();

        const rl = readline.createInterface({
          input: p.stdout,
          output: fs.createWriteStream('/dev/null')
        });

        var hasOutput = false;

        var stdoutWaitId = null;
        var stdoutBuffer = "";
        var stderrWaitId = null;
        var stderrBuffer = "";
        p.stderr.pipe(process.stderr, {end: false})
        p.stderr.on('end', function (argument) {
            p.stderr.unpipe(process.stderr)
        })
        rl.on('line', (cmd) => {
            try {
                cmd = JSON.parse(cmd);
                // console.log(cmd);
                if (cmd.type === 'stdout') {
                    hasOutput = true;
                    // console.log(stdoutWaitId, stdoutBuffer)
                    stdoutBuffer += cmd.text;

                    while (stdoutBuffer.length > 1333) {
                        var part = stdoutBuffer.slice(0, 1333);
                        stdoutBuffer = stdoutBuffer.slice(1333);
                        api.sendMessage(message.chat.id, '
' + escapeHtml(part) + '
', 0, {
                            parse_mode: 'HTML',
                            reply_to_message_id: message.message_id
                        });
                    }

                    clearTimeout(stdoutWaitId);
                    stdoutWaitId = setTimeout(function() {
                        // console.log('output stdout', stdoutBuffer)
                        api.sendMessage(message.chat.id, '
' + escapeHtml(stdoutBuffer) + '
', 0, {
                            parse_mode: 'HTML',
                            reply_to_message_id: message.message_id
                        });
                        stdoutBuffer = "";
                    }, 500)
                }
                if (cmd.type === 'log' && !isSilent) {
                    api.sendMessage(message.chat.id, cmd.text, 0, additionOptions);
                }
                if (cmd.type === 'stderr') {
                    hasOutput = true;
                    // console.log(stdoutWaitId, stdoutBuffer)
                    stderrBuffer += cmd.text;

                    while (stdoutBuffer.length > 1333) {
                        var part = stderrBuffer.slice(0, 1333);
                        stderrBuffer = stderrBuffer.slice(1333);
                        api.sendMessage(message.chat.id, 'stderr:
' + escapeHtml(part) + '
', 0, {
                            parse_mode: 'HTML',
                            reply_to_message_id: message.message_id
                        });
                    }

                    clearTimeout(stderrWaitId);
                    stderrWaitId = setTimeout(function() {
                        // console.log('output stderr', stdoutBuffer)
                        api.sendMessage(message.chat.id, 'stderr:
' + escapeHtml(stderrBuffer) + '
', 0, {
                            parse_mode: 'HTML',
                            reply_to_message_id: message.message_id
                        });
                        stderrBuffer = "";
                    }, 500)
                }
                if (cmd.type === 'throw' || cmd.type === 'error') {
                    api.sendMessage(message.chat.id, 'error: ' + cmd.text, 0, additionOptions);
                }
                if (cmd.type === 'status') {
                    if (cmd.text !== 'exited') {
                        api.sendChatAction(message.chat.id, 'typing');
                    }
                    console.log('status change: ' + cmd.text)
                }
                if (cmd.type === 'exit') {
                    try {
                        var res = JSON.parse(cmd.text);
                        if ((res.code !== 0 || res.signal != null) && isSilent) {
                            api.sendMessage(
                                message.chat.id,
                                'program ended with code ' + res.code + ' and signal ' + res.signal,
                                0,
                                additionOptions);
                        } else if (!hasOutput) {
                            api.sendMessage(
                                message.chat.id,
                                'program ended with code ' + res.code + ' and signal ' + res.signal + ' but doesn\'t has any output at all',
                                0,
                                additionOptions);
                        }
                    } catch (e) {
                        console.error(e);
                    }
                }
            } catch (e) {
                console.error(e)
            }
        });

        p.on('exit', function () {
            p.exited = true;
            // ensure cleared
            child_process.execFile('docker', ['rm', '-f', bot_id], function (err ,stdout, stderr) {
                // console.log(err ,stdout, stderr)
            })
        })

        setTimeout(function () {
            if (!p.exited) {
                console.log('force killing conatner ' + bot_id);
                api.sendMessage(message.chat.id, 'killed due to timeout', 0, additionOptions);
                p.kill('SIGTERM');
                child_process.execFile('docker', ['rm', '-f', bot_id], function (err ,stdout, stderr) {
                    console.log(err ,stdout, stderr)
                })
            }
        }, 10000)
    }

})<|endoftext|>


<commit_before>/* This class handles the framework for taking input
 from a client passing it to a router and then triggering
 an action for an application.
*/

const assert = require('assert');

/**
Constructs a new Bot with a delegate.

 - parameter delegate: The Delgate for the bot.
 */
function Bot(config) {

  assert(config, "No config was provided.")
  assert(config.client, "No client set on configuration.")
  assert(config.router, "No router set on configuration.")

  /* Connect all the pipework and ask for both the
     client and router from the application */
  this.client = config.client;
  this.router = config.router.bind(config);
  this.contextStore = config.contextStore

  /* Storage for actions and middleware */
  this.actions = {};
  this.middlewares = [];

  /* Register default speak action */
  this.action("speak", this.speak.bind(this))
}

Bot.prototype.action = function(name, func) {
  this.actions[name] = func;
}

Bot.prototype.dispatch = function(action, request) {
  var func = this.actions[action.name];
  assert(func, 'Action ' + action.name + ' not registered')

  console.log(request.context);

  this.middlewares.forEach(function(middleware){
    request.context = middleware(action, request)
  })

  console.log(request.context);

  func(action.payload, request)
}

Bot.prototype.speak = function(payload, request) {
  this.client.speak(payload.message, request.user)
}

Bot.prototype.use = function(middleware) {
  this.middlewares.push(middleware);
}

/**
 Call this to start the bot.
 */
Bot.prototype.start = function() {
  this.startContextStore(this.startClient.bind(this));
};

Bot.prototype.startContextStore = function(callback) {
  if (this.contextStore) {
    this.contextStore.start(callback)
  } else {
    callback()
  }
}

Bot.prototype.startClient = function() {
  assert(this.client.start, "Client doesn't implement start method.")

  // Start the client so the bot can listen to input.
  this.client.start(this)
}

Bot.prototype.didRecieveMessage = function(message, user, callback) {

  var contextHandler = function(context) {

    var request = {
      context: context,
      message: message,
      user: user
    }

    this.router(this, request, this.createRouterDidFinishHandler(user, callback).bind(this))
  }

  var context = this.contextForUser(user, contextHandler.bind(this))
}

Bot.prototype.createRouterDidFinishHandler = function(user, callback) {
  return function (newContext) {

    this.storeContextForUser(newContext, user)

    if (callback) {
      callback()
    }
  }
}

Bot.prototype.contextForUser = function(user, callback) {
  if (this.contextStore) {
    this.getContextForUser(user, callback);
  } else {
    callback({})
  }
}

Bot.prototype.getContextForUser = function(user, callback) {
  this.contextStore.get("conversation_" + user.conversationID, function(reply) {
    if (reply) {
      callback(reply);
    } else {
      callback({});
    }
  })
}

Bot.prototype.storeContextForUser = function(newContext, user) {
  if (this.contextStore) {
    this.contextStore.set("conversation_" + user.conversationID, newContext)
  }
}

module.exports = Bot
<commit_msg>fix contexts.<commit_after>/* This class handles the framework for taking input
 from a client passing it to a router and then triggering
 an action for an application.
*/

const assert = require('assert');

/**
Constructs a new Bot with a delegate.

 - parameter delegate: The Delgate for the bot.
 */
function Bot(config) {

  assert(config, "No config was provided.")
  assert(config.client, "No client set on configuration.")
  assert(config.router, "No router set on configuration.")

  /* Connect all the pipework and ask for both the
     client and router from the application */
  this.client = config.client;
  this.router = config.router.bind(config);
  this.contextStore = config.contextStore

  /* Storage for actions and middleware */
  this.actions = {};
  this.middlewares = [];

  /* Register default speak action */
  this.action("speak", this.speak.bind(this))
}

Bot.prototype.action = function(name, func) {
  this.actions[name] = func;
}

Bot.prototype.dispatch = function(action, request) {
  var func = this.actions[action.name];
  assert(func, 'Action ' + action.name + ' not registered')

  this.middlewares.forEach(function(middleware){
    request.context = middleware(action, request)
  })

  return func(action.payload, request)
}

Bot.prototype.speak = function(payload, request) {
  this.client.speak(payload.message, request.user)
  return request.context
}

Bot.prototype.use = function(middleware) {
  this.middlewares.push(middleware);
}

/**
 Call this to start the bot.
 */
Bot.prototype.start = function() {
  this.startContextStore(this.startClient.bind(this));
};

Bot.prototype.startContextStore = function(callback) {
  if (this.contextStore) {
    this.contextStore.start(callback)
  } else {
    callback()
  }
}

Bot.prototype.startClient = function() {
  assert(this.client.start, "Client doesn't implement start method.")

  // Start the client so the bot can listen to input.
  this.client.start(this)
}

Bot.prototype.didRecieveMessage = function(message, user, callback) {

  var contextHandler = function(context) {

    var request = {
      context: context,
      message: message,
      user: user
    }

    this.router(this, request, this.createRouterDidFinishHandler(user, callback).bind(this))
  }

  var context = this.contextForUser(user, contextHandler.bind(this))
}

Bot.prototype.createRouterDidFinishHandler = function(user, callback) {
  return function (newContext) {

    this.storeContextForUser(newContext, user)

    if (callback) {
      callback()
    }
  }
}

Bot.prototype.contextForUser = function(user, callback) {
  if (this.contextStore) {
    this.getContextForUser(user, callback);
  } else {
    callback({})
  }
}

Bot.prototype.getContextForUser = function(user, callback) {
  this.contextStore.get("conversation_" + user.conversationID, function(reply) {
    if (reply) {
      callback(reply);
    } else {
      callback({});
    }
  })
}

Bot.prototype.storeContextForUser = function(newContext, user) {
  if (this.contextStore) {
    this.contextStore.set("conversation_" + user.conversationID, newContext)
  }
}

module.exports = Bot
<|endoftext|>


<commit_before>const async  = require('async');
const logger = require('bole')('bot');

// Load internal modules
const config            = require('./config');
const TelegramServer    = require('./telegram').TelegramServer;
const TelegramProcessor = require('./telegram').TelegramProcessor;
const notifications     = require('./telegram/notifications.js');
const db                = require('./db');
const geocoding         = require('./maps').geocoding;
const Card              = require('./maps').Card;
const social            = require('./social.js');

const BROADCAST_THRESHOLD = config('ingv').broadcastThreshold;
const SOCIAL_THRESHOLD = config('social').threshold;
const SOCIAL_ENABLED = config('social').enabled;

// Create the HTTP server for handling tg messages
let serverPort = config('telegram').serverPort;
let server = new TelegramServer({ port: serverPort });

// Start the server
server.start();

// Process incoming message
server.on('update', (update) => {
	let pro = new TelegramProcessor(update);
	pro.process();
});

// Create the INGV poller, that will periodically check
// for new earthquakes (comparing the local copy)
const IngvPoller = require('./ingv/poller');

let options = {
	interval: config('ingv').pollingInterval,
	immediate: true
};

let poller = new IngvPoller(options);

// New earthquakes found
// That must be notified
poller.on('earthquakes', (earthquakes) => {
	logger.info(`Notifying ${earthquakes.length} events`);

	// Loop through them
	async.eachSeries(earthquakes, (ev, callback) => {
		logger.info('New event', ev);

		let { lat, lon } = ev['origin'];
		let magnitude = ev['magnitude']['value'];

		logger.info(`Reverse geocoding for event <${ev.id}>`);

		// Convert the geographical coordinates to a city name (reverse geocoding)
		geocoding.reverse(lat, lon, (err, result) => {
			if (err) ; // TODO: do something, please

			let city;
			if (result) {
				city = result['name'];
			}
			else {
				city = 'Zona ' + ev['zone'];
			}

			ev['city'] = city;
			// Update the db representation of the event
			db.history.setCity(ev['id'], city);

			// Generate the image card
			let card = new Card(ev);
			card.generate((err, filePath) => {
				if (!err && filePath) {
					ev['cardPath'] = filePath;
				}

				// Prepare and send out notifications to the chats
				// When the process is finished, callback will be called
				// and the next earthquake event processed
				if (magnitude >= BROADCAST_THRESHOLD) {
					notifications.broadcast(ev, callback);
				}
				else {
					notifications.send(ev, callback);
				}

				// Schedule SQS
				if (SOCIAL_ENABLED && magnitude >= SOCIAL_THRESHOLD) {
					social.enqueue(ev);
				}
			});
		});
	}, () => {
		logger.info('Done');
	});
});
<commit_msg>don't add 'zona' prefix when reverse geocoding fails<commit_after>const async  = require('async');
const logger = require('bole')('bot');

// Load internal modules
const config            = require('./config');
const TelegramServer    = require('./telegram').TelegramServer;
const TelegramProcessor = require('./telegram').TelegramProcessor;
const notifications     = require('./telegram/notifications.js');
const db                = require('./db');
const geocoding         = require('./maps').geocoding;
const Card              = require('./maps').Card;
const social            = require('./social.js');

const BROADCAST_THRESHOLD = config('ingv').broadcastThreshold;
const SOCIAL_THRESHOLD = config('social').threshold;
const SOCIAL_ENABLED = config('social').enabled;

// Create the HTTP server for handling tg messages
let serverPort = config('telegram').serverPort;
let server = new TelegramServer({ port: serverPort });

// Start the server
server.start();

// Process incoming message
server.on('update', (update) => {
	let pro = new TelegramProcessor(update);
	pro.process();
});

// Create the INGV poller, that will periodically check
// for new earthquakes (comparing the local copy)
const IngvPoller = require('./ingv/poller');

let options = {
	interval: config('ingv').pollingInterval,
	immediate: true
};

let poller = new IngvPoller(options);

// New earthquakes found
// That must be notified
poller.on('earthquakes', (earthquakes) => {
	logger.info(`Notifying ${earthquakes.length} events`);

	// Loop through them
	async.eachSeries(earthquakes, (ev, callback) => {
		logger.info('New event', ev);

		let { lat, lon } = ev['origin'];
		let magnitude = ev['magnitude']['value'];

		logger.info(`Reverse geocoding for event <${ev.id}>`);

		// Convert the geographical coordinates to a city name (reverse geocoding)
		geocoding.reverse(lat, lon, (err, result) => {
			if (err) ; // TODO: do something, please

			let city;
			if (result) {
				city = result['name'];
			}
			else {
				city = ev['zone'];
			}

			ev['city'] = city;
			// Update the db representation of the event
			db.history.setCity(ev['id'], city);

			// Generate the image card
			let card = new Card(ev);
			card.generate((err, filePath) => {
				if (!err && filePath) {
					ev['cardPath'] = filePath;
				}

				// Prepare and send out notifications to the chats
				// When the process is finished, callback will be called
				// and the next earthquake event processed
				if (magnitude >= BROADCAST_THRESHOLD) {
					notifications.broadcast(ev, callback);
				}
				else {
					notifications.send(ev, callback);
				}

				// Schedule SQS
				if (SOCIAL_ENABLED && magnitude >= SOCIAL_THRESHOLD) {
					social.enqueue(ev);
				}
			});
		});
	}, () => {
		logger.info('Done');
	});
});
<|endoftext|>


<commit_before>'use strict';

var browserify = require('browserify'),
    watchify = require('watchify'),
    convert = require('convert-source-map'),
    minimatch = require('minimatch'),
    escape = require('js-string-escape');

var path = require('path'),
    fs = require('fs');

var _ = require('lodash');

var BundleFile = require('./bundle-file');

function Bro(bundleFile) {

  var log;

  /**
   * Add bundle file to the list of files in the
   * configuration, right before the first browserified
   * test file and after everything else.
   *
   * That makes sure users can include non-commonJS files
   * prior to the browserified bundle.
   *
   * @param {BundleFile} bundleFile the file containing the browserify bundle
   * @param {Object} config the karma configuration to be updated
   */
  function addBundleFile(bundleFile, config) {

    var files = config.files,
        preprocessors = config.preprocessors;

    // list of patterns using our preprocessor
    var patterns = _.reduce(preprocessors, function(matched, val, key) {
      if (val.indexOf('browserify') !== -1) {
        matched.push(key);
      }
      return matched;
    }, []);

    // first file being preprocessed
    var file = _.find(files, function(f) {
      return _.any(patterns, function(p) {
        return minimatch(f.pattern, p);
      });
    });

    var idx = 0;

    if (file) {
      idx = files.indexOf(file);
    } else {
      log.debug('no matching preprocessed file was found, defaulting to prepend');
    }

    log.debug('add bundle to config.files at position', idx);

    // insert bundle on the correct spot
    files.splice(idx, 0, {
      pattern: bundleFile.location,
      served: true,
      included: true,
      watched: true
    });
  }

  /**
   * The browserify instance that creates the
   * minified bundle and gets added all test files to it.
   */
  var b;

  /**
   * The browserify framework that creates the initial logger and bundle file
   * as well as prepends the bundle file to the karma file configuration.
   */
  function framework(emitter, config, logger) {

    log = logger.create('framework.browserify');

    if (!bundleFile) {
      bundleFile = new BundleFile();
    }

    bundleFile.touch();
    log.debug('created browserify bundle: %s', bundleFile.location);

    b = createBundle(config);

    // TODO(Nikku): hook into karma karmas file update facilities
    // to remove files from the bundle once karma detects the deletion

    // hook into exit for cleanup
    emitter.on('exit', function(done) {
      log.debug('cleaning up');

      b.close();
      bundleFile.remove();
      done();
    });

    // add bundle file to the list of files defined in the
    // configuration. be smart by doing so.
    addBundleFile(bundleFile, config);
  }

  framework.$inject = [ 'emitter', 'config', 'logger' ];

  /**
   * Create the browserify bundle
   */
  function createBundle(config) {

    var bopts = config.browserify || {};

    function warn(key) {
      log.warn('Invalid config option: "' + key + 's" should be "' + key + '"');
    }

    _.forEach([ 'transform', 'plugin' ], function(key) {
      if (bopts[key + 's']) {
        warn(key);
      }
    });

    var browserifyOptions = _.extend({}, watchify.args, _.omit(bopts, [
      'transform', 'plugin', 'configure', 'bundleDelay'
    ]));

    if ('prebundle' in browserifyOptions) {
      log.warn('The prebundle hook got removed in favor of configure');
    }

    var w = watchify(browserify(browserifyOptions));
    w.setMaxListeners(Infinity);

    _.forEach(bopts.plugin, function(p) {
      // ensure we can pass plugin options as
      // the first parameter
      if (!Array.isArray(p)) {
        p = [ p ];
      }
      w.plugin.apply(w, p);
    });

    _.forEach(bopts.transform, function(t) {
      // ensure we can pass transform options as
      // the first parameter
      if (!Array.isArray(t)) {
        t = [ t ];
      }
      w.transform.apply(w, t);
    });

    // test if we have a configure function
    if (bopts.configure && typeof bopts.configure === 'function') {
      bopts.configure(w);
    }

    // register rebuild bundle on change
    if (config.autoWatch) {
      log.info('registering rebuild (autoWatch=true)');

      w.on('update', function(updated) {

        // we perform an update, karma will trigger one, too
        // because the bundling is deferred only one change will
        // be triggered. Anything else is the result of a
        // raise condition or a problem of watchify firing file
        // changes to late

        log.debug('files changed');
        deferredBundle();
      });
    }

    w.on('log', function(msg) {
      log.info(msg);
    });

    // update bundle file
    w.on('bundled', function(err, content) {
      if (w._builtOnce && !err) {
        bundleFile.update(content.toString('utf-8'));
        log.info('bundle updated');
      }

      w._builtOnce = true;
    });

    function deferredBundle(cb) {
      if (cb) {
        w.once('bundled', cb);
      }

      rebuild();
    }

    var rebuild = _.debounce(function rebuild() {

      if (w._bundled) {
        log.debug('resetting bundle');

        var recorded = w._recorded;
        w.reset();

        recorded.forEach(function(e) {
          // we remove missing files on the fly
          // to cope with bundle internals missing
          if (e.file && !fs.existsSync(e.file)) {
            log.debug('removing missing file', path.relative(config.basePath, e.file));
          } else {
            w.pipeline.write(e);
          }
        });
      }

      w.emit('prebundle', w);

      log.debug('bundling');

      w.bundle(function(err, content) {

        if (err) {
          log.error('bundle error');
          log.error(String(err));
        }

        w.emit('bundled', err, content);
      });
    }, bopts.bundleDelay || 500);

    w.bundleFile = function(file, done) {

      var absolutePath = file.path,
          relativePath = path.relative(config.basePath, absolutePath),
          cache = w._options.cache;

      // add file
      log.debug('updating %s in bundle', relativePath);

      // add the file during next prebundle step
      w.once('prebundle', function() {
        w.require('./' + relativePath, { expose: absolutePath });
      });

      deferredBundle(function(err) {
        done(err, 'require("' + absolutePath + '");');
      });
    };

    /**
     * Wait for the bundle creation to have stabilized (no more additions) and invoke a callback.
     *
     * @param {Function} [callback] invoked with (err, content)
     */
    w.deferredBundle = deferredBundle;

    return w;
  }

  /**
   * A processor that preprocesses commonjs test files which should be
   * delivered via browserify.
   */
  function testFilePreprocessor() {

    return function(content, file, done) {
      b.bundleFile(file, function(err, content) {
        done(content && content.toString());
      });
    };
  }

  testFilePreprocessor.$inject = [ ];

  /**
   * A special preprocessor that builds the main browserify bundle once and
   * passes the bundle contents through on all later preprocessing request.
   */
  function bundlePreprocessor(config) {

    var debug = config.browserify && config.browserify.debug;

    function updateSourceMap(file, content) {
      var map;

      if (debug) {
        map = convert.fromSource(content);

        if (map) {
          file.sourceMap = map.sourcemap;
        }
      }
    }

    return function(content, file, done) {

      if (b._builtOnce) {
        updateSourceMap(file, content);
        return done(content);
      }

      log.debug('building bundle');

      // wait for the initial bundle to be created
      b.deferredBundle(function(err, content) {

        if (err) {
          return done(err);
        }

        content = content.toString('utf-8');
        updateSourceMap(file, content);

        log.info('bundle built');
        done(content);
      });
    };
  }

  bundlePreprocessor.$inject = [ 'config' ];

  // API

  this.framework = framework;

  this.testFilePreprocessor = testFilePreprocessor;
  this.bundlePreprocessor = bundlePreprocessor;
}

// module exports

module.exports = Bro;
<commit_msg>fix(bro): increase default bundle delay to 700 ms<commit_after>'use strict';

var browserify = require('browserify'),
    watchify = require('watchify'),
    convert = require('convert-source-map'),
    minimatch = require('minimatch'),
    escape = require('js-string-escape');

var path = require('path'),
    fs = require('fs');

var _ = require('lodash');

var BundleFile = require('./bundle-file');

function Bro(bundleFile) {

  var log;

  /**
   * Add bundle file to the list of files in the
   * configuration, right before the first browserified
   * test file and after everything else.
   *
   * That makes sure users can include non-commonJS files
   * prior to the browserified bundle.
   *
   * @param {BundleFile} bundleFile the file containing the browserify bundle
   * @param {Object} config the karma configuration to be updated
   */
  function addBundleFile(bundleFile, config) {

    var files = config.files,
        preprocessors = config.preprocessors;

    // list of patterns using our preprocessor
    var patterns = _.reduce(preprocessors, function(matched, val, key) {
      if (val.indexOf('browserify') !== -1) {
        matched.push(key);
      }
      return matched;
    }, []);

    // first file being preprocessed
    var file = _.find(files, function(f) {
      return _.any(patterns, function(p) {
        return minimatch(f.pattern, p);
      });
    });

    var idx = 0;

    if (file) {
      idx = files.indexOf(file);
    } else {
      log.debug('no matching preprocessed file was found, defaulting to prepend');
    }

    log.debug('add bundle to config.files at position', idx);

    // insert bundle on the correct spot
    files.splice(idx, 0, {
      pattern: bundleFile.location,
      served: true,
      included: true,
      watched: true
    });
  }

  /**
   * The browserify instance that creates the
   * minified bundle and gets added all test files to it.
   */
  var b;

  /**
   * The browserify framework that creates the initial logger and bundle file
   * as well as prepends the bundle file to the karma file configuration.
   */
  function framework(emitter, config, logger) {

    log = logger.create('framework.browserify');

    if (!bundleFile) {
      bundleFile = new BundleFile();
    }

    bundleFile.touch();
    log.debug('created browserify bundle: %s', bundleFile.location);

    b = createBundle(config);

    // TODO(Nikku): hook into karma karmas file update facilities
    // to remove files from the bundle once karma detects the deletion

    // hook into exit for cleanup
    emitter.on('exit', function(done) {
      log.debug('cleaning up');

      b.close();
      bundleFile.remove();
      done();
    });

    // add bundle file to the list of files defined in the
    // configuration. be smart by doing so.
    addBundleFile(bundleFile, config);
  }

  framework.$inject = [ 'emitter', 'config', 'logger' ];

  /**
   * Create the browserify bundle
   */
  function createBundle(config) {

    var bopts = config.browserify || {};

    function warn(key) {
      log.warn('Invalid config option: "' + key + 's" should be "' + key + '"');
    }

    _.forEach([ 'transform', 'plugin' ], function(key) {
      if (bopts[key + 's']) {
        warn(key);
      }
    });

    var browserifyOptions = _.extend({}, watchify.args, _.omit(bopts, [
      'transform', 'plugin', 'configure', 'bundleDelay'
    ]));

    if ('prebundle' in browserifyOptions) {
      log.warn('The prebundle hook got removed in favor of configure');
    }

    var w = watchify(browserify(browserifyOptions));
    w.setMaxListeners(Infinity);

    _.forEach(bopts.plugin, function(p) {
      // ensure we can pass plugin options as
      // the first parameter
      if (!Array.isArray(p)) {
        p = [ p ];
      }
      w.plugin.apply(w, p);
    });

    _.forEach(bopts.transform, function(t) {
      // ensure we can pass transform options as
      // the first parameter
      if (!Array.isArray(t)) {
        t = [ t ];
      }
      w.transform.apply(w, t);
    });

    // test if we have a configure function
    if (bopts.configure && typeof bopts.configure === 'function') {
      bopts.configure(w);
    }

    // register rebuild bundle on change
    if (config.autoWatch) {
      log.info('registering rebuild (autoWatch=true)');

      w.on('update', function(updated) {

        // we perform an update, karma will trigger one, too
        // because the bundling is deferred only one change will
        // be triggered. Anything else is the result of a
        // raise condition or a problem of watchify firing file
        // changes to late

        log.debug('files changed');
        deferredBundle();
      });
    }

    w.on('log', function(msg) {
      log.info(msg);
    });

    // update bundle file
    w.on('bundled', function(err, content) {
      if (w._builtOnce && !err) {
        bundleFile.update(content.toString('utf-8'));
        log.info('bundle updated');
      }

      w._builtOnce = true;
    });

    function deferredBundle(cb) {
      if (cb) {
        w.once('bundled', cb);
      }

      rebuild();
    }

    var rebuild = _.debounce(function rebuild() {

      if (w._bundled) {
        log.debug('resetting bundle');

        var recorded = w._recorded;
        w.reset();

        recorded.forEach(function(e) {
          // we remove missing files on the fly
          // to cope with bundle internals missing
          if (e.file && !fs.existsSync(e.file)) {
            log.debug('removing missing file', path.relative(config.basePath, e.file));
          } else {
            w.pipeline.write(e);
          }
        });
      }

      w.emit('prebundle', w);

      log.debug('bundling');

      w.bundle(function(err, content) {

        if (err) {
          log.error('bundle error');
          log.error(String(err));
        }

        w.emit('bundled', err, content);
      });
    }, bopts.bundleDelay || 700);

    w.bundleFile = function(file, done) {

      var absolutePath = file.path,
          relativePath = path.relative(config.basePath, absolutePath),
          cache = w._options.cache;

      // add file
      log.debug('updating %s in bundle', relativePath);

      // add the file during next prebundle step
      w.once('prebundle', function() {
        w.require('./' + relativePath, { expose: absolutePath });
      });

      deferredBundle(function(err) {
        done(err, 'require("' + absolutePath + '");');
      });
    };

    /**
     * Wait for the bundle creation to have stabilized (no more additions) and invoke a callback.
     *
     * @param {Function} [callback] invoked with (err, content)
     */
    w.deferredBundle = deferredBundle;

    return w;
  }

  /**
   * A processor that preprocesses commonjs test files which should be
   * delivered via browserify.
   */
  function testFilePreprocessor() {

    return function(content, file, done) {
      b.bundleFile(file, function(err, content) {
        done(content && content.toString());
      });
    };
  }

  testFilePreprocessor.$inject = [ ];

  /**
   * A special preprocessor that builds the main browserify bundle once and
   * passes the bundle contents through on all later preprocessing request.
   */
  function bundlePreprocessor(config) {

    var debug = config.browserify && config.browserify.debug;

    function updateSourceMap(file, content) {
      var map;

      if (debug) {
        map = convert.fromSource(content);

        if (map) {
          file.sourceMap = map.sourcemap;
        }
      }
    }

    return function(content, file, done) {

      if (b._builtOnce) {
        updateSourceMap(file, content);
        return done(content);
      }

      log.debug('building bundle');

      // wait for the initial bundle to be created
      b.deferredBundle(function(err, content) {

        if (err) {
          return done(err);
        }

        content = content.toString('utf-8');
        updateSourceMap(file, content);

        log.info('bundle built');
        done(content);
      });
    };
  }

  bundlePreprocessor.$inject = [ 'config' ];

  // API

  this.framework = framework;

  this.testFilePreprocessor = testFilePreprocessor;
  this.bundlePreprocessor = bundlePreprocessor;
}

// module exports

module.exports = Bro;
<|endoftext|>


<commit_before>/*
  SystemJS CommonJS Format
*/
(function() {
  // CJS Module Format
  // require('...') || exports[''] = ... || exports.asd = ... || module.exports = ...
  var cjsExportsRegEx = /(?:^\uFEFF?|[^$_a-zA-Z\xA0-\uFFFF.]|module\.)exports\s*(\[['"]|\.)|(?:^\uFEFF?|[^$_a-zA-Z\xA0-\uFFFF.])module\.exports\s*[=,]/;
  // RegEx adjusted from https://github.com/jbrantly/yabble/blob/master/lib/yabble.js#L339
  var cjsRequireRegEx = /(?:^\uFEFF?|[^$_a-zA-Z\xA0-\uFFFF."'])require\s*\(\s*("[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')\s*\)/g;
  var commentRegEx = /(^|[^\\])(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg;

  var stringRegEx = /(?:"[^"\\\n\r]*(?:\\.[^"\\\n\r]*)*"|'[^'\\\n\r]*(?:\\.[^'\\\n\r]*)*')/g;

  function getCJSDeps(source) {
    cjsRequireRegEx.lastIndex = commentRegEx.lastIndex = stringRegEx.lastIndex = 0;

    var deps = [];

    var match;

    // track string and comment locations for unminified source
    var stringLocations = [], commentLocations = [];

    function inLocation(locations, match, starts) {
      var inLocation = false;
      for (var i = 0; i < locations.length; i++)
        if (locations[i][0] < match.index && locations[i][1] > match.index + (!starts ? match[0].length : 0))
          return true;
      return false;
    }

    if (source.length / source.split('\n').length < 200) {
      while (match = stringRegEx.exec(source))
        stringLocations.push([match.index, match.index + match[0].length]);

      while (match = commentRegEx.exec(source)) {
        // only track comments not starting in strings
        if (!inLocation(stringLocations, match, true))
          commentLocations.push([match.index, match.index + match[0].length]);
      }
    }

    while (match = cjsRequireRegEx.exec(source)) {
      // ensure we're not within a string or comment location
      if (!inLocation(stringLocations, match) && !inLocation(commentLocations, match))
        deps.push(match[1].substr(1, match[1].length - 2));
    }

    return deps;
  }

  if (typeof window != 'undefined' && typeof document != 'undefined' && window.location)
    var windowOrigin = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '');

  // include the node require since we're overriding it
  if (typeof require != 'undefined' && typeof process != 'undefined' && !process.browser)
    SystemJSLoader.prototype._nodeRequire = require;

  var nodeCoreModules = ['assert', 'buffer', 'child_process', 'cluster', 'console', 'constants',
      'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https', 'module', 'net', 'os', 'path',
      'process', 'punycode', 'querystring', 'readline', 'repl', 'stream', 'string_decoder', 'sys', 'timers',
      'tls', 'tty', 'url', 'util', 'vm', 'zlib'];

  hook('normalize', function(normalize) {
    return function(name, parentName) {
      // dynamically load node-core modules when requiring `@node/fs` for example
      if (name.substr(0, 6) == '@node/' && nodeCoreModules.indexOf(name.substr(6)) != -1) {
        if (!this._nodeRequire)
          throw new TypeError('Can only load node core modules in Node.');
        this.set(name, this.newModule(getESModule(this._nodeRequire(name.substr(6)))));
      }

      return normalize.apply(this, arguments);
    };
  });

  hook('instantiate', function(instantiate) {
    return function(load) {
      var loader = this;
      if (!load.metadata.format) {
        cjsExportsRegEx.lastIndex = 0;
        cjsRequireRegEx.lastIndex = 0;
        if (cjsRequireRegEx.exec(load.source) || cjsExportsRegEx.exec(load.source))
          load.metadata.format = 'cjs';
      }

      if (load.metadata.format == 'cjs') {
        var metaDeps = load.metadata.deps;
        var deps = getCJSDeps(load.source);

        for (var g in load.metadata.globals)
          deps.push(load.metadata.globals[g]);

        var entry = createEntry();

        load.metadata.entry = entry;

        entry.deps = deps;
        entry.executingRequire = true;
        entry.execute = function(require, exports, module) {
          // ensure meta deps execute first
          for (var i = 0; i < metaDeps.length; i++)
            require(metaDeps[i]);
          var address = load.address || '';

          var dirname = address.split('/');
          dirname.pop();
          dirname = dirname.join('/');

          if (address.substr(0, 8) == 'file:///') {
            address = address.substr(7);
            dirname = dirname.substr(7);

            // on windows remove leading '/'
            if (isWindows) {
              address = address.substr(1);
              dirname = dirname.substr(1);
            }
          }
          else if (windowOrigin && address.substr(0, windowOrigin.length) === windowOrigin) {
            address = address.substr(windowOrigin.length);
            dirname = dirname.substr(windowOrigin.length);
          }

          // disable AMD detection
          var define = __global.define;
          __global.define = undefined;

          __global.__cjsWrapper = {
            exports: exports,
            args: [require, exports, module, address, dirname, __global, __global]
          };

          var globals = '';
          if (load.metadata.globals) {
            for (var g in load.metadata.globals)
              globals += 'var ' + g + ' = require("' + load.metadata.globals[g] + '");';
          }

          load.source = "(function(require, exports, module, __filename, __dirname, global, GLOBAL) {" + globals
              + load.source + "\n}).apply(__cjsWrapper.exports, __cjsWrapper.args);";

          __exec.call(loader, load);

          __global.__cjsWrapper = undefined;
          __global.define = define;
        };
      }

      return instantiate.call(loader, load);
    };
  });
})();
<commit_msg>clarify node core error message<commit_after>/*
  SystemJS CommonJS Format
*/
(function() {
  // CJS Module Format
  // require('...') || exports[''] = ... || exports.asd = ... || module.exports = ...
  var cjsExportsRegEx = /(?:^\uFEFF?|[^$_a-zA-Z\xA0-\uFFFF.]|module\.)exports\s*(\[['"]|\.)|(?:^\uFEFF?|[^$_a-zA-Z\xA0-\uFFFF.])module\.exports\s*[=,]/;
  // RegEx adjusted from https://github.com/jbrantly/yabble/blob/master/lib/yabble.js#L339
  var cjsRequireRegEx = /(?:^\uFEFF?|[^$_a-zA-Z\xA0-\uFFFF."'])require\s*\(\s*("[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')\s*\)/g;
  var commentRegEx = /(^|[^\\])(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg;

  var stringRegEx = /(?:"[^"\\\n\r]*(?:\\.[^"\\\n\r]*)*"|'[^'\\\n\r]*(?:\\.[^'\\\n\r]*)*')/g;

  function getCJSDeps(source) {
    cjsRequireRegEx.lastIndex = commentRegEx.lastIndex = stringRegEx.lastIndex = 0;

    var deps = [];

    var match;

    // track string and comment locations for unminified source
    var stringLocations = [], commentLocations = [];

    function inLocation(locations, match, starts) {
      var inLocation = false;
      for (var i = 0; i < locations.length; i++)
        if (locations[i][0] < match.index && locations[i][1] > match.index + (!starts ? match[0].length : 0))
          return true;
      return false;
    }

    if (source.length / source.split('\n').length < 200) {
      while (match = stringRegEx.exec(source))
        stringLocations.push([match.index, match.index + match[0].length]);

      while (match = commentRegEx.exec(source)) {
        // only track comments not starting in strings
        if (!inLocation(stringLocations, match, true))
          commentLocations.push([match.index, match.index + match[0].length]);
      }
    }

    while (match = cjsRequireRegEx.exec(source)) {
      // ensure we're not within a string or comment location
      if (!inLocation(stringLocations, match) && !inLocation(commentLocations, match))
        deps.push(match[1].substr(1, match[1].length - 2));
    }

    return deps;
  }

  if (typeof window != 'undefined' && typeof document != 'undefined' && window.location)
    var windowOrigin = location.protocol + '//' + location.hostname + (location.port ? ':' + location.port : '');

  // include the node require since we're overriding it
  if (typeof require != 'undefined' && typeof process != 'undefined' && !process.browser)
    SystemJSLoader.prototype._nodeRequire = require;

  var nodeCoreModules = ['assert', 'buffer', 'child_process', 'cluster', 'console', 'constants',
      'crypto', 'dgram', 'dns', 'domain', 'events', 'fs', 'http', 'https', 'module', 'net', 'os', 'path',
      'process', 'punycode', 'querystring', 'readline', 'repl', 'stream', 'string_decoder', 'sys', 'timers',
      'tls', 'tty', 'url', 'util', 'vm', 'zlib'];

  hook('normalize', function(normalize) {
    return function(name, parentName) {
      // dynamically load node-core modules when requiring `@node/fs` for example
      if (name.substr(0, 6) == '@node/' && nodeCoreModules.indexOf(name.substr(6)) != -1) {
        if (!this._nodeRequire)
          throw new TypeError('Error loading ' + name + '. Can only load node core modules in Node.');
        this.set(name, this.newModule(getESModule(this._nodeRequire(name.substr(6)))));
      }

      return normalize.apply(this, arguments);
    };
  });

  hook('instantiate', function(instantiate) {
    return function(load) {
      var loader = this;
      if (!load.metadata.format) {
        cjsExportsRegEx.lastIndex = 0;
        cjsRequireRegEx.lastIndex = 0;
        if (cjsRequireRegEx.exec(load.source) || cjsExportsRegEx.exec(load.source))
          load.metadata.format = 'cjs';
      }

      if (load.metadata.format == 'cjs') {
        var metaDeps = load.metadata.deps;
        var deps = getCJSDeps(load.source);

        for (var g in load.metadata.globals)
          deps.push(load.metadata.globals[g]);

        var entry = createEntry();

        load.metadata.entry = entry;

        entry.deps = deps;
        entry.executingRequire = true;
        entry.execute = function(require, exports, module) {
          // ensure meta deps execute first
          for (var i = 0; i < metaDeps.length; i++)
            require(metaDeps[i]);
          var address = load.address || '';

          var dirname = address.split('/');
          dirname.pop();
          dirname = dirname.join('/');

          if (address.substr(0, 8) == 'file:///') {
            address = address.substr(7);
            dirname = dirname.substr(7);

            // on windows remove leading '/'
            if (isWindows) {
              address = address.substr(1);
              dirname = dirname.substr(1);
            }
          }
          else if (windowOrigin && address.substr(0, windowOrigin.length) === windowOrigin) {
            address = address.substr(windowOrigin.length);
            dirname = dirname.substr(windowOrigin.length);
          }

          // disable AMD detection
          var define = __global.define;
          __global.define = undefined;

          __global.__cjsWrapper = {
            exports: exports,
            args: [require, exports, module, address, dirname, __global, __global]
          };

          var globals = '';
          if (load.metadata.globals) {
            for (var g in load.metadata.globals)
              globals += 'var ' + g + ' = require("' + load.metadata.globals[g] + '");';
          }

          load.source = "(function(require, exports, module, __filename, __dirname, global, GLOBAL) {" + globals
              + load.source + "\n}).apply(__cjsWrapper.exports, __cjsWrapper.args);";

          __exec.call(loader, load);

          __global.__cjsWrapper = undefined;
          __global.define = define;
        };
      }

      return instantiate.call(loader, load);
    };
  });
})();
<|endoftext|>