<commit_before>'use strict';

// #############################################################################
// Create the first page

var globals = require('./settings/globals');
var content = require('./settings/globals').content.page;
var cms = require('./helpers/cms')();
var resizeButton;

casper.test.setUp(function (done) {
    casper.start()
        .then(cms.login())
        .run(done);
});

casper.test.tearDown(function (done) {
    casper.start()
        .then(cms.logout())
        .run(done);
});

casper.test.begin('Manipulate Modal', function (test) {
    casper
        .start(globals.editUrl)
        .waitUntilVisible('.cms-modal-open', function () {
            test.assertExist('.cms-modal-open', 'Modal is open');
            this.click('.cms-modal-maximize');
        })
        .then(function () {
            // Page size is 1280x1024
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').width();
            }, 1280, 'Modal maximized to corrent width');
            // Page size is 1280x1024
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').height();
            }, 1024, 'Modal maximized to corrent height');
        })
        // clicks on the maximize button
        .then(function () {
            test.assertExists('.cms-icon-window', 'maximize icon exists');
            this.click('.cms-modal-maximize');
        })
        // clicks on the minimize button icon
        .then(function () {
            test.assertExists('.cms-icon-minus', 'minimize icon exists');
            this.click('.cms-modal-minimize');
        })
        // checks width of the minimized windows
        .then(function () {
            // Page size is 1280x1024
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').width();
            }, 396, 'Window is minimized to corrent width');

            test.assertEvalEquals(function () {
                return $('.cms-modal-open').height();
            }, 46, 'Window is minimized to corrent height');
        })
        // expands the modal by clicking on the icon
        .then(function () {
            this.click('.cms-modal-minimize');
        })
        // checks the default height of the window
        .then(function () {
            // Page size is 1280x1024
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').height();
            }, 724, 'Modal opens with default height');
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').width();
            }, 980, 'Modal opens with default width');
        })
        // Function expands
        .then(function () {
            resizeButton = this.getElementBounds('.cms-modal-resize');
            // Chose number to expand the modal with the given pixel down
            var expandModal = 30;
            var standardModal = 724;
            this.mouse.down('.cms-modal-resize');
            this.mouse.move(resizeButton.left + resizeButton.width,
            resizeButton.top + (resizeButton.height / 2) + expandModal / 2);
            this.mouse.up(resizeButton.left + resizeButton.width,
            resizeButton.top + (resizeButton.height / 2) + expandModal / 2);
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').height();
            }, standardModal + expandModal, 'Modal resized bigger');
            resizeButton = this.getElementBounds('.cms-modal-resize');
            // Reverses the height to standard height of the modal
            this.mouse.down('.cms-modal-resize');
            this.mouse.move(resizeButton.left + resizeButton.width,
            resizeButton.top + (resizeButton.height / 2) - expandModal / 2);
            this.mouse.up(resizeButton.left + resizeButton.width,
            resizeButton.top + (resizeButton.height / 2) - expandModal / 2);
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').height();
            }, standardModal, 'Modal resized to standard again');
        })
        // function moves chosen element to the left
        .then(function () {
            this.click('.cms-modal-head');
            resizeButton = this.getElementBounds('.cms-modal-head'); //
            this.mouse.down('.cms-modal-head');
            // Chose random numbe to move the modal to the left
            var movingLeft = 50;
            var distanceLeft  = resizeButton.left;
            this.mouse.move(resizeButton.left + resizeButton.width / 2 - movingLeft,
            resizeButton.top + resizeButton.height / 2);
            this.mouse.up(resizeButton.left + resizeButton.width / 2 - movingLeft,
            resizeButton.top + resizeButton.height / 2);
            resizeButton = this.getElementBounds('.cms-modal');
            // checks if the modal moved 50px
            test.assertEquals(resizeButton.left, distanceLeft - movingLeft, 'Modal moved');
            this.mouse.down('.cms-modal-head');
            this.mouse.move(resizeButton.left + resizeButton.width / 2 + movingLeft,
            resizeButton.top + resizeButton.height * 0);
            this.mouse.up(resizeButton.left + resizeButton.width / 2 + movingLeft,
            resizeButton.top + resizeButton.height * 0);
            resizeButton = this.getElementBounds('.cms-modal-head');
            test.assertEquals(resizeButton.left, distanceLeft, 'Modal back');
        })
        // moves the modal diagonal
        .then(function () {
            this.click('.cms-modal-head');
            resizeButton = this.getElementBounds('.cms-modal-head'); //
            this.mouse.down('.cms-modal-head');
            // Chose random numbe to move the modal to the left
            var distanceTop  = resizeButton.top;
            var distanceLeft  = resizeButton.left;
            var movingUp = 50;
            var movingLeft = 20;
            this.mouse.move(resizeButton.left + resizeButton.width / 2 - movingLeft,
            resizeButton.top - movingUp + resizeButton.height / 2);
            this.mouse.up(resizeButton.left + resizeButton.width / 2 - movingLeft,
            resizeButton.top - movingUp + resizeButton.height / 2);
            resizeButton = this.getElementBounds('.cms-modal-head');
            test.assertEquals(resizeButton.left, distanceLeft - movingLeft, 'Modal moved vertical');
            test.assertEquals(resizeButton.top, distanceTop - movingUp, 'Modal moved vertical');
        })
        // check that modal cannot be resized to be smaller than default minimum dimensions
        .then(function () {
            resizeButton = this.getElementBounds('.cms-modal-resize');
            // Min height is 400px. 724px - 500px < 400
            var resizeUp = 500;
            var standardModal = 724;
            this.mouse.down('.cms-modal-resize');
            this.mouse.move(resizeButton.left + resizeButton.width,
            resizeButton.top + (resizeButton.height / 2) - resizeUp / 2);
            this.mouse.up(resizeButton.left + resizeButton.width,
            resizeButton.top + (resizeButton.height / 2) - resizeUp / 2);
            // takes the current modal height
            var height = this.evaluate(function () {
                return $('.cms-modal-open').height();
            });
            // checks if the current modal height didn't turn below 400
            test.assert(height !== standardModal - resizeUp, 'Modal reached min size');
            test.assert(height === 400, 'Modal reached 400px');
        })
        .run(function () {
            test.done();
        });
});
<commit_msg>stability<commit_after>'use strict';

// #############################################################################
// Create the first page

var globals = require('./settings/globals');
var content = require('./settings/globals').content.page;
var cms = require('./helpers/cms')();
var resizeButton;

casper.test.setUp(function (done) {
    casper.start()
        .then(cms.login())
        .run(done);
});

casper.test.tearDown(function (done) {
    casper.start()
        .then(cms.logout())
        .run(done);
});

