<commit_before>// Implementation of unicodedata

var $module = (function($B){

    var _b_ = $B.builtins

    // Load unicode table if not already loaded
    if($B.unicodedb === undefined){
        var xhr = new XMLHttpRequest
        xhr.open("GET",
            $B.brython_path + "unicode.txt", false)
        xhr.onreadystatechange = function(){
            if(this.readyState == 4){
                if(this.status == 200){
                    $B.unicodedb = this.responseText
                }else{
                    console.log("Warning - could not " +
                        "load unicode.txt")
                }
            }
        }
        xhr.send()
    }

    function _info(chr){
        var ord = chr.codePointAt(0),
            hex = ord.toString(16).toUpperCase()
        while(hex.length < 4){hex = "0" + hex}
        var re = new RegExp("^" + hex +";(.+?);(.*?);(.*?);(.*?);(.*?);(.*);(.*);(.*)$",
                "m"),
            search = re.exec($B.unicodedb)
        if(search === null){
            return null
        }else{
            return {
                name: search[1],
                category: search[2],
                combining: search[3],
                bidirectional: search[4],
                decomposition: search[5],
                decimal: search[6],
                digit: search[7],
                numeric: search[8]
            }
        }
    }

    function bidirectional(chr){
        var search = _info(chr)
        if(search === null){
            console.log("error", chr, hex)
            throw _b_.KeyError.$factory(chr)
        }
        return search.bidirectional
    }

    function category(chr){
        // Returns the general category assigned to the character chr as
        // string.
        if($B.is_unicode_cn(chr.codePointAt(0))){ // in unicode_data.js
            return "Cn"
        }
        var search = _info(chr)
        if(search === null){
            console.log("error", chr)
            throw _b_.KeyError.$factory(chr)
        }
        return search.category
    }

    function combining(chr){
        // Returns the general category assigned to the character chr as
        // string.
        var search = _info(chr)
        if(search === null){
            console.log("error", chr)
            throw _b_.KeyError.$factory(chr)
        }
        return parseInt(search.combining)
    }

    function decimal(chr, _default){
        // Returns the decimal value assigned to the character chr as integer.
        // If no such value is defined, default is returned, or, if not given,
        // ValueError is raised.
        var search = _info(chr)
        if(search === null){
            console.log("error", chr)
            throw _b_.KeyError.$factory(chr)
        }
        return parseInt(search.decimal)
    }

    function decomposition(chr, _default){
        // Returns the decimal value assigned to the character chr as integer.
        // If no such value is defined, default is returned, or, if not given,
        // ValueError is raised.
        var search = _info(chr)
        if(search === null){
            console.log("error", chr)
            throw _b_.KeyError.$factory(chr)
        }
        return search.decomposition
    }

    function digit(chr, _default){
        // Returns the decimal value assigned to the character chr as integer.
        // If no such value is defined, default is returned, or, if not given,
        // ValueError is raised.
        var search = _info(chr)
        if(search === null){
            console.log("error", chr)
            throw _b_.KeyError.$factory(chr)
        }
        return parseInt(search.digit)
    }

    function lookup(name){
        // Look up character by name. If a character with the given name is
        // found, return the corresponding character. If not found, KeyError
        // is raised.
        var re = new RegExp("^([0-9A-F]+);" +
            name + ";(.*)$", "m")
        search = re.exec($B.unicodedb)
        if(search === null){
            throw _b_.KeyError.$factory("undefined character name '" +
                name + "'")
        }
        var res = parseInt(search[1], 16)
        return _b_.chr(res)
    }

    function name(chr, _default){
        // Returns the name assigned to the character chr as a string. If no
        // name is defined, default is returned, or, if not given, ValueError
        // is raised.
        var search = _info(chr)
        if(search === null){
            if(_default){return _default}
            throw _b_.KeyError.$factory("undefined character name '" +
                chr + "'")
        }
        return search.name
    }

    function _norm(form, chr){
        var search = _info(chr)
        if(search === null){
            throw _b_.KeyError.$factory(chr)
        }
        switch(form){
            case "NFC":
                return chr
            case "NFD":
                var decomp = decomposition(chr),
                    parts = decomp.split(" "),
                    res = ""
                if(parts[0].startsWith("<")){
                    return chr
                }
                parts.forEach(function(part){
                    if(! part.startsWith("<")){
                        res += _b_.chr(parseInt(part, 16))
                    }
                })
                return res
            case "NFKC":
                var decomp = decomposition(chr),
                    parts = decomp.split(" ")
                if(parts[0] == "<compat>"){
                    var res = ""
                    parts.slice(1).forEach(function(part){
                        res += _b_.chr(parseInt(part, 16))
                    })
                    return res
                }
                return chr
            case "NFKD":
                var decomp = decomposition(chr),
                    parts = decomp.split(" ")
                if(parts[0] == "<compat>"){
                    var res = ""
                    parts.slice(1).forEach(function(part){
                        res += _b_.chr(parseInt(part, 16))
                    })
                    return res
                }
                return chr

            default:
                throw _b_.ValueError.$factory("invalid normalization form")
        }
    }

    function normalize(form, unistr){
        var res = ""
        for(var i = 0, len = unistr.length; i < len; i++){
            res += _norm(form, unistr.charAt(i))
        }
        return res
    }

    function numeric(chr, _default){
        // Returns the decimal value assigned to the character chr as integer.
        // If no such value is defined, default is returned, or, if not given,
        // ValueError is raised.
        var search = _info(chr)
        if(search === null){
            if(_default){return _default}
            throw _b_.KeyError.$factory(chr)
        }
        return new Number(eval(search.numeric))
    }

    var module = {
        bidirectional: bidirectional,
        category: category,
        combining: combining,
        decimal: decimal,
        decomposition: decomposition,
        digit: digit,
        lookup: lookup,
        name: name,
        normalize: normalize,
        numeric: numeric,
        unidata_version: "11.0.0"
    }
    module.ucd_3_2_0 = {}
    for(var key in module){
        if(key == "unidata_version"){
            module.ucd_3_2_0[key] = '3.2.0'
        }else{
            module.ucd_3_2_0[key] = module[key] // approximation...
        }
    }
    return module

})(__BRYTHON__)<commit_msg>Adapt unicodedata.js to support strings with surrogate pairs<commit_after>// Implementation of unicodedata

var $module = (function($B){

    var _b_ = $B.builtins

    // Load unicode table if not already loaded
    if($B.unicodedb === undefined){
        var xhr = new XMLHttpRequest
        xhr.open("GET",
            $B.brython_path + "unicode.txt", false)
        xhr.onreadystatechange = function(){
            if(this.readyState == 4){
                if(this.status == 200){
                    $B.unicodedb = this.responseText
                }else{
                    console.log("Warning - could not " +
                        "load unicode.txt")
                }
            }
        }
        xhr.send()
    }

    function _info(chr){
        var ord = _b_.ord(chr),
            hex = ord.toString(16).toUpperCase()
        while(hex.length < 4){hex = "0" + hex}
        var re = new RegExp("^" + hex +";(.+?);(.*?);(.*?);(.*?);(.*?);(.*);(.*);(.*)$",
                "m"),
            search = re.exec($B.unicodedb)
        if(search === null){
            return null
        }else{
            return {
                name: search[1],
                category: search[2],
                combining: search[3],
                bidirectional: search[4],
                decomposition: search[5],
                decimal: search[6],
                digit: search[7],
                numeric: search[8]
            }
        }
    }

    function bidirectional(chr){
        var search = _info(chr)
        if(search === null){
            console.log("error", chr, hex)
            throw _b_.KeyError.$factory(chr)
        }
        return search.bidirectional
    }

    function category(chr){
        // Returns the general category assigned to the character chr as
        // string.
        if($B.is_unicode_cn(chr.codePointAt(0))){ // in unicode_data.js
            return "Cn"
        }
        var search = _info(chr)
        if(search === null){
            console.log("error", chr)
            throw _b_.KeyError.$factory(chr)
        }
        return search.category
    }

    function combining(chr){
        // Returns the general category assigned to the character chr as
        // string.
        var search = _info(chr)
        if(search === null){
            console.log("error", chr)
            throw _b_.KeyError.$factory(chr)
        }
        return parseInt(search.combining)
    }

    function decimal(chr, _default){
        // Returns the decimal value assigned to the character chr as integer.
        // If no such value is defined, default is returned, or, if not given,
        // ValueError is raised.
        var search = _info(chr)
        if(search === null){
            console.log("error", chr)
            throw _b_.KeyError.$factory(chr)
        }
        return parseInt(search.decimal)
    }

    function decomposition(chr, _default){
        // Returns the decimal value assigned to the character chr as integer.
        // If no such value is defined, default is returned, or, if not given,
        // ValueError is raised.
        var search = _info(chr)
        if(search === null){
            console.log("error", chr)
            throw _b_.KeyError.$factory(chr)
        }
        return search.decomposition
    }

    function digit(chr, _default){
        // Returns the decimal value assigned to the character chr as integer.
        // If no such value is defined, default is returned, or, if not given,
        // ValueError is raised.
        var search = _info(chr)
        if(search === null){
            console.log("error", chr)
            throw _b_.KeyError.$factory(chr)
        }
        return parseInt(search.digit)
    }

    function lookup(name){
        // Look up character by name. If a character with the given name is
        // found, return the corresponding character. If not found, KeyError
        // is raised.
        var re = new RegExp("^([0-9A-F]+);" +
            name + ";(.*)$", "m")
        search = re.exec($B.unicodedb)
        if(search === null){
            throw _b_.KeyError.$factory("undefined character name '" +
                name + "'")
        }
        var res = parseInt(search[1], 16)
        return _b_.chr(res)
    }

    function name(chr, _default){
        // Returns the name assigned to the character chr as a string. If no
        // name is defined, default is returned, or, if not given, ValueError
        // is raised.
        var search = _info(chr)
        if(search === null){
            if(_default){return _default}
            throw _b_.KeyError.$factory("undefined character name '" +
                chr + "'")
        }
        return search.name
    }

    function _norm(form, chr){
        var search = _info(chr)
        if(search === null){
            throw _b_.KeyError.$factory(chr)
        }
        switch(form){
            case "NFC":
                return chr
            case "NFD":
                var decomp = decomposition(chr),
                    parts = decomp.split(" "),
                    res = ""
                if(parts[0].startsWith("<")){
                    return chr
                }
                parts.forEach(function(part){
                    if(! part.startsWith("<")){
                        res += _b_.chr(parseInt(part, 16))
                    }
                })
                return res
            case "NFKC":
                var decomp = decomposition(chr),
                    parts = decomp.split(" ")
                if(parts[0] == "<compat>"){
                    var res = ""
                    parts.slice(1).forEach(function(part){
                        res += _b_.chr(parseInt(part, 16))
                    })
                    return res
                }
                return chr
            case "NFKD":
                var decomp = decomposition(chr),
                    parts = decomp.split(" ")
                if(parts[0] == "<compat>"){
                    var res = ""
                    parts.slice(1).forEach(function(part){
                        res += _b_.chr(parseInt(part, 16))
                    })
                    return res
                }
                return chr

            default:
                throw _b_.ValueError.$factory("invalid normalization form")
        }
    }

    function normalize(form, unistr){
        var res = ""
        for(var i = 0, len = unistr.length; i < len; i++){
            res += _norm(form, unistr.charAt(i))
        }
        return res
    }

    function numeric(chr, _default){
        // Returns the decimal value assigned to the character chr as integer.
        // If no such value is defined, default is returned, or, if not given,
        // ValueError is raised.
        var search = _info(chr)
        if(search === null){
            if(_default){return _default}
            throw _b_.KeyError.$factory(chr)
        }
        return new Number(eval(search.numeric))
    }

    var module = {
        bidirectional: bidirectional,
        category: category,
        combining: combining,
        decimal: decimal,
        decomposition: decomposition,
        digit: digit,
        lookup: lookup,
        name: name,
        normalize: normalize,
        numeric: numeric,
        unidata_version: "11.0.0"
    }
    module.ucd_3_2_0 = {}
    for(var key in module){
        if(key == "unidata_version"){
            module.ucd_3_2_0[key] = '3.2.0'
        }else{
            module.ucd_3_2_0[key] = module[key] // approximation...
        }
    }
    return module

})(__BRYTHON__)<|endoftext|>


