<commit_before>/****************************************************************************
    url.js-extensions.js,

    (c) 2016, FCOO

    https://github.com/FCOO/url.js-extensions
    https://github.com/FCOO

****************************************************************************/

(function ($, window, document, undefined) {
    "use strict";

    /******************************************
    anyString(name, notDecoded, search, sep)
    Copy of Url.queryString with optional input string (search)
    and separaator (sep)
    ******************************************/
    function anyString(name, notDecoded, search, sep){
        name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");

        var regex = new RegExp("[\\"+sep+"&]" + name + "=([^&#]*)")
          , results = regex.exec(search)
          , encoded = null
          ;

        if (results === null) {
            regex = new RegExp("[\\"+sep+"&]" + name + "(\\&([^&#]*)|$)");
            if (regex.test(search)) {
                return true;
            }
            return undefined;
        } else {
            encoded = results[1].replace(/\+/g, " ");
            if (notDecoded) {
                return encoded;
            }
            return decodeURIComponent(encoded);
        }
    }

    /******************************************
    _upateSearchAndHash
    *******************************************/
    function _upateSearchAndHash( searchStr, hashStr ){
        return this._updateAll(
                   window.location.pathname +
                   (searchStr ? '?' + searchStr : '') +
                   (hashStr  ? '#' + hashStr  : '')
               );
    }

    /******************************************
    _correctSearchOrHash
    Check and correct search or hash = ID_VALUE[&ID_VALUE]
        ID_VALUE =
            ID or
            ID=VALUE or
            ID=VALUE,VALUE2,...,VALUEN
        VALUE contains only a-z 0-9 - _ SPACE
        ID contains only a-z 0-9 - _
    *******************************************/
    function _correctSearchOrHash( str, preChar ){
        function decodeStr( str ){
            try {
                decodeURIComponent( str );
                return decodeURIComponent( str );
            }
            catch(err) {
                return undefined;
            }
        }

        //Chack and correct the parameter and/or hash-tag
        preChar = preChar || '#';

        var strList,
            result = '',
            idRegEx = new RegExp(/[\w\-_]+/),
            idValues, id, values, value, oneValueOk, i, j;

        //Convert to char
        str = str.replace(/%3D/g, '=');
        str = str.replace(/%2C/g, ',');
        str = str.replace(/%3F/g, '?');
        str = str.replace(/%23/g, '#');
        str = str.replace(/%7B/g, '{');
        str = str.replace(/%7D/g, '}');
        str = str.replace(/%2B/g, '+');
        str = str.replace(/%22/g, '"');
        str = str.replace(/%3A/g, ':');

        //Remove pre-char
        while (str.length && (str.charAt(0) == preChar) )
            str = str.slice(1);

        strList = str.split('&');

        for (i=0; i<strList.length; i++ ){
            idValues = strList[i].split('=');
            id = decodeStr( idValues[0] );
            values = idValues[1] || undefined;
            oneValueOk = false;
            if ( id && (idRegEx.exec(id) == id ) ){
                //Correct id
                if (values === undefined){
                    oneValueOk = true;
                    valueList = [];
                }
                else {
                    //Check syntax of values
                    var valueList = values.split(',');
                    for (j=0; j<valueList.length; j++ ){
                        value = decodeStr( valueList[j] );
                        if ( value ){
                            if (value == 'undefined')
                              valueList[j] = 'false';
                            oneValueOk = true;
                        }
                        else
                            valueList[j] = undefined;
                    }
                }
                if ( oneValueOk ){
                    result += (result ? '&' : '') + id;
                    var firstValue = true;
                    for (j=0; j<valueList.length; j++ ){
                        value = valueList[j];
                        result += (firstValue ? '=' : ',') + (value ? value : '');
                        firstValue = false;
                    }
                }
            } //end of correct id
        }
        return decodeURIComponent(result);
    }

    /******************************************
    adjustUrl
    Check and correct the url
    *******************************************/
    function adjustUrl(){
        return this._upateSearchAndHash(
                   this._correctSearchOrHash( window.location.search, '?' ),
                   this._correctSearchOrHash( window.location.hash, '#' )
               );
    }

    /******************************************
    hashString
    Same as queryString but for the hash
    It is a adjusted copy of queryString
    *******************************************/
    function hashString(name, notDecoded){
        return anyString(name, notDecoded, window.location.hash, '#');
    }

    /******************************************
    parseHash
    Same as parseQuery but for the hash
    *******************************************/
    function parseHash(){
        return this.parseQuery( this.hash() );
    }

    /******************************************
    updateHashParam
    Same as updateSearchParam but for the hash
    *******************************************/
    function updateHashParam(hashParam, value, triggerPopState){
        var hashParsed = this.parseHash();
        if (value === undefined){
            delete hashParsed[hashParam];
        }
        else {
            if (hashParsed[hashParam] === value)
                return this;
            hashParsed[hashParam] = value;
        }
        this.hash (this.stringify(hashParsed), triggerPopState);
        return this;
    }

    /******************************************
    validateValue
    Validate value using validator
    validator = regExp | function( value ) | array of validator
    *******************************************/
    function validateJSONValue( value ){
        try {
            var jsonObj = JSON.parse( value );
            if ($.type( jsonObj ) == 'object')
                return true;
        }
        catch (e) {
            return false;
        }
        return false;
    }

    function validateValue( value, validator ){
        //Convert Boolean into String
        if ($.type( value ) === "boolean")
            value = value ? 'true' : 'false';
        value = value || '';

        if (validator === undefined)
            return true;

        if ( $.isFunction(validator) )
          return !!validator( value );

        if ( $.isArray(validator) ){
            var result = true;
            $.each( validator, function( index, _validator ){
                if ( !validateValue( value, _validator) ){
                    result = false;
                    return false;
                }
            });
            return result;
        }
        switch (validator){
            case 'BOOLEAN' : validator = /true|false/;           break;
            case 'NUMBER'  : validator = /[-+]?[0-9]*\.?[0-9]+/; break;
            case 'NOTEMPTY': validator = /.+/;                   break;

            //Special case for json-object-string
            case 'JSON'    : return validateValue( value, validateJSONValue);
        }

        var regExp = new RegExp(validator),
            execResult = regExp.exec(value);
        return !!(execResult && (execResult.length == 1) && (execResult[0] == value));
    }

    /******************************************
    parseAll( validatorObj, defaultObj, options )
    Parse the combined query-string and hash-tags
    Returns a object with `id: value` for both query-string and hash-tags

    validatorObj: object with {id: validator,..}. Failed values are removed
    defaultObj  : object with {id: value}. Values to be used if `id` is missing or fails validation
    options: {
        convertBoolean: Boolean (default = true ) If true all values == "true" or "false" are converted into Boolean
        convertNumber : Boolean (default = true ) If true all values representing a number is converted to float
        convertJSON   : Boolean (default = true ) If true all values representing a stringify json-object is converted to a real json-object
        queryOverHash : Boolean (default = true ) If true and the same id is given in both query-string and hash-tag the value from query-string is returned.
                                                  If false the value from hash-tag is returned
        updateUrl     : Boolean (default = true ) If true failed {id=value} are removed and any defaultObj {id:value} added to the url
    }

    *******************************************/
    function parseAll( validatorObj, defaultObj, options ){
        validatorObj = validatorObj || {};
        defaultObj = defaultObj || {};
        options = $.extend( {}, options, {
            convertBoolean: true,
            convertNumber : true,
            convertJSON   : true,
            queryOverHash : true,
            updateUrl     : true
        });

        var _this = this;

        //*****************************************************************
        function parseObj( str ){

            var obj = _this.parseQuery( str );
            //Use anyString(..) to get adjusted value
            $.each( obj, function( id/*, value*/ ){
                obj[id] = anyString(id, true, '?'+str, '?');
            });

            //Validate all values
            $.each( obj, function( id, value ){
                //Validate value
                if ( !_this.validateValue( value, validatorObj[id] ) )
                  value = undefined;

                //Convert "true" and false" to Boolean
                if ( options.convertBoolean && ( (value == 'true') || (value == 'false') ) )
                  value = (value == 'true');

                //Convert String to Float
                if (options.convertNumber && _this.validateValue( value, 'NUMBER') ){
                    value = parseFloat( value );
                }

                //Remove deleted keys
                if (value === undefined)
                    delete obj[id];
                else
                    obj[id] = value;
            });

            return obj;
        }
        //*****************************************************************

        var queryObj = parseObj( this._correctSearchOrHash( window.location.search, '?' ) ),
            hashObj  = parseObj( this._correctSearchOrHash( window.location.hash,   '#' ) );

        //Update url
        if (options.updateUrl)
            this._upateSearchAndHash(
                decodeURIComponent( this.stringify(queryObj) ),
                decodeURIComponent( this.stringify(hashObj) )
            );

        var result = $.extend( options.queryOverHash ? hashObj  : queryObj,
                               options.queryOverHash ? queryObj : hashObj   );

        //Convert String to json-object
        if (options.convertJSON)
            $.each( result, function( id, value ){
                if ( _this.validateValue( value, 'JSON') )
                    result[id] = JSON.parse( value );
            });

        //Insert default values
        $.each( defaultObj, function( id, value ){
            if (result[id] === undefined)
              result[id] = value;
        });
        return result;
    }

    function onHashChange(){
        this.adjustUrl();
    }

    //Extend window.Url with the new methods
    $.extend( window.Url, {
        _upateSearchAndHash  : _upateSearchAndHash,
        _correctSearchOrHash : _correctSearchOrHash,
        adjustUrl            : adjustUrl,
        hashString           : hashString,
        parseHash            : parseHash,
        updateHashParam      : updateHashParam,
        validateValue        : validateValue,
        parseAll             : parseAll,
        onHashChange         : onHashChange
    });

    $(window).on( 'hashchange', $.proxy( onHashChange, window.Url ) );

    /******************************************
    Initialize/ready
    *******************************************/
    $(function() {
        window.Url.adjustUrl();
    });
    //******************************************

}(jQuery, this, document));

/******************************************
Variables in window.location making up the full url

var newURL = window.location.protocol + "//" + window.location.host + "/" + window.location.pathname + window.location.search + window.location.hash;

window.location.protocol
window.location.host
window.location.pathname
window.location.search
window.location.hash

******************************************/
<commit_msg>Bug fix: Using encodeURI(..) in _upateSearchAndHash prevents 2xfire hashchange-event<commit_after>/****************************************************************************
    url.js-extensions.js,

    (c) 2016, FCOO

    https://github.com/FCOO/url.js-extensions
    https://github.com/FCOO

****************************************************************************/