casper.test.begin('Manipulate Modal', function (test) {
    casper
        .start(globals.editUrl)
        .waitUntilVisible('.cms-modal-open', function () {
            test.assertExist('.cms-modal-open', 'Modal is open');
            this.click('.cms-modal-maximize');
        })
        .then(function () {
            // Page size is 1280x1024
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').width();
            }, 1280, 'Modal maximized to current width');
            // Page size is 1280x1024
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').height();
            }, 1024, 'Modal maximized to current height');
        })
        // clicks on the maximize button
        .then(function () {
            test.assertExists('.cms-icon-window', 'maximize icon exists');
            this.click('.cms-modal-maximize');
        })
        // clicks on the minimize button icon
        .then(function () {
            test.assertExists('.cms-icon-minus', 'minimize icon exists');
            this.click('.cms-modal-minimize');
        })
        // checks width of the minimized windows
        .then(function () {
            // Page size is 1280x1024
            test.assertEval(function () {
                return $('.cms-modal-open').width() < 430
            }, 'Window is minimized to current width');

            test.assertEvalEquals(function () {
                return $('.cms-modal-open').height();
            }, 46, 'Window is minimized to current height');
        })
        // expands the modal by clicking on the icon
        .then(function () {
            this.click('.cms-modal-minimize');
        })
        // checks the default height of the window
        .then(function () {
            // Page size is 1280x1024
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').height();
            }, 724, 'Modal opens with default height');
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').width();
            }, 980, 'Modal opens with default width');
        })
        // Function expands
        .then(function () {
            resizeButton = this.getElementBounds('.cms-modal-resize');
            // Chose number to expand the modal with the given pixel down
            var expandModal = 30;
            var standardModal = 724;
            this.mouse.down('.cms-modal-resize');
            this.mouse.move(resizeButton.left + resizeButton.width,
            resizeButton.top + (resizeButton.height / 2) + expandModal / 2);
            this.mouse.up(resizeButton.left + resizeButton.width,
            resizeButton.top + (resizeButton.height / 2) + expandModal / 2);
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').height();
            }, standardModal + expandModal, 'Modal resized bigger');
            resizeButton = this.getElementBounds('.cms-modal-resize');
            // Reverses the height to standard height of the modal
            this.mouse.down('.cms-modal-resize');
            this.mouse.move(resizeButton.left + resizeButton.width,
            resizeButton.top + (resizeButton.height / 2) - expandModal / 2);
            this.mouse.up(resizeButton.left + resizeButton.width,
            resizeButton.top + (resizeButton.height / 2) - expandModal / 2);
            test.assertEvalEquals(function () {
                return $('.cms-modal-open').height();
            }, standardModal, 'Modal resized to standard again');
        })
        // function moves chosen element to the left
        .then(function () {
            this.click('.cms-modal-head');
            resizeButton = this.getElementBounds('.cms-modal-head'); //
            this.mouse.down('.cms-modal-head');
            // Chose random numbe to move the modal to the left
            var movingLeft = 50;
            var distanceLeft  = resizeButton.left;
            this.mouse.move(resizeButton.left + resizeButton.width / 2 - movingLeft,
            resizeButton.top + resizeButton.height / 2);
            this.mouse.up(resizeButton.left + resizeButton.width / 2 - movingLeft,
            resizeButton.top + resizeButton.height / 2);
            resizeButton = this.getElementBounds('.cms-modal');
            // checks if the modal moved 50px
            test.assertEquals(resizeButton.left, distanceLeft - movingLeft, 'Modal moved');
            this.mouse.down('.cms-modal-head');
            this.mouse.move(resizeButton.left + resizeButton.width / 2 + movingLeft,
            resizeButton.top + resizeButton.height * 0);
            this.mouse.up(resizeButton.left + resizeButton.width / 2 + movingLeft,
            resizeButton.top + resizeButton.height * 0);
            resizeButton = this.getElementBounds('.cms-modal-head');
            test.assertEquals(resizeButton.left, distanceLeft, 'Modal back');
        })
        // moves the modal diagonal
        .then(function () {
            this.click('.cms-modal-head');
            resizeButton = this.getElementBounds('.cms-modal-head'); //
            this.mouse.down('.cms-modal-head');
            // Chose random numbe to move the modal to the left
            var distanceTop  = resizeButton.top;
            var distanceLeft  = resizeButton.left;
            var movingUp = 50;
            var movingLeft = 20;
            this.mouse.move(resizeButton.left + resizeButton.width / 2 - movingLeft,
            resizeButton.top - movingUp + resizeButton.height / 2);
            this.mouse.up(resizeButton.left + resizeButton.width / 2 - movingLeft,
            resizeButton.top - movingUp + resizeButton.height / 2);
            resizeButton = this.getElementBounds('.cms-modal-head');
            test.assertEquals(resizeButton.left, distanceLeft - movingLeft, 'Modal moved vertical');
            test.assertEquals(resizeButton.top, distanceTop - movingUp, 'Modal moved vertical');
        })
        // check that modal cannot be resized to be smaller than default minimum dimensions
        .then(function () {
            resizeButton = this.getElementBounds('.cms-modal-resize');
            // Min height is 400px. 724px - 500px < 400
            var resizeUp = 500;
            var standardModal = 724;
            this.mouse.down('.cms-modal-resize');
            this.mouse.move(resizeButton.left + resizeButton.width,
            resizeButton.top + (resizeButton.height / 2) - resizeUp / 2);
            this.mouse.up(resizeButton.left + resizeButton.width,
            resizeButton.top + (resizeButton.height / 2) - resizeUp / 2);
            // takes the current modal height
            var height = this.evaluate(function () {
                return $('.cms-modal-open').height();
            });
            // checks if the current modal height didn't turn below 400
            test.assert(height !== standardModal - resizeUp, 'Modal reached min size');
            test.assert(height === 400, 'Modal reached 400px');
        })
        .run(function () {
            test.done();
        });
});
<|endoftext|>


<commit_before>//
// A parser for my W433 Weather receiver. Totally custom design,
// but very important to me.
//
// Supports the TX3 sensors.

// This object contains two entries:
//  - The low level parser for the serial port driver
//  - The high level parser for incoming serial port data

var serialport = require('serialport'),
    SerialPort  = serialport.SerialPort;

module.exports = {

    name: "w433",

    // Set a reference to the socket.io socket and port
    socket: null,
    recorder: null,
    instrument: null,

    setPortRef: function(s) {
    },
    setSocketRef: function(s) {
        this.socket = s;
    },
    setRecorderRef: function(s) {
        this.recorder = s;
    },
    setInstrumentRef: function(i) {
        this.instrument = i;
        console.log("W433: instrument reference passed, instrument data is: ");
        console.log(i.metadata);
	if (this.instrument.metadata == null)
		this.instrument.metadata = {};
    },

    lastStamp: new Date().getTime(),
    prevRes: null,

    sensor_types_tx3: ['temperature', '1', '2', '3', '4', '5', '6',
                        '7', '8', '9', '10', '11', '12', '13','humidity', '15'],

    setPortRef: function(s) {
    },
    setSocketRef: function(s) {
        this.socket = s;
    },

    // How the device is connected on the serial port
    portSettings: {
            baudRate: 9600,
            dataBits: 8,
            parity: 'none',
            stopBits: 1,
            flowControl: false,
            parser: serialport.parsers.readline('\n'),
    },

    // Called when the HTML app needs a unique identifier.
    // this is a standardized call across all drivers.
    // This particular device does not support this concept, so we
    // always return the same ID
    sendUniqueID: function() {
        this.socket.emit('uniqueID','00000000 (n.a.)');
    },

    // format should emit a JSON structure.
    format: function(data, recording) {
        // Remove any carriage return
        data = data.replace('\n','');
        var res = {};
        var valid = false;

        res.raw = data;

        if (data.length == 12) {
            if (this.check_ok_tx3(data)) {
                valid = true;
                res.reading_type = this.sensor_types_tx3[parseInt(data.substr(3,1),16)];
                res.sensor_address = parseInt(data.substr(4,2),16) & 0xFE;
                switch (res.reading_type) {
                    case 'temperature':
                        res.value = Math.round(data.substr(6,3)-500)/10;
                        break;
                    case 'humidity':
                        res.value = Math.round((data.substr(6,3)/10));
                        break;
                }
            }
        } else if (data.length == 14) {
            if (this.check_ok_tx19(data) ) {
                valid = true;
                res.reading_type = parseInt(data.substr(3,1),16);
                res.sensor_address = parseInt(data.substr(4,2),16);
                var sensor_model = parseInt(data.substr(2,1),16);

                switch (res.reading_type) {
                        case 0:
                        case 4:
                            // Temperature - TX19 Supposed to measure -29.9 to +69.9 according to the doc
                            // Current formula is therefore possibly wrong...
                            if (sensor_model == 6 ) { res.value = data.substr(8,3)/10-40; }
                            if (sensor_model == 9 ) { res.value = data.substr(8,3)/10-30; }
                            res.reading_type = 'temperature';
                            break;
                        case 1:
                        case 5:
                            //Humidity
                            if (sensor_model == 6 ) { res.value = data.substr(8,3)/10; }
                            if (sensor_model == 9 ) { res.value = data.substr(8,2); }
                            res.reading_type = 'humidity';
                        break;
                        case 3:
                        case 7:
                            // Wind -> problem, we have two values here!
                        /**

                            $direction = (hex substr $i,10,1)*22.5;
                            $type_txt = "wind-direction";

                            $speed = (hex substr $i,8,2)/10;
                            $type_txt = "wind-instant";
                        **/

                        break;
                        case 0xb:
                        case 0xf:
                            // Wind - gust -> we have two values again
                            /**
                            $direction = (hex substr $i,10,1)*22.5;
                            $type_txt = "wind-gust-dir";
                            check_sensor_known($sensor_address,$type_txt);
                            $updatesensor_query->execute($direction,$sensor_address,$type_txt);
                            print $type_txt . ") - $direction";
                            $speed = (hex substr $i,8,2)/10;
                            $type_txt = "wind-gust";
                            check_sensor_known($sensor_address,$type_txt);
                            $updatesensor_query->execute($speed,$sensor_address,$type_txt);
                            print " ( $type_txt ) - $speed";
                            **/
                        break;
                        case 2:
                        case 6:
                            // Rain - Unit is still unknown, mm probably ?
                            /**
                            $mmrain = hex substr $i,8,3;
                            $type_txt = "rain";
                            check_sensor_known($sensor_address,$type_txt);
                            $updatesensor_query->execute($mmrain,$sensor_address,$type_txt);
                            print " ($type_txt) - $mmrain";
                            **/
                        break;
                }
            }
        }

        if (!valid) return; // No need to waste time if our data was invalid!

        // Sensors send data multiple times, so we are going to dedupe:
        // if we got exactly the same reading less than 1.5 second ago, then
        // discard it.
        if ( (new Date().getTime()-this.prevStamp) < 1000 &&
              res.sensor_address == this.prevRes.sensor_address &&
              res.sensor_type == this.prevRes.sensor_type &&
              res.value == this.prevRes.value
             )
            return;

        this.prevRes = res;
        this.prevStamp = new Date().getTime();

        // Now: sensor addresses are all nice, but what we really want, is a sensor name: look up in our current
        // instrument whether we have a name for the sensor. If no name, use the address as the name.
        var name = this.instrument.metadata[res.sensor_address];
        if (name != undefined) {
            res.sensor_name = name;
        } else {
            this.instrument.metadata[res.sensor_address] = res.sensor_address;
            this.instrument.markModified('metadata');
            res.sensor_name = res.sensor_address;
            this.instrument.save();
        }

        // Last: smart detection of battery replacement. When a sensor gets a new battery, it will
        // send its data every 10 seconds for a while, so we can detect this. In the mean time, we can
        // also track a sensor that has gone stale for more than X minutes. If we have both a new sensor
        // within the last 5 minutes, and a sensor we have not seen for more than 5 minutes, then we will assume
        // that this sensor's battery got replaced, and we will rename it automatically.
        // Note: there is a chance that the new sensor gets the address of an existing
        // sensor, but there is nothing we can do about this, it is a shortcoming of the Lacross sensors.

        // TODO :-)

        this.recorder.record(res);
        this.socket.emit('serialEvent',res);
    },

    // output should return a string, and is used to format
    // the data that is sent on the serial port, coming from the
    // HTML interface.
    output: function(data) {
        return data + '\n';
    },

    /**
     * The following two subroutines check two things
     * 1) Checksum OK (simple sum of bytes in packet)
     * 2) Redundant information OK within packet (different in
     *    TX3 and TX19 sensors)
     **/

    check_ok_tx3: function(data) {
        var sum = 0;
        var s = data.split('');
        var chk = s.pop();
        var add = function(element) {
            sum += parseInt(element,16);
        }
        s.forEach(add);
        // console.log(chk + " - " + sum%16);
        return (parseInt(chk,16) == sum%16) &&
            (data.substr(6,2) == data.substr(9,2));
    },

    check_ok_tx19: function(data) {
        var sum = 0;
        var s = data.split('');
        var chk = s.pop();
        var add = function(element) {
            sum += parseInt(element,16);
        }
        s.forEach(add);
        var v1 = parseInt(data.substr(8,2),16);
        var v2 = ~(parseInt(data.substr(11,2),16))  & 0xff;
        return (parseInt(chk,16) == sum%16) &&
            (v1 == v2);
        /**
            my $input = shift(@_);
            my $sum = 0;
            $chk = hex (chop $input);
            for( split(//,$input) ) { $sum += hex($_);}
            $sum=$sum%16;
            $v1 = hex substr $input,8,2;
            $v2 =  ~( hex substr $input,11,2) & 0xFF;
            return ($sum==$chk) && ($v1==$v2);
        **/
    },

};
<commit_msg>Improve rounding on new sensor values for Lacrosse sensors<commit_after>//
// A parser for my W433 Weather receiver. Totally custom design,
// but very important to me.
//
// Supports the TX3 sensors.