<commit_before>// EMAIL NEWSLETTER SIGNUPS

// 1. Define all input fields
const emailBoxNames = [
	'hero',		// homepage hero email signup
	'event1',	// events pre-reg (top)
	'event2'	// events pre-reg (bottom)
]
const emailBoxFields = [
	'first_name',
	'last_name',
	'email',
	'questions',	// Only for homepage hero
	'phone'				// Only on events page
]

// 2. Assign enable button function to all relevant fields, and trigger submit if user presses enter
emailBoxNames.forEach(emailBoxName => {
	emailBoxFields.forEach(emailBoxField => {
		const field = getElementById(emailBoxName + '_' + emailBoxField)
		if (field) {
			field.addEventListener('keypress', e => {

				// Make sure first and last names don’t contain spaces
				if (e.target.name === 'first_name' || e.target.name === 'last_name') {
					field.value = standardisationName(field.value)
				}
				// Set phone number according to national format
				else if (e.target.name === 'phone') {
				}

				// Check to see if every field has been filled out correctly...
				const valid = emailBoxFields.every(checkEmailBoxField => {
					const checkField = getElementById(emailBoxName + '_' + checkEmailBoxField)
					// If field doesn’t exist, return true.
					if (!checkField)	return true
					// return true if all fields have been filled out
					return (
						// First and last names have to have at least 2 characters each...
						((checkEmailBoxField === 'first_name' || checkEmailBoxField === 'last_name') && checkField.value.length > 1)
						// ...email has to be at least 4 characters and valid...
						|| (checkEmailBoxField === 'email' && checkField.value.length > 4 && standardisationEmail.test(checkField.value))
						// Any other fields have to be at least 1 character long.
						|| checkField.value.length > 0
					)
				})
				// Only show alert once every field has been touched...
				const everyFieldHasBeenFilledOut = emailBoxFields.every(checkEmailBoxField => !getElementById(emailBoxName + '_' + checkEmailBoxField) || getElementById(emailBoxName + '_' + checkEmailBoxField).value.length > 0)
				const buttonField = getElementById(emailBoxName + '_button')
				const alertField = getElementById(emailBoxName + '_alert')
				const emailBoxForm = getElementById(emailBoxName + '_form')
				// Only show alert if all fields have been filled out somewhat, but not yet validated
				if (emailBoxName === 'hero' && !valid && everyFieldHasBeenFilledOut) {
					alertField.classList.remove('hidden')
					buttonField.disabled = true
					emailBoxForm.action = ''
					emailBoxForm.removeEventListener('click', () => null)
				}
				// ...and if all’s good to go, change button class to active, and submit emailBoxForm.
				else {
					alertField.classList.add('hidden')
					buttonField.disabled = false
					buttonField.addEventListener('click', () => {
						// If email box is used on homepage...
						if (emailBoxName === 'hero') {
							// ...collect email newsletter
							emailBoxForm.action = 'https://app.getresponse.com/add_subscriber.html'
							emailBoxForm.submit()
						}
						// ...otherwise, bring up reg form, since used in events page
						else {
							emailBoxFields.forEach(checkEmailBoxField => {
								// Transfer data onto reg form where it can be either used or cleared...
								const field = getElementById(emailBoxName + '_' + checkEmailBoxField)
								if (checkEmailBoxField === 'first_name') {
									eventFirstName.value = field.value
								}
								else if (checkEmailBoxField === 'last_name') {
									eventLastName.value = field.value
								}
								else if (checkEmailBoxField === 'email') {
									eventEmail.value = field.value
								}
								else if (checkEmailBoxField === 'phone') {
									eventMobile.value = field.value
								}
							})
							showRegForm()
						}
					})
				}
				const key = e.which || e.keyCode
				// If `enter` key is pressed, attempt to submit emailBoxForm
				if (key === 13) {
					const buttonField = getElementById(emailBoxName + '_button')
					buttonField.click()
				}
			})
		}
	})
})<commit_msg>001 - email box continue<commit_after>// EMAIL NEWSLETTER SIGNUPS

// 1. Define all input fields
const emailBoxNames = [
	'hero',		// homepage hero email signup
	'event1',	// events pre-reg (top)
	'event2'	// events pre-reg (bottom)
]
const emailBoxFields = [
	'first_name',
	'last_name',
	'email',
	'questions',	// Only for homepage hero
	'phone'				// Only on events page
]

// 2. Assign enable button function to all relevant fields, and trigger submit if user presses enter
emailBoxNames.forEach(emailBoxName => {
	emailBoxFields.forEach(emailBoxField => {
		const field = getElementById(emailBoxName + '_' + emailBoxField)
		if (field) {
			field.addEventListener('keypress', e => {

				// Make sure first and last names don’t contain spaces
				if (e.target.name === 'first_name' || e.target.name === 'last_name') {
					field.value = standardisationName(field.value)
				}
				// Set phone number according to national format
				else if (e.target.name === 'phone') {
				}

				// Check to see if every field has been filled out correctly...
				const valid = emailBoxFields.every(checkEmailBoxField => {
					const checkField = getElementById(emailBoxName + '_' + checkEmailBoxField)
					// If field doesn’t exist, return true.
					if (!checkField)	return true
					// return true if all fields have been filled out
					return (
						// First and last names have to have at least 2 characters each...
						((checkEmailBoxField === 'first_name' || checkEmailBoxField === 'last_name') && checkField.value.length > 1)
						// ...email has to be at least 4 characters and valid...
						|| (checkEmailBoxField === 'email' && checkField.value.length > 4 && standardisationEmail.test(checkField.value))
						// Any other fields have to be at least 1 character long.
						|| checkField.value.length > 0
					)
				})
				// Only show alert once every field has been touched...
				const everyFieldHasBeenFilledOut = emailBoxFields.every(checkEmailBoxField => !getElementById(emailBoxName + '_' + checkEmailBoxField) || getElementById(emailBoxName + '_' + checkEmailBoxField).value.length > 0)
				const buttonField = getElementById(emailBoxName + '_button')
				const alertField = getElementById(emailBoxName + '_alert')
				const emailBoxForm = getElementById(emailBoxName + '_form')
				// Only show alert if all fields have been filled out somewhat, but not yet validated
				console.log(emailBoxName, valid, everyFieldHasBeenFilledOut)
				if (emailBoxName === 'hero' && !valid && everyFieldHasBeenFilledOut) {
					alertField.classList.remove('hidden')
					buttonField.disabled = true
					emailBoxForm.action = ''
					emailBoxForm.removeEventListener('click', () => null)
				}
				// ...and if all’s good to go, change button class to active, and submit emailBoxForm.
				else {
					alertField.classList.add('hidden')
					buttonField.disabled = false
					buttonField.addEventListener('click', () => {
						// If email box is used on homepage...
						if (emailBoxName === 'hero') {
							// ...collect email newsletter
							emailBoxForm.action = 'https://app.getresponse.com/add_subscriber.html'
							emailBoxForm.submit()
						}
						// ...otherwise, bring up reg form, since used in events page
						else {
							emailBoxFields.forEach(checkEmailBoxField => {
								// Transfer data onto reg form where it can be either used or cleared...
								const field = getElementById(emailBoxName + '_' + checkEmailBoxField)
								if (checkEmailBoxField === 'first_name') {
									eventFirstName.value = field.value
								}
								else if (checkEmailBoxField === 'last_name') {
									eventLastName.value = field.value
								}
								else if (checkEmailBoxField === 'email') {
									eventEmail.value = field.value
								}
								else if (checkEmailBoxField === 'phone') {
									eventMobile.value = field.value
								}
							})
							showRegForm()
						}
					})
				}
				const key = e.which || e.keyCode
				// If `enter` key is pressed, attempt to submit emailBoxForm
				if (key === 13) {
					const buttonField = getElementById(emailBoxName + '_button')
					buttonField.click()
				}
			})
		}
	})
})<|endoftext|>


<commit_before>
var entity = {
  name: 'Menus',
  transform: {
/*    from: function(resource) {
      return resource;
    },*/
/*    to: function(object){
      // transform object to send
    }*/
  },
  endpoint: {
    url: 'http://localhost:3000/api/menus/'
    /* put here additional parameters to send (like tokens and another things) */
  },
  columns: [
    {key: 'title', label: 'Titulo', type: 'text'},
    {key: 'route', label: 'Rota', type: 'text'},
    {key: 'icon', label: 'Ícone', type: 'text'},
    {key: 'order', label: 'Ordem', type: 'text'},
    {key: 'status', label: 'Status', type: 'select', options: {choices: {'published': 'Publicado', 'draft': 'Rascunho'}}}
  ],
  fields: [
    {key: 'title', label: 'Titulo', type: 'text'},
    {key: 'route', label: 'Rota', type: 'text'},
    {key: 'icon', label: 'Ícone', type: 'text'},
    {key: 'order', label: 'Ordem', type: 'text'},
    {key: 'eventId', label: 'Evento', type: 'select', remote: {endpoint: 'events', label: 'name'}},
    {key: 'status', label: 'Status', type: 'select', choices: {
      'draft': 'Rascunho',
      'published': 'Publicado'
    }}
  ]
}

