<commit_before>import fivetwelve from '/libs/fivetwelve/index.js'
import USBSerial from './USBSerial.js'
import ArduinoLeonardoETHDriver from '/src/devices/dmx/driver/ArduinoLeonardoETHDriver.js'

/**
 * Manage USB ports.
 */
export default class USBManager {
  constructor(param) {

    this.config = param.config

    // List of MIDI controller
    this.list = new Map()

    // USBSerial
    this.serial = new USBSerial({})

    // USBPort
    this.port = null

    // @TODO: Move ALL OF THIS into it's own module
    const driver = new ArduinoLeonardoETHDriver(this.port, {})
    // Create the output by using the driver and set the amount of universes that are controlled by this interface
    // DmxOutput
    this.output = fivetwelve.default(driver, 1)
  }

  /*
   * Enable WebUSB and request a USBPort
   */
  enable() {
    console.log(this.serial.getPorts().then(list => {
      console.log(list)
    }))

    this.serial.requestPort().then(selectedPort => {

      this.port = selectedPort
      this.connect()

    }).
    catch(error => {
      console.error(error)
    })
  }

  /*
   * Connect to a selected USBPort
   */
  connect() {
    this.port.connect().then(() => {

      // Receive data
      this.port.onReceive = data => {
        const textDecoder = new TextDecoder()
        console.log(textDecoder.decode(data))
      }

      // Receive error
      this.port.onReceiveError = error => {
        console.error(error)
      }

    }, error => {
      console.error(error)
    })
  }

  /*
   * Update the value of a specific channel
   *
   * @TODO: Does this make any sense here? Shouldn't it be moved into the driver?
   */
  update(channel, value) {
    // @TODO: Fix for multiple universes
    this.output.getBuffer(1)[channel] = value

    // @TODO: Remove after debugging
    console.log(this.output.getBuffer(1))
  }

}
<commit_msg>Many things<commit_after>import fivetwelve from '/libs/fivetwelve/index.js'
import USBSerial from './USBSerial.js'
import ArduinoLeonardoETHDriver from '/src/devices/dmx/driver/ArduinoLeonardoETHDriver.js'

/**
 * Manage USB ports.
 */
export default class USBManager {
  constructor(param) {

    this.config = param.config

    // List of MIDI controller
    this.list = new Map()

    // USBSerial
    this.serial = new USBSerial({})

    // USBPort
    this.port = null

    this.devices = null

    // @TODO: Move ALL OF THIS into it's own module
    const driver = new ArduinoLeonardoETHDriver(this.port, {})
    // Create the output by using the driver and set the amount of universes that are controlled by this interface
    // DmxOutput
    this.output = fivetwelve.default(driver, 1)

    // Check for USB devices that are already paired
    this.serial.getPorts().then(list => {

      if (list[0] !== undefined && list[0].hasOwnProperty('device')) {
        this.port = list[0]
        this.connect()
      }

    })
  }

  /*
   * Enable WebUSB and request a USBPort
   */
  enable() {
    this.serial.requestPort().then(selectedPort => {

      this.port = selectedPort
      this.connect()

    }).
    catch(error => {
      console.error(error)
    })
  }

  /*
   * Connect to a selected USBPort
   */
  connect() {
    this.port.connect().then(() => {

      // Receive data
      this.port.onReceive = data => {
        const textDecoder = new TextDecoder()
        console.log(textDecoder.decode(data))
      }

      // Receive error
      this.port.onReceiveError = error => {
        console.error(error)
      }

    }, error => {
      console.error(error)
    })
  }

  /*
   * Update the value of a specific channel
   *
   * @TODO: Does this make any sense here? Shouldn't it be moved into the driver?
   */
  update(channel, value) {
    // @TODO: Fix for multiple universes
    this.output.getBuffer(1)[channel] = value

    // @TODO: Remove after debugging
    console.log(this.output.getBuffer(1))
  }

}
<|endoftext|>