// This object contains two entries:
//  - The low level parser for the serial port driver
//  - The high level parser for incoming serial port data

var serialport = require('serialport'),
    SerialPort  = serialport.SerialPort;

module.exports = {

    name: "w433",

    // Set a reference to the socket.io socket and port
    socket: null,
    recorder: null,
    instrument: null,

    setPortRef: function(s) {
    },
    setSocketRef: function(s) {
        this.socket = s;
    },
    setRecorderRef: function(s) {
        this.recorder = s;
    },
    setInstrumentRef: function(i) {
        this.instrument = i;
        console.log("W433: instrument reference passed, instrument data is: ");
        console.log(i.metadata);
	if (this.instrument.metadata == null)
		this.instrument.metadata = {};
    },

    lastStamp: new Date().getTime(),
    prevRes: null,

    sensor_types_tx3: ['temperature', '1', '2', '3', '4', '5', '6',
                        '7', '8', '9', '10', '11', '12', '13','humidity', '15'],

    setPortRef: function(s) {
    },
    setSocketRef: function(s) {
        this.socket = s;
    },

    // How the device is connected on the serial port
    portSettings: {
            baudRate: 9600,
            dataBits: 8,
            parity: 'none',
            stopBits: 1,
            flowControl: false,
            parser: serialport.parsers.readline('\n'),
    },

    // Called when the HTML app needs a unique identifier.
    // this is a standardized call across all drivers.
    // This particular device does not support this concept, so we
    // always return the same ID
    sendUniqueID: function() {
        this.socket.emit('uniqueID','00000000 (n.a.)');
    },

    // format should emit a JSON structure.
    format: function(data, recording) {
        // Remove any carriage return
        data = data.replace('\n','');
        var res = {};
        var valid = false;

        res.raw = data;

        if (data.length == 12) {
            if (this.check_ok_tx3(data)) {
                valid = true;
                res.reading_type = this.sensor_types_tx3[parseInt(data.substr(3,1),16)];
                res.sensor_address = parseInt(data.substr(4,2),16) & 0xFE;
                switch (res.reading_type) {
                    case 'temperature':
                        res.value = Math.round(data.substr(6,3)-500)/10;
                        break;
                    case 'humidity':
                        res.value = Math.round((data.substr(6,3)/10));
                        break;
                }
            }
        } else if (data.length == 14) {
            if (this.check_ok_tx19(data) ) {
                valid = true;
                res.reading_type = parseInt(data.substr(3,1),16);
                res.sensor_address = parseInt(data.substr(4,2),16);
                var sensor_model = parseInt(data.substr(2,1),16);

                switch (res.reading_type) {
                        case 0:
                        case 4:
                            // Temperature - TX19 Supposed to measure -29.9 to +69.9 according to the doc
                            // Current formula is therefore possibly wrong...
                            if (sensor_model == 6 ) { res.value = Math.round(data.substr(8,3)-400)/10; }
                            if (sensor_model == 9 ) { res.value = Math.round(data.substr(8,3)-300)/10; }
                            res.reading_type = 'temperature';
                            break;
                        case 1:
                        case 5:
                            //Humidity
                            if (sensor_model == 6 ) { res.value = data.substr(8,3)/10; }
                            if (sensor_model == 9 ) { res.value = data.substr(8,2); }
                            res.reading_type = 'humidity';
                        break;
                        case 3:
                        case 7:
                            // Wind -> problem, we have two values here!
                        /**

                            $direction = (hex substr $i,10,1)*22.5;
                            $type_txt = "wind-direction";

                            $speed = (hex substr $i,8,2)/10;
                            $type_txt = "wind-instant";
                        **/

                        break;
                        case 0xb:
                        case 0xf:
                            // Wind - gust -> we have two values again
                            /**
                            $direction = (hex substr $i,10,1)*22.5;
                            $type_txt = "wind-gust-dir";
                            check_sensor_known($sensor_address,$type_txt);
                            $updatesensor_query->execute($direction,$sensor_address,$type_txt);
                            print $type_txt . ") - $direction";
                            $speed = (hex substr $i,8,2)/10;
                            $type_txt = "wind-gust";
                            check_sensor_known($sensor_address,$type_txt);
                            $updatesensor_query->execute($speed,$sensor_address,$type_txt);
                            print " ( $type_txt ) - $speed";
                            **/
                        break;
                        case 2:
                        case 6:
                            // Rain - Unit is still unknown, mm probably ?
                            /**
                            $mmrain = hex substr $i,8,3;
                            $type_txt = "rain";
                            check_sensor_known($sensor_address,$type_txt);
                            $updatesensor_query->execute($mmrain,$sensor_address,$type_txt);
                            print " ($type_txt) - $mmrain";
                            **/
                        break;
                }
            }
        }

        if (!valid) return; // No need to waste time if our data was invalid!

        // Sensors send data multiple times, so we are going to dedupe:
        // if we got exactly the same reading less than 1.5 second ago, then
        // discard it.
        if ( (new Date().getTime()-this.prevStamp) < 1000 &&
              res.sensor_address == this.prevRes.sensor_address &&
              res.sensor_type == this.prevRes.sensor_type &&
              res.value == this.prevRes.value
             )
            return;

        this.prevRes = res;
        this.prevStamp = new Date().getTime();

        // Now: sensor addresses are all nice, but what we really want, is a sensor name: look up in our current
        // instrument whether we have a name for the sensor. If no name, use the address as the name.
        var name = this.instrument.metadata[res.sensor_address];
        if (name != undefined) {
            res.sensor_name = name;
        } else {
            this.instrument.metadata[res.sensor_address] = res.sensor_address;
            this.instrument.markModified('metadata');
            res.sensor_name = res.sensor_address;
            this.instrument.save();
        }

        // Last: smart detection of battery replacement. When a sensor gets a new battery, it will
        // send its data every 10 seconds for a while, so we can detect this. In the mean time, we can
        // also track a sensor that has gone stale for more than X minutes. If we have both a new sensor
        // within the last 5 minutes, and a sensor we have not seen for more than 5 minutes, then we will assume
        // that this sensor's battery got replaced, and we will rename it automatically.
        // Note: there is a chance that the new sensor gets the address of an existing
        // sensor, but there is nothing we can do about this, it is a shortcoming of the Lacross sensors.

        // TODO :-)

        this.recorder.record(res);
        this.socket.emit('serialEvent',res);
    },

    // output should return a string, and is used to format
    // the data that is sent on the serial port, coming from the
    // HTML interface.
    output: function(data) {
        return data + '\n';
    },

    /**
     * The following two subroutines check two things
     * 1) Checksum OK (simple sum of bytes in packet)
     * 2) Redundant information OK within packet (different in
     *    TX3 and TX19 sensors)
     **/

    check_ok_tx3: function(data) {
        var sum = 0;
        var s = data.split('');
        var chk = s.pop();
        var add = function(element) {
            sum += parseInt(element,16);
        }
        s.forEach(add);
        // console.log(chk + " - " + sum%16);
        return (parseInt(chk,16) == sum%16) &&
            (data.substr(6,2) == data.substr(9,2));
    },

    check_ok_tx19: function(data) {
        var sum = 0;
        var s = data.split('');
        var chk = s.pop();
        var add = function(element) {
            sum += parseInt(element,16);
        }
        s.forEach(add);
        var v1 = parseInt(data.substr(8,2),16);
        var v2 = ~(parseInt(data.substr(11,2),16))  & 0xff;
        return (parseInt(chk,16) == sum%16) &&
            (v1 == v2);
    },

};
<|endoftext|>