export default entity;
<commit_msg>modificado menu. Tela sera refeita<commit_after>
var entity = {
  name: 'Menus',
  transform: {
/*    from: function(resource) {
      return resource;
    },*/
/*    to: function(object){
      // transform object to send
    }*/
  },
  endpoint: {
    url: 'http://localhost:3000/api/menus/'
    /* put here additional parameters to send (like tokens and another things) */
  },
  columns: [
    {key: 'title', label: 'Titulo', type: 'text'},
    {key: 'icon', label: 'Ícone', type: 'text'},
    {key: 'order', label: 'Ordem', type: 'text'},
    {key: 'status', label: 'Status', type: 'select', options: {choices: {'published': 'Publicado', 'draft': 'Rascunho'}}}
  ],
  fields: [
    {key: 'title', label: 'Titulo', type: 'text'},
    {key: 'route', label: 'Rota', type: 'text'},
    {key: 'icon', label: 'Ícone', type: 'text'},
    {key: 'order', label: 'Ordem', type: 'text'},
    {key: 'eventId', label: 'Evento', type: 'select', remote: {endpoint: 'events', label: 'name'}},
    {key: 'status', label: 'Status', type: 'select', choices: {
      'draft': 'Rascunho',
      'published': 'Publicado'
    }}
  ]
}

export default entity;
<|endoftext|>


<commit_before>/**
 * @author https://github.com/bogdan-alexandrescu/ - @balx
 * @ngdoc filter
 * @name ngTasty.filter.slugify
 * @function
 *
 * @description
 * Transform text into an ascii slug by replacing whitespaces, accentuated,
 * and special characters with the coresponding latin character or completely
 * removing them when no latin equivalent is found. This can be used safely to
 * generate valid URLs.
 */
angular.module('ngTasty.filter.slugify', [])
.filter('slugify', function () {

  var makeString = function (object) {
    if (object == null) {
      return '';
    }
    return '' + object;
  };

  var defaultToWhiteSpace = function (characters) {
    if (characters == null) {
      return '\\s';
    } else if (characters.source) {
      return characters.source;
    } else {
      return '[' + characters.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1') + ']';
    }
  };

  var from  = 'ąàáäâãåæăćčĉęèéëêĝĥìíïîĵłľńňòóöőôõðøśșšŝťțŭùúüűûñÿýçżźž',
      to    = 'aaaaaaaaaccceeeeeghiiiijllnnoooooooossssttuuuuuunyyczzz',
      regex = new RegExp(defaultToWhiteSpace(from), 'g');

  return function (str) {
    str = makeString(str)
    .toString() // make sure is a string
    .toLowerCase()
    .replace(regex, function (c){
      var index = from.indexOf(c);
      return to.charAt(index) || '-';
    }) // normalize some foreign characters
    .replace(/[^\w\-\s]+/g, '') // remove unwanted characters
    .trim() //trim spaces
    .replace(/\s+/g, '-') // replace any space with a dash
    .replace(/\-\-+/g, '-'); // remove duplicate dashes
    return str;
  };
});
  <commit_msg>(update) The two first if statements in defaultToWhiteSpace() are unreachable because the variable 'from' is hard-coded value. The regex it's just wrapping the text with '['+ text + ']'. This function looks like an old code. Did I make ng-tasty faster?? :D<commit_after>/**
 * @author https://github.com/bogdan-alexandrescu/ - @balx
 * @ngdoc filter
 * @name ngTasty.filter.slugify
 * @function
 *
 * @description
 * Transform text into an ascii slug by replacing whitespaces, accentuated,
 * and special characters with the coresponding latin character or completely
 * removing them when no latin equivalent is found. This can be used safely to
 * generate valid URLs.
 */
angular.module('ngTasty.filter.slugify', [])
.filter('slugify', function () {

  var makeString = function (object) {
    if (object == null) {
      return '';
    }
    return '' + object;
  };

  var from  = 'ąàáäâãåæăćčĉęèéëêĝĥìíïîĵłľńňòóöőôõðøśșšŝťțŭùúüűûñÿýçżźž',
      to    = 'aaaaaaaaaccceeeeeghiiiijllnnoooooooossssttuuuuuunyyczzz',
      regex = new RegExp('[' + from + ']', 'g');

  return function (str) {
    str = makeString(str)
    .toString() // make sure is a string
    .toLowerCase()
    .replace(regex, function (c){
      var index = from.indexOf(c);
      return to.charAt(index) || '-';
    }) // normalize some foreign characters
    .replace(/[^\w\-\s]+/g, '') // remove unwanted characters
    .trim() //trim spaces
    .replace(/\s+/g, '-') // replace any space with a dash
    .replace(/\-\-+/g, '-'); // remove duplicate dashes
    return str;
  };
});
  <|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import classSet from 'classnames';
import Const from '../Const';

class SelectFilter extends Component {
  constructor(props) {
    super(props);
    this.filter = this.filter.bind(this);
    this.state = {
      isPlaceholderSelected: (this.props.defaultValue === undefined ||
              !this.props.options.hasOwnProperty(this.props.defaultValue))
    };
  }

  filter(event) {
    const { value } = event.target;
    this.setState({ isPlaceholderSelected: (value === '') });
    this.props.filterHandler(value, Const.FILTER_TYPE.SELECT);
  }

  cleanFiltered() {
    const value = (this.props.defaultValue !== undefined) ? this.props.defaultValue : '';
    this.setState({ isPlaceholderSelected: (value === '') });
    this.refs.selectInput.value = value;
    this.props.filterHandler(value, Const.FILTER_TYPE.SELECT);
  }

  applyFilter(filterOption) {
    filterOption = filterOption + '';
    this.setState({ isPlaceholderSelected: (filterOption === '') });
    this.refs.selectInput.value = filterOption;
    this.props.filterHandler(filterOption, Const.FILTER_TYPE.SELECT);
  }

  getOptions() {
    const optionTags = [];
    const { options, placeholder, columnName } = this.props;
    optionTags.push((
      <option key='-1' value=''>{ placeholder || `Select ${columnName}...` }</option>
    ));
    Object.keys(options).map(key => {
      optionTags.push(<option key={ key } value={ key }>{ options[key] + '' }</option>);
    });
    return optionTags;
  }

  componentDidMount() {
    const value = this.refs.selectInput.value;
    if (value) {
      this.props.filterHandler(value, Const.FILTER_TYPE.SELECT);
    }
  }

  render() {
    const selectClass = classSet('filter', 'select-filter', 'form-control',
              { 'placeholder-selected': this.state.isPlaceholderSelected });

    return (
      <select ref='selectInput'
          className={ selectClass }
          onChange={ this.filter }
          defaultValue={ (this.props.defaultValue !== undefined) ? this.props.defaultValue : '' } >
        { this.getOptions() }
      </select>
    );
  }
}

SelectFilter.propTypes = {
  filterHandler: PropTypes.func.isRequired,
  options: PropTypes.object.isRequired,
  placeholder: PropTypes.string,
  columnName: PropTypes.string
};

export default SelectFilter;
<commit_msg>Add an option to customize the "Select" text on SelectFilter filter.<commit_after>import React, { Component, PropTypes } from 'react';
import classSet from 'classnames';
import Const from '../Const';

class SelectFilter extends Component {
  constructor(props) {
    super(props);
    this.filter = this.filter.bind(this);
    this.state = {
      isPlaceholderSelected: (this.props.defaultValue === undefined ||
              !this.props.options.hasOwnProperty(this.props.defaultValue))
    };
  }

  filter(event) {
    const { value } = event.target;
    this.setState({ isPlaceholderSelected: (value === '') });
    this.props.filterHandler(value, Const.FILTER_TYPE.SELECT);
  }

  cleanFiltered() {
    const value = (this.props.defaultValue !== undefined) ? this.props.defaultValue : '';
    this.setState({ isPlaceholderSelected: (value === '') });
    this.refs.selectInput.value = value;
    this.props.filterHandler(value, Const.FILTER_TYPE.SELECT);
  }

  applyFilter(filterOption) {
    filterOption = filterOption + '';
    this.setState({ isPlaceholderSelected: (filterOption === '') });
    this.refs.selectInput.value = filterOption;
    this.props.filterHandler(filterOption, Const.FILTER_TYPE.SELECT);
  }

  getOptions() {
    const optionTags = [];
    const { options, placeholder, columnName, selectText } = this.props;
    const selectTextValue = (selectText !== undefined) ? selectText : 'Select';
    optionTags.push((
      <option key='-1' value=''>{ placeholder || `${selectTextValue} ${columnName}...` }</option>
    ));
    Object.keys(options).map(key => {
      optionTags.push(<option key={ key } value={ key }>{ options[key] + '' }</option>);
    });
    return optionTags;
  }

  componentDidMount() {
    const value = this.refs.selectInput.value;
    if (value) {
      this.props.filterHandler(value, Const.FILTER_TYPE.SELECT);
    }
  }

  render() {
    const selectClass = classSet('filter', 'select-filter', 'form-control',
              { 'placeholder-selected': this.state.isPlaceholderSelected });

    return (
      <select ref='selectInput'
          className={ selectClass }
          onChange={ this.filter }
          defaultValue={ (this.props.defaultValue !== undefined) ? this.props.defaultValue : '' } >
        { this.getOptions() }
      </select>
    );
  }
}

SelectFilter.propTypes = {
  filterHandler: PropTypes.func.isRequired,
  options: PropTypes.object.isRequired,
  placeholder: PropTypes.string,
  columnName: PropTypes.string
};

export default SelectFilter;
<|endoftext|>


<commit_before>import path from 'path';
import pathUtil from 'path-util';

const debug = require('debug')('flos:filter');

const DEFAULT_OPTIONS = {
  cwd: process.cwd(),
  trackFiltered: true
};

class Filter {

  /**
   * @param {Object} options        options for filter
   * @param {string} [options.cwd]  CWD (considered for relative filenames) should be absolute
   * @param {boolean} [options.trackFiltered]  set to true to store the path(s) of filtered files
   */
  constructor(options) {
    this.options = Object.assign({}, DEFAULT_OPTIONS, options);
    this.filtered = {}; // track filtered files
  }