(function ($, window, document, undefined) {
    "use strict";

    /******************************************
    anyString(name, notDecoded, search, sep)
    Copy of Url.queryString with optional input string (search)
    and separaator (sep)
    ******************************************/
    function anyString(name, notDecoded, search, sep){
        name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");

        var regex = new RegExp("[\\"+sep+"&]" + name + "=([^&#]*)")
          , results = regex.exec(search)
          , encoded = null
          ;

        if (results === null) {
            regex = new RegExp("[\\"+sep+"&]" + name + "(\\&([^&#]*)|$)");
            if (regex.test(search)) {
                return true;
            }
            return undefined;
        } else {
            encoded = results[1].replace(/\+/g, " ");
            if (notDecoded) {
                return encoded;
            }
            return decodeURIComponent(encoded);
        }
    }

    /******************************************
    _upateSearchAndHash
    *******************************************/
    function _upateSearchAndHash( searchStr, hashStr ){
        return this._updateAll(
                   window.location.pathname +
                   (searchStr ? '?' + encodeURI(searchStr) : '') +
                   (hashStr  ? '#' + encodeURI(hashStr)  : '')
               );
    }

    /******************************************
    _correctSearchOrHash
    Check and correct search or hash = ID_VALUE[&ID_VALUE]
        ID_VALUE =
            ID or
            ID=VALUE or
            ID=VALUE,VALUE2,...,VALUEN
        VALUE contains only a-z 0-9 - _ SPACE
        ID contains only a-z 0-9 - _
    *******************************************/
    function _correctSearchOrHash( str, preChar ){
        function decodeStr( str ){
            try {
                decodeURIComponent( str );
                return decodeURIComponent( str );
            }
            catch(err) {
                return undefined;
            }
        }

        //Chack and correct the parameter and/or hash-tag
        preChar = preChar || '#';

        var strList,
            result = '',
            idRegEx = new RegExp(/[\w\-_]+/),
            idValues, id, values, value, oneValueOk, i, j;

        //Convert to char
        str = str.replace(/%3D/g, '=');
        str = str.replace(/%2C/g, ',');
        str = str.replace(/%3F/g, '?');
        str = str.replace(/%23/g, '#');
        str = str.replace(/%7B/g, '{');
        str = str.replace(/%7D/g, '}');
        str = str.replace(/%2B/g, '+');
        str = str.replace(/%22/g, '"');
        str = str.replace(/%3A/g, ':');

        //Remove pre-char
        while (str.length && (str.charAt(0) == preChar) )
            str = str.slice(1);

        strList = str.split('&');

        for (i=0; i<strList.length; i++ ){
            idValues = strList[i].split('=');
            id = decodeStr( idValues[0] );
            values = idValues[1] || undefined;
            oneValueOk = false;
            if ( id && (idRegEx.exec(id) == id ) ){
                //Correct id
                if (values === undefined){
                    oneValueOk = true;
                    valueList = [];
                }
                else {
                    //Check syntax of values
                    var valueList = values.split(',');
                    for (j=0; j<valueList.length; j++ ){
                        value = decodeStr( valueList[j] );
                        if ( value ){
                            if (value == 'undefined')
                              valueList[j] = 'false';
                            oneValueOk = true;
                        }
                        else
                            valueList[j] = undefined;
                    }
                }
                if ( oneValueOk ){
                    result += (result ? '&' : '') + id;
                    var firstValue = true;
                    for (j=0; j<valueList.length; j++ ){
                        value = valueList[j];
                        result += (firstValue ? '=' : ',') + (value ? value : '');
                        firstValue = false;
                    }
                }
            } //end of correct id
        }
        return decodeURIComponent(result);
    }

    /******************************************
    adjustUrl
    Check and correct the url
    *******************************************/
    function adjustUrl(){
        return this._upateSearchAndHash(
                   this._correctSearchOrHash( window.location.search, '?' ),
                   this._correctSearchOrHash( window.location.hash, '#' )
               );
    }

    /******************************************
    hashString
    Same as queryString but for the hash
    It is a adjusted copy of queryString
    *******************************************/
    function hashString(name, notDecoded){
        return anyString(name, notDecoded, window.location.hash, '#');
    }

    /******************************************
    parseHash
    Same as parseQuery but for the hash
    *******************************************/
    function parseHash(){
        return this.parseQuery( this.hash() );
    }

    /******************************************
    updateHashParam
    Same as updateSearchParam but for the hash
    *******************************************/
    function updateHashParam(hashParam, value, triggerPopState){
        var hashParsed = this.parseHash();
        if (value === undefined){
            delete hashParsed[hashParam];
        }
        else {
            if (hashParsed[hashParam] === value)
                return this;
            hashParsed[hashParam] = value;
        }
        this.hash (this.stringify(hashParsed), triggerPopState);
        return this;
    }

    /******************************************
    validateValue
    Validate value using validator
    validator = regExp | function( value ) | array of validator
    *******************************************/
    function validateJSONValue( value ){
        try {
            var jsonObj = JSON.parse( value );
            if ($.type( jsonObj ) == 'object')
                return true;
        }
        catch (e) {
            return false;
        }
        return false;
    }

    function validateValue( value, validator ){
        //Convert Boolean into String
        if ($.type( value ) === "boolean")
            value = value ? 'true' : 'false';
        value = value || '';

        if (validator === undefined)
            return true;

        if ( $.isFunction(validator) )
          return !!validator( value );

        if ( $.isArray(validator) ){
            var result = true;
            $.each( validator, function( index, _validator ){
                if ( !validateValue( value, _validator) ){
                    result = false;
                    return false;
                }
            });
            return result;
        }
        switch (validator){
            case 'BOOLEAN' : validator = /true|false/;           break;
            case 'NUMBER'  : validator = /[-+]?[0-9]*\.?[0-9]+/; break;
            case 'NOTEMPTY': validator = /.+/;                   break;

            //Special case for json-object-string
            case 'JSON'    : return validateValue( value, validateJSONValue);
        }

        var regExp = new RegExp(validator),
            execResult = regExp.exec(value);
        return !!(execResult && (execResult.length == 1) && (execResult[0] == value));
    }

    /******************************************
    parseAll( validatorObj, defaultObj, options )
    Parse the combined query-string and hash-tags
    Returns a object with `id: value` for both query-string and hash-tags

    validatorObj: object with {id: validator,..}. Failed values are removed
    defaultObj  : object with {id: value}. Values to be used if `id` is missing or fails validation
    options: {
        convertBoolean: Boolean (default = true ) If true all values == "true" or "false" are converted into Boolean
        convertNumber : Boolean (default = true ) If true all values representing a number is converted to float
        convertJSON   : Boolean (default = true ) If true all values representing a stringify json-object is converted to a real json-object
        queryOverHash : Boolean (default = true ) If true and the same id is given in both query-string and hash-tag the value from query-string is returned.
                                                  If false the value from hash-tag is returned
        updateUrl     : Boolean (default = true ) If true failed {id=value} are removed and any defaultObj {id:value} added to the url
    }

    *******************************************/
    function parseAll( validatorObj, defaultObj, options ){
        validatorObj = validatorObj || {};
        defaultObj = defaultObj || {};
        options = $.extend( {}, options, {
            convertBoolean: true,
            convertNumber : true,
            convertJSON   : true,
            queryOverHash : true,
            updateUrl     : true
        });

        var _this = this;

        //*****************************************************************
        function parseObj( str ){

            var obj = _this.parseQuery( str );
            //Use anyString(..) to get adjusted value
            $.each( obj, function( id/*, value*/ ){
                obj[id] = anyString(id, true, '?'+str, '?');
            });

            //Validate all values
            $.each( obj, function( id, value ){
                //Validate value
                if ( !_this.validateValue( value, validatorObj[id] ) )
                  value = undefined;

                //Convert "true" and false" to Boolean
                if ( options.convertBoolean && ( (value == 'true') || (value == 'false') ) )
                  value = (value == 'true');

                //Convert String to Float
                if (options.convertNumber && _this.validateValue( value, 'NUMBER') ){
                    value = parseFloat( value );
                }

                //Remove deleted keys
                if (value === undefined)
                    delete obj[id];
                else
                    obj[id] = value;
            });

            return obj;
        }
        //*****************************************************************

        var queryObj = parseObj( this._correctSearchOrHash( window.location.search, '?' ) ),
            hashObj  = parseObj( this._correctSearchOrHash( window.location.hash,   '#' ) );

        //Update url
        if (options.updateUrl)
            this._upateSearchAndHash(
                decodeURIComponent( this.stringify(queryObj) ),
                decodeURIComponent( this.stringify(hashObj) )
            );

        var result = $.extend( options.queryOverHash ? hashObj  : queryObj,
                               options.queryOverHash ? queryObj : hashObj   );

        //Convert String to json-object
        if (options.convertJSON)
            $.each( result, function( id, value ){
                if ( _this.validateValue( value, 'JSON') )
                    result[id] = JSON.parse( value );
            });

        //Insert default values
        $.each( defaultObj, function( id, value ){
            if (result[id] === undefined)
              result[id] = value;
        });
        return result;
    }

    /******************************************
    onHashChange()
    ******************************************/
    function onHashChange(){
        this.adjustUrl();
    }

    //Extend window.Url with the new methods
    $.extend( window.Url, {
        _upateSearchAndHash  : _upateSearchAndHash,
        _correctSearchOrHash : _correctSearchOrHash,
        adjustUrl            : adjustUrl,
        hashString           : hashString,
        parseHash            : parseHash,
        updateHashParam      : updateHashParam,
        validateValue        : validateValue,
        parseAll             : parseAll,
        onHashChange         : onHashChange
    });

    $(window).on( 'hashchange', $.proxy( onHashChange, window.Url ) );

    /******************************************
    Initialize/ready
    *******************************************/
    $(function() {
        window.Url.adjustUrl();
    });
    //******************************************

}(jQuery, this, document));

/******************************************
Variables in window.location making up the full url

var newURL = window.location.protocol + "//" + window.location.host + "/" + window.location.pathname + window.location.search + window.location.hash;

window.location.protocol
window.location.host
window.location.pathname
window.location.search
window.location.hash

******************************************/
<|endoftext|>


<commit_before>/*
 * Javascript for DSV's Polopoly instance
 */

$(function () {
    var APP_URI = '//www2.dsv.su.se/daisyweb/';
    var DAISY_HOST = 'daisy.dsv.su.se';
    var DAISY_DIMS = {
        '/servlet/Momentinfo':                        [640, 450],
        '/servlet/anstalld.Anstalldinfo':             [500, 250],
        '/anstalld/anstalldinfo.jspa':                [500, 250],
        '/servlet/schema.moment.Momentschema':        [500, 500],
        '/servlet/student.Studentinfo':               [400, 300],
        '/anstalld/publikation/publicationInfo.jspa': [500, 500]
    };
    var THROBBER_URI = '//www2.dsv.su.se/images/throbber.gif';
    var lang = $('html').attr('lang');

    function handleDaisyPopupClick() {
        var dims = DAISY_DIMS[this.pathname];
        if (dims) {
            window.open(this.href, '_blank',
                        'scrollbars=yes,resizable=yes,width=' + dims[0] +
                        ',height=' + dims[1]);
            return false;
        } else {
            return true;
        }
    }

    function popupifyDaisyLinks(parent) {
        $('a', parent).filter(function () {
            return this.hostname === DAISY_HOST;
        }).click(handleDaisyPopupClick);
    }

    /*
     * Deserialize a query string.
     *
     * Based on code from
     * http://stackoverflow.com/questions/1131630
     */
    function deparam(query) {
        var hash = {};
        if (!query) return hash;
        var vars = query.split("&");

        for (var i = 0; i < vars.length; i++) {
            var pair = vars[i].split("=");
            if (pair.length != 2) continue;
            var k = decodeURIComponent(pair[0]);
            var v = decodeURIComponent(pair[1]);

            if (k.substr(k.length-2) === '[]') {
                if (!hash[k]) hash[k] = [];
                hash[k].push(v);
            } else {
                hash[k] = v;
            }
        }
        return hash;
    }

    function callMacro(element, func, args, extra_query) {
        var action = null;
        var query = {lang: lang};
        var base_uri = APP_URI;

        switch (func) {
        case 'dsv_staff':
        case 'dsv_staff_new':
            action = 'staff.php';
            break;
        case 'all_course_units':
        case 'course_segments':
            action = 'course_segments.php';
            $('<link rel="stylesheet" type="text/css" href="' + base_uri
              + 'css/course_segments.css" />').appendTo('head');
            $.getScript(base_uri + 'js/course_segments.js');
            break;
        case 'search_publications':
            action = 'publications.php';
            break;
        case 'publications':
            action = 'publications.php';
            query.included = 1;
            query.researchArea = args.area.split(',');
            break;
        }

        if (extra_query) $.extend(query, extra_query);

        if (action) {
            qs = $.param(query);
            if (qs !== '') qs = '&' + qs;

            $(element).addClass('dsv-macro-loading');

            function macroLoaded(html) {
                $(element).html(html).removeClass('dsv-macro-loading');
                popupifyDaisyLinks(element);
                $('a[href^="?"]', element).click(function () {
                    callMacro(element, func, args,
                              deparam(this.search.substr(1)));
                    return false;
                });
                $('form', element).submit(function () {
                    // It might seem silly to serialize and then deserialize
                    // the form values, but doing it directly is more code.
                    // (There is no form -> object function in jQuery.)
                    callMacro(element, func, args,
                              deparam($(this).serialize()));
                    return false;
                });
            }

            $.get(base_uri + action + '?' + qs, macroLoaded);
        } else {
            element.text('(Unknown macro.)');
        }
    }

    $('.dsv-macro').each(function () {
        var m = /\[\[([^\]]+)\]\]/.exec($(this).text());
        if (!m) return;
        var macro = m[1];
        m = /^(\S+)\s*/.exec(macro);
        if (!m) return;
        var func = m[1];
        var args = {};
        var arg_re = /(\S+)=("[^"]*"|[^" ]+)/g;
        while ((m = arg_re.exec(macro)) !== null) {
            args[m[1]] = m[2];
        }

        var throbber = $('')
            .attr('src', THROBBER_URI);
        $(this).empty().removeClass('dsv-macro').append(throbber);

        callMacro(this, func, args);
    });

    popupifyDaisyLinks(document);
});
<commit_msg>don't load course_segments.{js,css} twice<commit_after>/*
 * Javascript for DSV's Polopoly instance
 */