<commit_before>import { logout } from 'services/user';

import gfwFires from 'assets/logos/gfw-fires.png';
import gfwPro from 'assets/logos/gfw-pro.png';
import forestWatcher from 'assets/logos/gfw-watcher.png';

import developer from 'assets/icons/developer.svg';
import howto from 'assets/icons/howto.svg';
import sgf from 'assets/icons/sgf.svg';
import openData from 'assets/icons/open-data.svg';
import blog from 'assets/icons/blog.svg';
import forum from 'assets/icons/forum.svg';

export default {
  navMain: [
    {
      label: 'Map',
      path: '/map'
    },
    {
      label: 'Dashboard',
      path: '/dashboards'
    },
    {
      label: 'Topics',
      path: '/topics',
      submenu: [
        {
          label: 'Biodiversity',
          path: '/topics/biodiversity'
        },
        {
          label: 'Climate',
          path: '/topics/climate'
        },
        {
          label: 'Commodities',
          path: '/topics/commodities'
        },
        {
          label: 'Water',
          path: '/topics/water'
        },
        ['staging', 'preproduction'].includes(process.env.FEATURE_ENV) && {
          label: 'Fires',
          path: '/topics/fires'
        }
      ]
    },
    {
      label: 'Blog',
      extLink: 'https://blog.globalforestwatch.org'
    },
    {
      label: 'About',
      path: '/about'
    }
  ],
  myGfwLinks: [
    {
      label: 'My subscriptions',
      extLink: '/my-gfw/subscriptions'
    },
    {
      label: 'My profile',
      path: '/my-gfw'
    },
    {
      label: 'Logout',
      extLink: '/auth/logout',
      onSelect: e => {
        e.preventDefault();
        logout();
      }
    }
  ],
  apps: [
    {
      label: 'GFW Fires',
      extLink: 'http://fires.globalforestwatch.org',
      image: gfwFires
    },
    {
      label: 'GFW Pro',
      extLink: 'https://pro.globalforestwatch.org',
      image: gfwPro
    },
    {
      label: 'Forest Watcher',
      extLink: 'http://forestwatcher.globalforestwatch.org',
      image: forestWatcher
    }
  ],
  moreLinks: [
    {
      label: 'Developer Tools',
      extLink: 'http://developers.globalforestwatch.org',
      icon: developer
    },
    {
      label: 'How to Portal',
      extLink: 'https://www.globalforestwatch.org/howto',
      icon: howto
    },
    {
      label: 'Grants & Fellowships',
      path: '/grants-and-fellowships',
      icon: sgf
    },
    {
      label: 'Open data portal',
      extLink: 'https://data.globalforestwatch.org/',
      icon: openData
    },
    {
      label: 'Blog',
      extLink: 'https://blog.globalforestwatch.org',
      icon: blog
    },
    {
      label: 'Discussion Forum',
      extLink: 'https://groups.google.com/forum/#!forum/globalforestwatch',
      icon: forum
    }
  ]
};
<commit_msg>remove from header<commit_after>import { logout } from 'services/user';

import gfwFires from 'assets/logos/gfw-fires.png';
import gfwPro from 'assets/logos/gfw-pro.png';
import forestWatcher from 'assets/logos/gfw-watcher.png';

import developer from 'assets/icons/developer.svg';
import howto from 'assets/icons/howto.svg';
import sgf from 'assets/icons/sgf.svg';
import openData from 'assets/icons/open-data.svg';
import blog from 'assets/icons/blog.svg';
import forum from 'assets/icons/forum.svg';

export default {
  navMain: [
    {
      label: 'Map',
      path: '/map'
    },
    {
      label: 'Dashboard',
      path: '/dashboards'
    },
    {
      label: 'Topics',
      path: '/topics',
      submenu: [
        {
          label: 'Biodiversity',
          path: '/topics/biodiversity'
        },
        {
          label: 'Climate',
          path: '/topics/climate'
        },
        {
          label: 'Commodities',
          path: '/topics/commodities'
        },
        {
          label: 'Water',
          path: '/topics/water'
        },
        ['staging', 'preproduction'].includes(process.env.FEATURE_ENV) && {
          label: 'Fires',
          path: '/topics/fires'
        }
      ]
    },
    {
      label: 'Blog',
      extLink: 'https://blog.globalforestwatch.org'
    },
    {
      label: 'About',
      path: '/about'
    }
  ],
  myGfwLinks: [
    {
      label: 'My subscriptions',
      extLink: '/my-gfw/subscriptions'
    },
    {
      label: 'My profile',
      path: '/my-gfw'
    },
    {
      label: 'Logout',
      extLink: '/auth/logout',
      onSelect: e => {
        e.preventDefault();
        logout();
      }
    }
  ],
  apps: [
    {
      label: 'GFW Pro',
      extLink: 'https://pro.globalforestwatch.org',
      image: gfwPro
    },
    {
      label: 'Forest Watcher',
      extLink: 'http://forestwatcher.globalforestwatch.org',
      image: forestWatcher
    }
  ],
  moreLinks: [
    {
      label: 'Developer Tools',
      extLink: 'http://developers.globalforestwatch.org',
      icon: developer
    },
    {
      label: 'How to Portal',
      extLink: 'https://www.globalforestwatch.org/howto',
      icon: howto
    },
    {
      label: 'Grants & Fellowships',
      path: '/grants-and-fellowships',
      icon: sgf
    },
    {
      label: 'Open data portal',
      extLink: 'https://data.globalforestwatch.org/',
      icon: openData
    },
    {
      label: 'Blog',
      extLink: 'https://blog.globalforestwatch.org',
      icon: blog
    },
    {
      label: 'Discussion Forum',
      extLink: 'https://groups.google.com/forum/#!forum/globalforestwatch',
      icon: forum
    }
  ]
};
<|endoftext|>