  /**
   * @param {string} absolutePath Absolute file path to check
   * @param {string} relativePath Relative path to check
   * @returns {boolean} true if the file should be filtered, false otherwise
   */
  filter(absolutePath, relativePath) {
    debug('filter', relativePath, absolutePath);
    return false;
  }

  /**
   * @param {string} filePath  The file path to apply to the filter. Should be *nix format.
   * @returns {boolean} true if the file should be filtered, false otherwise
   */
  apply(filePath) {
    if (!filePath || typeof filePath !== 'string' || filePath.trim().length === 0) {
      throw new Error('Expected filePath argument of type string');
    }

    const base = path.resolve(this.options.cwd);
    const absolutePath = path.resolve(base, filePath.trim());
    const relativePath = pathUtil.toRelative(absolutePath, base);
    console.log('Base', base);
    console.log('Absolute', absolutePath);
    console.log('Relative', relativePath);
    const isFiltered = this.filter(absolutePath, relativePath);

    if (isFiltered && this.options.trackFiltered) {
      this.track(absolutePath, relativePath);
    }
    return isFiltered;
  }

  /**
   * @returns the base dir for this filter, defaults to process.cwd()
   */
  getBaseDir() {
    return this.options.cwd;
  }

  track(absolutePath, relativePath) {
    debug('track', relativePath);
    this.filtered[absolutePath] = true;
  }

  tracking(absolutePath) {
    return Boolean(this.filtered[absolutePath]);
  }
}

export default Filter;
<commit_msg>AppVeyor: fix absolute path<commit_after>import path from 'path';
import pathUtil from 'path-util';

const debug = require('debug')('flos:filter');

const DEFAULT_OPTIONS = {
  cwd: process.cwd(),
  trackFiltered: true
};

class Filter {

  /**
   * @param {Object} options        options for filter
   * @param {string} [options.cwd]  CWD (considered for relative filenames) should be absolute
   * @param {boolean} [options.trackFiltered]  set to true to store the path(s) of filtered files
   */
  constructor(options) {
    this.options = Object.assign({}, DEFAULT_OPTIONS, options);
    this.filtered = {}; // track filtered files
  }

  /**
   * @param {string} absolutePath Absolute file path to check
   * @param {string} relativePath Relative path to check
   * @returns {boolean} true if the file should be filtered, false otherwise
   */
  filter(absolutePath, relativePath) {
    debug('filter', relativePath, absolutePath);
    return false;
  }

  /**
   * @param {string} filePath  The file path to apply to the filter. Should be *nix format.
   * @returns {boolean} true if the file should be filtered, false otherwise
   */
  apply(filePath) {
    if (!filePath || typeof filePath !== 'string' || filePath.trim().length === 0) {
      throw new Error('Expected filePath argument of type string');
    }

    const base = path.resolve(this.options.cwd);
    const absolutePath = pathUtil.toAbsolute(filePath.trim(), base);
    const relativePath = pathUtil.toRelative(absolutePath, base);
    console.log('Base', base);
    console.log('Absolute', absolutePath);
    console.log('Relative', relativePath);
    const isFiltered = this.filter(absolutePath, relativePath);

    if (isFiltered && this.options.trackFiltered) {
      this.track(absolutePath, relativePath);
    }
    return isFiltered;
  }

  /**
   * @returns the base dir for this filter, defaults to process.cwd()
   */
  getBaseDir() {
    return this.options.cwd;
  }

  track(absolutePath, relativePath) {
    debug('track', relativePath);
    this.filtered[absolutePath] = true;
  }

  tracking(absolutePath) {
    return Boolean(this.filtered[absolutePath]);
  }
}

export default Filter;
<|endoftext|>


<commit_before>const axios = require('axios')
const FMI = require('./fmi-constants')
const {parseString} = require('xml2js')
const processors = require('xml2js/lib/processors')
const Promise = require('bluebird')
const url = require('url')

const parseXml = Promise.promisify(parseString)

const featureUrl = url.parse(FMI.WFS_FEATURE_URL)
featureUrl.query = {
  request: 'getFeature',
  // eslint-disable-next-line camelcase
  storedquery_id: 'fmi::observations::lightning::simple'
}
const fmiLightningsRequestUrl = url.format(featureUrl)
console.log(`Configured lightning URL: ${fmiLightningsRequestUrl}`)

async function fetchLightnings() {
  const {data} = await axios.get(fmiLightningsRequestUrl)
  const wfsResponse = await xmlToObject(data)
  return extractLocationsAndTimes(wfsResponse)
}

function xmlToObject(xml) {
  return parseXml(xml, {tagNameProcessors: [processors.stripPrefix, processors.firstCharLowerCase]})
}

function extractLocationsAndTimes(queryResult) {
  if(!queryResult.featureCollection.hasOwnProperty('member')) return [] // No lightnings atm
  return queryResult.featureCollection.member.map(({bsWfsElement}) =>
    ({
      location: bsWfsElement[0].location[0].point[0].pos[0].trim(),
      timestamp: bsWfsElement[0].time[0]
    })
  )
}

module.exports = {
  fetchLightnings
}<commit_msg>Use mock lightning data for development<commit_after>const axios = require('axios')
const FMI = require('./fmi-constants')
const {parseString} = require('xml2js')
const processors = require('xml2js/lib/processors')
const Promise = require('bluebird')
const url = require('url')
const fs = require('fs')

const parseXml = Promise.promisify(parseString)

const featureUrl = url.parse(FMI.WFS_FEATURE_URL)
featureUrl.query = {
  request: 'getFeature',
  // eslint-disable-next-line camelcase
  storedquery_id: 'fmi::observations::lightning::simple'
}
const fmiLightningsRequestUrl = url.format(featureUrl)
console.log(`Configured lightning URL: ${fmiLightningsRequestUrl}`)

async function fetchLightnings() {
  // const {data} = await axios.get(fmiLightningsRequestUrl)
  const data = fs.readFileSync('src/lightnings.xml') // Mock data for developing
  const wfsResponse = await xmlToObject(data)
  return extractLocationsAndTimes(wfsResponse)
}

function xmlToObject(xml) {
  return parseXml(xml, {tagNameProcessors: [processors.stripPrefix, processors.firstCharLowerCase]})
}

function extractLocationsAndTimes(queryResult) {
  if(!queryResult.featureCollection.hasOwnProperty('member')) return [] // No lightnings atm
  return queryResult.featureCollection.member.map(({bsWfsElement}) =>
    ({
      location: bsWfsElement[0].location[0].point[0].pos[0].trim(),
      timestamp: bsWfsElement[0].time[0]
    })
  )
}

module.exports = {
  fetchLightnings
}<|endoftext|>


<commit_before>/**

    Utility

**/