<commit_before>idrinth.tier = {
    /**
     *
     * @type {object}
     */
    list: { },
    /**
     *
     * @type {object}
     */
    taggedSlots: { },
    /**
     *
     * @param {string} name
     * @returns {undefined}
     */
    addTagged: function ( name ) {
        /**
         *
         * @param {string} key
         * @returns {Boolean}
         */
        var isValidParameter = function ( name ) {
            return name && idrinth.tier.list.hasOwnProperty ( name ) && typeof idrinth.tier.list[name] !== 'function' && !document.getElementById ( 'idrinth-tier-box-' + name );
        };
        /**
         *
         * @param {string} key
         * @returns {Boolean}
         */
        var isFreeSlot = function ( key ) {
            return idrinth.tier.taggedSlots.hasOwnProperty ( key ) && typeof key !== 'function' && idrinth.tier.taggedSlots[key] === null;
        };
        if ( !isValidParameter ( name ) ) {
            return;
        }
        var boss = this.list[name];
        /**
         *
         * @param {int} x
         * @param {string} name
         * @returns {undefined}
         */
        var make = function ( x, name ) {
            var makeElement = function ( label, number, description ) {
                return {
                    content: label + ' ' + idrinth.ui.formatNumber ( number ),
                    attributes: [ {
                            name: 'title',
                            value: description
                        } ]
                };
            };
            var info = [
                makeElement ( 'FS', boss.fs.nm, 'Fair share' ),
                makeElement ( 'AP', boss.ap, 'Achievement point damage' )
            ];
            if ( boss.os && boss.os.nm ) {
                info.push ( makeElement ( 'OS', boss.os.nm, 'Optimal share' ) );
                info.unshift ( makeElement ( 'MA', boss.nm[boss.nm.length - 1], 'Maximum/highest tier' ) );
                info.unshift ( makeElement ( 'MI', boss.nm[0], 'Minimum/lowest tier' ) );
            }
            info.unshift (
                    {
                        type: 'strong',
                        content: boss.name.replace ( /\(.*$/, '' )
                    } );
            idrinth.tier.taggedSlots[x] = idrinth.ui.buildElement (
                    {
                        id: 'idrinth-tier-box-' + name,
                        css: 'idrinth-hovering-box idrinth-tier-box',
                        children: [ {
                                children: info
                            } ],
                        attributes: [
                            {
                                name: 'title',
                                value: 'click to close'
                            },
                            {
                                name: 'onclick',
                                value: 'idrinth.ui.removeElement(this.id);idrinth.tier.taggedSlots[\'' + x + '\']=null;'
                            },
                            {
                                name: 'style',
                                value: 'left:' + x + 'px;background-image: url(https://dotd.idrinth.de/static/raid-image-service/' + boss.url + '/);'
                            }
                        ]
                    }
            );
            idrinth.ui.body.appendChild ( idrinth.tier.taggedSlots[x] );
        };
        for (var key in this.taggedSlots) {
            if ( isFreeSlot ( key ) ) {
                return make ( key, name );
            }
        }
        idrinth.core.alert ( idrinth.text.get ( "tier.maxBoxes" ) );
    },
    /**
     * initializes this module
     * @returns {undefined}
     */
    start: function ( ) {
        'use strict';
        var pos = 1;
        /**
         * parsed a json-response and fills tier list and exclusion list
         * @param {string} data
         * @returns {undefined}
         */
        var importData = function ( data ) {
            'use strict';
            data = JSON.parse ( data );
            if ( data ) {
                idrinth.tier.list = data;
                var create = function ( name, url ) {
                    'use strict';
                    if ( !idrinth.settings.data.bannedRaids[name] ) {
                        idrinth.settings.data.bannedRaids[name] = false;
                        window.localStorage.setItem ( 'idotd', JSON.stringify ( idrinth.settings.data ) );
                    }
                    document.getElementById ( 'idrinth-raid-may-join-list' ).appendChild ( idrinth.ui.buildElement ( {
                        name: 'bannedRaids#' + name,
                        rType: '#input',
                        type: 'checkbox',
                        id: 'idrinth-raid-may-join-list-' + name,
                        label: idrinth.text.get ( "raids.disableJoining" ) + name
                    } ) );
                    document.getElementById ( 'idrinth-raid-may-join-list' ).lastChild.setAttribute ( 'style',
                            'background-image:url(https://dotd.idrinth.de/static/raid-image-service/' + url + '/);' );
                };
                for (var key in data) {
                    if ( data[key].name ) {
                        create ( data[key].name, data[key].url );
                    }
                }
            } else {
                window.setTimeout ( idrinth.tier.start, 1000 );
            }
        };
        while ( 0 < window.innerWidth - 140 * ( pos + 1 ) ) {
            this.taggedSlots[( pos * 140 ).toString ( )] = null;
            pos++;
        }
        idrinth.core.ajax.runHome (
                'tier-service/',
                importData,
                function ( ) {
                    window.setTimeout ( idrinth.tier.start, 10000 );
                },
                function ( ) {
                    window.setTimeout ( idrinth.tier.start, 10000 );
                }
        );
    },
    /**
     * displays bosses that match both name and type
     * @returns {undefined}
     */
    getMatchingTiers: function ( ) {
        var name = document.getElementById ( 'idrinth-tierlist-namesearch' ).value;
        var type = document.getElementById ( 'idrinth-tierlist-typesearch' ).value;
        /**
         *
         * @param {HTMLElement} elem
         * @returns {undefined}
         */
        var clearInnerHtml = function ( elem ) {
            elem.innerHTML = '';
        };
        /**
         *
         * @param {string} list
         * @returns {undefined}
         */
        var makeList = function ( list ) {
            /**
             *
             * @param {string} listKey
             * @param {string} difficulty
             * @param {string} ic
             * @returns {object} for the buildElement wrapper
             */
            var makeField = function ( listKey, difficulty, ic ) {
                var ln = {
                    type: 'td'
                };
                try {
                    ln.styles = idrinth.tier.list[listKey].os[difficulty] === idrinth.tier[listKey][difficulty][ic] ? 'is-os' : '';
                } catch ( E ) {
                    idrinth.core.log ( E.toString ( ) );
                }
                try {
                    ln.content = idrinth.ui.formatNumber ( idrinth.tier.list[listKey][difficulty][ic] ) + ' ' +
                            idrinth.tier.list[listKey].epics[difficulty][ic] + 'E';
                } catch ( E2 ) {
                    idrinth.core.log ( E2.toString ( ) );
                    try {
                        ln.content = idrinth.ui.formatNumber ( idrinth.tier.list[listKey][difficulty][ic] );
                    } catch ( E3 ) {
                        idrinth.core.log ( E3.toString ( ) );
                    }
                }
                return ln;
            };
            /**
             *
             * @param {string} title
             * @param {object} dataset
             * @returns {HTMLElement}
             */
            var makeRow = function ( title, dataset ) {
                return {
                    type: 'tr',
                    children: [
                        {
                            type: 'th',
                            content: title
                        },
                        {
                            type: 'td',
                            content: idrinth.ui.formatNumber ( dataset.n )
                        },
                        {
                            type: 'td',
                            content: idrinth.ui.formatNumber ( dataset.h )
                        },
                        {
                            type: 'td',
                            content: idrinth.ui.formatNumber ( dataset.l )
                        },
                        {
                            type: 'td',
                            content: idrinth.ui.formatNumber ( dataset.nm )
                        }
                    ]
                };
            };
            var wrapper = document.getElementById ( 'idrinth-tierlist' );
            clearInnerHtml ( wrapper );
            for (var count = list.length - 1; count >= 0; count--) {
                var sub = idrinth.ui.buildElement ( {
                    css: 'tier-wrapper',
                    children: [
                        {
                            type: 'img',
                            attributes: [ {
                                    name: 'src',
                                    value: 'https://dotd.idrinth.de/static/raid-image-service/' + idrinth.tier.list[list[count]].url + '/'
                                } ]
                        },
                        {
                            type: 'strong',
                            content: idrinth.tier.list[list[count]].name
                        },
                        {
                            type: 'span',
                            content: idrinth.tier.list[list[count]].types.join ( ', ' )
                        },
                        {
                            type: 'button',
                            content: idrinth.text.get ( "tier.tag" ),
                            attributes: [
                                {
                                    name: 'onclick',
                                    value: 'idrinth.tier.addTagged(\'' + list[count].replace ( /'/g, '\\\'' ) + '\');'
                                },
                                {
                                    name: 'type',
                                    value: 'action'
                                }
                            ]
                        },
                        {
                            type: 'span',
                            content: 'AP: ' + idrinth.ui.formatNumber ( idrinth.tier.list[list[count]].ap )
                        },
                        {
                            type: 'table',
                            children: [
                                {
                                    type: 'thead',
                                    children: [
                                        {
                                            type: 'tr',
                                            children: [
                                                {
                                                    type: 'th',
                                                    content: '#'
                                                },
                                                {
                                                    type: 'th',
                                                    content: idrinth.text.get ( "tier.diff.normal" )
                                                },
                                                {
                                                    type: 'th',
                                                    content: idrinth.text.get ( "tier.diff.hard" )
                                                },
                                                {
                                                    type: 'th',
                                                    content: idrinth.text.get ( "tier.diff.legend" )
                                                },
                                                {
                                                    type: 'th',
                                                    content: idrinth.text.get ( "tier.diff.night" )
                                                }
                                            ]
                                        }
                                    ]
                                },
                                {
                                    type: 'tbody',
                                    children: [
                                        makeRow ( 'FS', idrinth.tier.list[list[count]].fs ),
                                        makeRow ( 'OS', idrinth.tier.list[list[count]].os ),
                                        makeRow ( '', {
                                            n: '',
                                            l: '',
                                            h: '',
                                            nm: ''
                                        } )
                                    ]
                                }
                            ]
                        }
                    ]
                } );
                var maxTiers = Math.max ( idrinth.tier.list[list[count]].n.length, idrinth.tier.list[list[count]].h.length, idrinth.tier.list[list[count]].l.length, idrinth.tier.list[list[count]].nm.length );
                for (var ic = 0; ic < maxTiers; ic++) {
                    sub.lastChild.lastChild.appendChild ( idrinth.ui.buildElement ( {
                        type: 'tr',
                        children: [
                            {
                                type: 'th',
                                content: ic + 1
                            },
                            makeField ( list[count], 'n', ic ),
                            makeField ( list[count], 'h', ic ),
                            makeField ( list[count], 'l', ic ),
                            makeField ( list[count], 'nm', ic )
                        ]
                    } ) );
                }
                wrapper.appendChild ( sub );
            }
        };
        /**
         *
         * @param {Array} list
         * @param {RegExp} regExp
         * @returns {Boolean}
         */
        var matchesAny = function ( list, regExp ) {
            for (var count = 0; count < list.length; count++) {
                if ( list[count] && list[count].match ( regExp ) ) {
                    return true;
                }
            }
            return false;
        };
        if ( ( !name || name.length === 0 ) && ( !type || type.length === 0 ) ) {
            clearInnerHtml ( document.getElementById ( 'idrinth-tierlist' ) );
            return;
        }
        var result = [ ];
        var nameRegExp = new RegExp ( name, 'i' );
        var typeRegExp = new RegExp ( type, 'i' );
        for (var key in idrinth.tier.list) {
            if ( key.match ( nameRegExp ) && matchesAny ( idrinth.tier.list[key].types, typeRegExp ) ) {
                result.push ( key );
            }
        }
        makeList ( result );
    }
};
<commit_msg>removing unused "use strict" statements<commit_after>idrinth.tier = {
    /**
     *
     * @type {object}
     */
    list: { },
    /**
     *
     * @type {object}
     */
    taggedSlots: { },
    /**
     *
     * @param {string} name
     * @returns {undefined}
     */
    addTagged: function ( name ) {
        /**
         *
         * @param {string} key
         * @returns {Boolean}
         */
        var isValidParameter = function ( name ) {
            return name && idrinth.tier.list.hasOwnProperty ( name ) && typeof idrinth.tier.list[name] !== 'function' && !document.getElementById ( 'idrinth-tier-box-' + name );
        };
        /**
         *
         * @param {string} key
         * @returns {Boolean}
         */
        var isFreeSlot = function ( key ) {
            return idrinth.tier.taggedSlots.hasOwnProperty ( key ) && typeof key !== 'function' && idrinth.tier.taggedSlots[key] === null;
        };
        if ( !isValidParameter ( name ) ) {
            return;
        }
        var boss = this.list[name];
        /**
         *
         * @param {int} x
         * @param {string} name
         * @returns {undefined}
         */
        var make = function ( x, name ) {
            var makeElement = function ( label, number, description ) {
                return {
                    content: label + ' ' + idrinth.ui.formatNumber ( number ),
                    attributes: [ {
                            name: 'title',
                            value: description
                        } ]
                };
            };
            var info = [
                makeElement ( 'FS', boss.fs.nm, 'Fair share' ),
                makeElement ( 'AP', boss.ap, 'Achievement point damage' )
            ];
            if ( boss.os && boss.os.nm ) {
                info.push ( makeElement ( 'OS', boss.os.nm, 'Optimal share' ) );
                info.unshift ( makeElement ( 'MA', boss.nm[boss.nm.length - 1], 'Maximum/highest tier' ) );
                info.unshift ( makeElement ( 'MI', boss.nm[0], 'Minimum/lowest tier' ) );
            }
            info.unshift (
                    {
                        type: 'strong',
                        content: boss.name.replace ( /\(.*$/, '' )
                    } );
            idrinth.tier.taggedSlots[x] = idrinth.ui.buildElement (
                    {
                        id: 'idrinth-tier-box-' + name,
                        css: 'idrinth-hovering-box idrinth-tier-box',
                        children: [ {
                                children: info
                            } ],
                        attributes: [
                            {
                                name: 'title',
                                value: 'click to close'
                            },
                            {
                                name: 'onclick',
                                value: 'idrinth.ui.removeElement(this.id);idrinth.tier.taggedSlots[\'' + x + '\']=null;'
                            },
                            {
                                name: 'style',
                                value: 'left:' + x + 'px;background-image: url(https://dotd.idrinth.de/static/raid-image-service/' + boss.url + '/);'
                            }
                        ]
                    }
            );
            idrinth.ui.body.appendChild ( idrinth.tier.taggedSlots[x] );
        };
        for (var key in this.taggedSlots) {
            if ( isFreeSlot ( key ) ) {
                return make ( key, name );
            }
        }
        idrinth.core.alert ( idrinth.text.get ( "tier.maxBoxes" ) );
    },
    /**
     * initializes this module
     * @returns {undefined}
     */
    start: function ( ) {
        'use strict';
        var pos = 1;
        /**
         * parsed a json-response and fills tier list and exclusion list
         * @param {string} data
         * @returns {undefined}
         */
        var importData = function ( data ) {
            data = JSON.parse ( data );
            if ( data ) {
                idrinth.tier.list = data;
                var create = function ( name, url ) {
                    if ( !idrinth.settings.data.bannedRaids[name] ) {
                        idrinth.settings.data.bannedRaids[name] = false;
                        window.localStorage.setItem ( 'idotd', JSON.stringify ( idrinth.settings.data ) );
                    }
                    document.getElementById ( 'idrinth-raid-may-join-list' ).appendChild ( idrinth.ui.buildElement ( {
                        name: 'bannedRaids#' + name,
                        rType: '#input',
                        type: 'checkbox',
                        id: 'idrinth-raid-may-join-list-' + name,
                        label: idrinth.text.get ( "raids.disableJoining" ) + name
                    } ) );
                    document.getElementById ( 'idrinth-raid-may-join-list' ).lastChild.setAttribute ( 'style',
                            'background-image:url(https://dotd.idrinth.de/static/raid-image-service/' + url + '/);' );
                };
                for (var key in data) {
                    if ( data[key].name ) {
                        create ( data[key].name, data[key].url );
                    }
                }
            } else {
                window.setTimeout ( idrinth.tier.start, 1000 );
            }
        };
        while ( 0 < window.innerWidth - 140 * ( pos + 1 ) ) {
            this.taggedSlots[( pos * 140 ).toString ( )] = null;
            pos++;
        }
        idrinth.core.ajax.runHome (
                'tier-service/',
                importData,
                function ( ) {
                    window.setTimeout ( idrinth.tier.start, 10000 );
                },
                function ( ) {
                    window.setTimeout ( idrinth.tier.start, 10000 );
                }
        );
    },
    /**
     * displays bosses that match both name and type
     * @returns {undefined}
     */
    getMatchingTiers: function ( ) {
        var name = document.getElementById ( 'idrinth-tierlist-namesearch' ).value;
        var type = document.getElementById ( 'idrinth-tierlist-typesearch' ).value;
        /**
         *
         * @param {HTMLElement} elem
         * @returns {undefined}
         */
        var clearInnerHtml = function ( elem ) {
            elem.innerHTML = '';
        };
        /**
         *
         * @param {string} list
         * @returns {undefined}
         */
        var makeList = function ( list ) {
            /**
             *
             * @param {string} listKey
             * @param {string} difficulty
             * @param {string} ic
             * @returns {object} for the buildElement wrapper
             */
            var makeField = function ( listKey, difficulty, ic ) {
                var ln = {
                    type: 'td'
                };
                try {
                    ln.styles = idrinth.tier.list[listKey].os[difficulty] === idrinth.tier[listKey][difficulty][ic] ? 'is-os' : '';
                } catch ( E ) {
                    idrinth.core.log ( E.toString ( ) );
                }
                try {
                    ln.content = idrinth.ui.formatNumber ( idrinth.tier.list[listKey][difficulty][ic] ) + ' ' +
                            idrinth.tier.list[listKey].epics[difficulty][ic] + 'E';
                } catch ( E2 ) {
                    idrinth.core.log ( E2.toString ( ) );
                    try {
                        ln.content = idrinth.ui.formatNumber ( idrinth.tier.list[listKey][difficulty][ic] );
                    } catch ( E3 ) {
                        idrinth.core.log ( E3.toString ( ) );
                    }
                }
                return ln;
            };
            /**
             *
             * @param {string} title
             * @param {object} dataset
             * @returns {HTMLElement}
             */
            var makeRow = function ( title, dataset ) {
                return {
                    type: 'tr',
                    children: [
                        {
                            type: 'th',
                            content: title
                        },
                        {
                            type: 'td',
                            content: idrinth.ui.formatNumber ( dataset.n )
                        },
                        {
                            type: 'td',
                            content: idrinth.ui.formatNumber ( dataset.h )
                        },
                        {
                            type: 'td',
                            content: idrinth.ui.formatNumber ( dataset.l )
                        },
                        {
                            type: 'td',
                            content: idrinth.ui.formatNumber ( dataset.nm )
                        }
                    ]
                };
            };
            var wrapper = document.getElementById ( 'idrinth-tierlist' );
            clearInnerHtml ( wrapper );
            for (var count = list.length - 1; count >= 0; count--) {
                var sub = idrinth.ui.buildElement ( {
                    css: 'tier-wrapper',
                    children: [
                        {
                            type: 'img',
                            attributes: [ {
                                    name: 'src',
                                    value: 'https://dotd.idrinth.de/static/raid-image-service/' + idrinth.tier.list[list[count]].url + '/'
                                } ]
                        },
                        {
                            type: 'strong',
                            content: idrinth.tier.list[list[count]].name
                        },
                        {
                            type: 'span',
                            content: idrinth.tier.list[list[count]].types.join ( ', ' )
                        },
                        {
                            type: 'button',
                            content: idrinth.text.get ( "tier.tag" ),
                            attributes: [
                                {
                                    name: 'onclick',
                                    value: 'idrinth.tier.addTagged(\'' + list[count].replace ( /'/g, '\\\'' ) + '\');'
                                },
                                {
                                    name: 'type',
                                    value: 'action'
                                }
                            ]
                        },
                        {
                            type: 'span',
                            content: 'AP: ' + idrinth.ui.formatNumber ( idrinth.tier.list[list[count]].ap )
                        },
                        {
                            type: 'table',
                            children: [
                                {
                                    type: 'thead',
                                    children: [
                                        {
                                            type: 'tr',
                                            children: [
                                                {
                                                    type: 'th',
                                                    content: '#'
                                                },
                                                {
                                                    type: 'th',
                                                    content: idrinth.text.get ( "tier.diff.normal" )
                                                },
                                                {
                                                    type: 'th',
                                                    content: idrinth.text.get ( "tier.diff.hard" )
                                                },
                                                {
                                                    type: 'th',
                                                    content: idrinth.text.get ( "tier.diff.legend" )
                                                },
                                                {
                                                    type: 'th',
                                                    content: idrinth.text.get ( "tier.diff.night" )
                                                }
                                            ]
                                        }
                                    ]
                                },
                                {
                                    type: 'tbody',
                                    children: [
                                        makeRow ( 'FS', idrinth.tier.list[list[count]].fs ),
                                        makeRow ( 'OS', idrinth.tier.list[list[count]].os ),
                                        makeRow ( '', {
                                            n: '',
                                            l: '',
                                            h: '',
                                            nm: ''
                                        } )
                                    ]
                                }
                            ]
                        }
                    ]
                } );
                var maxTiers = Math.max ( idrinth.tier.list[list[count]].n.length, idrinth.tier.list[list[count]].h.length, idrinth.tier.list[list[count]].l.length, idrinth.tier.list[list[count]].nm.length );
                for (var ic = 0; ic < maxTiers; ic++) {
                    sub.lastChild.lastChild.appendChild ( idrinth.ui.buildElement ( {
                        type: 'tr',
                        children: [
                            {
                                type: 'th',
                                content: ic + 1
                            },
                            makeField ( list[count], 'n', ic ),
                            makeField ( list[count], 'h', ic ),
                            makeField ( list[count], 'l', ic ),
                            makeField ( list[count], 'nm', ic )
                        ]
                    } ) );
                }
                wrapper.appendChild ( sub );
            }
        };
        /**
         *
         * @param {Array} list
         * @param {RegExp} regExp
         * @returns {Boolean}
         */
        var matchesAny = function ( list, regExp ) {
            for (var count = 0; count < list.length; count++) {
                if ( list[count] && list[count].match ( regExp ) ) {
                    return true;
                }
            }
            return false;
        };
        if ( ( !name || name.length === 0 ) && ( !type || type.length === 0 ) ) {
            clearInnerHtml ( document.getElementById ( 'idrinth-tierlist' ) );
            return;
        }
        var result = [ ];
        var nameRegExp = new RegExp ( name, 'i' );
        var typeRegExp = new RegExp ( type, 'i' );
        for (var key in idrinth.tier.list) {
            if ( key.match ( nameRegExp ) && matchesAny ( idrinth.tier.list[key].types, typeRegExp ) ) {
                result.push ( key );
            }
        }
        makeList ( result );
    }
};
<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2017 Mickael Jeanroy
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

'use strict';

const _ = require('lodash');
const bower = require('bower');
const Q = require('q');

module.exports = {
  list(options = {}) {
    return list(options);
  },
};

/**
 * List all dependencies of a bower package.
 *
 * @param {Object} options Bower options.
 * @return {Promise<Object>} The promise of dependency object.
 */
function list(options) {
  const deferred = Q.defer();

  const json = options.json !== false;
  const offline = options.offline !== false;
  const cwd = options.cwd || process.cwd();
  const config = {json, offline, cwd};

  bower.commands.list(undefined, config)
    .on('end', (conf) => {
      deferred.resolve(flatten(conf));
    })
    .on('error', (error) => {
      deferred.reject(error);
    });

  return deferred.promise;
}

/**
 * Flatten dependency tree into a single dependency object:
 * - Object entry is the dependency name (i.e package name).
 * - Object value is the dependency metadata.
 *
 * @param {Object} pkg The package entrypoint.
 * @param {Object} dependencies Current dependencies (object populated and returned).
 * @return {Object} The dependencies.
 */
function flatten(pkg, dependencies = {}) {
  _.forEach(pkg.dependencies, (dep, id) => {
    if (!_.has(dependencies, id)) {
      // Store current dependency...
      dependencies[id] = dep;

      // ... and add transitive dependencies
      _.extend(dependencies, flatten(dep, dependencies));
    }
  });

  return dependencies;
}
<commit_msg>core: rename internal function<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2017 Mickael Jeanroy
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

'use strict';

const _ = require('lodash');
const bower = require('bower');
const Q = require('q');

module.exports.list = function(options = {}) {
  return execList(options);
};

/**
 * List all dependencies of a bower package.
 *
 * @param {Object} options Bower options.
 * @return {Promise<Object>} The promise of dependency object.
 */
function execList(options) {
  const deferred = Q.defer();

  const json = options.json !== false;
  const offline = options.offline !== false;
  const cwd = options.cwd || process.cwd();
  const config = {json, offline, cwd};

  bower.commands.list(undefined, config)
    .on('end', (conf) => {
      deferred.resolve(flatten(conf));
    })
    .on('error', (error) => {
      deferred.reject(error);
    });

  return deferred.promise;
}

/**
 * Flatten dependency tree into a single dependency object:
 * - Object entry is the dependency name (i.e package name).
 * - Object value is the dependency metadata.
 *
 * @param {Object} pkg The package entrypoint.
 * @param {Object} dependencies Current dependencies (object populated and returned).
 * @return {Object} The dependencies.
 */
function flatten(pkg, dependencies = {}) {
  _.forEach(pkg.dependencies, (dep, id) => {
    if (!_.has(dependencies, id)) {
      // Store current dependency...
      dependencies[id] = dep;

      // ... and add transitive dependencies
      _.extend(dependencies, flatten(dep, dependencies));
    }
  });

  return dependencies;
}
<|endoftext|>


<commit_before>/**
 * Provices event schedules for F1 season.
 */

"use strict";

let EventEmitter = require("events");
let fs = require("fs");
let ical = require("ical.js");
let moment = require("moment");
let proxy = require("../core/proxy");
let util = require("util");

class EventCalendar {
  constructor(config) {
    this.events = new EventEmitter;
    this.config = config;
    this.calendar = [];

    this.timers = {
      weekStart: null,
      weekendStart: null,
      weekendEnd: null,
    };
  }

  reload() {
    return new Promise((resolve, reject) => {
      fs.readFile(this.filePath, (error, data) => {
        if (error) {
          return reject(error);
        }

        (new CalendarParser).parse(data.toString()).then(events => {
          this.calendar = events;
          resolve();
        });
      });
    });
  }

  watch() {
    if (this.watching) {
      return;
    }

    let race = this.nextRace;
    let ref_date = moment.utc(race.date).substract(2, "days").hours(0);

    this.timers.weekStart = setTimeout(() => {
      this.events.emit("race.week.begin");
    }, moment(ref).startOf("isoweek").diff());

    this.timers.weekendStart = setTimeout(() => {
      this.events.emit("race.weekend.begin");
    }, moment(ref).diff());

    this.timers.weekendEnd = setTimeout(() => {
      this.events.emit("race.week.end");
      this.events.emit("race.weekend.end");
    }, moment(race.date).add(1.5, "hours").diff());
  }

  race(num) {
    for (let i = 0; i < this.calendar.length; i++) {
      let event = this.calendar[i];
      if (event.type == EventInfo.RACE) {
        if (--num == 0) {
          return event;
        }
      }
    }
  },

  findNext(type) {
    let now = new Date;
    for (let i = 0; i < this.calendar.length; i++) {
      let event = this.calendar[i];
      if (event.date >= now) {
        if (!type || event.type == type) {
          return event;
        }
      }
    }
  }

  get currentEvent() {
    let now = new Date;
    for (let i = 0; i < this.calendar.length; i++) {
      let event = this.calendar[i];
      if (event.data.start >= now && event.data.end <= now) {
        return event;
      }
    }
  }

  get nextEvent() {
    return this.findNext();
  }

  get nextRace() {
    return this.findNext(EventInfo.RACE);
  }

  get nextQualifying() {
    return this.findNext(EventInfo.QUALIFYING);
  }

  get lastRace() {
    let now = new Date;
    let race_i = 0;
    for (let i = 0; i < this.calendar.length; i++) {
      let event = this.calendar[i];
      if (event.type == EventInfo.RACE) {
        race_i++;
        if (event.date > now) {
          return this.race(race_i - 1);
        }
      }
    }
    return this.calendar[this.calendar.length - 1];
  }

  get filePath() {
    return this.config.file;
  }

  get watching() {
    return this.timers.weekendStart != null;
  }
}

class CalendarParser {
  parse(data) {
    return new Promise((resolve, reject) => {
      let parsed = ical.parse(data);
      let cal = new ical.Component(parsed);
      let items = cal.getAllSubcomponents("vevent");
      let events = [];
      let round = 1;

      items.forEach((vevent, i) => {
        process.nextTick(() => {
          let event = new ical.Event(vevent);
          let parsed = event.summary.match(/([\w\s]+) Session \(([\w\s]+)\)/);
          let title = event.summary;

          if (parsed) {
            title = parsed[1] + ", " + parsed[2];
          }

          let type = title.match(/practi[cs]e/i) ? EventInfo.PRACTISE
            : (title.match(/quali/i) ? EventInfo.QUALIFYING : EventInfo.RACE);

          events.push(new EventInfo({
            title: title,
            location: event.location,
            start: event.startDate.toJSDate(),
            end: event.endDate.toJSDate(),
            type: type,
            round: round,
          }));

          if (type == EventInfo.RACE) {
            round++;
          }

          if (events.length == items.length) {
            resolve(events);
          }
        });
      });
    });
  }
}

class EventInfo {
  constructor(data) {
    this.data = data;
  }

  get date() {
    return this.data.start;
  }

  get type() {
    return this.data.type;
  }

  get title() {
    return this.data.title;
  }

  get round() {
    return this.data.round;
  }
}

EventInfo.PRACTISE = 1;
EventInfo.QUALIFYING = 2;
EventInfo.RACE = 3;

exports.configure = function(connection) {
  let calendar = new EventCalendar(connection.config.modules.seasoncalendar);

  calendar.reload().then(proxy(calendar.watch, calendar), error => {
    console.error("eventcalendar:", error.stack);
  });

  connection.addCommand("next", () => {
    return new Promise((resolve, reject) => {
      let current = calendar.currentEvent;

      if (current) {
        return resolve(util.format("Currently running: %s", current.title));
      }

      let event = calendar.nextEvent;

      if (!event) {
        return reject("No event info found");
      }

      let date = moment.utc(event.date);
      let diff = moment.duration(date.diff());
      let timestamp = date.format("MMMM D, HH:mm UTC");
      let display = [event.title + ": ", timestamp];

      if (diff.days() > 0 || diff.hours() > 0 || diff.minutes() > 0) {
        display.push(" (in");

        if (diff.weeks() > 0) {
          display.push(util.format(" %d weeks", diff.weeks()));
        }

        if (diff.days() > 0) {
          display.push(util.format(" %d days", diff.days() % 7));
        }

        if (diff.hours()) {
          display.push(util.format(" %d hours", diff.hours()));
        }

        if (diff.minutes()) {
          display.push(util.format(" %d minutes", diff.minutes()));
        }

        display.push(")");
      }

      resolve(display.join(""));
    });
  });

  return calendar;
};
<commit_msg>Fix syntax error<commit_after>/**
 * Provices event schedules for F1 season.
 */

"use strict";

let EventEmitter = require("events");
let fs = require("fs");
let ical = require("ical.js");
let moment = require("moment");
let proxy = require("../core/proxy");
let util = require("util");

class EventCalendar {
  constructor(config) {
    this.events = new EventEmitter;
    this.config = config;
    this.calendar = [];

    this.timers = {
      weekStart: null,
      weekendStart: null,
      weekendEnd: null,
    };
  }

  reload() {
    return new Promise((resolve, reject) => {
      fs.readFile(this.filePath, (error, data) => {
        if (error) {
          return reject(error);
        }

        (new CalendarParser).parse(data.toString()).then(events => {
          this.calendar = events;
          resolve();
        });
      });
    });
  }

  watch() {
    if (this.watching) {
      return;
    }

    let race = this.nextRace;
    let ref_date = moment.utc(race.date).substract(2, "days").hours(0);

    this.timers.weekStart = setTimeout(() => {
      this.events.emit("race.week.begin");
    }, moment(ref).startOf("isoweek").diff());

    this.timers.weekendStart = setTimeout(() => {
      this.events.emit("race.weekend.begin");
    }, moment(ref).diff());

    this.timers.weekendEnd = setTimeout(() => {
      this.events.emit("race.week.end");
      this.events.emit("race.weekend.end");
    }, moment(race.date).add(1.5, "hours").diff());
  }

  race(num) {
    for (let i = 0; i < this.calendar.length; i++) {
      let event = this.calendar[i];
      if (event.type == EventInfo.RACE) {
        if (--num == 0) {
          return event;
        }
      }
    }
  }

  findNext(type) {
    let now = new Date;
    for (let i = 0; i < this.calendar.length; i++) {
      let event = this.calendar[i];
      if (event.date >= now) {
        if (!type || event.type == type) {
          return event;
        }
      }
    }
  }

  get currentEvent() {
    let now = new Date;
    for (let i = 0; i < this.calendar.length; i++) {
      let event = this.calendar[i];
      if (event.data.start >= now && event.data.end <= now) {
        return event;
      }
    }
  }

  get nextEvent() {
    return this.findNext();
  }

  get nextRace() {
    return this.findNext(EventInfo.RACE);
  }

  get nextQualifying() {
    return this.findNext(EventInfo.QUALIFYING);
  }

  get lastRace() {
    let now = new Date;
    let race_i = 0;
    for (let i = 0; i < this.calendar.length; i++) {
      let event = this.calendar[i];
      if (event.type == EventInfo.RACE) {
        race_i++;
        if (event.date > now) {
          return this.race(race_i - 1);
        }
      }
    }
    return this.calendar[this.calendar.length - 1];
  }

  get filePath() {
    return this.config.file;
  }

  get watching() {
    return this.timers.weekendStart != null;
  }
}

class CalendarParser {
  parse(data) {
    return new Promise((resolve, reject) => {
      let parsed = ical.parse(data);
      let cal = new ical.Component(parsed);
      let items = cal.getAllSubcomponents("vevent");
      let events = [];
      let round = 1;

      items.forEach((vevent, i) => {
        process.nextTick(() => {
          let event = new ical.Event(vevent);
          let parsed = event.summary.match(/([\w\s]+) Session \(([\w\s]+)\)/);
          let title = event.summary;

          if (parsed) {
            title = parsed[1] + ", " + parsed[2];
          }

          let type = title.match(/practi[cs]e/i) ? EventInfo.PRACTISE
            : (title.match(/quali/i) ? EventInfo.QUALIFYING : EventInfo.RACE);

          events.push(new EventInfo({
            title: title,
            location: event.location,
            start: event.startDate.toJSDate(),
            end: event.endDate.toJSDate(),
            type: type,
            round: round,
          }));

          if (type == EventInfo.RACE) {
            round++;
          }

          if (events.length == items.length) {
            resolve(events);
          }
        });
      });
    });
  }
}

class EventInfo {
  constructor(data) {
    this.data = data;
  }

  get date() {
    return this.data.start;
  }

  get type() {
    return this.data.type;
  }

  get title() {
    return this.data.title;
  }

  get round() {
    return this.data.round;
  }
}

EventInfo.PRACTISE = 1;
EventInfo.QUALIFYING = 2;
EventInfo.RACE = 3;

exports.configure = function(connection) {
  let calendar = new EventCalendar(connection.config.modules.seasoncalendar);

  calendar.reload().then(proxy(calendar.watch, calendar), error => {
    console.error("eventcalendar:", error.stack);
  });

  connection.addCommand("next", () => {
    return new Promise((resolve, reject) => {
      let current = calendar.currentEvent;

      if (current) {
        return resolve(util.format("Currently running: %s", current.title));
      }

      let event = calendar.nextEvent;

      if (!event) {
        return reject("No event info found");
      }

      let date = moment.utc(event.date);
      let diff = moment.duration(date.diff());
      let timestamp = date.format("MMMM D, HH:mm UTC");
      let display = [event.title + ": ", timestamp];

      if (diff.days() > 0 || diff.hours() > 0 || diff.minutes() > 0) {
        display.push(" (in");

        if (diff.weeks() > 0) {
          display.push(util.format(" %d weeks", diff.weeks()));
        }

        if (diff.days() > 0) {
          display.push(util.format(" %d days", diff.days() % 7));
        }

        if (diff.hours()) {
          display.push(util.format(" %d hours", diff.hours()));
        }

        if (diff.minutes()) {
          display.push(util.format(" %d minutes", diff.minutes()));
        }

        display.push(")");
      }

      resolve(display.join(""));
    });
  });

  return calendar;
};
<|endoftext|>


<commit_before>import * as fs from 'fs'

import { createHash } from 'crypto'

import parse from './parse'
import resolve from './resolve'
import isIgnored from './ignore'

// map from settings sha1 => path => export map objects
const exportCaches = new Map()

export default class ExportMap {
  constructor(context) {
    this.context = context
    this.named = new Set()

    this.errors = []
  }

  get settings() { return this.context && this.context.settings }

  get hasDefault() { return this.named.has('default') }
  get hasNamed() { return this.named.size > (this.hasDefault ? 1 : 0) }

  static get(source, context) {

    var path = resolve(source, context)
    if (path == null) return null

    return ExportMap.for(path, context)
  }

  static for(path, context) {
    let exportMap

    const cacheKey = hashObject(context.settings)
    let exportCache = exportCaches.get(cacheKey)
    if (exportCache === undefined) {
      exportCache = new Map()
      exportCaches.set(cacheKey, exportCache)
    }

    exportMap = exportCache.get(path)
    // return cached ignore
    if (exportMap === null) return null

    const stats = fs.statSync(path)
    if (exportMap != null) {
      // date equality check
      if (exportMap.mtime - stats.mtime === 0) {
        return exportMap
      }
      // future: check content equality?
    }

    exportMap = ExportMap.parse(path, context)
    exportMap.mtime = stats.mtime

    // ignore empties, optionally
    if (exportMap.named.size === 0 && isIgnored(path, context)) {
      exportMap = null
    }

    exportCache.set(path, exportMap)

    return exportMap
  }

  static parse(path, context) {
    var m = new ExportMap(context)

    try {
      var ast = parse(path, context)
    } catch (err) {
      m.errors.push(err)
      return m // can't continue
    }

    ast.body.forEach(function (n) {
      m.captureDefault(n)
      m.captureAll(n, path)
      m.captureNamedDeclaration(n, path)
    })

    return m
  }

  resolveReExport(node, base) {
    var remotePath = resolve.relative(node.source.value, base, this.settings)
    if (remotePath == null) return null

    return ExportMap.for(remotePath, this.context)
  }

  captureDefault(n) {
    if (n.type !== 'ExportDefaultDeclaration') return
    this.named.add('default')
  }

  /**
   * capture all named exports from remote module.
   *
   * returns null if this node wasn't an ExportAllDeclaration
   * returns false if it was not resolved
   * returns true if it was resolved + parsed
   *
   * @param  {node} n
   * @param  {string} path - the path of the module currently parsing
   * @return {boolean?}
   */
  captureAll(n, path) {
    if (n.type !== 'ExportAllDeclaration') return null

    var remoteMap = this.resolveReExport(n, path)
    if (remoteMap == null) return false

    remoteMap.named.forEach(function (name) { this.named.add(name) }.bind(this))

    return true
  }

  captureNamedDeclaration(n, path) {
    if (n.type !== 'ExportNamedDeclaration') return

    // capture declaration
    if (n.declaration != null) {
      switch (n.declaration.type) {
        case 'FunctionDeclaration':
        case 'ClassDeclaration':
        case 'TypeAlias': // flowtype with babel-eslint parser
          this.named.add(n.declaration.id.name)
          break
        case 'VariableDeclaration':
          n.declaration.declarations.forEach((d) =>
            recursivePatternCapture(d.id, id => this.named.add(id.name)))
          break
      }
    }

    // capture specifiers
    let remoteMap
    if (n.source) remoteMap = this.resolveReExport(n, path)

    n.specifiers.forEach(function (s) {
      if (s.type === 'ExportDefaultSpecifier') {
        // don't add it if it is not present in the exported module
        if (!remoteMap || !remoteMap.hasDefault) return
      }

      this.named.add(s.exported.name)
    }.bind(this))
  }

  reportErrors(context, declaration) {
    context.report({
      node: declaration.source,
      message: `Parse errors in imported module '${declaration.source.value}': ` +
                  `${this.errors
                        .map(e => `${e.message} (${e.lineNumber}:${e.column})`)
                        .join(', ')}`,
    })
  }
}

/**
 * Traverse a patter/identifier node, calling 'callback'
 * for each leaf identifier.
 * @param  {node}   pattern
 * @param  {Function} callback
 * @return {void}
 */
export function recursivePatternCapture(pattern, callback) {
  switch (pattern.type) {
    case 'Identifier': // base case
      callback(pattern)
      break

    case 'ObjectPattern':
      pattern.properties.forEach(({ value }) => {
        recursivePatternCapture(value, callback)
      })
      break

    case 'ArrayPattern':
      pattern.elements.forEach((element) => {
        if (element == null) return
        recursivePatternCapture(element, callback)
      })
      break
  }
}

function hashObject(object) {
  const settingsShasum = createHash('sha1')
  settingsShasum.update(JSON.stringify(object))
  return settingsShasum.digest('hex')
}
<commit_msg>add parser, options to parse cache key<commit_after>import * as fs from 'fs'

import { createHash } from 'crypto'

import parse from './parse'
import resolve from './resolve'
import isIgnored from './ignore'

// map from settings sha1 => path => export map objects
const exportCaches = new Map()

export default class ExportMap {
  constructor(context) {
    this.context = context
    this.named = new Set()

    this.errors = []
  }

  get settings() { return this.context && this.context.settings }

  get hasDefault() { return this.named.has('default') }
  get hasNamed() { return this.named.size > (this.hasDefault ? 1 : 0) }

  static get(source, context) {

    var path = resolve(source, context)
    if (path == null) return null

    return ExportMap.for(path, context)
  }

  static for(path, context) {
    let exportMap

    const cacheKey = hashObject({
      settings: context.settings,
      parser: context.parserPath,
      parserOptions: context.parserOptions,
    })
    let exportCache = exportCaches.get(cacheKey)
    if (exportCache === undefined) {
      exportCache = new Map()
      exportCaches.set(cacheKey, exportCache)
    }

    exportMap = exportCache.get(path)
    // return cached ignore
    if (exportMap === null) return null

    const stats = fs.statSync(path)
    if (exportMap != null) {
      // date equality check
      if (exportMap.mtime - stats.mtime === 0) {
        return exportMap
      }
      // future: check content equality?
    }

    exportMap = ExportMap.parse(path, context)
    exportMap.mtime = stats.mtime

    // ignore empties, optionally
    if (exportMap.named.size === 0 && isIgnored(path, context)) {
      exportMap = null
    }

    exportCache.set(path, exportMap)

    return exportMap
  }

  static parse(path, context) {
    var m = new ExportMap(context)

    try {
      var ast = parse(path, context)
    } catch (err) {
      m.errors.push(err)
      return m // can't continue
    }

    ast.body.forEach(function (n) {
      m.captureDefault(n)
      m.captureAll(n, path)
      m.captureNamedDeclaration(n, path)
    })

    return m
  }

  resolveReExport(node, base) {
    var remotePath = resolve.relative(node.source.value, base, this.settings)
    if (remotePath == null) return null

    return ExportMap.for(remotePath, this.context)
  }

  captureDefault(n) {
    if (n.type !== 'ExportDefaultDeclaration') return
    this.named.add('default')
  }

  /**
   * capture all named exports from remote module.
   *
   * returns null if this node wasn't an ExportAllDeclaration
   * returns false if it was not resolved
   * returns true if it was resolved + parsed
   *
   * @param  {node} n
   * @param  {string} path - the path of the module currently parsing
   * @return {boolean?}
   */
  captureAll(n, path) {
    if (n.type !== 'ExportAllDeclaration') return null

    var remoteMap = this.resolveReExport(n, path)
    if (remoteMap == null) return false

    remoteMap.named.forEach(function (name) { this.named.add(name) }.bind(this))

    return true
  }

  captureNamedDeclaration(n, path) {
    if (n.type !== 'ExportNamedDeclaration') return

    // capture declaration
    if (n.declaration != null) {
      switch (n.declaration.type) {
        case 'FunctionDeclaration':
        case 'ClassDeclaration':
        case 'TypeAlias': // flowtype with babel-eslint parser
          this.named.add(n.declaration.id.name)
          break
        case 'VariableDeclaration':
          n.declaration.declarations.forEach((d) =>
            recursivePatternCapture(d.id, id => this.named.add(id.name)))
          break
      }
    }

    // capture specifiers
    let remoteMap
    if (n.source) remoteMap = this.resolveReExport(n, path)

    n.specifiers.forEach(function (s) {
      if (s.type === 'ExportDefaultSpecifier') {
        // don't add it if it is not present in the exported module
        if (!remoteMap || !remoteMap.hasDefault) return
      }

      this.named.add(s.exported.name)
    }.bind(this))
  }

  reportErrors(context, declaration) {
    context.report({
      node: declaration.source,
      message: `Parse errors in imported module '${declaration.source.value}': ` +
                  `${this.errors
                        .map(e => `${e.message} (${e.lineNumber}:${e.column})`)
                        .join(', ')}`,
    })
  }
}

/**
 * Traverse a patter/identifier node, calling 'callback'
 * for each leaf identifier.
 * @param  {node}   pattern
 * @param  {Function} callback
 * @return {void}
 */
export function recursivePatternCapture(pattern, callback) {
  switch (pattern.type) {
    case 'Identifier': // base case
      callback(pattern)
      break

    case 'ObjectPattern':
      pattern.properties.forEach(({ value }) => {
        recursivePatternCapture(value, callback)
      })
      break

    case 'ArrayPattern':
      pattern.elements.forEach((element) => {
        if (element == null) return
        recursivePatternCapture(element, callback)
      })
      break
  }
}

function hashObject(object) {
  const settingsShasum = createHash('sha1')
  settingsShasum.update(JSON.stringify(object))
  return settingsShasum.digest('hex')
}
<|endoftext|>


<commit_before>import cond from 'lodash.cond'
import builtinModules from 'builtin-modules'
import { join } from 'path'

import resolve from 'eslint-module-utils/resolve'

function constant(value) {
  return () => value
}

export function isAbsolute(name) {
  return name.indexOf('/') === 0
}

export function isBuiltIn(name, settings) {
  const extras = (settings && settings['import/core-modules']) || []
  return builtinModules.indexOf(name) !== -1 || extras.indexOf(name) > -1
}

function isExternalPath(path, name, settings) {
  const folders = (settings && settings['import/external-module-folders']) || ['node_modules']
  return !path || folders.some(folder => -1 < path.indexOf(join(folder, name)))
}

const externalModuleRegExp = /^\w/
function isExternalModule(name, settings, path) {
  return externalModuleRegExp.test(name) && isExternalPath(path, name, settings)
}

const scopedRegExp = /^@[^\/]+\/[^\/]+/
function isScoped(name) {
  return scopedRegExp.test(name)
}

function isInternalModule(name, settings, path) {
  return externalModuleRegExp.test(name) && !isExternalPath(path, name, settings)
}

function isRelativeToParent(name) {
  return name.indexOf('../') === 0
}

const indexFiles = ['.', './', './index', './index.js']
function isIndex(name) {
  return indexFiles.indexOf(name) !== -1
}

function isRelativeToSibling(name) {
  return name.indexOf('./') === 0
}

const typeTest = cond([
  [isAbsolute, constant('absolute')],
  [isBuiltIn, constant('builtin')],
  [isExternalModule, constant('external')],
  [isScoped, constant('external')],
  [isInternalModule, constant('internal')],
  [isRelativeToParent, constant('parent')],
  [isIndex, constant('index')],
  [isRelativeToSibling, constant('sibling')],
  [constant(true), constant('unknown')],
])

export default function resolveImportType(name, context) {
  return typeTest(name, context.settings, resolve(name, context))
}
<commit_msg>[Fix] unescape unnecessarily escaped regex slashes<commit_after>import cond from 'lodash.cond'
import builtinModules from 'builtin-modules'
import { join } from 'path'

import resolve from 'eslint-module-utils/resolve'

function constant(value) {
  return () => value
}

export function isAbsolute(name) {
  return name.indexOf('/') === 0
}

export function isBuiltIn(name, settings) {
  const extras = (settings && settings['import/core-modules']) || []
  return builtinModules.indexOf(name) !== -1 || extras.indexOf(name) > -1
}

function isExternalPath(path, name, settings) {
  const folders = (settings && settings['import/external-module-folders']) || ['node_modules']
  return !path || folders.some(folder => -1 < path.indexOf(join(folder, name)))
}

const externalModuleRegExp = /^\w/
function isExternalModule(name, settings, path) {
  return externalModuleRegExp.test(name) && isExternalPath(path, name, settings)
}

const scopedRegExp = /^@[^/]+\/[^/]+/
function isScoped(name) {
  return scopedRegExp.test(name)
}

function isInternalModule(name, settings, path) {
  return externalModuleRegExp.test(name) && !isExternalPath(path, name, settings)
}

function isRelativeToParent(name) {
  return name.indexOf('../') === 0
}

const indexFiles = ['.', './', './index', './index.js']
function isIndex(name) {
  return indexFiles.indexOf(name) !== -1
}

function isRelativeToSibling(name) {
  return name.indexOf('./') === 0
}

const typeTest = cond([
  [isAbsolute, constant('absolute')],
  [isBuiltIn, constant('builtin')],
  [isExternalModule, constant('external')],
  [isScoped, constant('external')],
  [isInternalModule, constant('internal')],
  [isRelativeToParent, constant('parent')],
  [isIndex, constant('index')],
  [isRelativeToSibling, constant('sibling')],
  [constant(true), constant('unknown')],
])

export default function resolveImportType(name, context) {
  return typeTest(name, context.settings, resolve(name, context))
}
<|endoftext|>


<commit_before>const cron = require('node-cron');
const nodemailer = require('nodemailer');
const swig = require('swig');
const vendortemplate = swig.compileFile(__dirname + '/../mails/vendor.swig');
const remindertemplate = swig.compileFile(__dirname + '/../mails/reminder.swig');
const htmlToText = require('html-to-text');
const winston = require('winston');

class MailCron {

  /**
   * @constuctor
   * @param {*} app
   * @param {EventEmitter} mailEmitter
   * @param {String} pattern
   * @param {Integer} daysSince
   */
  constructor(app, mailEmitter) {
    this.app = app;
    this.config = app.get('mailserver');
    this.cronconfig = app.get('mailcron');
    this.mailEmitter = mailEmitter;
    this.daysSince = parseInt(this.cronconfig.dayssince, 10);
    this.cron = cron.schedule(this.cronconfig.pattern, () => {
      this.fire();
    });
    this.mailer = nodemailer.createTransport(this.config);
    this.active = true;
    this.mailEmitter.on('mailstatus', status => {
      this.active = status;
    });
    this.fire();
  }

  /**
   * Logs a message
   * @param {String} type the type (one of info|warning|error)
   * @param {String} msg the Message to be logged
   */
  log(type, msg) {
    winston[type](`MailCron: ${msg}`);
  }

  /**
   * Fires the process to send mails
   * @returns {Promise}
   */
  async fire() {
    if (!this.active) return;
    try {
      const mails = await this.checkMailsToSend();
      if(!mails.length) return;
      this.sendMails(mails);
    } catch(err) {
      this.log("error", "Error in checkMailsToSend" + err.message);
    }
  }

  async getVendorById(id) {
    return this.app.service('vendors').get(id).then(vendor => {
      if (!vendor || !vendor.hasOwnProperty('email') || !vendor.email) {
        throw new Error('No valid vendor Data');
      }
      // get all entries that aren't sent yet
      return vendor;
    })
  }

  async getEntriesForProducts(ids) {
    return this.app.service('entries').find({
        query: {
          ProductId: ids,
          sent: 0
        },
        group: ['ProductId']
    });
  }

  getAllVendorMails(id) {
    return this.app.service('mails').find({
        query: {
          vendorId: id,
          sent: 0
        },
        attributes: ['id']
    });
  }

  buildMailData(entries) {
      let mailEntries = [];
      // combine data for the mail
      entries.data.forEach(entry => {
        let idx = 0;
        var itm = mailEntries.filter((entryItem, idx) => {
          if(entryItem.ProductId === entry.ProductId || entryItem.barcode === entry.barcode) {
            idx = idx;
            return true
          }
          return false;
        });
        if(!itm.length) {
          mailEntries.push({
            barcode: entry.barcode,
            ProductId: entry.id,
            count: 1,
            barcode: entry.barcode,
            productname: `${entry['Product.name']} - ${entry['Product.detailname']}`
          });
        } else {
          mailEntries[idx].count++;
        }
      });
      return mailEntries;
  }

  /**
   * Iterates all passed mail entrys, checks if they've got
   * a vendor and sends them the Emails. The "sent" flag of
   * successfully sent mails is set to "1" afterwards
   * @param {Array} mails The Mail-Entrys to be sent
   * @returns undefined
   */
  async sendMails(mails) {
    let foundEntries = [],
        foundVendor;

    const vendors = new Set(mails.map(mail => mail.vendorId));

    for(let vendorid of vendors) {

      try {
        const vendor = await this.getVendorById(vendorid);
        const vendorMails = await this.getAllVendorMails(vendorid);
        if(!vendorMails.data.length) {
          throw new Error(`No Mails found for vendor ${vendorid}`);
        }

        const mailProductIds = vendorMails.data.map(mail => mail.productId);
        const entries = await this.getEntriesForProducts(mailProductIds);
        if(!entries.data.length) {
          throw new Error(`No Entries found ${vendorid}`);
        }

        foundEntries = this.buildMailData(entries);
        var fullAmount = foundEntries.reduce((a,b) => {
          if(a.hasOwnProperty('count')) { // first iteration
            return (a.count ? parseInt(a.count,10) : 0) + parseInt(b.count,10);
          }
          return parseInt(a, 10) + parseInt(b.count,10);
        });
        let mailText = vendortemplate({
          foundEntries: foundEntries,
          productsString: foundEntries.map(product => product.productname).join(', '),
          fullAmount: typeof fullAmount === 'object' ? 'Einige' : fullAmount
        });

        var mail = await this.mailer.sendMail(Object.assign(this.config, {
          to: typeof(process.env.NODE_ENV) !== 'undefined' && process.env.NODE_ENV === 'development' ? this.config.reminderEmail : [this.config.reminderEmail, vendor.email],
          html: mailText,
          text: htmlToText.fromString(mailText)
        }));
        if(!mail.accepted.length) {
          throw new Error(`No Mails could be sent to found ${vendor.email}`);
        }
        this.log("info", `Mail sent to: ${mail.accepted.join(',')} (messageId: ${mail.messageId})`);
        let mailsToPatch = vendorMails.data.map(mail => {
          return mail.id;
        });
        await this.app.service('mails').patch(mailsToPatch, {
          sent: 1,
          reminded: 1
        });
        this.log("info", `Mails patched (sent): ${mailsToPatch.join(',')}`);
        let entriesToPatch = entries.data.map(entry => {
          return entry.id;
        });
        await this.app.service('entries').patch(entry.id, {
          sent: 1
        });
        this.log("info", `Entries patched (sent): ${entriesToPatch.join(',')}`);

        return foundEntries;

      } catch(err) {
        console.log("ERROR!", err);
      }

    }

  }

  /**
   * Searches for mails that need to be send
   */
  async checkMailsToSend() {
    return this.app.service('mails').find({
      query: {
        createdAt: {
          $lt: new Date(new Date() - 24 * 60 * 60 * this.daysSince * 1000)
        },
        sent: 0
      }
    }).then(mails => {
      let retVal = [];
      if (mails.hasOwnProperty('total') && mails.total > 0) {
        // filter for those mails that have a product and a
        // vendor assigned to them
        retVal = mails.data.filter(mail => {
          return mail.productId && mail.vendorId;
        });
        /* if (retVal.length < mails.data.length) {
          // send mails to admin: reminder to add vendors to products
          this.sendReminderMails(mails);
        } */
      }
      return retVal;
    }).catch(err => {
      this.log("error", "Failed checking for Mails:" + err.message);
    });
  }

  sendReminderMails(mails) {
    // get all mails that have no related vendor or product
    // and send a reminder to the admin
    let mailsToSend = mails.data.filter(mail => {
      return mail && (!mail.productId || !mail.vendorId) && (!mail.reminded || mail.reminded === 0);
    });

    if (!mailsToSend.length) return;

    // fill email text with amount of mails to be completed
    let mailText = remindertemplate({
      amount: mailsToSend.length
    });

    // send email
    this.mailer.sendMail(Object.assign(this.config, {
      to: this.config.reminderEmail,
      subject: `ReplacePlastic: ${mailsToSend.length} Zuordnungen fehlen.`,
      html: mailText,
      text: htmlToText.fromString(mailText)
    })).then(res => {
      // set status of all emails to "reminded" to avoid
      // spamming the admin with reminders
      return Promise.all(mailsToSend.map(mail => {
        return this.app.service('mails').patch(mail.id, {
          reminded: 1
        });
      }));
    }).then(res => {
      this.log("info", "++++++ Reminder Mail sent successfully ++++++");
    }).catch(err => {
      this.log("error", "Failed sending reminder mail:" + err.message);
    });

  }

}

module.exports = MailCron;
<commit_msg>Bugfix: Handle single Entries when sending Mails<commit_after>const cron = require('node-cron');
const nodemailer = require('nodemailer');
const swig = require('swig');
const vendortemplate = swig.compileFile(__dirname + '/../mails/vendor.swig');
const remindertemplate = swig.compileFile(__dirname + '/../mails/reminder.swig');
const htmlToText = require('html-to-text');
const winston = require('winston');

class MailCron {

  /**
   * @constuctor
   * @param {*} app
   * @param {EventEmitter} mailEmitter
   * @param {String} pattern
   * @param {Integer} daysSince
   */
  constructor(app, mailEmitter) {
    this.app = app;
    this.config = app.get('mailserver');
    this.cronconfig = app.get('mailcron');
    this.mailEmitter = mailEmitter;
    this.daysSince = parseInt(this.cronconfig.dayssince, 10);
    this.cron = cron.schedule(this.cronconfig.pattern, () => {
      this.fire();
    });
    this.mailer = nodemailer.createTransport(this.config);
    this.active = true;
    this.mailEmitter.on('mailstatus', status => {
      this.active = status;
    });
    this.fire();
  }

  /**
   * Logs a message
   * @param {String} type the type (one of info|warning|error)
   * @param {String} msg the Message to be logged
   */
  log(type, msg) {
    winston[type](`MailCron: ${msg}`);
  }

  /**
   * Fires the process to send mails
   * @returns {Promise}
   */
  async fire() {
    if (!this.active) return;
    try {
      const mails = await this.checkMailsToSend();
      if(!mails.length) return;
      this.sendMails(mails);
    } catch(err) {
      this.log("error", "Error in checkMailsToSend" + err.message);
    }
  }

  async getVendorById(id) {
    return this.app.service('vendors').get(id).then(vendor => {
      if (!vendor || !vendor.hasOwnProperty('email') || !vendor.email) {
        throw new Error('No valid vendor Data');
      }
      // get all entries that aren't sent yet
      return vendor;
    })
  }

  async getEntriesForProducts(ids) {
    return this.app.service('entries').find({
        query: {
          ProductId: ids,
          sent: 0
        },
        group: ['ProductId']
    });
  }

  getAllVendorMails(id) {
    return this.app.service('mails').find({
        query: {
          vendorId: id,
          sent: 0
        },
        attributes: ['id']
    });
  }

  buildMailData(entries) {
      let mailEntries = [];
      // combine data for the mail
      entries.data.forEach(entry => {
        let idx = 0;
        var itm = mailEntries.filter((entryItem, idx) => {
          if(entryItem.ProductId === entry.ProductId || entryItem.barcode === entry.barcode) {
            idx = idx;
            return true
          }
          return false;
        });
        if(!itm.length) {
          mailEntries.push({
            barcode: entry.barcode,
            ProductId: entry.id,
            count: 1,
            barcode: entry.barcode,
            productname: `${entry['Product.name']} - ${entry['Product.detailname']}`
          });
        } else {
          mailEntries[idx].count++;
        }
      });
      return mailEntries;
  }

  /**
   * Iterates all passed mail entrys, checks if they've got
   * a vendor and sends them the Emails. The "sent" flag of
   * successfully sent mails is set to "1" afterwards
   * @param {Array} mails The Mail-Entrys to be sent
   * @returns undefined
   */
  async sendMails(mails) {
    let foundEntries = [],
        foundVendor;

    const vendors = new Set(mails.map(mail => mail.vendorId));

    for(let vendorid of vendors) {

      try {
        const vendor = await this.getVendorById(vendorid);
        const vendorMails = await this.getAllVendorMails(vendorid);
        if(!vendorMails.data.length) {
          throw new Error(`No Mails found for vendor ${vendorid}`);
        }

        const mailProductIds = vendorMails.data.map(mail => mail.productId);
        const entries = await this.getEntriesForProducts(mailProductIds);
        if(!entries.data.length) {
          throw new Error(`No Entries found ${vendorid}`);
        }

        foundEntries = this.buildMailData(entries);
        if(foundEntries.length>1) {
          var fullAmount = foundEntries.reduce((a,b) => {
            if(a.hasOwnProperty('count')) { // first iteration
              return (a.count ? parseInt(a.count,10) : 0) + parseInt(b.count,10);
            }
            return parseInt(a, 10) + parseInt(b.count,10);
          });
        } else {
          fullAmount = foundEntries[0].count;
        }
        let mailText = vendortemplate({
          foundEntries: foundEntries,
          productsString: foundEntries.map(product => product.productname).join(', '),
          fullAmount: typeof fullAmount === 'object' ? 'Einige' : fullAmount
        });

        var mail = await this.mailer.sendMail(Object.assign(this.config, {
          to: typeof(process.env.NODE_ENV) !== 'undefined' && process.env.NODE_ENV === 'development' ? this.config.reminderEmail : [this.config.reminderEmail, vendor.email],
          html: mailText,
          text: htmlToText.fromString(mailText)
        }));
        if(!mail.accepted.length) {
          throw new Error(`No Mails could be sent to found ${vendor.email}`);
        }
        this.log("info", `Mail sent to: ${mail.accepted.join(',')} (messageId: ${mail.messageId})`);
        let mailsToPatch = vendorMails.data.map(mail => {
          return mail.id;
        });
        await this.app.service('mails').patch(mailsToPatch, {
          sent: 1,
          reminded: 1
        });
        this.log("info", `Mails patched (sent): ${mailsToPatch.join(',')}`);
        let entriesToPatch = entries.data.map(entry => {
          return entry.id;
        });
        await this.app.service('entries').patch(entriesToPatch, {
          sent: 1
        });
        this.log("info", `Entries patched (sent): ${entriesToPatch.join(',')}`);

        return foundEntries;

      } catch(err) {
        console.log("ERROR!", err);
      }

    }

  }

  /**
   * Searches for mails that need to be send
   */
  async checkMailsToSend() {
    return this.app.service('mails').find({
      query: {
        createdAt: {
          $lt: new Date(new Date() - 24 * 60 * 60 * this.daysSince * 1000)
        },
        sent: 0
      }
    }).then(mails => {
      let retVal = [];
      if (mails.hasOwnProperty('total') && mails.total > 0) {
        // filter for those mails that have a product and a
        // vendor assigned to them
        retVal = mails.data.filter(mail => {
          return mail.productId && mail.vendorId;
        });
        /* if (retVal.length < mails.data.length) {
          // send mails to admin: reminder to add vendors to products
          this.sendReminderMails(mails);
        } */
      }
      return retVal;
    }).catch(err => {
      this.log("error", "Failed checking for Mails:" + err.message);
    });
  }

  sendReminderMails(mails) {
    // get all mails that have no related vendor or product
    // and send a reminder to the admin
    let mailsToSend = mails.data.filter(mail => {
      return mail && (!mail.productId || !mail.vendorId) && (!mail.reminded || mail.reminded === 0);
    });

    if (!mailsToSend.length) return;

    // fill email text with amount of mails to be completed
    let mailText = remindertemplate({
      amount: mailsToSend.length
    });

    // send email
    this.mailer.sendMail(Object.assign(this.config, {
      to: this.config.reminderEmail,
      subject: `ReplacePlastic: ${mailsToSend.length} Zuordnungen fehlen.`,
      html: mailText,
      text: htmlToText.fromString(mailText)
    })).then(res => {
      // set status of all emails to "reminded" to avoid
      // spamming the admin with reminders
      return Promise.all(mailsToSend.map(mail => {
        return this.app.service('mails').patch(mail.id, {
          reminded: 1
        });
      }));
    }).then(res => {
      this.log("info", "++++++ Reminder Mail sent successfully ++++++");
    }).catch(err => {
      this.log("error", "Failed sending reminder mail:" + err.message);
    });

  }

}

module.exports = MailCron;
<|endoftext|>