<commit_before>/* This file is part of Indico.
 * Copyright (C) 2002 - 2016 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

// Global scripts that should be executed on all pages

$(document).ready(function() {
    // Create static tabs. They just load the target URL and use no ajax whatsoever
    $('.static-tabs').each(function() {
        var tabCtrl = $(this);
        tabCtrl.tabs({
            active: tabCtrl.data('active')
        });
        // Turn tabs into plain links and fix urls (needed for the active tab)
        $('> .ui-tabs-nav a', this).each(function() {
            var $this = $(this);
            tabCtrl.data('ui-tabs')._off($this, 'click');
            $this.attr('href', $this.data('href'));
        });
    });

    // Remove ui-widget-content style from static tabs as it messes up e.g. link colors
    $('.static-tabs').find('.ui-widget-content').addBack().removeClass('ui-widget-content');

    $('.main-breadcrumb a[href="#"]').css({cursor: 'default', outline: 'none'}).on('click', function(e) {
        e.preventDefault();
    });

    // Use qtip for context help

    $.fn.qtip.defaults = $.extend(true, {}, $.fn.qtip.defaults, {
        position: {
            my: 'top center',
            at: 'bottom center'
        },
        hide: {
            event: 'click mouseout'
        }
    });

    $('.contextHelp[title]').qtip();

    $(document).on("mouseenter", '[title]:not([title=""]):not(iframe)', function(event) {
        if (!$(this).attr('title').trim()) {
            return;
        }

        var extraOpts = $(this).data('qtipOpts') || {},
            qtipClass = $(this).data('qtip-style');

        $(this).qtip($.extend(true, {}, {
            overwrite: false,
            show: {
                event: event.type,
                ready: true
            },

            content: {
                text: function() {
                    var html = $(this).attr('title') || $(this).attr('alt');
                    return html ? html.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") : '';
                }
            },

            events: {
                show: function(event) {
                    if ($(event.originalEvent.target).hasClass('open')) {
                        event.preventDefault();
                    }
                }
            },
            hide: {
                event: "mouseleave"
            },

            style: {
                classes: qtipClass ? 'qtip-' + qtipClass : null
            },

            onHide: function() {
                // If the parent element is destroyed we need to destroy the qTip too
                $(this).qtip('destroy');
            }
        }, extraOpts), event);
    });

    // Enable colorbox for links with .js-lightbox
    $('body').on('click', 'a.js-lightbox', function() {
        $(this).colorbox({
            maxHeight: '90%',
            maxWidth: '90%',
            loop: false,
            photo: true,
            returnFocus: false
        });
    });

    $('.contextHelp[data-src]').qtip({
        content: {
            text: function() {
                return $($(this).data('src')).removeClass('tip');
            }
        }
    });

    $('.js-dropdown').each(function() {
        this.id = this.id || uniqueId();
        $(this).parent().dropdown({selector: '#' + this.id});
    });

    $('body').on('click', '[data-confirm]:not(button[data-href]):not(input:button[data-href]):not(a[data-method][data-href])', function() {
        var $this = $(this);
        new ConfirmPopup($(this).data("title"), $(this).data("confirm"), function(confirmed){
            if (confirmed){
                if ($this.is('form')) {
                    $this.submit();
                } else {
                    window.location = $this.attr('href');
                }
            }
        }).open();
        return false;
    });

    $('body').on('click', 'button[data-method][data-href], input:button[data-method][data-href], a[data-method][data-href]', function(e) {
        e.preventDefault();
        var $this = $(this);
        var url = $this.data('href');
        var method = $this.data('method').toUpperCase();
        var params = $this.data('params') || {};
        var update = $this.data('update');
        if (!$.isPlainObject(params)) {
            throw new Error('Invalid params. Must be valid JSON if set.');
        }

        function execute() {
            var evt = $.Event('indico:confirmed');
            $this.trigger(evt);

            // Handle custom code
            if (evt.isDefaultPrevented()) {
                return;
            }

            // Handle html update
            if (update) {
                $.ajax({
                    method: method,
                    url: url,
                    data: params,
                    error: handleAjaxError,
                    complete: IndicoUI.Dialogs.Util.progress(),
                    success: function(data) {
                        $(update).html(data.html);
                    }
                });
                return;
            }

            // Handle normal GET/POST
            if (method === 'GET') {
                location.href = build_url(url, params);
            } else if (method === 'POST') {
                var form = $('<form>', {
                    action: url,
                    method: method
                });
                form.append($('<input>', {type: 'hidden', name: 'csrf_token', value: $('#csrf-token').attr('content')}));
                $.each(params, function(key, value) {
                    form.append($('<input>', {type: 'hidden', name: key, value: value}));
                });
                form.appendTo('body').submit();
            }
        }

        var promptMsg = $this.data('confirm');
        var confirmed;
        if (!promptMsg) {
            confirmed = $.Deferred().resolve();
        } else {
            confirmed = confirmPrompt(promptMsg, $(this).data('title') || $T('Confirm action'));
        }
        confirmed.then(execute);
    });

    if (navigator.userAgent.match(/Trident\/7\./)) {
        // Silly IE11 will clear the second password field if
        // password autocompletion is enabled!
        // https://social.msdn.microsoft.com/Forums/en-US/7d02173f-8f45-4a74-90bf-5dfbd8f9c1de/ie-11-issue-with-two-password-input-fields
        $('input:password').each(function(){
            if (!this.value && this.getAttribute('value')) {
                this.value = this.getAttribute('value');
            }
        });
    }

    // jQuery UI prevents anything outside modal dialogs from gaining focus.
    // This breaks e.g. the session color date selector. To fix this we prevent
    // the focus trap (focusin event bound on document) from ever receiving the
    // event in case the z-index of the focused event is higher than the dialog's.
    function getMaxZ(elem) {
        var maxZ = 0;
        elem.parents().addBack().each(function() {
            var z = +$(this).css('zIndex');
            if (!isNaN(z)) {
                maxZ = Math.max(z, maxZ);
            }
        });
        return maxZ;
    }

    $('body').on('focusin', function(e) {
        if(!$.ui.dialog.overlayInstances) {
            return;
        }

        if(getMaxZ($(e.target)) > getMaxZ($('.ui-dialog:visible:last'))) {
            e.stopPropagation();
        }
    });

    $('input, textarea').placeholder();

    // Prevent BACK in browser with backspace when focused on a readonly field
    $('input, textarea').on('keydown', function(e) {
        if (this.readOnly && e.which == K.BACKSPACE) {
            e.preventDefault();
        }
    });

    $('input.permalink').on('focus', function() {
        this.select();
    });

    showFormErrors();
});
<commit_msg>Add data-ajax-dialog for quick AjaxDialog creation<commit_after>/* This file is part of Indico.
 * Copyright (C) 2002 - 2016 European Organization for Nuclear Research (CERN).
 *
 * Indico is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 *
 * Indico is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Indico; if not, see <http://www.gnu.org/licenses/>.
 */

// Global scripts that should be executed on all pages

$(document).ready(function() {
    // Create static tabs. They just load the target URL and use no ajax whatsoever
    $('.static-tabs').each(function() {
        var tabCtrl = $(this);
        tabCtrl.tabs({
            active: tabCtrl.data('active')
        });
        // Turn tabs into plain links and fix urls (needed for the active tab)
        $('> .ui-tabs-nav a', this).each(function() {
            var $this = $(this);
            tabCtrl.data('ui-tabs')._off($this, 'click');
            $this.attr('href', $this.data('href'));
        });
    });

    // Remove ui-widget-content style from static tabs as it messes up e.g. link colors
    $('.static-tabs').find('.ui-widget-content').addBack().removeClass('ui-widget-content');

    $('.main-breadcrumb a[href="#"]').css({cursor: 'default', outline: 'none'}).on('click', function(e) {
        e.preventDefault();
    });

    // Use qtip for context help

    $.fn.qtip.defaults = $.extend(true, {}, $.fn.qtip.defaults, {
        position: {
            my: 'top center',
            at: 'bottom center'
        },
        hide: {
            event: 'click mouseout'
        }
    });

    $('.contextHelp[title]').qtip();

    $(document).on("mouseenter", '[title]:not([title=""]):not(iframe)', function(event) {
        if (!$(this).attr('title').trim()) {
            return;
        }

        var extraOpts = $(this).data('qtipOpts') || {},
            qtipClass = $(this).data('qtip-style');

        $(this).qtip($.extend(true, {}, {
            overwrite: false,
            show: {
                event: event.type,
                ready: true
            },

            content: {
                text: function() {
                    var html = $(this).attr('title') || $(this).attr('alt');
                    return html ? html.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">") : '';
                }
            },

            events: {
                show: function(event) {
                    if ($(event.originalEvent.target).hasClass('open')) {
                        event.preventDefault();
                    }
                }
            },
            hide: {
                event: "mouseleave"
            },

            style: {
                classes: qtipClass ? 'qtip-' + qtipClass : null
            },

            onHide: function() {
                // If the parent element is destroyed we need to destroy the qTip too
                $(this).qtip('destroy');
            }
        }, extraOpts), event);
    });

    // Enable colorbox for links with .js-lightbox
    $('body').on('click', 'a.js-lightbox', function() {
        $(this).colorbox({
            maxHeight: '90%',
            maxWidth: '90%',
            loop: false,
            photo: true,
            returnFocus: false
        });
    });

    $('.contextHelp[data-src]').qtip({
        content: {
            text: function() {
                return $($(this).data('src')).removeClass('tip');
            }
        }
    });

    $('.js-dropdown').each(function() {
        this.id = this.id || uniqueId();
        $(this).parent().dropdown({selector: '#' + this.id});
    });

    $('body').on('click', '[data-confirm]:not(button[data-href]):not(input:button[data-href]):not(a[data-method][data-href])', function() {
        var $this = $(this);
        new ConfirmPopup($(this).data("title"), $(this).data("confirm"), function(confirmed){
            if (confirmed){
                if ($this.is('form')) {
                    $this.submit();
                } else {
                    window.location = $this.attr('href');
                }
            }
        }).open();
        return false;
    });

    $('body').on('click', 'button[data-method][data-href], input:button[data-method][data-href], a[data-method][data-href]', function(e) {
        e.preventDefault();
        var $this = $(this);
        var url = $this.data('href');
        var method = $this.data('method').toUpperCase();
        var params = $this.data('params') || {};
        var update = $this.data('update');
        var dialog = $this.data('ajax-dialog') !== undefined;
        if (!$.isPlainObject(params)) {
            throw new Error('Invalid params. Must be valid JSON if set.');
        }

        function execute() {
            var evt = $.Event('indico:confirmed');
            $this.trigger(evt);

            // Handle custom code
            if (evt.isDefaultPrevented()) {
                return;
            }

            // Handle AJAX dialog
            if (dialog) {
                ajaxDialog({
                    trigger: $this,
                    url: url,
                    title: $this.data('title'),
                    onClose: function(data) {
                        if (data && update) {
                            $(update).html(data.html);
                        }
                    }
                });
                return;
            }

            // Handle html update
            if (update) {
                $.ajax({
                    method: method,
                    url: url,
                    data: params,
                    error: handleAjaxError,
                    complete: IndicoUI.Dialogs.Util.progress(),
                    success: function(data) {
                        $(update).html(data.html);
                    }
                });
                return;
            }

            // Handle normal GET/POST
            if (method === 'GET') {
                location.href = build_url(url, params);
            } else if (method === 'POST') {
                var form = $('<form>', {
                    action: url,
                    method: method
                });
                form.append($('<input>', {type: 'hidden', name: 'csrf_token', value: $('#csrf-token').attr('content')}));
                $.each(params, function(key, value) {
                    form.append($('<input>', {type: 'hidden', name: key, value: value}));
                });
                form.appendTo('body').submit();
            }
        }

        var promptMsg = $this.data('confirm');
        var confirmed;
        if (!promptMsg) {
            confirmed = $.Deferred().resolve();
        } else {
            confirmed = confirmPrompt(promptMsg, $(this).data('title') || $T('Confirm action'));
        }
        confirmed.then(execute);
    });

    if (navigator.userAgent.match(/Trident\/7\./)) {
        // Silly IE11 will clear the second password field if
        // password autocompletion is enabled!
        // https://social.msdn.microsoft.com/Forums/en-US/7d02173f-8f45-4a74-90bf-5dfbd8f9c1de/ie-11-issue-with-two-password-input-fields
        $('input:password').each(function(){
            if (!this.value && this.getAttribute('value')) {
                this.value = this.getAttribute('value');
            }
        });
    }

    // jQuery UI prevents anything outside modal dialogs from gaining focus.
    // This breaks e.g. the session color date selector. To fix this we prevent
    // the focus trap (focusin event bound on document) from ever receiving the
    // event in case the z-index of the focused event is higher than the dialog's.
    function getMaxZ(elem) {
        var maxZ = 0;
        elem.parents().addBack().each(function() {
            var z = +$(this).css('zIndex');
            if (!isNaN(z)) {
                maxZ = Math.max(z, maxZ);
            }
        });
        return maxZ;
    }

    $('body').on('focusin', function(e) {
        if(!$.ui.dialog.overlayInstances) {
            return;
        }

        if(getMaxZ($(e.target)) > getMaxZ($('.ui-dialog:visible:last'))) {
            e.stopPropagation();
        }
    });

    $('input, textarea').placeholder();

    // Prevent BACK in browser with backspace when focused on a readonly field
    $('input, textarea').on('keydown', function(e) {
        if (this.readOnly && e.which == K.BACKSPACE) {
            e.preventDefault();
        }
    });

    $('input.permalink').on('focus', function() {
        this.select();
    });

    showFormErrors();
});
<|endoftext|>