define([], function () {

  var template, Util, _ = {},

  fn = {

    init: function (lodash) {
      console.log("init:", window._ ? "LODASH/UNDERSCORE!" : "(no lodash/underscore)");
      _ = lodash || window._ || _;
      Util.extend(Util, _);
    },

    clone: function (a, b, deep, transform, defaults) {
      b = b || (Util.isArray( a ) ? [] : {});
      transform = transform || Util.noop;

      for(var i in a){
        if(a.hasOwnProperty( i ) && (!defaults || Util.isUndefined( b[ i ] ))){
          b[ i ] = deep && Util.isObject( a[ i ] ) ? fn.clone( a[ i ], null, true ) : transform(a[ i ], i, b);
        }
      }
      return b;
    },

    cloneDeep: function (a, b, transform) {
      return fn.clone(a, b, true, transform);
    },

    cookie: function (name) {
      // http://stackoverflow.com/a/25490531/720204
      var value = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)');
      return value ? value.pop() : '';
    },

    defaults: function (a, b, deep) {
      return fn.clone(b, a, !!deep, null, true);
    },

    defaultsDeep: function (a, b) {
      return fn.defaults(a, b, true);
    },

    each: function (list, fn, context) {
      if(Util.isArray( list )) list.forEach( fn.bind(context || window) );
      else for(var i in list) fn.bind(context || window)(list[ i ], i, list);
    },

    extend: function (a, b, deep) {
      return fn.clone(b, a, !!deep);
    },

    filter: function (a, b, single) {
      var r = [];
      for(var i in a) {
        if(fn.isEqual(a[ i ], b, i)){
          r.push(a[ i ]);
          if( single ) break;
        }
      }
      return single ? r[ 0 ] : r;
    },

    find: function (a, b) {
      return Util.filter(a, b, true);
    },

    findWhere: function (a, props) {
      return Util.find(a, props);
    },

    get: function (o, path, defaultValue) {
      var pathtree = o.hasOwnProperty( path ) ? [ path ] : Util.isArray( path ) ? path : path.split( /[\[\].:]+/ );

      return pathtree.reduce(function (o, path) {
        return o===defaultValue || Util.isUndefined( o[ path ] ) ? defaultValue : o[ path ];
      }, o);
    },

    getProp: function (o, path) {
      var pathtree = Util.isArray( path ) ? path : path.split(":"),
          key = pathtree.slice( -1 )[ 0 ],
          prop = {};
      prop[ key ] = Util.get(o, pathtree.join( "." ));
      return prop;
    },

    isArray: function (o) {
       return Object.prototype.toString.call( o ) === "[object Array]";
    },

    isBoolean: function (o) {
      return typeof o === "boolean";
    },

    isDomSelection: function (o) {
      return Util.isNodeList( o ) || Util.isNode( o ) || Util.isJquery( o );
    },

    isEqual: function (a, b, args) {
      if(!Util.isObject( a ) && typeof a !== typeof b) return false;
      if(Util.isBoolean( b )) return !!a === b;
      if(Util.isFunction( b )) return b(a, isNaN( args ) ? args : +args);
      if(Util.isObject( b )) {
        for(var i in b) {
          if(!b.hasOwnProperty( i )) continue;
          if(!a.hasOwnProperty( i ) || !fn.isEqual(a[ i ], b[ i ])) {
            return false;
          }
        }
        return true;
      }

      // if number, string, etc
      return Util.isObject( a ) ? a[ b ] : a === b;
    },

    isFunction: function (o) {
      return typeof o === "function";
    },

    isIE: (function () {
      return typeof ScriptEngineMajorVersion === "function" ? ScriptEngineMajorVersion() : undefined;
    })(),

    isJquery: function (o) {
      return window.jQuery && o instanceof window.jQuery;
    },

    isNode: function (o) {
      return Object.prototype.toString.call( o ) === "[object HTMLElement]";
    },

    isNodeList: function (o) {
      return Object.prototype.toString.call( o ) === "[object NodeList]";
    },

    isObject: function (o, noArray) {
       return noArray ? Object.prototype.toString.call( o ) === "[object Object]" : typeof o === "object";
    },

    isRegExp: function (o) {
      return Object.prototype.toString.call( o ) === "[object RegExp]";
    },

    isString: function (o) {
      return typeof o === "string";
    },

    isUndefined: function (o) {
      return typeof o === "undefined";
    },

    noop: function (v) {
      return v;
    },

    object: function (list, values) {
      var array = Util.isArray( list[ 0 ] );
      return list.reduce(function (o, val, i) {
        o[array ? val[ 0 ] : val] = array ? val[ 1 ] : values[ i ];
        return o;
      }, {});
    },

    omit: function (o, keys) {
      return Util.pick2(o, Util.isArray( keys ) ? keys : Util.toArray( arguments ).slice( 1 ), true);
    },

    pick: function (o, keys) {
      return Util.pick2(o, Util.isArray( keys ) ? keys : Util.toArray( arguments ).slice( 1 ));
    },

    pick2: function (o, keys, without) {
      return Object.keys( o ).reduce(function (picked, key) {
        var hasKey = keys.indexOf( key ) >= 0;
        if(hasKey && !without || !hasKey && without) picked[ key ] = o[ key ];
        return picked;
      }, {});
    },

    randomString: function (length) {
      return Array(length + 1).join( (Math.random().toString( 36 ) + '00000000000000000').slice(2, 18) ).slice(0, length);
    },

    serialise: function (data, prefix) {
      // http://stackoverflow.com/a/1714899/720204
      var str = [];
      for(var i in data) {
        if( data.hasOwnProperty( i ) ) {
          var key = prefix ? prefix + "[" + i + "]" : i,
              value = data[ i ];
          str.push(typeof value == "object" ? this.serialise(value, key)
            : encodeURIComponent( key ) + "=" + encodeURIComponent( value ));
        }
      }
      return str.join( "&" );
    },

    // set/get/remove items from local/session storage
    storage: (function (window) {
      var uid = new Date,
      Storage = function (type, uid) {

        this.data = (function (type, uid) {
          try {
            var storage = window[type + 'Storage'];
            storage.setItem(uid, uid);
            var result = storage.getItem(uid) == uid;
            storage.removeItem(uid);
            return result && storage;
          } catch (exception) {}
        })(type, uid);

        this.setItem = function (key, value) {
          if(this.data) this.data.setItem(key, JSON.stringify(value));
        };

        this.getItem = function (key, isJSON) {
          if(!this.data) return;
          var data = this.data.getItem(key);
          return isJSON!==false ? JSON.parse(data) : data;
        };

        this.removeItem = function (key) {
          if(this.data) this.data.removeItem(key);
        };
      };

      return {
        local: new Storage('local', uid),
        session: new Storage('session', uid)
      };
    })(window),

    template: function (str) {
      // Adapted from http://goo.gl/7KvWuU with single-quote fix from http://goo.gl/fOuW28
      // John Resig - http://ejohn.org/ - MIT Licensed
      // Figure out if we're getting a template, or if we need to
      // load the template - and be sure to cache the result.
      var fn = !/\W/.test( str ) ? template[ str ] = template[ str ] || this.template( $(str)[ 0 ].innerHTML ) :

        // Generate a reusable function that will serve as a template
        // generator (and which will be cached).
        new Function("obj",
          "var p=[],print=function(){p.push.apply(p,arguments);};" +

          // Introduce the data as local variables using with(){}
          "with(obj){p.push('" +

          // Convert the template into pure JavaScript
          str.replace(/[\r\t\n]/g, " ")
         .replace(/'(?=[^%]*%>)/g,"\t")
         .split("'").join("\\'")
         .split("\t").join("'")
         .replace(/<%=(.+?)%>/g, "',$1,'")
         .replace(/{{(.+?)}}/g, "',$1,'")
         .split("<%").join("');")
         .split("%>").join("p.push('")
         + "');}return p.join('');");

      // Provide some basic currying to the user
      return function (data) {
        return fn( Util.defaults(data, {_: Util}));
      };
    },

    toArray: function (args) {
      return [].slice.call( args );
    },

    uniq: function (list) {
      // http://stackoverflow.com/a/9229821/720204
      return list.filter(function(value, i, self) {
          return self.indexOf(value) === i;
      });
    },

    // convert an xpath to a CSS3 selector e.g. "xpath://body/a[3]" => "body:nth-of-type(1) a:nth-of-type(3)"
    xpathToSelector: function (xpath) {
      return xpath.replace(/^xpath:\/\//, '').split('/').reduce(function (selector, value) {
         return selector.concat(value.replace(/\[(\d+)\]|$/, function ($0, $1) {
            return ':nth-of-type(' + ($1 || 1) + ')';
         }));
      }, []).join(" ");
    }
  };

  // create Util getters from functions
  Util = {};
  for(var i in fn) {
    (function (i) {
      Object.defineProperty(Util, i, {
        get: function () {

          // return lodash version if available
          return _[ i ] || fn[ i ];
        }
      });
    })( i );
  }

  return Util;
});<commit_msg>utils: allow wildcards (*) in 'get'<commit_after>/**

    Utility

**/

define([], function () {

  var template, Util, _ = {},

  fn = {

    init: function (lodash) {
      console.log("init:", window._ ? "LODASH/UNDERSCORE!" : "(no lodash/underscore)");
      _ = lodash || window._ || _;
      Util.extend(Util, _);
    },

    clone: function (a, b, deep, transform, defaults) {
      b = b || (Util.isArray( a ) ? [] : {});
      transform = transform || Util.noop;

      for(var i in a){
        if(a.hasOwnProperty( i ) && (!defaults || Util.isUndefined( b[ i ] ))){
          b[ i ] = deep && Util.isObject( a[ i ] ) ? fn.clone( a[ i ], null, true ) : transform(a[ i ], i, b);
        }
      }
      return b;
    },

    cloneDeep: function (a, b, transform) {
      return fn.clone(a, b, true, transform);
    },

    cookie: function (name) {
      // http://stackoverflow.com/a/25490531/720204
      var value = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)');
      return value ? value.pop() : '';
    },

    defaults: function (a, b, deep) {
      return fn.clone(b, a, !!deep, null, true);
    },

    defaultsDeep: function (a, b) {
      return fn.defaults(a, b, true);
    },

    each: function (list, fn, context) {
      if(Util.isArray( list )) list.forEach( fn.bind(context || window) );
      else for(var i in list) fn.bind(context || window)(list[ i ], i, list);
    },

    extend: function (a, b, deep) {
      return fn.clone(b, a, !!deep);
    },

    filter: function (a, b, single) {
      var r = [];
      for(var i in a) {
        if(fn.isEqual(a[ i ], b, i)){
          r.push(a[ i ]);
          if( single ) break;
        }
      }
      return single ? r[ 0 ] : r;
    },

    find: function (a, b) {
      return Util.filter(a, b, true);
    },

    findWhere: function (a, props) {
      return Util.find(a, props);
    },

    get: function (o, path, defaultValue) {
      var pathtree = o.hasOwnProperty( path ) ? [ path ] : Util.isArray( path ) ? path : path.split( /[\[\].:]+/ ),
          multi,
          fn = function (o, path, i, pathtree) {
            if(path==="*" && Util.isObject( o )) {
              return Object.keys( o ).reduce(function (a, key) {
                multi = true;
                var value = Util.get(o[ key ], pathtree.slice(i + 1));
                return Util.isUndefined( value ) ? a : a.concat(value);
              }, []);
            }
            return o===defaultValue || Util.isUndefined( o[ path ] ) ? (multi && o.length ? o : defaultValue) : o[ path ];
          };

      return pathtree.reduce(fn, o);
    },

    getProp: function (o, path) {
      var pathtree = Util.isArray( path ) ? path : path.split(":"),
          key = pathtree.slice( -1 )[ 0 ],
          prop = {};
      prop[ key ] = Util.get(o, pathtree.join( "." ));
      return prop;
    },

    isArray: function (o) {
       return Object.prototype.toString.call( o ) === "[object Array]";
    },

    isBoolean: function (o) {
      return typeof o === "boolean";
    },

    isDomSelection: function (o) {
      return Util.isNodeList( o ) || Util.isNode( o ) || Util.isJquery( o );
    },

    isEqual: function (a, b, args) {
      if(!Util.isObject( a ) && typeof a !== typeof b) return false;
      if(Util.isBoolean( b )) return !!a === b;
      if(Util.isFunction( b )) return b(a, isNaN( args ) ? args : +args);
      if(Util.isObject( b )) {
        for(var i in b) {
          if(!b.hasOwnProperty( i )) continue;
          if(!a.hasOwnProperty( i ) || !fn.isEqual(a[ i ], b[ i ])) {
            return false;
          }
        }
        return true;
      }

      // if number, string, etc
      return Util.isObject( a ) ? a[ b ] : a === b;
    },

    isFunction: function (o) {
      return typeof o === "function";
    },

    isIE: (function () {
      return typeof ScriptEngineMajorVersion === "function" ? ScriptEngineMajorVersion() : undefined;
    })(),

    isJquery: function (o) {
      return window.jQuery && o instanceof window.jQuery;
    },

    isNode: function (o) {
      return Object.prototype.toString.call( o ) === "[object HTMLElement]";
    },

    isNodeList: function (o) {
      return Object.prototype.toString.call( o ) === "[object NodeList]";
    },

    isObject: function (o, noArray) {
       return noArray ? Object.prototype.toString.call( o ) === "[object Object]" : typeof o === "object";
    },

    isRegExp: function (o) {
      return Object.prototype.toString.call( o ) === "[object RegExp]";
    },

    isString: function (o) {
      return typeof o === "string";
    },

    isUndefined: function (o) {
      return typeof o === "undefined";
    },

    noop: function (v) {
      return v;
    },

    object: function (list, values) {
      var array = Util.isArray( list[ 0 ] );
      return list.reduce(function (o, val, i) {
        o[array ? val[ 0 ] : val] = array ? val[ 1 ] : values[ i ];
        return o;
      }, {});
    },

    omit: function (o, keys) {
      return Util.pick2(o, Util.isArray( keys ) ? keys : Util.toArray( arguments ).slice( 1 ), true);
    },

    pick: function (o, keys) {
      return Util.pick2(o, Util.isArray( keys ) ? keys : Util.toArray( arguments ).slice( 1 ));
    },

    pick2: function (o, keys, without) {
      return Object.keys( o ).reduce(function (picked, key) {
        var hasKey = keys.indexOf( key ) >= 0;
        if(hasKey && !without || !hasKey && without) picked[ key ] = o[ key ];
        return picked;
      }, {});
    },

    randomString: function (length) {
      return Array(length + 1).join( (Math.random().toString( 36 ) + '00000000000000000').slice(2, 18) ).slice(0, length);
    },

    serialise: function (data, prefix) {
      // http://stackoverflow.com/a/1714899/720204
      var str = [];
      for(var i in data) {
        if( data.hasOwnProperty( i ) ) {
          var key = prefix ? prefix + "[" + i + "]" : i,
              value = data[ i ];
          str.push(typeof value == "object" ? this.serialise(value, key)
            : encodeURIComponent( key ) + "=" + encodeURIComponent( value ));
        }
      }
      return str.join( "&" );
    },

    // set/get/remove items from local/session storage
    storage: (function (window) {
      var uid = new Date,
      Storage = function (type, uid) {

        this.data = (function (type, uid) {
          try {
            var storage = window[type + 'Storage'];
            storage.setItem(uid, uid);
            var result = storage.getItem(uid) == uid;
            storage.removeItem(uid);
            return result && storage;
          } catch (exception) {}
        })(type, uid);

        this.setItem = function (key, value) {
          if(this.data) this.data.setItem(key, JSON.stringify(value));
        };

        this.getItem = function (key, isJSON) {
          if(!this.data) return;
          var data = this.data.getItem(key);
          return isJSON!==false ? JSON.parse(data) : data;
        };

        this.removeItem = function (key) {
          if(this.data) this.data.removeItem(key);
        };
      };

      return {
        local: new Storage('local', uid),
        session: new Storage('session', uid)
      };
    })(window),

    template: function (str) {
      // Adapted from http://goo.gl/7KvWuU with single-quote fix from http://goo.gl/fOuW28
      // John Resig - http://ejohn.org/ - MIT Licensed
      // Figure out if we're getting a template, or if we need to
      // load the template - and be sure to cache the result.
      var fn = !/\W/.test( str ) ? template[ str ] = template[ str ] || this.template( $(str)[ 0 ].innerHTML ) :

        // Generate a reusable function that will serve as a template
        // generator (and which will be cached).
        new Function("obj",
          "var p=[],print=function(){p.push.apply(p,arguments);};" +

          // Introduce the data as local variables using with(){}
          "with(obj){p.push('" +

          // Convert the template into pure JavaScript
          str.replace(/[\r\t\n]/g, " ")
         .replace(/'(?=[^%]*%>)/g,"\t")
         .split("'").join("\\'")
         .split("\t").join("'")
         .replace(/<%=(.+?)%>/g, "',$1,'")
         .replace(/{{(.+?)}}/g, "',$1,'")
         .split("<%").join("');")
         .split("%>").join("p.push('")
         + "');}return p.join('');");

      // Provide some basic currying to the user
      return function (data) {
        return fn( Util.defaults(data, {_: Util}));
      };
    },

    toArray: function (args) {
      return [].slice.call( args );
    },

    uniq: function (list) {
      // http://stackoverflow.com/a/9229821/720204
      return list.filter(function(value, i, self) {
          return self.indexOf(value) === i;
      });
    },

    // convert an xpath to a CSS3 selector e.g. "xpath://body/a[3]" => "body:nth-of-type(1) a:nth-of-type(3)"
    xpathToSelector: function (xpath) {
      return xpath.replace(/^xpath:\/\//, '').split('/').reduce(function (selector, value) {
         return selector.concat(value.replace(/\[(\d+)\]|$/, function ($0, $1) {
            return ':nth-of-type(' + ($1 || 1) + ')';
         }));
      }, []).join(" ");
    }
  };

  // create Util getters from functions
  Util = {};
  for(var i in fn) {
    (function (i) {
      Object.defineProperty(Util, i, {
        get: function () {

          // return lodash version if available
          return _[ i ] || fn[ i ];
        }
      });
    })( i );
  }

  return Util;
});<|endoftext|>