$(function () {
    var APP_URI = '//www2.dsv.su.se/daisyweb/';
    var DAISY_HOST = 'daisy.dsv.su.se';
    var DAISY_DIMS = {
        '/servlet/Momentinfo':                        [640, 450],
        '/servlet/anstalld.Anstalldinfo':             [500, 250],
        '/anstalld/anstalldinfo.jspa':                [500, 250],
        '/servlet/schema.moment.Momentschema':        [500, 500],
        '/servlet/student.Studentinfo':               [400, 300],
        '/anstalld/publikation/publicationInfo.jspa': [500, 500]
    };
    var THROBBER_URI = '//www2.dsv.su.se/images/throbber.gif';
    var lang = $('html').attr('lang');

    function handleDaisyPopupClick() {
        var dims = DAISY_DIMS[this.pathname];
        if (dims) {
            window.open(this.href, '_blank',
                        'scrollbars=yes,resizable=yes,width=' + dims[0] +
                        ',height=' + dims[1]);
            return false;
        } else {
            return true;
        }
    }

    function popupifyDaisyLinks(parent) {
        $('a', parent).filter(function () {
            return this.hostname === DAISY_HOST;
        }).click(handleDaisyPopupClick);
    }

    /*
     * Deserialize a query string.
     *
     * Based on code from
     * http://stackoverflow.com/questions/1131630
     */
    function deparam(query) {
        var hash = {};
        if (!query) return hash;
        var vars = query.split("&");

        for (var i = 0; i < vars.length; i++) {
            var pair = vars[i].split("=");
            if (pair.length != 2) continue;
            var k = decodeURIComponent(pair[0]);
            var v = decodeURIComponent(pair[1]);

            if (k.substr(k.length-2) === '[]') {
                if (!hash[k]) hash[k] = [];
                hash[k].push(v);
            } else {
                hash[k] = v;
            }
        }
        return hash;
    }

    function callMacro(element, func, args, extra_query) {
        var action = null;
        var query = {lang: lang};
        var base_uri = APP_URI;

        switch (func) {
        case 'dsv_staff':
        case 'dsv_staff_new':
            action = 'staff.php';
            break;
        case 'all_course_units':
        case 'course_segments':
            action = 'course_segments.php';
            if (!window.footable) {
                $('<link rel="stylesheet" type="text/css" href="' + base_uri
                  + 'css/course_segments.css" />').appendTo('head');
                $.getScript(base_uri + 'js/course_segments.js');
            }
            break;
        case 'search_publications':
            action = 'publications.php';
            break;
        case 'publications':
            action = 'publications.php';
            query.included = 1;
            query.researchArea = args.area.split(',');
            break;
        }

        if (extra_query) $.extend(query, extra_query);

        if (action) {
            qs = $.param(query);
            if (qs !== '') qs = '&' + qs;

            $(element).addClass('dsv-macro-loading');

            function macroLoaded(html) {
                $(element).html(html).removeClass('dsv-macro-loading');
                popupifyDaisyLinks(element);
                $('a[href^="?"]', element).click(function () {
                    callMacro(element, func, args,
                              deparam(this.search.substr(1)));
                    return false;
                });
                $('form', element).submit(function () {
                    // It might seem silly to serialize and then deserialize
                    // the form values, but doing it directly is more code.
                    // (There is no form -> object function in jQuery.)
                    callMacro(element, func, args,
                              deparam($(this).serialize()));
                    return false;
                });
            }

            $.get(base_uri + action + '?' + qs, macroLoaded);
        } else {
            element.text('(Unknown macro.)');
        }
    }

    $('.dsv-macro').each(function () {
        var m = /\[\[([^\]]+)\]\]/.exec($(this).text());
        if (!m) return;
        var macro = m[1];
        m = /^(\S+)\s*/.exec(macro);
        if (!m) return;
        var func = m[1];
        var args = {};
        var arg_re = /(\S+)=("[^"]*"|[^" ]+)/g;
        while ((m = arg_re.exec(macro)) !== null) {
            args[m[1]] = m[2];
        }

        var throbber = $('')
            .attr('src', THROBBER_URI);
        $(this).empty().removeClass('dsv-macro').append(throbber);

        callMacro(this, func, args);
    });

    popupifyDaisyLinks(document);
});
<|endoftext|>


<commit_before>var fs = require('fs');
var parse = require('fast-plist').parse;

var musicLibrayXmlFilename = process.argv[2];

if(!musicLibrayXmlFilename){
	console.error("usage: " + process.argv[0] + " " + process.argv[1] + ' <path to "iTunes Music Library.xml">');
	process.exit(1);
}