<commit_before>/* UI stuff that doesn't need to be loaded per window */
var backstage = Cu.import("resource:///modules/CustomizableUI.jsm");
Cu.import("resource://services-common/stringbundle.js");

exports.load = function () {
	backstage.CustomizableUIInternal.registerArea("GiT-addon-bar", {
		legacy: false,
		type: CustomizableUI.TYPE_TOOLBAR,
		defaultPlacements: [
			"GiT-addon-bar-toggle-button",
			"spring",
			"GiT-status-bar-container"
		],
		defaultCollapsed: false
	}, true);

	let sb = new StringBundle("chrome://GiT-addonbar/locale/addonbar.properties");
	let toolbarName = sb.get("addonbar");
	let statusbarName = sb.get("statusbar");

	CustomizableUI.createWidget({
		id: "GiT-addon-bar-toggle-button",
		type: "button",
		label: toolbarName,
		tooltiptext: toolbarName,
		onCommand: function (e) {
			let addonbar = e.target.ownerDocument.getElementById("GiT-addon-bar");
			let window = e.target.ownerDocument.defaultView;
			if (addonbar.collapsed === false) {
				addonbar.collapsed = true;
			} else {
				addonbar.collapsed = false;
			}
		}
	});

	CustomizableUI.createWidget({
		id: "GiT-status-bar-container",
		type: "custom",
		onBuild: function (doc) {
			let item = doc.createElement("toolbaritem");
			item.id = "GiT-status-bar-container";
			item.setAttribute("removable", true);
			item.setAttribute("label", statusbarName);
			item.setAttribute("class", "panel-wide-item");
			item.setAttribute("closemenu", "none");
			let palette = doc.defaultView.gNavToolbox.palette;
			let statusbar = doc.getElementById("status-bar") ||
					palette.querySelector("status-bar");
			item.appendChild(statusbar);
			return item;
		}
	});
};

exports.unload = function () {

	let listener = {
		onWidgetBeforeDOMChange: function (node, nextNode, container, removing) {
			if (removing) {
				if (node.id === "GiT-status-bar-container") {
					if (node.firstChild && node.firstChild.id === "status-bar") {
						try {
							node.ownerDocument.getElementById("addon-bar").appendChild(node.firstChild);
						} catch (e) { throw(e) }
					}
				}
			}
		}
	}

	CustomizableUI.addListener(listener);
	CustomizableUI.destroyWidget("GiT-addon-bar-toggle-button");
	CustomizableUI.destroyWidget("GiT-status-bar-container");
	CustomizableUI.unregisterArea("GiT-addon-bar");
	CustomizableUI.removeListener(listener);
}
<commit_msg>ensure status-bar placement. Part of #3<commit_after>/* UI stuff that doesn't need to be loaded per window */
var backstage = Cu.import("resource:///modules/CustomizableUI.jsm");
Cu.import("resource://services-common/stringbundle.js");

exports.load = function () {
	backstage.CustomizableUIInternal.registerArea("GiT-addon-bar", {
		legacy: false,
		type: CustomizableUI.TYPE_TOOLBAR,
		defaultPlacements: [
			"GiT-addon-bar-toggle-button",
			"spring",
			"GiT-status-bar-container"
		],
		defaultCollapsed: false
	}, true);

	let sb = new StringBundle("chrome://GiT-addonbar/locale/addonbar.properties");
	let toolbarName = sb.get("addonbar");
	let statusbarName = sb.get("statusbar");

	CustomizableUI.createWidget({
		id: "GiT-addon-bar-toggle-button",
		type: "button",
		label: toolbarName,
		tooltiptext: toolbarName,
		onCommand: function (e) {
			let addonbar = e.target.ownerDocument.getElementById("GiT-addon-bar");
			let window = e.target.ownerDocument.defaultView;
			if (addonbar.collapsed === false) {
				addonbar.collapsed = true;
			} else {
				addonbar.collapsed = false;
			}
		}
	});

	CustomizableUI.createWidget({
		id: "GiT-status-bar-container",
		type: "custom",
		onBuild: function (doc) {
			let item = doc.createElement("toolbaritem");
			item.id = "GiT-status-bar-container";
			item.setAttribute("removable", true);
			item.setAttribute("label", statusbarName);
			item.setAttribute("class", "panel-wide-item");
			item.setAttribute("closemenu", "none");
			let palette = doc.defaultView.gNavToolbox.palette;
			let statusbar = doc.getElementById("status-bar") ||
					palette.querySelector("status-bar");
			item.appendChild(statusbar);
			/* ensure status-bar placement */
			doc.defaultView.setTimeout(function () {
				item.appendChild(statusbar);
			}, 210);
			return item;
		}
	});
};

exports.unload = function () {

	let listener = {
		onWidgetBeforeDOMChange: function (node, nextNode, container, removing) {
			if (removing) {
				if (node.id === "GiT-status-bar-container") {
					if (node.firstChild && node.firstChild.id === "status-bar") {
						try {
							node.ownerDocument.getElementById("addon-bar").appendChild(node.firstChild);
						} catch (e) { throw(e) }
					}
				}
			}
		}
	}

	CustomizableUI.addListener(listener);
	CustomizableUI.destroyWidget("GiT-addon-bar-toggle-button");
	CustomizableUI.destroyWidget("GiT-status-bar-container");
	CustomizableUI.unregisterArea("GiT-addon-bar");
	CustomizableUI.removeListener(listener);
}
<|endoftext|>


<commit_before>var axios = require("axios");

function HTTPBinary(configuration){
  this.config = configuration;

  this.config["headers"] = {
    "Content-Type":"application/cloudevents+json; charset=utf-8"
  };
}

HTTPBinary.prototype.emit = function(cloudevent){

  // Create new request object
  var _config = JSON.parse(JSON.stringify(this.config));

  // Always set stuff in _config
  var _headers = _config["headers"];

  if(cloudevent.getContenttype())
    _headers["Content-Type"] = cloudevent.getContenttype();

  _headers["CE-EventType"]          = cloudevent.getType();
  if(cloudevent.getEventTypeVersion())
    _headers["CE-EventTypeVersion"] = cloudevent.getEventTypeVersion();
  _headers["CE-CloudEventsVersion"] = cloudevent.getSpecversion();
  _headers["CE-Source"] = cloudevent.getSource();
  _headers["CE-EventID"] = cloudevent.getId();
  if(cloudevent.getTime())
    _headers["CE-EventTime"] = cloudevent.getTime();
  _headers["CE-SchemaURL"] = cloudevent.getSchemaurl();

  // Set the cloudevent payload
  _config["data"] = cloudevent.format().data;

  // Return the Promise
  return axios.request(_config);
};

module.exports = HTTPBinary;
<commit_msg>curly<commit_after>var axios = require("axios");

function HTTPBinary(configuration){
  this.config = configuration;

  this.config["headers"] = {
    "Content-Type":"application/cloudevents+json; charset=utf-8"
  };
}

HTTPBinary.prototype.emit = function(cloudevent){

  // Create new request object
  var _config = JSON.parse(JSON.stringify(this.config));

  // Always set stuff in _config
  var _headers = _config["headers"];

  if(cloudevent.getContenttype()) {
    _headers["Content-Type"] = cloudevent.getContenttype();
  }

  _headers["CE-EventType"] = cloudevent.getType();
  if(cloudevent.getEventTypeVersion()) {
    _headers["CE-EventTypeVersion"] = cloudevent.getEventTypeVersion();
  }
  _headers["CE-CloudEventsVersion"] = cloudevent.getSpecversion();
  _headers["CE-Source"] = cloudevent.getSource();
  _headers["CE-EventID"] = cloudevent.getId();
  if(cloudevent.getTime()) {
    _headers["CE-EventTime"] = cloudevent.getTime();
  }
  _headers["CE-SchemaURL"] = cloudevent.getSchemaurl();

  // Set the cloudevent payload
  _config["data"] = cloudevent.format().data;

  // Return the Promise
  return axios.request(_config);
};