<commit_before>function _getParameters(ctx) {
    let requestOptions = {};
    let path = ctx._matchedRoute;
    requestOptions.path = path.endsWith('/') ? path.substring(0, path.length - 1) : path;
    requestOptions.headers = ctx.request.req.headers;
    requestOptions.params = ctx.params;
    requestOptions.query = ctx.query;
    requestOptions.files = ctx.req.files;
    requestOptions.method = ctx.req.method;
    requestOptions.body = ctx.req.body || ctx.request.body;

    return requestOptions;
}

async function validate(validateRequest, ctx, next) {
    let requestOptions, errors;
    requestOptions = _getParameters(ctx, next);
    errors = await validateRequest(requestOptions);
    if (errors) {
        throw errors;
    }
    next();
}

module.exports = {
    validate: validate
};
<commit_msg>Fix koa validation (#42)<commit_after>function _getParameters(ctx) {
    let requestOptions = {};
    let path = ctx._matchedRoute;
    requestOptions.path = path.endsWith('/') ? path.substring(0, path.length - 1) : path;
    requestOptions.headers = ctx.request.req.headers;
    requestOptions.params = ctx.params;
    requestOptions.query = ctx.query;
    requestOptions.files = ctx.req.files;
    requestOptions.method = ctx.req.method;
    requestOptions.body = ctx.req.body || ctx.request.body;

    return requestOptions;
}

async function validate(validateRequest, ctx, next) {
    let requestOptions, errors;
    requestOptions = _getParameters(ctx, next);
    errors = await validateRequest(requestOptions);
    if (errors) {
        throw errors;
    }
    await next();
}

module.exports = {
    validate: validate
};
<|endoftext|>


<commit_before>import {Vector} from '../vector';
import {Geo} from '../geo';
import {GL} from './gl';
export var GLBuilders = {};

GLBuilders.debug = false;

// Tesselate a flat 2D polygon
// x & y coordinates will be set as first two elements of provided vertex_template
GLBuilders.buildPolygons = function (
    polygons,
    vertex_data, vertex_template,
    { texcoord_index, texcoord_scale }) {

    var [[min_u, min_v], [max_u, max_v]] = texcoord_scale || [[0, 0], [1, 1]];
    var num_polygons = polygons.length;
    for (var p=0; p < num_polygons; p++) {
        var polygon = polygons[p];

        // Find polygon extents to calculate UVs, fit them to the axis-aligned bounding box
        if (texcoord_index) {
            var [min_x, min_y, max_x, max_y] = Geo.findBoundingBox(polygon);
            var span_x = max_x - min_x;
            var span_y = max_y - min_y;
            var scale_u = (max_u - min_u) / span_x;
            var scale_v = (max_v - min_v) / span_y;
        }

        // Tessellate
        var vertices = GL.triangulatePolygon(polygon);

        // Add vertex data
        var num_vertices = vertices.length;
        for (var v=0; v < num_vertices; v++) {
            var vertex = vertices[v];
            vertex_template[0] = vertex[0];
            vertex_template[1] = vertex[1];

            // Add UVs
            if (texcoord_index) {
                vertex_template[texcoord_index + 0] = (vertex[0] - min_x) * scale_u + min_u;
                vertex_template[texcoord_index + 1] = (vertex[1] - min_y) * scale_v + min_v;
            }

            vertex_data.addVertex(vertex_template);
        }
    }
};

// Tesselate and extrude a flat 2D polygon into a simple 3D model with fixed height and add to GL vertex buffer
GLBuilders.buildExtrudedPolygons = function (
    polygons,
    z, height, min_height,
    vertex_data, vertex_template,
    normal_index,
    { texcoord_index, texcoord_scale }) {

    var min_z = z + (min_height || 0);
    var max_z = z + height;
    var [[min_u, min_v], [max_u, max_v]] = texcoord_scale || [[0, 0], [1, 1]];

    // Top
    vertex_template[2] = max_z;
    GLBuilders.buildPolygons(polygons, vertex_data, vertex_template, { texcoord_index });

    // Walls
    var num_polygons = polygons.length;
    for (var p=0; p < num_polygons; p++) {
        var polygon = polygons[p];

        for (var q=0; q < polygon.length; q++) {
            var contour = polygon[q];

            for (var w=0; w < contour.length - 1; w++) {
                // Two triangles for the quad formed by each vertex pair, going from bottom to top height
                var wall_vertices = [
                    // Triangle
                    [contour[w+1][0], contour[w+1][1], max_z],
                    [contour[w+1][0], contour[w+1][1], min_z],
                    [contour[w][0], contour[w][1], min_z],
                    // Triangle
                    [contour[w][0], contour[w][1], min_z],
                    [contour[w][0], contour[w][1], max_z],
                    [contour[w+1][0], contour[w+1][1], max_z]
                ];

                // Fit UVs to wall quad
                if (texcoord_index) {
                    var texcoords = [
                        [min_u, max_v],
                        [min_u, min_v],
                        [max_u, min_v],

                        [max_u, min_v],
                        [max_u, max_v],
                        [min_u, max_v]
                    ];
                }

                // Calc the normal of the wall from up vector and one segment of the wall triangles
                var normal = Vector.cross(
                    [0, 0, 1],
                    Vector.normalize([contour[w+1][0] - contour[w][0], contour[w+1][1] - contour[w][1], 0])
                );

                // Update vertex template with current surface normal
                vertex_template[normal_index + 0] = normal[0];
                vertex_template[normal_index + 1] = normal[1];
                vertex_template[normal_index + 2] = normal[2];

                for (var wv=0; wv < wall_vertices.length; wv++) {
                    vertex_template[0] = wall_vertices[wv][0];
                    vertex_template[1] = wall_vertices[wv][1];
                    vertex_template[2] = wall_vertices[wv][2];

                    if (texcoord_index) {
                        vertex_template[texcoord_index + 0] = texcoords[wv][0];
                        vertex_template[texcoord_index + 1] = texcoords[wv][1];
                    }

                    vertex_data.addVertex(vertex_template);
                }
            }
        }
    }
};