function escapeQuotes(s){
	return s.replace(/'/g, "''");
}

function formatRequired(value, isString){
	if(isString){
		return `'${escapeQuotes(value)}'`;
	}
	return value;
}

function formatOptional(value, isString){
	if(value === null || value === undefined){
		return 'NULL';
	}
	return formatRequired(value, isString);
}

function formatLocation(location){
	return decodeURI(location).replace(/^.*iTunes Music\//g, '');
}

function formatDate(date){
	return formatRequired(date.toISOString().replace(/T/, ' ').replace(/\.\d+Z$/, ''), true) + '::timestamp';

}

function formatRequiredInt(d){
	if(!d){
		return 0;
	}
	return d;
}

function objToSql(tableName, obj){
	tableNames = [];
	values = [];
	Object.keys(obj).forEach(function(key){
		tableNames.push(key);
		values.push(obj[key]);
	});

	return `INSERT INTO ${tableName}(${tableNames.join(', ')}) VALUES (${values.join(', ')});`

}

function trackToSql(track){
	var trackTable = "tracks";

	var sqlMap = {
		artist: formatOptional(track.Artist, true),
		name: formatRequired(track.Name, true),
		genre: formatOptional(track.Genre, true),
		composer: formatOptional(track.Composer,  true),
		file_size: formatRequired(track.Size),
		total_time: formatRequired(track['Total Time']),
		year: formatRequired(track.Year),
		file_location: formatRequired(formatLocation(track.Location), true),
		date_added: formatDate(track['Date Added']),
		play_count: formatRequiredInt(track['Play Count']),
		bit_rate: formatRequiredInt(track['Bit Rate'])
	};

	return objToSql(trackTable, sqlMap);
}

function printKeys(obj){
	function formatKey(s){
		return `'\${track["${s}"]}'`
	}
	console.log(Object.keys(obj).map(formatKey).join(', '));
}

function printKinds(tracks){
	var kinds = new Map();

	for(var id in tracks){
		var track = tracks[id];

		if(!kinds.has(track.Kind)){
			kinds.set(track.Kind, 1);
		}
		else{
			kinds.set(track.Kind, kinds.get(track.Kind) + 1);
		}
	}
	console.log(kinds.entries());
}

var plist = parse(fs.readFileSync(musicLibrayXmlFilename, 'utf8'));

var tracks = plist.Tracks;

for(var id in tracks){
	var track = tracks[id];
	if(!track.Kind.match(/\baudio\b/)){
		continue;
	}
	console.log(trackToSql(track));

	// printKeys(track);
	// break;
}

<commit_msg>Rename format int to unsigned int to better reflect functionality<commit_after>var fs = require('fs');
var parse = require('fast-plist').parse;

var musicLibrayXmlFilename = process.argv[2];

if(!musicLibrayXmlFilename){
	console.error("usage: " + process.argv[0] + " " + process.argv[1] + ' <path to "iTunes Music Library.xml">');
	process.exit(1);
}

function escapeQuotes(s){
	return s.replace(/'/g, "''");
}

function formatRequired(value, isString){
	if(isString){
		return `'${escapeQuotes(value)}'`;
	}
	return value;
}

function formatOptional(value, isString){
	if(value === null || value === undefined){
		return 'NULL';
	}
	return formatRequired(value, isString);
}

function formatLocation(location){
	return decodeURI(location).replace(/^.*iTunes Music\//g, '');
}

function formatDate(date){
	return formatRequired(date.toISOString().replace(/T/, ' ').replace(/\.\d+Z$/, ''), true) + '::timestamp';

}

function formatRequiredUnsignedInt(d){
	if(!d){
		return 0;
	}
	return d;
}

function objToSql(tableName, obj){
	tableNames = [];
	values = [];
	Object.keys(obj).forEach(function(key){
		tableNames.push(key);
		values.push(obj[key]);
	});

	return `INSERT INTO ${tableName}(${tableNames.join(', ')}) VALUES (${values.join(', ')});`

}

function trackToSql(track){
	var trackTable = "tracks";

	var sqlMap = {
		artist: formatOptional(track.Artist, true),
		name: formatRequired(track.Name, true),
		genre: formatOptional(track.Genre, true),
		composer: formatOptional(track.Composer,  true),
		file_size: formatRequired(track.Size),
		total_time: formatRequired(track['Total Time']),
		year: formatRequired(track.Year),
		file_location: formatRequired(formatLocation(track.Location), true),
		date_added: formatDate(track['Date Added']),
		play_count: formatRequiredUnsignedInt(track['Play Count']),
		bit_rate: formatRequiredUnsignedInt(track['Bit Rate'])
	};

	return objToSql(trackTable, sqlMap);
}

function printKeys(obj){
	function formatKey(s){
		return `'\${track["${s}"]}'`
	}
	console.log(Object.keys(obj).map(formatKey).join(', '));
}

function printKinds(tracks){
	var kinds = new Map();

	for(var id in tracks){
		var track = tracks[id];

		if(!kinds.has(track.Kind)){
			kinds.set(track.Kind, 1);
		}
		else{
			kinds.set(track.Kind, kinds.get(track.Kind) + 1);
		}
	}
	console.log(kinds.entries());
}

var plist = parse(fs.readFileSync(musicLibrayXmlFilename, 'utf8'));

var tracks = plist.Tracks;

for(var id in tracks){
	var track = tracks[id];
	if(!track.Kind.match(/\baudio\b/)){
		continue;
	}
	console.log(trackToSql(track));

	// printKeys(track);
	// break;
}

<|endoftext|>


<commit_before>/*
 * grunt-carpenter
 * https://github.com/TxSSC/grunt-carpenter
 *
 * Copyright (c) 2013 Cody Stoltman
 * Licensed under the MIT license.
 */

'use strict';

var marked = require('marked'),
    Handlebars = require('handlebars');

module.exports = function(grunt) {

  // Set Defaults, should be configurable in Multi-Task
  var defaults = {
    layoutFolder: "templates/layouts",
    templatesFolder: "templates"
  };

  grunt.registerMultiTask('carpenter', 'Your task description goes here.', function() {
    var self = this;

    this.files.forEach(function(f) {

      f.src.forEach(function(item) {

        var options = grunt.util._.clone(defaults);
        options.destination = f.dest;

        if(grunt.file.isDir(item)) {
          expandFolder(item, options);
        }
      });
    });
  });

  var expandFolder = function(dir, options) {
    var files = grunt.file.expand(dir + '/*'),
        config = options || {},
        folders = [];

    // Check for a data.json file and load config
    files.forEach(function(file) {
      var filename = file.split('/').pop();
      if(filename === 'data.json') {
        var data = grunt.file.readJSON(file);
        config = grunt.util._.merge(options, data);
      }
    });

    // Create the filetree giving priority to top level files
    files.forEach(function(file) {
      if(grunt.file.isDir(file)) {
        folders.push(file);
        return false;
      }

      var filename = file.split('/').pop();
      if(filename !== 'data.json') {
        var data = grunt.util._.clone(config);
        data = loadLayouts(data);
        writeFile(file, data);
      }
    });

    // Expand Each Folder
    folders.forEach(function(folder) {
      expandFolder(folder, config);
    });

  };

  /**
   * Extract Metadata from the page head
   */

  var extractMetadata = function(content) {
    var metadata, markdown;

    if (content.slice(0, 3) === '---') {
      var result = content.match(/^-{3,}\s([\s\S]*?)-{3,}(\s[\s\S]*|\s?)$/);
      if ((result != null ? result.length : void 0) === 3) {
        metadata = result[1];
        markdown = result[2];
      } else {
        metadata = '';
        markdown = content;
      }
    }

    return { metadata: metadata, content: markdown };
  };

  /**
   * Build an object from each line of the Metadata
   */

  var buildMetadata = function(content) {
    var obj = {};

    function grabLine(str) {
      var match = str.match(/(\w+):\s+(.*)/);
      obj[match[1]] = match[2];

      str = str.substr(match[0].length).trim();
      if(str.length > 0) grabLine(str);
    }

    grabLine(content);
    return obj;
  };

  var writeFile = function(path, options) {
    var file = grunt.file.read(path),
        metadata = extractMetadata(file),
        dest = options.destination || "",
        data = buildMetadata(metadata.metadata),
        destination;

    data.content = marked(metadata.content);
    grunt.util._.merge(data, options);

    path = path.split('content/')[1];
    destination = dest + '/' + path.split('.md')[0] + '.html';

    if(options.template) {
      data.content = compileTemplate(options.template, data);
    }

    if(options.layout) {
      data.content = compileTemplate(options.layout, data);
    }

    grunt.file.write(destination, data.content);
  };

  // Set the Layout and Template value, should be per file
  var loadLayouts = function(options) {
    options.layout = options.layout ?
      grunt.file.read(options.layoutFolder + "/"  + options.layout) : "{{{content}}}";

    options.template = options.template ?
      grunt.file.read(options.templatesFolder + "/"  + options.template) : "{{{content}}}";

    return options;
  };

  // Compile the Template using Handlebars
  var compileTemplate = function(template, data) {
    var fn = Handlebars.compile(template);
    return fn(data);
  };

};
<commit_msg>fix issue where build fails if no metadata is present<commit_after>/*
 * grunt-carpenter
 * https://github.com/TxSSC/grunt-carpenter
 *
 * Copyright (c) 2013 Cody Stoltman
 * Licensed under the MIT license.
 */

'use strict';

var marked = require('marked'),
    Handlebars = require('handlebars');

module.exports = function(grunt) {

  // Set Defaults, should be configurable in Multi-Task
  var defaults = {
    layoutFolder: "templates/layouts",
    templatesFolder: "templates"
  };

  grunt.registerMultiTask('carpenter', 'Your task description goes here.', function() {
    var self = this;

    this.files.forEach(function(f) {

      f.src.forEach(function(item) {

        var options = grunt.util._.clone(defaults);
        options.destination = f.dest;

        if(grunt.file.isDir(item)) {
          expandFolder(item, options);
        }
      });
    });
  });

  var expandFolder = function(dir, options) {
    var files = grunt.file.expand(dir + '/*'),
        config = options || {},
        folders = [];

    // Check for a data.json file and load config
    files.forEach(function(file) {
      var filename = file.split('/').pop();
      if(filename === 'data.json') {
        var data = grunt.file.readJSON(file);
        config = grunt.util._.merge(options, data);
      }
    });

    // Create the filetree giving priority to top level files
    files.forEach(function(file) {
      if(grunt.file.isDir(file)) {
        folders.push(file);
        return false;
      }

      var filename = file.split('/').pop();
      if(filename !== 'data.json') {
        var data = grunt.util._.clone(config);
        data = loadLayouts(data);
        writeFile(file, data);
      }
    });

    // Expand Each Folder
    folders.forEach(function(folder) {
      expandFolder(folder, config);
    });

  };

  /**
   * Extract Metadata from the page head
   */

  var extractMetadata = function(content) {
    var metadata, markdown;

    if (content.slice(0, 3) === '---') {
      var result = content.match(/^-{3,}\s([\s\S]*?)-{3,}(\s[\s\S]*|\s?)$/);
      if ((result != null ? result.length : void 0) === 3) {
        metadata = result[1];
        markdown = result[2];
      } else {
        metadata = '';
        markdown = content;
      }
    } else {
      metadata = '';
      markdown = content;
    }

    return { metadata: metadata, content: markdown };
  };

  /**
   * Build an object from each line of the Metadata
   */

  var buildMetadata = function(content) {
    var obj = {};

    function grabLine(str) {
      var match = str.match(/(\w+):\s+(.*)/);
      obj[match[1]] = match[2];

      str = str.substr(match[0].length).trim();
      if(str.length > 0) grabLine(str);
    }

    grabLine(content);
    return obj;
  };

  var writeFile = function(path, options) {
    var file = grunt.file.read(path),
        metadata = extractMetadata(file),
        dest = options.destination || "",
        data = {},
        destination;

    if(metadata.metadata.length > 0) {
      data = buildMetadata(metadata.metadata);
    }

    data.content = marked(metadata.content);
    grunt.util._.merge(data, options);

    path = path.split('content/')[1];
    destination = dest + '/' + path.split('.md')[0] + '.html';

    if(options.template) {
      data.content = compileTemplate(options.template, data);
    }

    if(options.layout) {
      data.content = compileTemplate(options.layout, data);
    }

    grunt.file.write(destination, data.content);
  };

  // Set the Layout and Template value, should be per file
  var loadLayouts = function(options) {
    options.layout = options.layout ?
      grunt.file.read(options.layoutFolder + "/"  + options.layout) : "{{{content}}}";

    options.template = options.template ?
      grunt.file.read(options.templatesFolder + "/"  + options.template) : "{{{content}}}";

    return options;
  };

  // Compile the Template using Handlebars
  var compileTemplate = function(template, data) {
    var fn = Handlebars.compile(template);
    return fn(data);
  };

};
<|endoftext|>


<commit_before>function loadEnv(envFile) {
  require('fs').readFileSync(envFile)
    .toString()
    .split('\n')
    .forEach(function(line) {
      var segments = line.split('='),
          variable = segments[0],
          value = segments[1];

      if ( variable && value ) {
        process.env[variable] = value;
      }
    });
}

function ensureInEnv(variables) {
  variables.forEach(function(variable) {
    if ( !process.env[variable] ) {
      console.log(variable, 'is needed in .env.')
      process.exit(1);
    }
  });
}

function configure(grunt, targetPath, data) {
  var templatePath = targetPath + '.template',
      template = grunt.file.read(templatePath),
      output = grunt.template.process(template, data);

  if ( !grunt.file.exists(targetPath) || grunt.file.read(targetPath) !== output ) {
    grunt.file.write(targetPath, output);
  }
}

function configureGoogleAnalytics(grunt) {
  configure(grunt, 'app/index.html', {
    GOOGLE_ANALYTICS_TOKEN: process.env.GOOGLE_ANALYTICS_TOKEN,
    GOOGLE_ANALYTICS_HOST: process.env.GOOGLE_ANALYTICS_HOST
  });
}

function configureGlobalJson(grunt) {
  configure(grunt, 'server/config/global.json', {
    PARSE_DEV_APP_ID:      process.env.PARSE_DEV_APP_ID,
    PARSE_DEV_MASTER_KEY:  process.env.PARSE_DEV_MASTER_KEY,
    PARSE_PROD_APP_ID:     process.env.PARSE_PROD_APP_ID,
    PARSE_PROD_MASTER_KEY: process.env.PARSE_PROD_MASTER_KEY
  });
}

module.exports = function(grunt) {
  grunt.registerTask('configure:development', 'Configure for the development environment.', function() {
    loadEnv('.env');

    ensureInEnv([
      'PARSE_DEV_APP_ID',
      'PARSE_DEV_JS_KEY',
      'PARSE_DEV_MASTER_KEY',
      'GOOGLE_ANALYTICS_DEV_TOKEN',
      'GOOGLE_ANALYTICS_DEV_HOST'
    ]);

    process.env.PARSE_APP_ID = process.env.PARSE_DEV_APP_ID;
    process.env.PARSE_JS_KEY = process.env.PARSE_DEV_JS_KEY;
    process.env.GOOGLE_ANALYTICS_TOKEN = process.env.GOOGLE_ANALYTICS_DEV_TOKEN;
    process.env.GOOGLE_ANALYTICS_HOST = process.env.GOOGLE_ANALYTICS_DEV_HOST;

    configureGlobalJson(grunt);
    configureGoogleAnalytics(grunt);
  });

  grunt.registerTask('configure:production', 'Configure for the production environment.', function() {
    loadEnv('.env');

    ensureInEnv([
      'PARSE_PROD_APP_ID',
      'PARSE_PROD_JS_KEY',
      'PARSE_PROD_MASTER_KEY',
      'GOOGLE_ANALYTICS_PROD_TOKEN',
      'GOOGLE_ANALYTICS_PROD_HOST'
    ]);

    process.env.PARSE_APP_ID = process.env.PARSE_PROD_APP_ID;
    process.env.PARSE_JS_KEY = process.env.PARSE_PROD_JS_KEY;
    process.env.GOOGLE_ANALYTICS_TOKEN = process.env.GOOGLE_ANALYTICS_PROD_TOKEN;
    process.env.GOOGLE_ANALYTICS_HOST = process.env.GOOGLE_ANALYTICS_PROD_HOST;

    configureGlobalJson(grunt);
    configureGoogleAnalytics(grunt);
  });
};
<commit_msg>Revert "repair configure.js task"<commit_after>function loadEnv(envFile) {
  require('fs').readFileSync(envFile)
    .toString()
    .split('\n')
    .forEach(function(line) {
      var segments = line.split('='),
          variable = segments[0],
          value = segments[1];

      if ( variable && value ) {
        process.env[variable] = value;
      }
    });
}

function ensureInEnv(variables) {
  variables.forEach(function(variable) {
    if ( !process.env[variable] ) {
      console.log(variable, 'is needed in .env.')
      process.exit(1);
    }
  });
}

function configure(grunt, targetPath, data) {
  var templatePath = targetPath + '.template',
      template = grunt.file.read(templatePath),
      output = grunt.template.process(template, data);

  if ( !grunt.file.exists(targetPath) || grunt.file.read(targetPath) !== output ) {
    grunt.file.write(targetPath, output);
  }
}

function configureGoogleAnalytics(grunt) {
  var targetPath = 'app/index.html',
      data = {
        GOOGLE_ANALYTICS_TOKEN: process.env.GOOGLE_ANALYTICS_TOKEN
        GOOGLE_ANALYTICS_HOST: process.env.GOOGLE_ANALYTICS_HOST
      };

  configure(grunt, targetPath, data);
}

function configureGlobalJson(grunt) {
  var targetPath = 'server/config/global.json',
      data: {
        PARSE_DEV_APP_ID:      process.env.PARSE_DEV_APP_ID,
        PARSE_DEV_MASTER_KEY:  process.env.PARSE_DEV_MASTER_KEY,
        PARSE_PROD_APP_ID:     process.env.PARSE_PROD_APP_ID,
        PARSE_PROD_MASTER_KEY: process.env.PARSE_PROD_MASTER_KEY
      };

  configure(grunt, targetPath, data);
}

module.exports = function(grunt) {
  grunt.registerTask('configure:development', 'Configure for the development environment.', function() {
    loadEnv('.env');

    ensureInEnv([
      'PARSE_DEV_APP_ID',
      'PARSE_DEV_JS_KEY',
      'PARSE_DEV_MASTER_KEY',
      'GOOGLE_ANALYTICS_DEV_TOKEN',
      'GOOGLE_ANALYTICS_DEV_HOST'
    ]);

    process.env.PARSE_APP_ID = process.env.PARSE_DEV_APP_ID;
    process.env.PARSE_JS_KEY = process.env.PARSE_DEV_JS_KEY;
    process.env.GOOGLE_ANALYTICS_TOKEN = process.env.GOOGLE_ANALYTICS_DEV_TOKEN;
    process.env.GOOGLE_ANALYTICS_HOST = process.env.GOOGLE_ANALYTICS_DEV_HOST;

    configureGlobalJson(grunt);
    configureGoogleAnalytics(grunt);
  });

  grunt.registerTask('configure:production', 'Configure for the production environment.', function() {
    loadEnv('.env');

    ensureInEnv([
      'PARSE_PROD_APP_ID',
      'PARSE_PROD_JS_KEY',
      'PARSE_PROD_MASTER_KEY',
      'GOOGLE_ANALYTICS_PROD_TOKEN',
      'GOOGLE_ANALYTICS_PROD_HOST'
    ]);

    process.env.PARSE_APP_ID = process.env.PARSE_PROD_APP_ID;
    process.env.PARSE_JS_KEY = process.env.PARSE_PROD_JS_KEY;
    process.env.GOOGLE_ANALYTICS_TOKEN = process.env.GOOGLE_ANALYTICS_PROD_TOKEN;
    process.env.GOOGLE_ANALYTICS_HOST = process.env.GOOGLE_ANALYTICS_PROD_HOST;

    configureGlobalJson(grunt);
    configureGoogleAnalytics(grunt);
  });
};
<|endoftext|>


<commit_before>function loadEnv(envFile) {
  require('fs').readFileSync(envFile)
    .toString()
    .split('\n')
    .forEach(function(line) {
      var segments = line.split('='),
          variable = segments[0],
          value = segments[1];

      if ( variable && value ) {
        process.env[variable] = value;
      }
    });
}

function ensureInEnv(variables) {
  variables.forEach(function(variable) {
    if ( !process.env[variable] ) {
      console.log(variable, 'is needed in .env.')
      process.exit(1);
    }
  });
}

function configure(grunt, targetPath, data) {
  var templatePath = targetPath + '.template',
      template = grunt.file.read(templatePath),
      output = grunt.template.process(template, data);

  if ( !grunt.file.exists(targetPath) || grunt.file.read(targetPath) !== output ) {
    grunt.file.write(targetPath, output);
  }
}

function configureGoogleAnalytics(grunt) {
  var targetPath = 'app/index.html',
      data = {
        GOOGLE_ANALYTICS_TOKEN: process.env.GOOGLE_ANALYTICS_TOKEN
        GOOGLE_ANALYTICS_HOST: process.env.GOOGLE_ANALYTICS_HOST
      };

  configure(grunt, targetPath, data);
}

function configureGlobalJson(grunt) {
  var targetPath = 'server/config/global.json',
      data: {
        PARSE_DEV_APP_ID:      process.env.PARSE_DEV_APP_ID,
        PARSE_DEV_MASTER_KEY:  process.env.PARSE_DEV_MASTER_KEY,
        PARSE_PROD_APP_ID:     process.env.PARSE_PROD_APP_ID,
        PARSE_PROD_MASTER_KEY: process.env.PARSE_PROD_MASTER_KEY
      };

  configure(grunt, targetPath, data);
}

module.exports = function(grunt) {
  grunt.registerTask('configure:development', 'Configure for the development environment.', function() {
    loadEnv('.env');

    ensureInEnv([
      'PARSE_DEV_APP_ID',
      'PARSE_DEV_JS_KEY',
      'PARSE_DEV_MASTER_KEY',
      'GOOGLE_ANALYTICS_DEV_TOKEN',
      'GOOGLE_ANALYTICS_DEV_HOST'
    ]);

    process.env.PARSE_APP_ID = process.env.PARSE_DEV_APP_ID;
    process.env.PARSE_JS_KEY = process.env.PARSE_DEV_JS_KEY;
    process.env.GOOGLE_ANALYTICS_TOKEN = process.env.GOOGLE_ANALYTICS_DEV_TOKEN;
    process.env.GOOGLE_ANALYTICS_HOST = process.env.GOOGLE_ANALYTICS_DEV_HOST;

    configureGlobalJson(grunt);
    configureGoogleAnalytics(grunt);
  });

  grunt.registerTask('configure:production', 'Configure for the production environment.', function() {
    loadEnv('.env');

    ensureInEnv([
      'PARSE_PROD_APP_ID',
      'PARSE_PROD_JS_KEY',
      'PARSE_PROD_MASTER_KEY',
      'GOOGLE_ANALYTICS_PROD_TOKEN',
      'GOOGLE_ANALYTICS_PROD_HOST'
    ]);

    process.env.PARSE_APP_ID = process.env.PARSE_PROD_APP_ID;
    process.env.PARSE_JS_KEY = process.env.PARSE_PROD_JS_KEY;
    process.env.GOOGLE_ANALYTICS_TOKEN = process.env.GOOGLE_ANALYTICS_PROD_TOKEN;
    process.env.GOOGLE_ANALYTICS_HOST = process.env.GOOGLE_ANALYTICS_PROD_HOST;

    configureGlobalJson(grunt);
    configureGoogleAnalytics(grunt);
  });
};
<commit_msg>Revert "Revert "repair configure.js task""<commit_after>function loadEnv(envFile) {
  require('fs').readFileSync(envFile)
    .toString()
    .split('\n')
    .forEach(function(line) {
      var segments = line.split('='),
          variable = segments[0],
          value = segments[1];

      if ( variable && value ) {
        process.env[variable] = value;
      }
    });
}

function ensureInEnv(variables) {
  variables.forEach(function(variable) {
    if ( !process.env[variable] ) {
      console.log(variable, 'is needed in .env.')
      process.exit(1);
    }
  });
}

function configure(grunt, targetPath, data) {
  var templatePath = targetPath + '.template',
      template = grunt.file.read(templatePath),
      output = grunt.template.process(template, data);

  if ( !grunt.file.exists(targetPath) || grunt.file.read(targetPath) !== output ) {
    grunt.file.write(targetPath, output);
  }
}

function configureGoogleAnalytics(grunt) {
  configure(grunt, 'app/index.html', {
    GOOGLE_ANALYTICS_TOKEN: process.env.GOOGLE_ANALYTICS_TOKEN,
    GOOGLE_ANALYTICS_HOST: process.env.GOOGLE_ANALYTICS_HOST
  });
}

function configureGlobalJson(grunt) {
  configure(grunt, 'server/config/global.json', {
    PARSE_DEV_APP_ID:      process.env.PARSE_DEV_APP_ID,
    PARSE_DEV_MASTER_KEY:  process.env.PARSE_DEV_MASTER_KEY,
    PARSE_PROD_APP_ID:     process.env.PARSE_PROD_APP_ID,
    PARSE_PROD_MASTER_KEY: process.env.PARSE_PROD_MASTER_KEY
  });
}

module.exports = function(grunt) {
  grunt.registerTask('configure:development', 'Configure for the development environment.', function() {
    loadEnv('.env');

    ensureInEnv([
      'PARSE_DEV_APP_ID',
      'PARSE_DEV_JS_KEY',
      'PARSE_DEV_MASTER_KEY',
      'GOOGLE_ANALYTICS_DEV_TOKEN',
      'GOOGLE_ANALYTICS_DEV_HOST'
    ]);

    process.env.PARSE_APP_ID = process.env.PARSE_DEV_APP_ID;
    process.env.PARSE_JS_KEY = process.env.PARSE_DEV_JS_KEY;
    process.env.GOOGLE_ANALYTICS_TOKEN = process.env.GOOGLE_ANALYTICS_DEV_TOKEN;
    process.env.GOOGLE_ANALYTICS_HOST = process.env.GOOGLE_ANALYTICS_DEV_HOST;

    configureGlobalJson(grunt);
    configureGoogleAnalytics(grunt);
  });

  grunt.registerTask('configure:production', 'Configure for the production environment.', function() {
    loadEnv('.env');

    ensureInEnv([
      'PARSE_PROD_APP_ID',
      'PARSE_PROD_JS_KEY',
      'PARSE_PROD_MASTER_KEY',
      'GOOGLE_ANALYTICS_PROD_TOKEN',
      'GOOGLE_ANALYTICS_PROD_HOST'
    ]);

    process.env.PARSE_APP_ID = process.env.PARSE_PROD_APP_ID;
    process.env.PARSE_JS_KEY = process.env.PARSE_PROD_JS_KEY;
    process.env.GOOGLE_ANALYTICS_TOKEN = process.env.GOOGLE_ANALYTICS_PROD_TOKEN;
    process.env.GOOGLE_ANALYTICS_HOST = process.env.GOOGLE_ANALYTICS_PROD_HOST;

    configureGlobalJson(grunt);
    configureGoogleAnalytics(grunt);
  });
};
<|endoftext|>


<commit_before>var r = require('../redis');
var redis = r.client;
var utility = require('../utility');
var getData = utility.getData;
var async = require('async');
var fs = require('fs');

module.exports = function constants(cb) {
    var urls = {
        "items": "http://www.dota2.com/jsfeed/itemdata?l=english",
        "abilities": "http://www.dota2.com/jsfeed/abilitydata",
        "heropickerdata": "http://www.dota2.com/jsfeed/heropickerdata",
        "herodata": "http://www.dota2.com/jsfeed/heropediadata?feeds=herodata",
        "heroes": utility.generateJob("api_heroes", {
            language: "en-us"
        }).url,
        "leagues": utility.generateJob("api_leagues").url
    };
    var constants = require('../sources.json');
    async.each(Object.keys(urls), function(key, cb) {
        var val = urls[key];
        //grab raw data from each url and place under that key
        getData(val, function(err, result) {
            constants[key] = result;
            cb(err);
        });
    }, function(err) {
        if (err) {
            return cb(err);
        }
        var heroes = JSON.parse(JSON.stringify(constants.heroes.result.heroes));
        heroes.sort(function(a, b) {
            return a.localized_name.localeCompare(b.localized_name);
        });
        constants.alpha_heroes = heroes;
        //key heroes by id
        constants.heroes = {};
        //key heroes by name
        constants.hero_names = {};
        heroes.forEach(function(h) {
            h.img = "http://cdn.dota2.com/apps/dota2/images/heroes/"+h.name.replace("npc_dota_hero_", "")+"_sb.png";
            constants.heroes[h.id] = h;
            constants.hero_names[h.name] = h;
        });
        //leagues, key by id
        var leagues = JSON.parse(JSON.stringify(constants.leagues.result.leagues));
        constants.leagues = {};
        leagues.forEach(function(l) {
            constants.leagues[l.leagueid] = l;
        });
        //items, already keyed by name
        var items = constants.items.itemdata;
        constants.item_ids = {};
        for (var key in items) {
            constants.item_ids[items[key].id] = key;
            items[key].img = "http://cdn.dota2.com/apps/dota2/images/items/" + items[key].img;
        }
        constants.items = items;
        //significant items
        constants.big_items = {};
        for (var key in items) {
            if (items[key].cost > 1400) {
                constants.big_items[key] = items[key];
            }
        }
        //abilities, already keyed by name
        var abilities = constants.abilities.abilitydata;
        for (var key2 in abilities) {
            abilities[key2].img = "http://cdn.dota2.com/apps/dota2/images/abilities/" + key2 + "_md.png";
        }
        abilities.nevermore_shadowraze2 = abilities.nevermore_shadowraze1;
        abilities.nevermore_shadowraze3 = abilities.nevermore_shadowraze1;
        abilities.stats = {
            dname: "Stats",
            img: '../../public/images/Stats.png',
            attrib: "+2 All Attributes"
        };
        constants.abilities = abilities;
        constants.lanes = [];
        for (var i = 0; i < 128; i++) {
            constants.lanes.push([]);
            for (var j = 0; j < 128; j++) {
                var lane;
                if (Math.abs(i - (127 - j)) < 8) {
                    lane = 2; //mid
                }
                else if (j < 27 || i < 27) {
                    lane = 3; //top
                }
                else if (j >= 100 || i >= 100) {
                    lane = 1; //bot
                }
                else if (i < 50) {
                    lane = 5; //djung
                }
                else if (i >= 77) {
                    lane = 4; //rjung
                }
                else {
                    lane = 2; //mid
                }
                constants.lanes[i].push(lane);
            }
        }
        fs.writeFile('./constants.json', JSON.stringify(constants, null, 2), function(err) {
            if (!err) {
                console.log("[CONSTANTS] generated constants file");
            }
            return cb(err);
        });
    });
}<commit_msg>added no key case to constants<commit_after>//var r = require('../redis');
//var redis = r.client;
var utility = require('../utility');
var getData = utility.getData;
var async = require('async');
var fs = require('fs');
var config = require('../config');
module.exports = function constants(cb) {
    var urls = {
        "items": "http://www.dota2.com/jsfeed/itemdata?l=english",
        "abilities": "http://www.dota2.com/jsfeed/abilitydata",
        "heropickerdata": "http://www.dota2.com/jsfeed/heropickerdata",
        "herodata": "http://www.dota2.com/jsfeed/heropediadata?feeds=herodata",
        "heroes": config.STEAM_API_KEY ? utility.generateJob("api_heroes", {
            language: "en-us"
        }).url : null,
        "leagues": config.STEAM_API_KEY ? utility.generateJob("api_leagues").url : null
    };
    var constants = require('../sources.json');
    async.each(Object.keys(urls), function(key, cb) {
        var val = urls[key];
        if (val) {
            //grab raw data from each url and place under that key
            getData(val, function(err, result) {
                constants[key] = result;
                cb(err);
            });
        }
        else {
            constants[key] = {};
            cb();
        }
    }, function(err) {
        if (err) {
            return cb(err);
        }
        var heroes = JSON.parse(JSON.stringify(constants.heroes.result.heroes));
        heroes.sort(function(a, b) {
            return a.localized_name.localeCompare(b.localized_name);
        });
        constants.alpha_heroes = heroes;
        //key heroes by id
        constants.heroes = {};
        //key heroes by name
        constants.hero_names = {};
        heroes.forEach(function(h) {
            h.img = "http://cdn.dota2.com/apps/dota2/images/heroes/" + h.name.replace("npc_dota_hero_", "") + "_sb.png";
            constants.heroes[h.id] = h;
            constants.hero_names[h.name] = h;
        });
        //leagues, key by id
        var leagues = JSON.parse(JSON.stringify(constants.leagues.result.leagues));
        constants.leagues = {};
        leagues.forEach(function(l) {
            constants.leagues[l.leagueid] = l;
        });
        //items, already keyed by name
        var items = constants.items.itemdata;
        constants.item_ids = {};
        for (var key in items) {
            constants.item_ids[items[key].id] = key;
            items[key].img = "http://cdn.dota2.com/apps/dota2/images/items/" + items[key].img;
        }
        constants.items = items;
        //significant items
        constants.big_items = {};
        for (var key in items) {
            if (items[key].cost > 1400) {
                constants.big_items[key] = items[key];
            }
        }
        //abilities, already keyed by name
        var abilities = constants.abilities.abilitydata;
        for (var key2 in abilities) {
            abilities[key2].img = "http://cdn.dota2.com/apps/dota2/images/abilities/" + key2 + "_md.png";
        }
        abilities.nevermore_shadowraze2 = abilities.nevermore_shadowraze1;
        abilities.nevermore_shadowraze3 = abilities.nevermore_shadowraze1;
        abilities.stats = {
            dname: "Stats",
            img: '../../public/images/Stats.png',
            attrib: "+2 All Attributes"
        };
        constants.abilities = abilities;
        constants.lanes = [];
        for (var i = 0; i < 128; i++) {
            constants.lanes.push([]);
            for (var j = 0; j < 128; j++) {
                var lane;
                if (Math.abs(i - (127 - j)) < 8) {
                    lane = 2; //mid
                }
                else if (j < 27 || i < 27) {
                    lane = 3; //top
                }
                else if (j >= 100 || i >= 100) {
                    lane = 1; //bot
                }
                else if (i < 50) {
                    lane = 5; //djung
                }
                else if (i >= 77) {
                    lane = 4; //rjung
                }
                else {
                    lane = 2; //mid
                }
                constants.lanes[i].push(lane);
            }
        }
        fs.writeFile('./constants.json', JSON.stringify(constants, null, 2), function(err) {
            if (!err) {
                console.log("[CONSTANTS] generated constants file");
            }
            return cb(err);
        });
    });
}<|endoftext|>


<commit_before>var storage = window.sessionStorage, key = '_uikit_style', keyinverse = '_uikit_inverse';

var styles = Object.assign({
    core: {
        file: '../css/uikit.core.css',
        components: [
            '../css/components/core/notify.css',
            '../css/components/core/sortable.css',
            '../css/components/core/spinner.css',
            '../css/components/core/tooltip.css'
        ]
    },
    theme: {
        file: '../css/uikit.theme.css',
        components: [
            '../css/components/theme/notify.css',
            '../css/components/theme/sortable.css',
            '../css/components/theme/spinner.css',
            '../css/components/theme/tooltip.css'
        ]
    }
}, JSON.parse(_load('../themes.json') || '{}'));

if (_get('style') && _get('style').match(/\.(json|css)$/)) {
    styles.custom = _get('style');
}

storage[key] = storage[key] || 'core';
storage[keyinverse] = storage[keyinverse] || 'default';

var style = styles[storage[key]] || styles.theme;

// add UIkit core
document.writeln(`<link rel="stylesheet" href="${style.file}">`);

// add  UIkit components
(style.components || []).forEach(file => {
    document.writeln(`<link rel="stylesheet" href="${file}">`);
});

document.writeln(`<script src="../vendor/jquery.js"></script>`);
document.writeln(`<script src="../js/uikit.js"></script>`);

// add  UIkit components

var component = location.pathname.split('/').pop().replace(/.html$/, '');
var components = [
    'notify',
    'sortable',
    'spinner',
    'tooltip',
    'upload'
];

components.forEach(name => {
    document.writeln(`<script src="../js/components/${name}.js"></script>`);
});

document.addEventListener("DOMContentLoaded", () => {

    var $ = jQuery;

    var $container = $('

').prependTo('body');
    var $tests = $('<select class="uk-select"></select>').css('margin', '20px 20px 20px 0').prependTo($container);
    var $styles = $('<select class="uk-select"></select>').css('margin', '20px').appendTo($container);
    var $inverse = $('<select class="uk-select"></select>').css('margin', '20px').appendTo($container);

    // Tests
    // ------------------------------

    [
        'accordion',
        'alert',
        'align',
        'animation',
        'article',
        'background',
        'badge',
        'base',
        'breadcrumb',
        'button',
        'card',
        'close',
        'column',
        'comment',
        'container',
        'cover',
        'description-list',
        'drop',
        'dropdown',
        'element',
        'flex',
        'form',
        'grid',
        'height-expand',
        'height-viewport',
        'icon',
        'label',
        'lightbox',
        'list',
        'margin',
        'modal',
        'nav',
        'navbar',
        'offcanvas',
        'overlay',
        'padding',
        'pagination',
        'position',
        'scroll',
        'scrollspy',
        'search',
        'section',
        'slidenav',
        'sticky',
        'subnav',
        'switcher',
        'tab',
        'table',
        'text',
        'toggle',
        'totop',
        'transition',
        'utility',
        'visibility',
        'width'
    ].concat(components).sort().forEach(name => {

        $(`<option value="${name}.html">${name.split('-').map(name => {
            return ucfirst(name);
        }).join(' ')}</option>`).appendTo($tests);
    });

    $tests.on('change', () => {
        if ($tests.val()) {
            var style = styles.custom ? `?style=${_get('style')}` : '';
            location.href = `../${document.querySelector('script[src*="test.js"]').getAttribute('src').replace('js/test.js', '')}tests/${$tests.val()}${style}`;
        }
    }).val(component && `${component}.html`);

    $tests.prepend(`<option value="index.html">Overview</option>`);

    // Styles
    // ------------------------------

    Object.keys(styles).forEach(style => {
        $styles.append(`<option value="${style}">${ucfirst(style)}</option>`);
    });

    $styles.on('change', () => {
        storage[key] = $styles.val();
        location.reload();
    }).val(storage[key]);

    // Variations
    // ------------------------------

    var variations = {
        'default': 'Default',
        'light': 'Dark',
        'dark': 'Light'
    };

    Object.keys(variations).forEach(name => {
        $(`<option value="${name}">${variations[name]}</option>`).appendTo($inverse);
    });

    $inverse.on('change', () => {

        document.body.classList.remove('uk-dark');
        document.body.classList.remove('uk-light');

        switch ($inverse.val()) {
            case 'dark':
                document.documentElement.style.background = '#fff';
                document.body.classList.add('uk-dark');
                break;

            case 'light':
                document.documentElement.style.background = '#222';
                document.body.classList.add('uk-light');
                break;

            default:
                document.documentElement.style.background = '';
        }

        storage[keyinverse] = $inverse.val();

    }).val(storage[keyinverse]).trigger('change');

    $('html').css('padding-top', '');

});

document.querySelector('html').style.paddingTop = '80px';

function ucfirst(str) {
    return str.length ? str.charAt(0).toUpperCase() + str.slice(1) : '';
};

function _get(name) {
    var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
    return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}

function _load(url) {
    var request = new XMLHttpRequest();
    request.open('GET', url, false);  // `false` makes the request synchronous
    request.send(null);
    return request.status === 200 ? request.responseText : undefined;
}
<commit_msg>ie fix<commit_after>
var storage = window.sessionStorage, key = '_uikit_style', keyinverse = '_uikit_inverse';

var styles = extend({
    core: {
        file: '../css/uikit.core.css',
        components: [
            '../css/components/core/notify.css',
            '../css/components/core/sortable.css',
            '../css/components/core/spinner.css',
            '../css/components/core/tooltip.css'
        ]
    },
    theme: {
        file: '../css/uikit.theme.css',
        components: [
            '../css/components/theme/notify.css',
            '../css/components/theme/sortable.css',
            '../css/components/theme/spinner.css',
            '../css/components/theme/tooltip.css'
        ]
    }
}, JSON.parse(_load('../themes.json') || '{}'));

if (_get('style') && _get('style').match(/\.(json|css)$/)) {
    styles.custom = _get('style');
}

storage[key] = storage[key] || 'core';
storage[keyinverse] = storage[keyinverse] || 'default';

var style = styles[storage[key]] || styles.theme;

// add UIkit core
document.writeln(`<link rel="stylesheet" href="${style.file}">`);

// add  UIkit components
(style.components || []).forEach(file => {
    document.writeln(`<link rel="stylesheet" href="${file}">`);
});

document.writeln(`<script src="../vendor/jquery.js"></script>`);
document.writeln(`<script src="../js/uikit.js"></script>`);

// add  UIkit components

var component = location.pathname.split('/').pop().replace(/.html$/, '');
var components = [
    'notify',
    'sortable',
    'spinner',
    'tooltip',
    'upload'
];

components.forEach(name => {
    document.writeln(`<script src="../js/components/${name}.js"></script>`);
});

document.addEventListener("DOMContentLoaded", () => {

    var $ = jQuery;

    var $container = $('

').prependTo('body');
    var $tests = $('<select class="uk-select"></select>').css('margin', '20px 20px 20px 0').prependTo($container);
    var $styles = $('<select class="uk-select"></select>').css('margin', '20px').appendTo($container);
    var $inverse = $('<select class="uk-select"></select>').css('margin', '20px').appendTo($container);

    // Tests
    // ------------------------------

    [
        'accordion',
        'alert',
        'align',
        'animation',
        'article',
        'background',
        'badge',
        'base',
        'breadcrumb',
        'button',
        'card',
        'close',
        'column',
        'comment',
        'container',
        'cover',
        'description-list',
        'drop',
        'dropdown',
        'element',
        'flex',
        'form',
        'grid',
        'height-expand',
        'height-viewport',
        'icon',
        'label',
        'lightbox',
        'list',
        'margin',
        'modal',
        'nav',
        'navbar',
        'offcanvas',
        'overlay',
        'padding',
        'pagination',
        'position',
        'scroll',
        'scrollspy',
        'search',
        'section',
        'slidenav',
        'sticky',
        'subnav',
        'switcher',
        'tab',
        'table',
        'text',
        'toggle',
        'totop',
        'transition',
        'utility',
        'visibility',
        'width'
    ].concat(components).sort().forEach(name => {

        $(`<option value="${name}.html">${name.split('-').map(name => {
            return ucfirst(name);
        }).join(' ')}</option>`).appendTo($tests);
    });

    $tests.on('change', () => {
        if ($tests.val()) {
            var style = styles.custom ? `?style=${_get('style')}` : '';
            location.href = `../${document.querySelector('script[src*="test.js"]').getAttribute('src').replace('js/test.js', '')}tests/${$tests.val()}${style}`;
        }
    }).val(component && `${component}.html`);

    $tests.prepend(`<option value="index.html">Overview</option>`);

    // Styles
    // ------------------------------

    Object.keys(styles).forEach(style => {
        $styles.append(`<option value="${style}">${ucfirst(style)}</option>`);
    });

    $styles.on('change', () => {
        storage[key] = $styles.val();
        location.reload();
    }).val(storage[key]);

    // Variations
    // ------------------------------

    var variations = {
        'default': 'Default',
        'light': 'Dark',
        'dark': 'Light'
    };

    Object.keys(variations).forEach(name => {
        $(`<option value="${name}">${variations[name]}</option>`).appendTo($inverse);
    });

    $inverse.on('change', () => {

        document.body.classList.remove('uk-dark');
        document.body.classList.remove('uk-light');

        switch ($inverse.val()) {
            case 'dark':
                document.documentElement.style.background = '#fff';
                document.body.classList.add('uk-dark');
                break;

            case 'light':
                document.documentElement.style.background = '#222';
                document.body.classList.add('uk-light');
                break;

            default:
                document.documentElement.style.background = '';
        }

        storage[keyinverse] = $inverse.val();

    }).val(storage[keyinverse]).trigger('change');

    $('html').css('padding-top', '');

});

document.querySelector('html').style.paddingTop = '80px';

function extend(target) {

    for (var index = 1, source; index < arguments.length; index++) {
        source = arguments[index];
        for (var key in source) {
            target[key] = source[key];
        }
    }

    return target;
}

function ucfirst(str) {
    return str.length ? str.charAt(0).toUpperCase() + str.slice(1) : '';
};

function _get(name) {
    var match = RegExp('[?&]' + name + '=([^&]*)').exec(window.location.search);
    return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
}

function _load(url) {
    var request = new XMLHttpRequest();
    request.open('GET', url, false);  // `false` makes the request synchronous
    request.send(null);
    return request.status === 200 ? request.responseText : undefined;
}
<|endoftext|>


<commit_before>function fontFace(face) {
	if (tinymce.isOpera) {
		return "'" + face + "'";
	} else {
		return face;
	}
}

function findContainer(selector) {
	var container;
	if (tinymce.is(selector, 'string')) {
		container = editor.dom.select(selector)[0];
	} else {
		container = selector;
	}
	if (container.firstChild) {
		container = container.firstChild;
	}
	return container;
}

function setSelection(startSelector, startOffset, endSelector, endOffset) {
	if (!endSelector) {
		endSelector = startSelector;
		endOffset = startOffset;
	}
	var startContainer = findContainer(startSelector);
	var endContainer = findContainer(endSelector);
	var rng = editor.dom.createRng();

	function setRange(container, offset, start) {
		if (offset === 'after') {
			if (start) {
				rng.setStartAfter(container);
			} else {
				rng.setEndAfter(container);
			}
			return;
		} else if (offset === 'afterNextCharacter') {
			container = container.nextSibling;
			offset = 1;
		}
		if (start) {
			rng.setStart(container, offset);
		} else {
			rng.setEnd(container, offset);
		}
	}

	setRange(startContainer, startOffset, true);
	setRange(endContainer, endOffset, false);
	editor.selection.setRng(rng);
}

function initWhenTinyAndRobotAreReady(initTinyFunction) {
	function loaded() {
		QUnit.start();
	}

	tinymce.onAddEditor.add(function(tinymce, ed) {
		ed.onInit.add(function() {
			loaded();
		});
	});
	window.robot.onload(initTinyFunction);
}

function trimContent(content) {
	return content.replace(/^<p> <\/p>\n?/, '').replace(/\n?<p> <\/p>$/, '');
}

/**
 * Fakes a key event.
 *
 * @param {Element/String} e DOM element object or element id to send fake event to.
 * @param {String} na Event name to fake like "keydown".
 * @param {Object} o Optional object with data to send with the event like keyCode and charCode.
 */
function fakeKeyEvent(e, na, o) {
	var ev;

	o = tinymce.extend({
		keyCode : 13,
		charCode : 0
	}, o);

	e = tinymce.DOM.get(e);

	if (e.fireEvent) {
		ev = document.createEventObject();
		tinymce.extend(ev, o);
		e.fireEvent('on' + na, ev);
		return;
	}

	if (document.createEvent) {
		try {
			// Fails in Safari
			ev = document.createEvent('KeyEvents');
			ev.initKeyEvent(na, true, true, window, false, false, false, false, o.keyCode, o.charCode);
		} catch (ex) {
			ev = document.createEvent('Events');
			ev.initEvent(na, true, true);

			ev.keyCode = o.keyCode;
			ev.charCode = o.charCode;
		}
	} else {
		ev = document.createEvent('UIEvents');

		if (ev.initUIEvent)
			ev.initUIEvent(na, true, true, window, 1);

		ev.keyCode = o.keyCode;
		ev.charCode = o.charCode;
	}

	e.dispatchEvent(ev);
}

function normalizeRng(rng) {
	if (rng.startContainer.nodeType == 3) {
		if (rng.startOffset == 0)
			rng.setStartBefore(rng.startContainer);
		else if (rng.startOffset >= rng.startContainer.nodeValue.length - 1)
			rng.setStartAfter(rng.startContainer);
	}

	if (rng.endContainer.nodeType == 3) {
		if (rng.endOffset == 0)
			rng.setEndBefore(rng.endContainer);
		else if (rng.endOffset >= rng.endContainer.nodeValue.length - 1)
			rng.setEndAfter(rng.endContainer);
	}

	return rng;
}

// TODO: Replace this with the new event logic in 3.5
function type(chr) {
	var editor = tinymce.activeEditor, keyCode, charCode, event = tinymce.dom.Event, evt, startElm;

	function fakeEvent(target, type, evt) {
		var event, preventDefault;

		evt = evt || {};
		evt.type = type;

		if (target.fireEvent) {
			var event = document.createEventObject();
			tinymce.extend(event, evt);
			target.fireEvent('on' + type, event);
			return;
		}

		if (document.createEvent) {
			try {
				// Fails in Safari
				event = document.createEvent('KeyEvents');
				event.initKeyEvent(type, true, true, window, false, false, false, false, evt.keyCode, evt.charCode);
				event.preventDefault();
			} catch (ex) {
				event = document.createEvent('Events');
				event.initEvent(type, true, true);
				event.keyCode = evt.keyCode;
				event.charCode = evt.charCode;
			}
		} else {
			event = document.createEvent('UIEvents');

			if (event.initUIEvent)
				event.initUIEvent(type, true, true, window, 1);

			event.keyCode = evt.keyCode;
			event.charCode = evt.charCode;
		}

		preventDefault = event.preventDefault;
		event.preventDefault = function() {
			if (preventDefault) {
				preventDefault.call(this);
			} else {
				this.returnValue = false; // IE
			}

			evt.prevented = true;
		};

		target.dispatchEvent(event);
	};

	// Numeric keyCode
	if (typeof(chr) == "number") {
		charCode = keyCode = chr;
	} else if (typeof(chr) == "string") {
		// String value
		if (chr == '\b') {
			keyCode = 8;
			charCode = chr.charCodeAt(0);
		} else if (chr == '\n') {
			keyCode = 13;
			charCode = chr.charCodeAt(0);
		} else {
			charCode = chr.charCodeAt(0);
			keyCode = charCode;
		}
	} else {
		evt = chr;
	}

	evt = evt || {keyCode: keyCode, charCode: charCode};

	startElm = editor.selection.getStart();
	fakeEvent(startElm, 'keydown', evt);
	fakeEvent(startElm, 'keypress', evt);

	if (!evt.prevented) {
		if (keyCode == 8) {
			if (editor.getDoc().selection) {
				var rng = editor.getDoc().selection.createRange();
				rng.moveStart('character', -1);
				rng.select();
				rng.execCommand('Delete', false, null);
			} else {
				editor.getDoc().execCommand('Delete', false, null);
			}
		} else if (typeof(chr) == 'string') {
			var rng = editor.selection.getRng(true);

			if (rng.startContainer.nodeType == 3 && rng.collapsed) {
				rng.startContainer.insertData(rng.startOffset, chr);
			} else {
				rng.insertNode(editor.getDoc().createTextNode(chr));
			}
		}
	}

	fakeEvent(startElm, 'keyup', evt);
}

function cleanHtml(html) {
	return html.toLowerCase().replace(/\n/g, '');
}<commit_msg>Updated type test function to use new events API.<commit_after>function fontFace(face) {
	if (tinymce.isOpera) {
		return "'" + face + "'";
	} else {
		return face;
	}
}

function findContainer(selector) {
	var container;
	if (tinymce.is(selector, 'string')) {
		container = editor.dom.select(selector)[0];
	} else {
		container = selector;
	}
	if (container.firstChild) {
		container = container.firstChild;
	}
	return container;
}

function setSelection(startSelector, startOffset, endSelector, endOffset) {
	if (!endSelector) {
		endSelector = startSelector;
		endOffset = startOffset;
	}
	var startContainer = findContainer(startSelector);
	var endContainer = findContainer(endSelector);
	var rng = editor.dom.createRng();

	function setRange(container, offset, start) {
		if (offset === 'after') {
			if (start) {
				rng.setStartAfter(container);
			} else {
				rng.setEndAfter(container);
			}
			return;
		} else if (offset === 'afterNextCharacter') {
			container = container.nextSibling;
			offset = 1;
		}
		if (start) {
			rng.setStart(container, offset);
		} else {
			rng.setEnd(container, offset);
		}
	}

	setRange(startContainer, startOffset, true);
	setRange(endContainer, endOffset, false);
	editor.selection.setRng(rng);
}

function initWhenTinyAndRobotAreReady(initTinyFunction) {
	function loaded() {
		QUnit.start();
	}

	tinymce.onAddEditor.add(function(tinymce, ed) {
		ed.onInit.add(function() {
			loaded();
		});
	});
	window.robot.onload(initTinyFunction);
}

function trimContent(content) {
	return content.replace(/^<p> <\/p>\n?/, '').replace(/\n?<p> <\/p>$/, '');
}

/**
 * Fakes a key event.
 *
 * @param {Element/String} e DOM element object or element id to send fake event to.
 * @param {String} na Event name to fake like "keydown".
 * @param {Object} o Optional object with data to send with the event like keyCode and charCode.
 */
function fakeKeyEvent(e, na, o) {
	var ev;

	o = tinymce.extend({
		keyCode : 13,
		charCode : 0
	}, o);

	e = tinymce.DOM.get(e);

	if (e.fireEvent) {
		ev = document.createEventObject();
		tinymce.extend(ev, o);
		e.fireEvent('on' + na, ev);
		return;
	}

	if (document.createEvent) {
		try {
			// Fails in Safari
			ev = document.createEvent('KeyEvents');
			ev.initKeyEvent(na, true, true, window, false, false, false, false, o.keyCode, o.charCode);
		} catch (ex) {
			ev = document.createEvent('Events');
			ev.initEvent(na, true, true);

			ev.keyCode = o.keyCode;
			ev.charCode = o.charCode;
		}
	} else {
		ev = document.createEvent('UIEvents');

		if (ev.initUIEvent)
			ev.initUIEvent(na, true, true, window, 1);

		ev.keyCode = o.keyCode;
		ev.charCode = o.charCode;
	}

	e.dispatchEvent(ev);
}

function normalizeRng(rng) {
	if (rng.startContainer.nodeType == 3) {
		if (rng.startOffset == 0)
			rng.setStartBefore(rng.startContainer);
		else if (rng.startOffset >= rng.startContainer.nodeValue.length - 1)
			rng.setStartAfter(rng.startContainer);
	}

	if (rng.endContainer.nodeType == 3) {
		if (rng.endOffset == 0)
			rng.setEndBefore(rng.endContainer);
		else if (rng.endOffset >= rng.endContainer.nodeValue.length - 1)
			rng.setEndAfter(rng.endContainer);
	}

	return rng;
}

// TODO: Replace this with the new event logic in 3.5
function type(chr) {
	var editor = tinymce.activeEditor, keyCode, charCode, event = tinymce.dom.Event, evt, startElm;

	function fakeEvent(target, type, evt) {
		editor.dom.fire(target, type, evt);
	};

	// Numeric keyCode
	if (typeof(chr) == "number") {
		charCode = keyCode = chr;
	} else if (typeof(chr) == "string") {
		// String value
		if (chr == '\b') {
			keyCode = 8;
			charCode = chr.charCodeAt(0);
		} else if (chr == '\n') {
			keyCode = 13;
			charCode = chr.charCodeAt(0);
		} else {
			charCode = chr.charCodeAt(0);
			keyCode = charCode;
		}
	} else {
		evt = chr;
	}

	evt = evt || {keyCode: keyCode, charCode: charCode};

	startElm = editor.selection.getStart();
	fakeEvent(startElm, 'keydown', evt);
	fakeEvent(startElm, 'keypress', evt);

	if (!evt.isDefaultPrevented()) {
		if (keyCode == 8) {
			if (editor.getDoc().selection) {
				var rng = editor.getDoc().selection.createRange();
				rng.moveStart('character', -1);
				rng.select();
				rng.execCommand('Delete', false, null);
			} else {
				editor.getDoc().execCommand('Delete', false, null);
			}
		} else if (typeof(chr) == 'string') {
			var rng = editor.selection.getRng(true);

			if (rng.startContainer.nodeType == 3 && rng.collapsed) {
				rng.startContainer.insertData(rng.startOffset, chr);
				rng.setStart(rng.startContainer, rng.startOffset + 1);
				rng.collapse(true);
				editor.selection.setRng(rng);
			} else {
				rng.insertNode(editor.getDoc().createTextNode(chr));
			}
		}
	}

	fakeEvent(startElm, 'keyup', evt);
}

function cleanHtml(html) {
	return html.toLowerCase().replace(/\n/g, '');
}<|endoftext|>


<commit_before>
const { getGuildString } = require('../../locales.js');
const music = require('../../music.js');

module.exports = {
  variants: ['leave', 'lv'],
  usage: 'lv',
  async action(message, arg) {
    const l = getGuildString(message.guild);
    const queue = music.getQueue(message.guild.id);
    if (!queue.connection) {
      message.channel.send(l('not_connected'));
      return;
    }
    const channel = queue.connection.channel;
    const perms = channel.permissionsFor(message.member);
    if (!perms.has('MANAGE_CHANNELS')) {
      message.channel.send(l('no_permissions'));
      return;
    }
    music.leave(queue);
  }
}
<commit_msg>Allow lv for everyone in not playing<commit_after>
const { getGuildString } = require('../../locales.js');
const music = require('../../music.js');

module.exports = {
  variants: ['leave', 'lv'],
  usage: 'lv',
  async action(message, arg) {
    const l = getGuildString(message.guild);
    const queue = music.getQueue(message.guild.id);
    if (!queue.connection) {
      message.channel.send(l('not_connected'));
      return;
    }
    const channel = queue.connection.channel;
    const perms = channel.permissionsFor(message.member);
    if (!queue.playing && !perms.has('MANAGE_CHANNELS')) {
      message.channel.send(l('no_permissions'));
      return;
    }
    music.leave(queue);
  }
}
<|endoftext|>


<commit_before>/**
 * All Hunter abilities except talents go in here. You can also put a talent in here if you want to override something imported in the `./talents` folder, but that should be extremely rare.
 * You need to do this manually, usually an easy way to do this is by opening a WCL report and clicking the icons of spells to open the relevant Wowhead pages, here you can get the icon name by clicking the icon, copy the name of the spell and the ID is in the URL.
 * You can access these entries like other entries in the spells files by importing `common/SPELLS` and using the assigned property on the SPELLS object. Please try to avoid abbreviating properties.
 */

export default {
  // Beast Mastery:
  // ...

  // Marksmanship:
  // ...

  WINDBURST: {
    id: 204147,
    name: 'Windburst',
    icon: 'inv_bow_1h_artifactwindrunner_d_02',
  },
  WINDBURST_MOVEMENT_SPEED: {
    id: 204477,
    name: 'Windburst',
    icon: 'ability_hunter_focusedaim',
  },
  AIMED_SHOT: {
    id: 19434,
    name: 'Aimed Shot',
    icon: 'inv_spear_07',
  },
  ARCANE_SHOT: {
    id: 185358,
    name: 'Arcane Shot',
    icon: 'ability_impalingbolt',
  },
  MARKED_SHOT: {
    id: 185901,
    name: 'Marked Shot',
    icon: 'ability_hunter_markedshot',
  },
  DISENGAGE: {
    id: 781,
    name: 'Disengage',
    icon: 'ability_rogue_feint',
  },
  TRUESHOT: {
    id: 193526,
    name: 'Trueshot',
    icon: 'ability_trueshot',
  },
  MULTISHOT: {
    id: 2643,
    name: 'Multi-Shot',
    icon: 'ability_upgrademoonglaive',
  },
  EXHILARATION: {
    id: 109304,
    name: 'Exhilaration',
    icon: 'ability_hunter_onewithnature',
  },
  ASPECT_OF_THE_CHEETAH: {
    id: 186257,
    name: 'Aspect of the Cheetah',
    icon: 'ability_mount_jungletiger',
  },
  ASPECT_OF_THE_TURTLE: {
    id: 186265,
    name: 'Aspect of the Turtle',
    icon: 'ability_hunter_pet_turtle',
  },
  BURSTING_SHOT: {
    id: 224729,
    name: 'Bursting Shot',
    icon: 'ability_hunter_burstingshot',
  },
  CONCUSSIVE_SHOT: {
    id: 27634,
    name: 'Concussive Shot',
    icon: 'spell_frost_stun',
  },
  COUNTER_SHOT: {
    id: 147362,
    name: 'Counter Shot',
    icon: 'inv_ammo_arrow_03',
  },
  MISDIRECTION: {
    id: 34477,
    name: 'Misdrection',
    icon: 'ability_hunter_misdirection',
  },
  FREEZING_TRAP: {
    id: 187650,
    name: 'Freezing Trap',
    icon: 'spell_frost_chainsofice',
  },
  TAR_TRAP: {
    id: 187698,
    name: 'Tar Trap',
    icon: 'spell_yorsahj_bloodboil_black',
  },
  VULNERABLE: {
    id: 187131,
    name: 'Vulnerable',
    icon: 'ability_hunter_mastermarksman',
  },

  // Survival:
  // ...

  // Shared:
  // ...
  NETHERWINDS: {
    id: 160452,
    name: 'Netherwinds',
    icon: 'spell_arcane_massdispel',
  },
  ANCIENT_HYSTERIA: {
    id: 90355,
    name: 'Ancient Hysteria',
    icon: 'spell_shadow_unholyfrenzy',
  },
};
<commit_msg>Added spells for Focus Tracker<commit_after>/**
 * All Hunter abilities except talents go in here. You can also put a talent in here if you want to override something imported in the `./talents` folder, but that should be extremely rare.
 * You need to do this manually, usually an easy way to do this is by opening a WCL report and clicking the icons of spells to open the relevant Wowhead pages, here you can get the icon name by clicking the icon, copy the name of the spell and the ID is in the URL.
 * You can access these entries like other entries in the spells files by importing `common/SPELLS` and using the assigned property on the SPELLS object. Please try to avoid abbreviating properties.
 */

export default {
  // Beast Mastery:
  // ...

  // Marksmanship:
  // ...

  WINDBURST: {
    id: 204147,
    name: 'Windburst',
    icon: 'inv_bow_1h_artifactwindrunner_d_02',
  },
  WINDBURST_MOVEMENT_SPEED: {
    id: 204477,
    name: 'Windburst',
    icon: 'ability_hunter_focusedaim',
  },
  AIMED_SHOT: {
    id: 19434,
    name: 'Aimed Shot',
    icon: 'inv_spear_07',
  },
  ARCANE_SHOT: {
    id: 185358,
    name: 'Arcane Shot',
    icon: 'ability_impalingbolt',
  },
  MARKED_SHOT: {
    id: 185901,
    name: 'Marked Shot',
    icon: 'ability_hunter_markedshot',
  },
  DISENGAGE: {
    id: 781,
    name: 'Disengage',
    icon: 'ability_rogue_feint',
  },
  TRUESHOT: {
    id: 193526,
    name: 'Trueshot',
    icon: 'ability_trueshot',
  },
  MULTISHOT: {
    id: 2643,
    name: 'Multi-Shot',
    icon: 'ability_upgrademoonglaive',
  },
  EXHILARATION: {
    id: 109304,
    name: 'Exhilaration',
    icon: 'ability_hunter_onewithnature',
  },
  ASPECT_OF_THE_CHEETAH: {
    id: 186257,
    name: 'Aspect of the Cheetah',
    icon: 'ability_mount_jungletiger',
  },
  ASPECT_OF_THE_TURTLE: {
    id: 186265,
    name: 'Aspect of the Turtle',
    icon: 'ability_hunter_pet_turtle',
  },
  BURSTING_SHOT: {
    id: 224729,
    name: 'Bursting Shot',
    icon: 'ability_hunter_burstingshot',
  },
  CONCUSSIVE_SHOT: {
    id: 27634,
    name: 'Concussive Shot',
    icon: 'spell_frost_stun',
  },
  COUNTER_SHOT: {
    id: 147362,
    name: 'Counter Shot',
    icon: 'inv_ammo_arrow_03',
  },
  MISDIRECTION: {
    id: 34477,
    name: 'Misdrection',
    icon: 'ability_hunter_misdirection',
  },
  FREEZING_TRAP: {
    id: 187650,
    name: 'Freezing Trap',
    icon: 'spell_frost_chainsofice',
  },
  TAR_TRAP: {
    id: 187698,
    name: 'Tar Trap',
    icon: 'spell_yorsahj_bloodboil_black',
  },
  VULNERABLE: {
    id: 187131,
    name: 'Vulnerable',
    icon: 'ability_hunter_mastermarksman',
  },

  //CATEGORY
  AUTO_SHOT_FOCUSMODULE: {
	id: 75,
	name: 'Auto Shot',
	icon: 'ability_hunter_focusfire',
  },
  CRITICAL_FOCUS_FOCUSMODULE: {
	id: 215107,
	name: 'Critical Focus',
	icon: 'ability_druid_replenish',
  },
  MULTISHOT_FOCUSMODULE: {
    id: 213363,
    name: 'Multi-Shot',
    icon: 'ability_upgrademoonglaive',
  },
  ARCANE_SHOT_FOCUSMODULE: {
    id: 187675,
    name: 'Arcane Shot',
    icon: 'ability_impalingbolt',
  },

  // Survival:
  // ...

  // Shared:
  // ...
  NETHERWINDS: {
    id: 160452,
    name: 'Netherwinds',
    icon: 'spell_arcane_massdispel',
  },
  ANCIENT_HYSTERIA: {
    id: 90355,
    name: 'Ancient Hysteria',
    icon: 'spell_shadow_unholyfrenzy',
  },
};
<|endoftext|>