module.exports = HTTPBinary;
<|endoftext|>


<commit_before>
//
// Copyright 2016 Kary Foundation, Inc.
//   Author: Pouya Kary <k@karyfoundation.org>
//

//
// ─── MENU ───────────────────────────────────────────────────────────────────────
//

    var MainMenu = [

        //
        // ─── FILE ────────────────────────────────────────────────────────
        //

            {
                label: 'File',
                submenu: [
                    {
                        label: 'New File',
                        accelerator: 'CmdOrCtrl+N',
                        click: onNewFile
                    },
                    {
                        label: 'New Window',
                        accelerator: 'Shift+CmdOrCtrl+N',
                        click: ( ) => { }
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Open...',
                        accelerator: 'CmdOrCtrl+O',
                        click: onOpenFile
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Save',
                        accelerator: 'CmdOrCtrl+S',
                        click: ( ) => onSaveFile( )
                    },
                    {
                        label: 'Save As',
                        accelerator: 'Shift+CmdOrCtrl+S',
                        click: onSaveFileAs
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Export to Image',
                        click: onExportWorkspaceToSVG
                    },
                ]
            },

        //
        // ─── EDIT MENU ───────────────────────────────────────────────────
        //

            {
                label: 'Edit',
                submenu: [
                    {
                        label: 'Undo',
                        accelerator: 'CmdOrCtrl+Z',
                        role: 'undo'
                    },
                    {
                        label: 'Redo',
                        accelerator: 'Shift+CmdOrCtrl+Z',
                        role: 'redo'
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Cut',
                        accelerator: 'CmdOrCtrl+X',
                        role: 'cut'
                    },
                    {
                        label: 'Copy',
                        accelerator: 'CmdOrCtrl+C',
                        role: 'copy'
                    },
                    {
                        label: 'Paste',
                        accelerator: 'CmdOrCtrl+V',
                        role: 'paste'
                    },
                    {
                        label: 'Select All',
                        accelerator: 'CmdOrCtrl+A',
                        role: 'selectall'
                    }
                ]
            },

        //
        // ─── WINDOW MENU ────────────────────────────────────────────────────────────────
        //

            {
                label: 'Window',
                role: 'window',
                submenu: [
                    {
                        label: 'Minimize',
                        accelerator: 'CmdOrCtrl+M',
                        role: 'minimize'
                    },
                    {
                        label: 'Close',
                        accelerator: 'CmdOrCtrl+W',
                        role: 'close'
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: "Open Developer Tools",
                        click: OrchestraWindow.openDevTools
                    }
                ]
            },

        //
        // ─── HELP MENU ──────────────────────────────────────────────────────────────────
        //

            {
                label: 'Help',
                role: 'help',
                submenu: [
                    {
                        label: "Kary Foundtation's Website",
                        click: ( ) => openExternal('https://www.karyfoundation.org/')
                    },
                    {
                        label: "Report an issue...",
                        click: ( ) => openExternal('https://github.com/karyfoundation/orchestra/issues')
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: "RegExp on Mozilla Developer Network",
                        click: ( ) => openExternal('https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/RegExp')
                    },
                ]
            },

        // ────────────────────────────────────────────────────────────────────────────────

    ];

//
// ─── OS SPECIFIC MENUS ──────────────────────────────────────────────────────────
//

    var AboutPageButton = {
        role: 'about'
    }

    if ( process.platform == 'darwin' ) {
        var name = require( 'electron' ).remote.app.getName( );
        var menuIndex = MainMenu.length - 1;
        MainMenu.unshift(
            {
                label: name,
                submenu: [
                    AboutPageButton,
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Services',
                        role: 'services',
                        submenu: [ ]
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Hide ' + name,
                        accelerator: 'Command+H',
                        role: 'hide'
                    },
                    {
                        label: 'Hide Others',
                        accelerator: 'Command+Alt+H',
                        role: 'hideothers'
                    },
                    {
                        label: 'Show All',
                        role: 'unhide'
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Quit',
                        accelerator: 'Command+Q',
                        click: ( ) => fireWindowCloseRequest( )
                    },
                ]
            }
        );
    } else {
        MainMenu[ menuIndex ].submenu.push( AboutPageButton );
    }

//
// ─── INIT MENU ──────────────────────────────────────────────────────────────────
//

    function initMainMenu ( ) {
        const remote = require('electron').remote;
        const Menu = remote.Menu;
        const MenuItem = remote.MenuItem;

        var menu = new Menu();

        /*window.addEventListener( 'contextmenu' , function ( e ) {
            e.preventDefault( );
            menu.popup( remote.getCurrentWindow() );
        }, false);*/

        var menu = Menu.buildFromTemplate( MainMenu );
        Menu.setApplicationMenu( menu );
    }

// ────────────────────────────────────────────────────────────────────────────────
<commit_msg>better naming...<commit_after>
//
// Copyright 2016 Kary Foundation, Inc.
//   Author: Pouya Kary <k@karyfoundation.org>
//

//
// ─── MENU ───────────────────────────────────────────────────────────────────────
//

    var MainMenu = [

        //
        // ─── FILE ────────────────────────────────────────────────────────
        //

            {
                label: 'File',
                submenu: [
                    {
                        label: 'New File',
                        accelerator: 'CmdOrCtrl+N',
                        click: onNewFile
                    },
                    {
                        label: 'New Window',
                        accelerator: 'Shift+CmdOrCtrl+N',
                        click: ( ) => { }
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Open...',
                        accelerator: 'CmdOrCtrl+O',
                        click: onOpenFile
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Save',
                        accelerator: 'CmdOrCtrl+S',
                        click: ( ) => onSaveFile( )
                    },
                    {
                        label: 'Save As',
                        accelerator: 'Shift+CmdOrCtrl+S',
                        click: onSaveFileAs
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Export to SVG',
                        click: onExportWorkspaceToSVG
                    },
                ]
            },

        //
        // ─── EDIT MENU ───────────────────────────────────────────────────
        //

            {
                label: 'Edit',
                submenu: [
                    {
                        label: 'Undo',
                        accelerator: 'CmdOrCtrl+Z',
                        role: 'undo'
                    },
                    {
                        label: 'Redo',
                        accelerator: 'Shift+CmdOrCtrl+Z',
                        role: 'redo'
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Cut',
                        accelerator: 'CmdOrCtrl+X',
                        role: 'cut'
                    },
                    {
                        label: 'Copy',
                        accelerator: 'CmdOrCtrl+C',
                        role: 'copy'
                    },
                    {
                        label: 'Paste',
                        accelerator: 'CmdOrCtrl+V',
                        role: 'paste'
                    },
                    {
                        label: 'Select All',
                        accelerator: 'CmdOrCtrl+A',
                        role: 'selectall'
                    }
                ]
            },

        //
        // ─── WINDOW MENU ────────────────────────────────────────────────────────────────
        //

            {
                label: 'Window',
                role: 'window',
                submenu: [
                    {
                        label: 'Minimize',
                        accelerator: 'CmdOrCtrl+M',
                        role: 'minimize'
                    },
                    {
                        label: 'Close',
                        accelerator: 'CmdOrCtrl+W',
                        role: 'close'
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: "Open Developer Tools",
                        click: OrchestraWindow.openDevTools
                    }
                ]
            },

        //
        // ─── HELP MENU ──────────────────────────────────────────────────────────────────
        //

            {
                label: 'Help',
                role: 'help',
                submenu: [
                    {
                        label: "Kary Foundtation's Website",
                        click: ( ) => openExternal('https://www.karyfoundation.org/')
                    },
                    {
                        label: "Report an issue...",
                        click: ( ) => openExternal('https://github.com/karyfoundation/orchestra/issues')
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: "RegExp on Mozilla Developer Network",
                        click: ( ) => openExternal('https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/RegExp')
                    },
                ]
            },

        // ────────────────────────────────────────────────────────────────────────────────

    ];

//
// ─── OS SPECIFIC MENUS ──────────────────────────────────────────────────────────
//

    var AboutPageButton = {
        role: 'about'
    }

    if ( process.platform == 'darwin' ) {
        var name = require( 'electron' ).remote.app.getName( );
        var menuIndex = MainMenu.length - 1;
        MainMenu.unshift(
            {
                label: name,
                submenu: [
                    AboutPageButton,
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Services',
                        role: 'services',
                        submenu: [ ]
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Hide ' + name,
                        accelerator: 'Command+H',
                        role: 'hide'
                    },
                    {
                        label: 'Hide Others',
                        accelerator: 'Command+Alt+H',
                        role: 'hideothers'
                    },
                    {
                        label: 'Show All',
                        role: 'unhide'
                    },
                    {
                        type: 'separator'
                    },
                    {
                        label: 'Quit',
                        accelerator: 'Command+Q',
                        click: ( ) => fireWindowCloseRequest( )
                    },
                ]
            }
        );
    } else {
        MainMenu[ menuIndex ].submenu.push( AboutPageButton );
    }