// Build tessellated triangles for a polyline
// Basically following the method described here for miter joints:
// http://artgrammer.blogspot.co.uk/2011/07/drawing-polylines-by-tessellation.html
GLBuilders.buildPolylines = function (
    lines,
    z, width,
    vertex_data, vertex_template,
    {
        closed_polygon,
        remove_tile_edges,
        texcoord_index,
        texcoord_scale,
        scaling_index
    }) {

    // Build triangles
    var vertices = [],
        scalingVecs = [],   //  vertices directions for then (on GLSL vertex shader) extrude
        texcoords = [],
        halfWidth = width/2,
        num_lines = lines.length;

    var [[min_u, min_v], [max_u, max_v]] = texcoord_scale || [[0, 0], [1, 1]];

    for (var ln = 0; ln < num_lines; ln++) {
        var line = lines[ln];
        var lineSize = line.length;

        if (line.length > 2) {

            var normPrevCurr; // Right normal to segment between previous and current m_points
            var normCurrNext; // Right normal to segment between current and next m_points
            var rightNorm; // Right "normal" at current point, scaled for miter joint

            var prevCoord; // Previous point coordinates
            var currCoord = lines[0]; // Current point coordinates
            var nextCoord = lines[1]; // Next point coordinates

            normCurrNext[0] = nextCoord[1] - currCoord[1];
            normCurrNext[1] = currCoord[0] - nextCoord[0];
            normCurrNext = Vector.normalize(normCurrNext);

            rightNorm = normCurrNext;

            for(var i = 1; i < lineSize - 1 ; i++){
                prevCoord = currCoord;
                currCoord = nextCoord;
                nextCoord = line[i+1];

                normPrevCurr = normCurrNext;

                normCurrNext[0] = nextCoord[1] - currCoord[1];
                normCurrNext[1] = currCoord[0] - nextCoord[0];

                rightNorm = normPrevCurr + normCurrNext;
                rightNorm = Vector.normalize(rightNorm);
                float scale = Math.sqrt(2. / (1. + Vector.dot(normPrevCurr,normCurrNext) ));
                rightNorm *= scale;

                if (scaling_index) {
                    vertices.push(currCoord);
                    vertices.push(currCoord);
                    scalingVecs.push(rightNorm);
                    scalingVecs.push(-rightNorm);
                } else {
                    vertices.push([ currCoord[0] + rightNorm[0] * halfWidth, currCoord[1] + rightNorm[1] * halfWidth, z ]);
                    vertices.push([ currCoord[0] - rightNorm[0] * halfWidth, currCoord[1] - rightNorm[1] * halfWidth, z ]);
                }

                // Add UVs
                if (texcoord_index) {
                    var frac = i/lineSize;
                    texcoords.push( [max_u, min_v+frac*max_v],
                                    [min_u, min_v+frac*max_v] );
                }
            }

            normCurrNext = Vector.normalize(normCurrNext);

            if (scaling_index) {
                vertices.push(nextCoord);
                vertices.push(nextCoord);
                scalingVecs.push(rightNorm);
                scalingVecs.push(-rightNorm);
            } else {
                vertices.push([currCoord[0] + rightNorm[0] * halfWidth, currCoord[1] + rightNorm[1] * halfWidth, z]);
                vertices.push([currCoord[0] - rightNorm[0] * halfWidth, currCoord[1] - rightNorm[1] * halfWidth, z]);
            }

            if (texcoord_index) {
                texcoords.push( [max_u, max_v],
                                [min_u, max_v] );
            }
        }
    }

    // Add vertices to buffer
    for (var v=0; v < vertices.length; v++) {
        vertex_template[0] = vertices[v][0];
        vertex_template[1] = vertices[v][1];

        // Add UVs
        if (texcoord_index) {
            vertex_template[texcoord_index + 0] = texcoords[v][0];
            vertex_template[texcoord_index + 1] = texcoords[v][1];
        }

        // Add Scaling vertex ( X,Y normal direction + Z haltwidth as attribute )
        if (scaling_index) {
            vertex_template[scaling_index + 0] = scalingVecs[v][0];
            vertex_template[scaling_index + 1] = scalingVecs[v][1];
            vertex_template[scaling_index + 2] = halfWidth;
        }

        vertex_data.addVertex(vertex_template);
    }
};

// Build a quad centered on a point
GLBuilders.buildQuadsForPoints = function (
    points, width, height,
    vertex_data, vertex_template,
    { texcoord_index, texcoord_scale }) {

    var [[min_u, min_v], [max_u, max_v]] = texcoord_scale || [[0, 0], [1, 1]];
    var num_points = points.length;
    for (var p=0; p < num_points; p++) {
        var point = points[p];

        var positions = [
            [point[0] - width/2, point[1] - height/2],
            [point[0] + width/2, point[1] - height/2],
            [point[0] + width/2, point[1] + height/2],

            [point[0] - width/2, point[1] - height/2],
            [point[0] + width/2, point[1] + height/2],
            [point[0] - width/2, point[1] + height/2],
        ];

        if (texcoord_index) {
            var texcoords = [
                [min_u, min_v],
                [max_u, min_v],
                [max_u, max_v],

                [min_u, min_v],
                [max_u, max_v],
                [min_u, max_v]
            ];
        }

        for (var pos=0; pos < 6; pos++) {
            // Add texcoords
            if (texcoord_index) {
                vertex_template[texcoord_index + 0] = texcoords[pos][0];
                vertex_template[texcoord_index + 1] = texcoords[pos][1];
            }

            vertex_template[0] = positions[pos][0];
            vertex_template[1] = positions[pos][1];
            vertex_data.addVertex(vertex_template);
        }
    }
};

/* Utility functions */

// Tests if a line segment (from point A to B) is nearly coincident with the edge of a tile
GLBuilders.isOnTileEdge = function (pa, pb, options)
{
    options = options || {};

    var tolerance_function = options.tolerance_function || GLBuilders.valuesWithinTolerance;
    var tolerance = options.tolerance || 1; // tweak this adjust if catching too few/many line segments near tile edges
    var tile_min = GLBuilders.tile_bounds[0];
    var tile_max = GLBuilders.tile_bounds[1];
    var edge = null;

    if (tolerance_function(pa[0], tile_min.x, tolerance) && tolerance_function(pb[0], tile_min.x, tolerance)) {
        edge = 'left';
    }
    else if (tolerance_function(pa[0], tile_max.x, tolerance) && tolerance_function(pb[0], tile_max.x, tolerance)) {
        edge = 'right';
    }
    else if (tolerance_function(pa[1], tile_min.y, tolerance) && tolerance_function(pb[1], tile_min.y, tolerance)) {
        edge = 'top';
    }
    else if (tolerance_function(pa[1], tile_max.y, tolerance) && tolerance_function(pb[1], tile_max.y, tolerance)) {
        edge = 'bottom';
    }
    return edge;
};

GLBuilders.setTileScale = function (scale)
{
    GLBuilders.tile_bounds = [
        { x: 0, y: 0},
        { x: scale, y: -scale } // TODO: correct for flipped y-axis?
    ];
};

GLBuilders.valuesWithinTolerance = function (a, b, tolerance)
{
    tolerance = tolerance || 1;
    return (Math.abs(a - b) < tolerance);
};

// Build a zigzag line pattern for testing joins and caps
GLBuilders.buildZigzagLineTestPattern = function ()
{
    var min = { x: 0, y: 0}; //  tile.min;
    var max = { x: 4096, y: 4096 }; // tile.max;

    var g = {
        id: 123,
        geometry: {
            type: 'LineString',
            coordinates: [
                [min.x * 0.75 + max.x * 0.25, min.y * 0.75 + max.y * 0.25],
                [min.x * 0.75 + max.x * 0.25, min.y * 0.5 + max.y * 0.5],
                [min.x * 0.25 + max.x * 0.75, min.y * 0.75 + max.y * 0.25],
                [min.x * 0.25 + max.x * 0.75, min.y * 0.25 + max.y * 0.75],
                [min.x * 0.4 + max.x * 0.6, min.y * 0.5 + max.y * 0.5],
                [min.x * 0.5 + max.x * 0.5, min.y * 0.25 + max.y * 0.75],
                [min.x * 0.75 + max.x * 0.25, min.y * 0.25 + max.y * 0.75],
                [min.x * 0.75 + max.x * 0.25, min.y * 0.4 + max.y * 0.6]
            ]
        },
        properties: {
            kind: 'debug'
        }
    };
    return g;
};
<commit_msg>fixing typo to compile<commit_after>import {Vector} from '../vector';
import {Geo} from '../geo';
import {GL} from './gl';
export var GLBuilders = {};

GLBuilders.debug = false;

// Tesselate a flat 2D polygon
// x & y coordinates will be set as first two elements of provided vertex_template
GLBuilders.buildPolygons = function (
    polygons,
    vertex_data, vertex_template,
    { texcoord_index, texcoord_scale }) {

    var [[min_u, min_v], [max_u, max_v]] = texcoord_scale || [[0, 0], [1, 1]];
    var num_polygons = polygons.length;
    for (var p=0; p < num_polygons; p++) {
        var polygon = polygons[p];

        // Find polygon extents to calculate UVs, fit them to the axis-aligned bounding box
        if (texcoord_index) {
            var [min_x, min_y, max_x, max_y] = Geo.findBoundingBox(polygon);
            var span_x = max_x - min_x;
            var span_y = max_y - min_y;
            var scale_u = (max_u - min_u) / span_x;
            var scale_v = (max_v - min_v) / span_y;
        }

        // Tessellate
        var vertices = GL.triangulatePolygon(polygon);

        // Add vertex data
        var num_vertices = vertices.length;
        for (var v=0; v < num_vertices; v++) {
            var vertex = vertices[v];
            vertex_template[0] = vertex[0];
            vertex_template[1] = vertex[1];

            // Add UVs
            if (texcoord_index) {
                vertex_template[texcoord_index + 0] = (vertex[0] - min_x) * scale_u + min_u;
                vertex_template[texcoord_index + 1] = (vertex[1] - min_y) * scale_v + min_v;
            }

            vertex_data.addVertex(vertex_template);
        }
    }
};

// Tesselate and extrude a flat 2D polygon into a simple 3D model with fixed height and add to GL vertex buffer
GLBuilders.buildExtrudedPolygons = function (
    polygons,
    z, height, min_height,
    vertex_data, vertex_template,
    normal_index,
    { texcoord_index, texcoord_scale }) {

    var min_z = z + (min_height || 0);
    var max_z = z + height;
    var [[min_u, min_v], [max_u, max_v]] = texcoord_scale || [[0, 0], [1, 1]];

    // Top
    vertex_template[2] = max_z;
    GLBuilders.buildPolygons(polygons, vertex_data, vertex_template, { texcoord_index });

    // Walls
    var num_polygons = polygons.length;
    for (var p=0; p < num_polygons; p++) {
        var polygon = polygons[p];

        for (var q=0; q < polygon.length; q++) {
            var contour = polygon[q];

            for (var w=0; w < contour.length - 1; w++) {
                // Two triangles for the quad formed by each vertex pair, going from bottom to top height
                var wall_vertices = [
                    // Triangle
                    [contour[w+1][0], contour[w+1][1], max_z],
                    [contour[w+1][0], contour[w+1][1], min_z],
                    [contour[w][0], contour[w][1], min_z],
                    // Triangle
                    [contour[w][0], contour[w][1], min_z],
                    [contour[w][0], contour[w][1], max_z],
                    [contour[w+1][0], contour[w+1][1], max_z]
                ];

                // Fit UVs to wall quad
                if (texcoord_index) {
                    var texcoords = [
                        [min_u, max_v],
                        [min_u, min_v],
                        [max_u, min_v],

                        [max_u, min_v],
                        [max_u, max_v],
                        [min_u, max_v]
                    ];
                }

                // Calc the normal of the wall from up vector and one segment of the wall triangles
                var normal = Vector.cross(
                    [0, 0, 1],
                    Vector.normalize([contour[w+1][0] - contour[w][0], contour[w+1][1] - contour[w][1], 0])
                );

                // Update vertex template with current surface normal
                vertex_template[normal_index + 0] = normal[0];
                vertex_template[normal_index + 1] = normal[1];
                vertex_template[normal_index + 2] = normal[2];

                for (var wv=0; wv < wall_vertices.length; wv++) {
                    vertex_template[0] = wall_vertices[wv][0];
                    vertex_template[1] = wall_vertices[wv][1];
                    vertex_template[2] = wall_vertices[wv][2];

                    if (texcoord_index) {
                        vertex_template[texcoord_index + 0] = texcoords[wv][0];
                        vertex_template[texcoord_index + 1] = texcoords[wv][1];
                    }

                    vertex_data.addVertex(vertex_template);
                }
            }
        }
    }
};

// Build tessellated triangles for a polyline
// Basically following the method described here for miter joints:
// http://artgrammer.blogspot.co.uk/2011/07/drawing-polylines-by-tessellation.html
GLBuilders.buildPolylines = function (
    lines,
    z, width,
    vertex_data, vertex_template,
    {
        closed_polygon,
        remove_tile_edges,
        texcoord_index,
        texcoord_scale,
        scaling_index
    }) {

    // Build triangles
    var vertices = [],
        scalingVecs = [],   //  vertices directions for then (on GLSL vertex shader) extrude
        texcoords = [],
        halfWidth = width/2,
        num_lines = lines.length;

    var [[min_u, min_v], [max_u, max_v]] = texcoord_scale || [[0, 0], [1, 1]];

    for (var ln = 0; ln < num_lines; ln++) {
        var line = lines[ln];
        var lineSize = line.length;

        if (line.length > 2) {

            var normPrevCurr; // Right normal to segment between previous and current m_points
            var normCurrNext; // Right normal to segment between current and next m_points
            var rightNorm; // Right "normal" at current point, scaled for miter joint

            var prevCoord; // Previous point coordinates
            var currCoord = lines[0]; // Current point coordinates
            var nextCoord = lines[1]; // Next point coordinates

            normCurrNext[0] = nextCoord[1] - currCoord[1];
            normCurrNext[1] = currCoord[0] - nextCoord[0];
            normCurrNext = Vector.normalize(normCurrNext);

            rightNorm = normCurrNext;

            for(var i = 1; i < lineSize - 1 ; i++){
                prevCoord = currCoord;
                currCoord = nextCoord;
                nextCoord = line[i+1];

                normPrevCurr = normCurrNext;

                normCurrNext[0] = nextCoord[1] - currCoord[1];
                normCurrNext[1] = currCoord[0] - nextCoord[0];

                rightNorm = normPrevCurr + normCurrNext;
                rightNorm = Vector.normalize(rightNorm);
                var scale = Math.sqrt(2. / (1. + Vector.dot(normPrevCurr,normCurrNext)));
                rightNorm *= scale;

                if (scaling_index) {
                    vertices.push(currCoord);
                    vertices.push(currCoord);
                    scalingVecs.push(rightNorm);
                    scalingVecs.push(-rightNorm);
                } else {
                    vertices.push([ currCoord[0] + rightNorm[0] * halfWidth, currCoord[1] + rightNorm[1] * halfWidth, z ]);
                    vertices.push([ currCoord[0] - rightNorm[0] * halfWidth, currCoord[1] - rightNorm[1] * halfWidth, z ]);
                }

                // Add UVs
                if (texcoord_index) {
                    var frac = i/lineSize;
                    texcoords.push( [max_u, min_v+frac*max_v],
                                    [min_u, min_v+frac*max_v] );
                }
            }

            normCurrNext = Vector.normalize(normCurrNext);

            if (scaling_index) {
                vertices.push(nextCoord);
                vertices.push(nextCoord);
                scalingVecs.push(rightNorm);
                scalingVecs.push(-rightNorm);
            } else {
                vertices.push([currCoord[0] + rightNorm[0] * halfWidth, currCoord[1] + rightNorm[1] * halfWidth, z]);
                vertices.push([currCoord[0] - rightNorm[0] * halfWidth, currCoord[1] - rightNorm[1] * halfWidth, z]);
            }

            if (texcoord_index) {
                texcoords.push( [max_u, max_v],
                                [min_u, max_v] );
            }
        }
    }

    // Add vertices to buffer
    for (var v=0; v < vertices.length; v++) {
        vertex_template[0] = vertices[v][0];
        vertex_template[1] = vertices[v][1];

        // Add UVs
        if (texcoord_index) {
            vertex_template[texcoord_index + 0] = texcoords[v][0];
            vertex_template[texcoord_index + 1] = texcoords[v][1];
        }

        // Add Scaling vertex ( X,Y normal direction + Z haltwidth as attribute )
        if (scaling_index) {
            vertex_template[scaling_index + 0] = scalingVecs[v][0];
            vertex_template[scaling_index + 1] = scalingVecs[v][1];
            vertex_template[scaling_index + 2] = halfWidth;
        }

        vertex_data.addVertex(vertex_template);
    }
};

// Build a quad centered on a point
GLBuilders.buildQuadsForPoints = function (
    points, width, height,
    vertex_data, vertex_template,
    { texcoord_index, texcoord_scale }) {

    var [[min_u, min_v], [max_u, max_v]] = texcoord_scale || [[0, 0], [1, 1]];
    var num_points = points.length;
    for (var p=0; p < num_points; p++) {
        var point = points[p];

        var positions = [
            [point[0] - width/2, point[1] - height/2],
            [point[0] + width/2, point[1] - height/2],
            [point[0] + width/2, point[1] + height/2],

            [point[0] - width/2, point[1] - height/2],
            [point[0] + width/2, point[1] + height/2],
            [point[0] - width/2, point[1] + height/2],
        ];

        if (texcoord_index) {
            var texcoords = [
                [min_u, min_v],
                [max_u, min_v],
                [max_u, max_v],

                [min_u, min_v],
                [max_u, max_v],
                [min_u, max_v]
            ];
        }

        for (var pos=0; pos < 6; pos++) {
            // Add texcoords
            if (texcoord_index) {
                vertex_template[texcoord_index + 0] = texcoords[pos][0];
                vertex_template[texcoord_index + 1] = texcoords[pos][1];
            }

            vertex_template[0] = positions[pos][0];
            vertex_template[1] = positions[pos][1];
            vertex_data.addVertex(vertex_template);
        }
    }
};

/* Utility functions */

// Tests if a line segment (from point A to B) is nearly coincident with the edge of a tile
GLBuilders.isOnTileEdge = function (pa, pb, options)
{
    options = options || {};

    var tolerance_function = options.tolerance_function || GLBuilders.valuesWithinTolerance;
    var tolerance = options.tolerance || 1; // tweak this adjust if catching too few/many line segments near tile edges
    var tile_min = GLBuilders.tile_bounds[0];
    var tile_max = GLBuilders.tile_bounds[1];
    var edge = null;

    if (tolerance_function(pa[0], tile_min.x, tolerance) && tolerance_function(pb[0], tile_min.x, tolerance)) {
        edge = 'left';
    }
    else if (tolerance_function(pa[0], tile_max.x, tolerance) && tolerance_function(pb[0], tile_max.x, tolerance)) {
        edge = 'right';
    }
    else if (tolerance_function(pa[1], tile_min.y, tolerance) && tolerance_function(pb[1], tile_min.y, tolerance)) {
        edge = 'top';
    }
    else if (tolerance_function(pa[1], tile_max.y, tolerance) && tolerance_function(pb[1], tile_max.y, tolerance)) {
        edge = 'bottom';
    }
    return edge;
};

GLBuilders.setTileScale = function (scale)
{
    GLBuilders.tile_bounds = [
        { x: 0, y: 0},
        { x: scale, y: -scale } // TODO: correct for flipped y-axis?
    ];
};

GLBuilders.valuesWithinTolerance = function (a, b, tolerance)
{
    tolerance = tolerance || 1;
    return (Math.abs(a - b) < tolerance);
};

// Build a zigzag line pattern for testing joins and caps
GLBuilders.buildZigzagLineTestPattern = function ()
{
    var min = { x: 0, y: 0}; //  tile.min;
    var max = { x: 4096, y: 4096 }; // tile.max;

    var g = {
        id: 123,
        geometry: {
            type: 'LineString',
            coordinates: [
                [min.x * 0.75 + max.x * 0.25, min.y * 0.75 + max.y * 0.25],
                [min.x * 0.75 + max.x * 0.25, min.y * 0.5 + max.y * 0.5],
                [min.x * 0.25 + max.x * 0.75, min.y * 0.75 + max.y * 0.25],
                [min.x * 0.25 + max.x * 0.75, min.y * 0.25 + max.y * 0.75],
                [min.x * 0.4 + max.x * 0.6, min.y * 0.5 + max.y * 0.5],
                [min.x * 0.5 + max.x * 0.5, min.y * 0.25 + max.y * 0.75],
                [min.x * 0.75 + max.x * 0.25, min.y * 0.25 + max.y * 0.75],
                [min.x * 0.75 + max.x * 0.25, min.y * 0.4 + max.y * 0.6]
            ]
        },
        properties: {
            kind: 'debug'
        }
    };
    return g;
};
<|endoftext|>