//
// ─── INIT MENU ──────────────────────────────────────────────────────────────────
//

    function initMainMenu ( ) {
        const remote = require('electron').remote;
        const Menu = remote.Menu;
        const MenuItem = remote.MenuItem;

        var menu = new Menu();

        /*window.addEventListener( 'contextmenu' , function ( e ) {
            e.preventDefault( );
            menu.popup( remote.getCurrentWindow() );
        }, false);*/

        var menu = Menu.buildFromTemplate( MainMenu );
        Menu.setApplicationMenu( menu );
    }

// ────────────────────────────────────────────────────────────────────────────────
<|endoftext|>


<commit_before>;(function () {
  const { chrome, InboxSDK, Kefir } = window

  let mouseEventsToElementsHandler = predicate => (emitter, e) => {
    if (e.type === 'end') {
      emitter.end()
    } else if (e.type === 'value') {
      let mouseEvent = e.value
      for (let i = mouseEvent.path.length - 1; i >= 0; i--) {
        let el = mouseEvent.path[i]
        if (predicate(el)) {
          emitter.emit(el)
          // emitter.end()
          break
        }
      }
    }
  }

  let elementClassFilter = className => el => {
    let classAttr = el.getAttribute && el.getAttribute('class')
    if (typeof classAttr === 'string') {
      let classes = classAttr.split(/\s/g)
      return classes.some(cls => cls === className)
    }
    return false
  }

  let sidebarEl = document.createElement('div')

  let showSidebar = false

  let wrapSidebarContent = contentHtml => `

      ${contentHtml}

`

  let updateSidebarContent = contentHtml => {
    sidebarEl.innerHTML = wrapSidebarContent(contentHtml)
  }

  let getSidebarAgentsInfoHtml = agents => agents.map(agent => `

        ${agent.name}

        ${agent.description}

`).join('
')

  let updateAgentsInfo = agents => updateSidebarContent(getSidebarAgentsInfoHtml(agents))

  let sidebarClicks$ = Kefir.fromEvents(sidebarEl, 'click')
  // sidebarClicks$.log('sidebarClicks$')

  sidebarClicks$
    .withHandler(mouseEventsToElementsHandler(elementClassFilter('msext-agent-info')))
    .map(el => el.dataset.agentId)
    // .log('clickedAgentInfoElements$')
    .onValue(agentId => {
      chrome.runtime.sendMessage({
        type: 'SHOW_AGENT',
        targetTab: 'https://online.moysklad.ru/app/*',
        switchTab: true,
        agentId
      })
    })

  InboxSDK.load('1.0', 'sdk_moysklad_gmail_c6ce2e116e').then(function (sdk) {
    let currentThreadView
    let currentUserEmail = sdk.User.getEmailAddress()

    let updateCurrentThreadSidebar = threadView => {
      if (!threadView) { return }

      let messageViews = threadView.getMessageViewsAll()

      let sendersByEmail = messageViews
        .reduce((res, messageView) => {
          let contacts = []
          try {
            contacts.push(messageView.getSender())
          } catch (e) {}
          try {
            contacts = contacts.concat(messageView.getRecipients())
          } catch (e) {}

          return res.concat(contacts)
        }, [])
        .reduce((res, contact) => {
          if (currentUserEmail !== contact.emailAddress) {
            res[contact.emailAddress] = contact
          }
          return res
        }, {})

      // console.log('sendersByEmail', sendersByEmail)

      chrome.runtime.sendMessage({
        type: 'GET_AGENTS_INFO',
        targetTab: 'https://online.moysklad.ru/app/*',
        agentEmails: Object.keys(sendersByEmail)
      }, response => {
        // console.log('response', response)
        if (response) {
          switch (true) {
            case response.length > 0:
              updateAgentsInfo(response)
              break

            case response.length === 0:
              updateSidebarContent('Контрагенты для этой цеопчки писем не найдены')
              break

            default:
              if (response.error) {
                console.error(response.error)
              }
              updateSidebarContent('Ошибка при обращении к сервису МойСклад')
          }
        } else {
          updateSidebarContent('Для работы расширения необходимо открыть хотя бы одну вкладку ' +
            'приложения ' +
            'МойСклад в текущем окне')
        }
      })
    }

    sdk.Conversations.registerThreadViewHandler(threadView => {
      // console.log('ThreadViewHandler')
      currentThreadView = threadView

      updateCurrentThreadSidebar(threadView)

      threadView.addSidebarContentPanel({
        title: 'Контрагенты МойСклад',
        el: sidebarEl
      })

      threadView.on('destroy', () => updateSidebarContent(''))
    })

    sdk.Conversations.registerMessageViewHandler(messageView => {
      // console.log('MessageViewHandler')
      updateCurrentThreadSidebar(currentThreadView)
    })
  })
})()

<commit_msg>Комментарии<commit_after>;(function () {
  const { chrome, InboxSDK, Kefir } = window

  let mouseEventsToElementsHandler = predicate => (emitter, e) => {
    if (e.type === 'end') {
      emitter.end()
    } else if (e.type === 'value') {
      let mouseEvent = e.value
      for (let i = mouseEvent.path.length - 1; i >= 0; i--) {
        let el = mouseEvent.path[i]
        if (predicate(el)) {
          emitter.emit(el)
          // emitter.end()
          break
        }
      }
    }
  }

  let elementClassFilter = className => el => {
    let classAttr = el.getAttribute && el.getAttribute('class')
    if (typeof classAttr === 'string') {
      let classes = classAttr.split(/\s/g)
      return classes.some(cls => cls === className)
    }
    return false
  }

  let sidebarEl = document.createElement('div')

  let wrapSidebarContent = contentHtml => `

      ${contentHtml}

`

  let updateSidebarContent = contentHtml => {
    sidebarEl.innerHTML = wrapSidebarContent(contentHtml)
  }

  let getSidebarAgentsInfoHtml = agents => agents.map(agent => `

        ${agent.name}

        ${agent.description}

`).join('
')

  let updateAgentsInfo = agents => updateSidebarContent(getSidebarAgentsInfoHtml(agents))

  let sidebarClicks$ = Kefir.fromEvents(sidebarEl, 'click')
  // sidebarClicks$.log('sidebarClicks$')

  sidebarClicks$
    .withHandler(mouseEventsToElementsHandler(elementClassFilter('msext-agent-info')))
    .map(el => el.dataset.agentId)
    // .log('clickedAgentInfoElements$')
    .onValue(agentId => {
      // TODO Если вкладка не открыта, открывать по ссылке
      chrome.runtime.sendMessage({
        type: 'SHOW_AGENT',
        targetTab: 'https://online.moysklad.ru/app/*',
        switchTab: true,
        agentId
      })
    })

  InboxSDK.load('1.0', 'sdk_moysklad_gmail_c6ce2e116e').then(function (sdk) {
    let currentThreadView
    let currentUserEmail = sdk.User.getEmailAddress()

    let updateCurrentThreadSidebar = threadView => {
      if (!threadView) { return }

      let messageViews = threadView.getMessageViewsAll()

      let sendersByEmail = messageViews
        .reduce((res, messageView) => {
          let contacts = []
          try {
            contacts.push(messageView.getSender())
          } catch (e) {}
          try {
            contacts = contacts.concat(messageView.getRecipients())
          } catch (e) {}

          return res.concat(contacts)
        }, [])
        .reduce((res, contact) => {
          if (currentUserEmail !== contact.emailAddress) {
            res[contact.emailAddress] = contact
          }
          return res
        }, {})

      // console.log('sendersByEmail', sendersByEmail)

      // TODO Если ответа нет долго, то, возможно, МойСклад запросил авторизацию ..
      // Уведомить пользователя о необходимости ввести логин и пароль
      chrome.runtime.sendMessage({
        type: 'GET_AGENTS_INFO',
        targetTab: 'https://online.moysklad.ru/app/*',
        agentEmails: Object.keys(sendersByEmail)
      }, response => {
        // console.log('response', response)
        if (response) {
          switch (true) {
            case response.length > 0:
              updateAgentsInfo(response)
              break

            case response.length === 0:
              updateSidebarContent('Контрагенты для этой цеопчки писем не найдены')
              break

            default:
              if (response.error) {
                console.error(response.error)
              }
              updateSidebarContent('Ошибка при обращении к сервису МойСклад')
          }
        } else {
          updateSidebarContent('Для работы расширения необходимо открыть хотя бы одну вкладку ' +
            'приложения ' +
            'МойСклад в текущем окне')
        }
      })
    }

    sdk.Conversations.registerThreadViewHandler(threadView => {
      // console.log('ThreadViewHandler')
      currentThreadView = threadView

      updateCurrentThreadSidebar(threadView)

      threadView.addSidebarContentPanel({
        title: 'Контрагенты МойСклад',
        el: sidebarEl
      })

      threadView.on('destroy', () => updateSidebarContent(''))
    })

    sdk.Conversations.registerMessageViewHandler(messageView => {
      // console.log('MessageViewHandler')
      updateCurrentThreadSidebar(currentThreadView)
    })
  })
})()

<|endoftext|>