<commit_before>/*
 *  SonosBridge.js
 *
 *  David Janes
 *  IOTDB.org
 *  2015-04-03
 *
 *  Copyright [2013-2015] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict";

var iotdb = require('iotdb');
var _ = iotdb._;
var bunyan = iotdb.bunyan;

var sonos = require('sonos');

var logger = bunyan.createLogger({
    name: 'homestar-sonos',
    module: 'SonosBridge',
});

var mode_play = _.ld.expand("iot-attribute:media.mode.play");
var mode_pause = _.ld.expand("iot-attribute:media.mode.pause");
var mode_stop = _.ld.expand("iot-attribute:media.mode.stop");

/**
 *  EXEMPLAR and INSTANCE
 *

 *  No subclassing needed! The following functions are
 *  injected _after_ this is created, and before .discover and .connect
 *

 *
discovered - tell IOTDB that we're talking to a new Thing
 *
pulled - got new data
 *
connected - this is connected to a Thing
 *
disconnnected - this has been disconnected from a Thing
 *

 */
var SonosBridge = function (initd, native) {
    var self = this;

    self.initd = _.defaults(initd,
        iotdb.keystore().get("bridges/SonosBridge/initd"), {
            poll: 30
        }
    );
    self.native = native;

    if (self.native) {
        self.native.uuid = "00000000-0000-0000-0000-000000000000";
        self.queue = _.queue("SonosBridge");
        self.stated = {};
    }
};

/* --- lifecycle --- */

/**
 *  EXEMPLAR.
 *  Discover Hue
 *

 *
look for Things (using self.bridge data to initialize)
 *
find / create a native that does the talking
 *
create an SonosBridge(native)
 *
call self.discovered(bridge) with it
 */
SonosBridge.prototype.discover = function () {
    var self = this;

    logger.info({
        method: "discover"
    }, "called");

    sonos.search(function (native) {
        self.discovered(new SonosBridge(self.initd, native));
    });
};

/**
 *  INSTANCE
 *  This is called when the Bridge is no longer needed. When
 */
SonosBridge.prototype.connect = function (connectd) {
    var self = this;
    if (!self.native) {
        return;
    }

    self._setup_polling();
    self.pull();
};

SonosBridge.prototype._setup_polling = function () {
    var self = this;
    if (!self.initd.poll) {
        return;
    }

    var timer = setInterval(function () {
        if (!self.native) {
            clearInterval(timer);
            return;
        }

        self.pull();
    }, self.initd.poll * 1000);
};

SonosBridge.prototype._forget = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    logger.info({
        method: "_forget"
    }, "called");

    self.native = null;
    self.pulled();
};

/**
 *  INSTANCE and EXEMPLAR (during shutdown).
 *  This is called when the Bridge is no longer needed.
 */
SonosBridge.prototype.disconnect = function () {
    var self = this;
    if (!self.native || !self.native) {
        return;
    }

    self._forget();
};

/* --- data --- */

/**
 *  INSTANCE.
 *  Send data to whatever you're taking to.
 */
SonosBridge.prototype.push = function (pushd) {
    var self = this;
    if (!self.native) {
        return;
    }

    logger.info({
        method: "push",
        pushd: pushd,
    }, "push");

    if (pushd.mute !== undefined) {
        self._push_mute(pushd.mute);
    }

    if (pushd.volume !== undefined) {
        self._push_volume(pushd.volume);
    }

    if (pushd.next) {
        self._push_next();
    }

    if (pushd.previous) {
        self._push_previous();
    }

    if (pushd.mode === mode_play) {
        self._push_mode_play();
    } else if (pushd.mode === mode_pause) {
        self._push_mode_pause();
    } else if (pushd.mode === mode_stop) {
        self._push_mode_stop();
    }
};

SonosBridge.prototype._push_volume = function (volume) {
    var self = this;

    self.queue.add({
        id: "_push_volume",
        run: function (queue, qitem) {
            self.native.setVolume(volume, function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_volume/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        volume: volume,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mute = function (mute) {
    var self = this;

    self.queue.add({
        id: "_push_mute",
        run: function (queue, qitem) {
            self.native.setMuted(mute, function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mute/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mute: mute,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mode_play = function () {
    var self = this;

    self.queue.add({
        id: "_push_mode",
        run: function (queue, qitem) {
            self.native.play(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mode_play/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mode: mode_play,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mode_pause = function () {
    var self = this;

    self.queue.add({
        id: "_push_mode",
        run: function (queue, qitem) {
            self.native.pause(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mode_pause/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mode: mode_pause,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mode_stop = function () {
    var self = this;

    self.queue.add({
        id: "_push_mode",
        run: function (queue, qitem) {
            self.native.stop(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mode_stop/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mode: mode_stop,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_next = function () {
    var self = this;

    self.queue.add({
        id: "push-next",
        run: function (queue, qitem) {
            self.native.next(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_next/callback",
                        error: error,
                    }, "Sonos error");
                }
            });
        }
    });
};

SonosBridge.prototype._push_previous = function () {
    var self = this;

    self.queue.add({
        id: "push-previous",
        run: function (queue, qitem) {
            self.native.previous(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_previous/callback",
                        error: error,
                    }, "Sonos error");
                }
            });
        }
    });
};

/**
 *  INSTANCE.
 *  Pull data from whatever we're talking to. You don't
 *  have to implement this if it doesn't make sense
 */
SonosBridge.prototype.pull = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    self._pull_volume();
    self._pull_mute();
    self._pull_state();
};

SonosBridge.prototype._pull_volume = function () {
    var self = this;

    self.queue.add({
        id: "_pull_volume",
        run: function (queue, qitem) {
            self.native.getVolume(function (error, volume) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_pull_volume/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        volume: volume,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._pull_mute = function () {
    var self = this;

    self.queue.add({
        id: "_pull_mute",
        run: function (queue, qitem) {
            self.native.getMuted(function (error, mute) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_pull_mute/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mute: mute,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._pull_state = function () {
    var self = this;

    self.queue.add({
        id: "_pull_state",
        run: function (queue, qitem) {
            self.native.getCurrentState(function (error, state) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_pull_state/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    logger.debug({
                        method: "_pull_state/callback",
                        error: error,
                        state: state,
                    }, "XXX - have the state but don't know what to do with it just yet");
                }
            });
        }
    });
};

/* --- state --- */

/**
 *  INSTANCE.
 *  Return the metadata - compact form can be used.
 *  Does not have to work when not reachable
 *

 *  Really really useful things are:
 *

 *
iot:thing required - a unique ID
 *
iot:device suggested if linking multiple things together
 *
schema:name
 *
schema:manufacturer
 *
schema:model
 */
SonosBridge.prototype.meta = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    return {
        "iot:thing": _.id.thing_urn.unique("Sonos", self.native.uuid),
        "schema:name": self.native.name || "Sonos",
        "schema:manufacturer": "http://www.sonos.com/",
    };
};

/**
 *  INSTANCE.
 *  Return True if this is reachable. You
 *  do not need to worry about connect / disconnect /
 *  shutdown states, they will be always checked first.
 */
SonosBridge.prototype.reachable = function () {
    return this.native !== null;
};

/**
 *  INSTANCE.
 *  Configure an express web page to configure this Bridge.
 *  Return the name of the Bridge, which may be
 *  listed and displayed to the user.
 */
SonosBridge.prototype.configure = function (app) {};

/* --- injected: THIS CODE WILL BE REMOVED AT RUNTIME, DO NOT MODIFY  --- */
SonosBridge.prototype.discovered = function (bridge) {
    throw new Error("SonosBridge.discovered not implemented");
};

SonosBridge.prototype.pulled = function (pulld) {
    throw new Error("SonosBridge.pulled not implemented");
};

/*
 *  API
 */
exports.Bridge = SonosBridge;
<commit_msg>subclass from iotdb.Bridge<commit_after>/*
 *  SonosBridge.js
 *
 *  David Janes
 *  IOTDB.org
 *  2015-04-03
 *
 *  Copyright [2013-2015] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict";

var iotdb = require('iotdb');
var _ = iotdb._;
var bunyan = iotdb.bunyan;

var sonos = require('sonos');

var logger = bunyan.createLogger({
    name: 'homestar-sonos',
    module: 'SonosBridge',
});

var mode_play = _.ld.expand("iot-attribute:media.mode.play");
var mode_pause = _.ld.expand("iot-attribute:media.mode.pause");
var mode_stop = _.ld.expand("iot-attribute:media.mode.stop");

/**
 *  EXEMPLAR and INSTANCE
 *

 *  No subclassing needed! The following functions are
 *  injected _after_ this is created, and before .discover and .connect
 *

 *
discovered - tell IOTDB that we're talking to a new Thing
 *
pulled - got new data
 *
connected - this is connected to a Thing
 *
disconnnected - this has been disconnected from a Thing
 *

 */
var SonosBridge = function (initd, native) {
    var self = this;

    self.initd = _.defaults(initd,
        iotdb.keystore().get("bridges/SonosBridge/initd"), {
            poll: 30
        }
    );
    self.native = native;

    if (self.native) {
        self.native.uuid = "00000000-0000-0000-0000-000000000000";
        self.queue = _.queue("SonosBridge");
        self.stated = {};
    }
};

SonosBridge.prototype = new iotdb.Bridge();

SonosBridge.prototype.name = function () {
    return "SonosBridge";
};

/* --- lifecycle --- */

/**
 *  EXEMPLAR.
 *  Discover Hue
 *

 *
look for Things (using self.bridge data to initialize)
 *
find / create a native that does the talking
 *
create an SonosBridge(native)
 *
call self.discovered(bridge) with it
 */
SonosBridge.prototype.discover = function () {
    var self = this;

    logger.info({
        method: "discover"
    }, "called");

    sonos.search(function (native) {
        self.discovered(new SonosBridge(self.initd, native));
    });
};

/**
 *  INSTANCE
 *  This is called when the Bridge is no longer needed. When
 */
SonosBridge.prototype.connect = function (connectd) {
    var self = this;
    if (!self.native) {
        return;
    }

    self._setup_polling();
    self.pull();
};

SonosBridge.prototype._setup_polling = function () {
    var self = this;
    if (!self.initd.poll) {
        return;
    }

    var timer = setInterval(function () {
        if (!self.native) {
            clearInterval(timer);
            return;
        }

        self.pull();
    }, self.initd.poll * 1000);
};

SonosBridge.prototype._forget = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    logger.info({
        method: "_forget"
    }, "called");

    self.native = null;
    self.pulled();
};

/**
 *  INSTANCE and EXEMPLAR (during shutdown).
 *  This is called when the Bridge is no longer needed.
 */
SonosBridge.prototype.disconnect = function () {
    var self = this;
    if (!self.native || !self.native) {
        return;
    }

    self._forget();
};

/* --- data --- */

/**
 *  INSTANCE.
 *  Send data to whatever you're taking to.
 */
SonosBridge.prototype.push = function (pushd) {
    var self = this;
    if (!self.native) {
        return;
    }

    logger.info({
        method: "push",
        pushd: pushd,
    }, "push");

    if (pushd.mute !== undefined) {
        self._push_mute(pushd.mute);
    }

    if (pushd.volume !== undefined) {
        self._push_volume(pushd.volume);
    }

    if (pushd.next) {
        self._push_next();
    }

    if (pushd.previous) {
        self._push_previous();
    }

    if (pushd.mode === mode_play) {
        self._push_mode_play();
    } else if (pushd.mode === mode_pause) {
        self._push_mode_pause();
    } else if (pushd.mode === mode_stop) {
        self._push_mode_stop();
    }
};

SonosBridge.prototype._push_volume = function (volume) {
    var self = this;

    self.queue.add({
        id: "_push_volume",
        run: function (queue, qitem) {
            self.native.setVolume(volume, function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_volume/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        volume: volume,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mute = function (mute) {
    var self = this;

    self.queue.add({
        id: "_push_mute",
        run: function (queue, qitem) {
            self.native.setMuted(mute, function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mute/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mute: mute,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mode_play = function () {
    var self = this;

    self.queue.add({
        id: "_push_mode",
        run: function (queue, qitem) {
            self.native.play(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mode_play/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mode: mode_play,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mode_pause = function () {
    var self = this;

    self.queue.add({
        id: "_push_mode",
        run: function (queue, qitem) {
            self.native.pause(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mode_pause/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mode: mode_pause,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mode_stop = function () {
    var self = this;

    self.queue.add({
        id: "_push_mode",
        run: function (queue, qitem) {
            self.native.stop(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mode_stop/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mode: mode_stop,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_next = function () {
    var self = this;

    self.queue.add({
        id: "push-next",
        run: function (queue, qitem) {
            self.native.next(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_next/callback",
                        error: error,
                    }, "Sonos error");
                }
            });
        }
    });
};

SonosBridge.prototype._push_previous = function () {
    var self = this;

    self.queue.add({
        id: "push-previous",
        run: function (queue, qitem) {
            self.native.previous(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_previous/callback",
                        error: error,
                    }, "Sonos error");
                }
            });
        }
    });
};

/**
 *  INSTANCE.
 *  Pull data from whatever we're talking to. You don't
 *  have to implement this if it doesn't make sense
 */
SonosBridge.prototype.pull = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    self._pull_volume();
    self._pull_mute();
    self._pull_state();
};

SonosBridge.prototype._pull_volume = function () {
    var self = this;

    self.queue.add({
        id: "_pull_volume",
        run: function (queue, qitem) {
            self.native.getVolume(function (error, volume) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_pull_volume/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        volume: volume,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._pull_mute = function () {
    var self = this;

    self.queue.add({
        id: "_pull_mute",
        run: function (queue, qitem) {
            self.native.getMuted(function (error, mute) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_pull_mute/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mute: mute,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._pull_state = function () {
    var self = this;

    self.queue.add({
        id: "_pull_state",
        run: function (queue, qitem) {
            self.native.getCurrentState(function (error, state) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_pull_state/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    logger.debug({
                        method: "_pull_state/callback",
                        error: error,
                        state: state,
                    }, "XXX - have the state but don't know what to do with it just yet");
                }
            });
        }
    });
};

/* --- state --- */

/**
 *  INSTANCE.
 *  Return the metadata - compact form can be used.
 *  Does not have to work when not reachable
 *

 *  Really really useful things are:
 *

 *
iot:thing required - a unique ID
 *
iot:device suggested if linking multiple things together
 *
schema:name
 *
schema:manufacturer
 *
schema:model
 */
SonosBridge.prototype.meta = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    return {
        "iot:thing": _.id.thing_urn.unique("Sonos", self.native.uuid),
        "schema:name": self.native.name || "Sonos",
        "schema:manufacturer": "http://www.sonos.com/",
    };
};

/**
 *  INSTANCE.
 *  Return True if this is reachable. You
 *  do not need to worry about connect / disconnect /
 *  shutdown states, they will be always checked first.
 */
SonosBridge.prototype.reachable = function () {
    return this.native !== null;
};

/**
 *  INSTANCE.
 *  Configure an express web page to configure this Bridge.
 *  Return the name of the Bridge, which may be
 *  listed and displayed to the user.
 */
SonosBridge.prototype.configure = function (app) {};

/* --- injected: THIS CODE WILL BE REMOVED AT RUNTIME, DO NOT MODIFY  --- */
SonosBridge.prototype.discovered = function (bridge) {
    throw new Error("SonosBridge.discovered not implemented");
};

SonosBridge.prototype.pulled = function (pulld) {
    throw new Error("SonosBridge.pulled not implemented");
};

/*
 *  API
 */
exports.Bridge = SonosBridge;
<|endoftext|>


<commit_before>import Plotly from 'plotly'; // plotly core only
import {Spinner} from 'spin.js';

Plotly.register([
    require('../../../../../../node_modules/plotly.js/lib/scatterternary')
]);

function makeAxis(title, tickangle) {
    return {
        title: title, titlefont: { size: 20 },
        tickangle: tickangle, tickfont: { size: 15 },
        tickcolor: 'rgba(0,0,0,0)', ticklen: 5,
        showline: true, showgrid: true
    }
};

$(document).ready(function () {
    var target = document.getElementById('spinner_graph');
    var spinner_plot = new Spinner({scale: 0.5});
    spinner_plot.spin(target);

    var api_url = window.api['host'] + 'projects/swf/graph';
    var graph = document.getElementById('graph');

    var layout = {
        hovermode: 'closest', height: 900,
        title: 'In-plane Coercive Field Maps',
        xaxis1: {
            title: 'Percent V [at%]',
            domain: [0, 0.45], anchor: 'y1'
        },
        yaxis1: {
            title: 'Film Thickness [nm]',
            domain: [0.6, 1], anchor: 'x1'
        },
        xaxis2: {
            title: 'Percent V [at%]',
            domain: [0.55, 1], anchor: 'y2'
        },
        yaxis2: { domain: [0.6, 1], anchor: 'x2' },
        ternary: {
            aaxis: makeAxis('Fe', 0),
            baxis: makeAxis('
Co', 45),
            caxis: makeAxis('
V', -45),
            sum: 100, domain: {x: [0, 0.25], y: [0, 0.45]}
        },
        ternary2: {
            aaxis: makeAxis('Fe', 0),
            baxis: makeAxis('
Co', 45),
            caxis: makeAxis('
V', -45),
            sum: 100, domain: {x: [0.375, 0.625], y: [0, 0.45]}
        },
        ternary3: {
            aaxis: makeAxis('Fe', 0),
            baxis: makeAxis('
Co', 45),
            caxis: makeAxis('
V', -45),
            sum: 100, domain: {x: [0.75, 1], y: [0, 0.45]}
        },
        showlegend: false,
    };

    var graph_columns = [
        ['V', 'thickness', 'Hc|MOKE'],
        ['V', 'thickness', 'Hc|VSM'],
        ['Fe', 'Co', 'V', 'BH|max'],
        ['Fe', 'Co', 'V', 'Hc|MOKE'],
        ['Fe', 'Co', 'V', 'Hc|VSM']
    ];
    var colorbars = [[0.45, 0.8], [1, 0.8], [0.25, 0.3], [0.625, 0.3], [1, 0.3]]

    var gets = $.map(graph_columns, function(columns) {
        return $.get({
            url: api_url, data: {'columns': columns.join(',')},
            headers: window.api['headers']
        });
    })

    $.when.apply($, gets).done(function() {
        var data = [];
        $.each(arguments, function(index, response) {
            var r = response[0]['data'];
            if (index < 2) {
                data.push({
                    name: graph_columns[index][2],
                    x: r[0]['y'], // V
                    y: r[1]['y'], // thickness
                    xaxis: 'x'+(index+1), yaxis: 'y'+(index+1),
                    text: r[2]['text'], // cid
                    mode: 'markers', type: 'scatter', showlegend: false,
                    marker: {
                        size: 16, colorscale: 'Jet', showscale: true,
                        color: r[2]['y'],  // Hc|MOKE and Hc|VSM
                        colorbar: {
                            title: graph_columns[index][2],
                            xanchor: "left", len: 0.4,
                            x: colorbars[index][0], y: colorbars[index][1]
                        }
                    }
                });
            } else {
                data.push({
                    type: 'scatterternary', mode: 'markers',
                    a: r[0]['y'], b: r[1]['y'], c: r[2]['y'],
                    name: graph_columns[index][3],
                    subplot: 'ternary'+(index-1),
                    text: r[0]['text'], // cid
                    marker: {
                        symbol: 0, showscale: true, colorscale: 'Jet', size: 12,
                        color: r[3]['y'], colorbar: {
                            title: graph_columns[index][3],
                            xanchor: "left", len: 0.35,
                            x: colorbars[index][0], y: colorbars[index][1]
                        }
                    }
                });
            }
        });
        Plotly.plot(graph, data, layout, {displayModeBar: true, responsive: true});
        graph.on('plotly_click', function(d){
            var cid = d.points[0].text;
            var url = '/' + cid;
            window.open(url, '_blank');
        });
        spinner_plot.stop();
    });
});
<commit_msg>save work on swf<commit_after>import Plotly from 'plotly'; // plotly core only
import {Spinner} from 'spin.js';

Plotly.register([
    require('../../../../../../node_modules/plotly.js/lib/scatterternary')
]);

function makeAxis(title, tickangle) {
    return {
        title: title, titlefont: { size: 20 },
        tickangle: tickangle, tickfont: { size: 15 },
        tickcolor: 'rgba(0,0,0,0)', ticklen: 5,
        showline: true, showgrid: true
    }
};

$(document).ready(function () {
    var graph = document.getElementById('graph_custom');
    var target = document.getElementById('spinner_graph_custom');
    var spinner_plot = new Spinner({scale: 0.5});
    spinner_plot.spin(target);

    var layout = {
        hovermode: 'closest', height: 900,
        title: 'In-plane Coercive Field Maps',
        xaxis1: {
            title: 'Percent V [at%]',
            domain: [0, 0.45], anchor: 'y1'
        },
        yaxis1: {
            title: 'Film Thickness [nm]',
            domain: [0.6, 1], anchor: 'x1'
        },
        xaxis2: {
            title: 'Percent V [at%]',
            domain: [0.55, 1], anchor: 'y2'
        },
        yaxis2: { domain: [0.6, 1], anchor: 'x2' },
        ternary: {
            aaxis: makeAxis('Fe', 0),
            baxis: makeAxis('
Co', 45),
            caxis: makeAxis('
V', -45),
            sum: 100, domain: {x: [0, 0.25], y: [0, 0.45]}
        },
        ternary2: {
            aaxis: makeAxis('Fe', 0),
            baxis: makeAxis('
Co', 45),
            caxis: makeAxis('
V', -45),
            sum: 100, domain: {x: [0.375, 0.625], y: [0, 0.45]}
        },
        ternary3: {
            aaxis: makeAxis('Fe', 0),
            baxis: makeAxis('
Co', 45),
            caxis: makeAxis('
V', -45),
            sum: 100, domain: {x: [0.75, 1], y: [0, 0.45]}
        },
        showlegend: false,
    };

    var graph_columns = [
        ['V', 'thickness', 'Hc|MOKE'],
        ['V', 'thickness', 'Hc|VSM'],
        ['Fe', 'Co', 'V', 'BH|max'],
        ['Fe', 'Co', 'V', 'Hc|MOKE'],
        ['Fe', 'Co', 'V', 'Hc|VSM']
    ];
    var colorbars = [[0.45, 0.8], [1, 0.8], [0.25, 0.3], [0.625, 0.3], [1, 0.3]]

    var fields = ['identifier', 'id'].concat(
        $.map(['Fe', 'Co', 'V', 'thickness', 'Hc|MOKE', 'Hc|VSM', 'BH|max'], function(col) {
            return 'data.' + col + '.value';
        })
    );
    var gets = [
        $.get({
            url: window.api['host'] + 'contributions/', headers: window.api['headers'], data: {
                '_fields': fields.join(','), 'project': project
            }
        })
    ];

    $.when.apply($, gets).done(function() {
        var data = [];
        $.each(arguments, function(index, response) {
            var r = response[0]['data'];
            if (index < 2) {
                data.push({
                    name: graph_columns[index][2],
                    x: r[0]['y'], // V
                    y: r[1]['y'], // thickness
                    xaxis: 'x'+(index+1), yaxis: 'y'+(index+1),
                    text: r[2]['text'], // cid
                    mode: 'markers', type: 'scatter', showlegend: false,
                    marker: {
                        size: 16, colorscale: 'Jet', showscale: true,
                        color: r[2]['y'],  // Hc|MOKE and Hc|VSM
                        colorbar: {
                            title: graph_columns[index][2],
                            xanchor: "left", len: 0.4,
                            x: colorbars[index][0], y: colorbars[index][1]
                        }
                    }
                });
            } else {
                data.push({
                    type: 'scatterternary', mode: 'markers',
                    a: r[0]['y'], b: r[1]['y'], c: r[2]['y'],
                    name: graph_columns[index][3],
                    subplot: 'ternary'+(index-1),
                    text: r[0]['text'], // cid
                    marker: {
                        symbol: 0, showscale: true, colorscale: 'Jet', size: 12,
                        color: r[3]['y'], colorbar: {
                            title: graph_columns[index][3],
                            xanchor: "left", len: 0.35,
                            x: colorbars[index][0], y: colorbars[index][1]
                        }
                    }
                });
            }
        });
        Plotly.plot(graph, data, layout, {displayModeBar: true, responsive: true});
        graph.on('plotly_click', function(d){
            var cid = d.points[0].text;
            var url = '/' + cid;
            window.open(url, '_blank');
        });
        spinner_plot.stop();
    });
});
<|endoftext|>


<commit_before>function draw(x_mean, y_mean, scale) {
    var canvas = document.getElementById('fractale');
	if (canvas.getContext) {
        canvas.width = 200;
        canvas.height = 200;
        drawDetaille(x_mean, y_mean, scale, 1000);
    }
}

function drawPrecise(x_mean, y_mean, scale) {
    var canvas = document.getElementById('fractale');
	if (canvas.getContext) {
        canvas.width = parseInt(document.getElementById("width").value);
        canvas.height = parseInt(document.getElementById("height").value);
        nbMaxIter = parseInt(document.getElementById("max").value);
        drawDetaille(x_mean, y_mean, scale, nbMaxIter);
    }
}

function drawDetaille(x_mean, y_mean, scale, max){
	var canvas = document.getElementById('fractale');
	if (canvas.getContext){
		var ctx = canvas.getContext('2d');
		var width = canvas.width;
		var height = canvas.height;

		var id = ctx.createImageData(1,1); // only do this once per page
		var d  = id.data;       			// only do this once per page
		d[0]   = 0;//r
		d[1]   = 0;//g
		d[2]   = 0;//b
		d[3]   = 255;//a: transparency, 0..255

		 // = -0.77568377;
		 // = 0.13646737;
		 // = 0.01;

		var h_min = 1, h_max = 0, b_min = 1, b_max = 0, iteration_min = max, iteration_max = 0;

		for (var col = 0; col < width; col+=15) {
			for (var row = 0; row < height; row+=15) {
				var c_re = (scale/2.0)*(col - width/2.0)*4.0/width + x_mean;
				var c_im = (scale/2.0)*(row - height/2.0)*4.0/width + y_mean;
				var x = 0, y = 0;
				var iteration = 0;
				while (x*x+y*y <= 4 && iteration < max) {
					var x_new = x*x - y*y + c_re;
					y = 2*x*y + c_im;
					x = x_new;
					iteration++;
				}
				if (iteration < max) {
					iteration_min = Math.min(iteration, iteration_min);
					iteration_max = Math.max(iteration, iteration_max);
					var h = iteration/max;
					h_min = Math.min(h, h_min);
					h_max = Math.max(h, h_max);
					var b = iteration/(iteration+8);
					b_min = Math.min(b, b_min);
					b_max = Math.max(b, b_max);
				}
				//console.log(iteration);
			}
		}

		for (var row = 0; row < height; row++) {
			for (var col = 0; col < width; col++) {
				var c_re = (scale/2.0)*(col - width/2.0)*4.0/width + x_mean;
				var c_im = (scale/2.0)*(-row + height/2.0)*4.0/width + y_mean;
				var x = 0, y = 0;
				var iteration = 0;
				while (x*x+y*y <= 4 && iteration < max) {
					var x_new = x*x - y*y + c_re;
					y = 2*x*y + c_im;
					x = x_new;
					iteration++;
				}
				if (iteration < max) {
					var h0 = iteration/max;
					var h = (h0-(h_max+h_min)/2)/(h_max-h_min)+1/2;
					var s   = 1;
					var b0 = iteration/(iteration+8);
					var b  = (b0-(b_max+b_min)/2)*0.8/(b_max-b_min)+1.2/2;
					var hsbToRgb = HSVtoRGB(h, s, b);
					d[0] = hsbToRgb.r;//r
					d[1] = hsbToRgb.g;//g
					d[2] = hsbToRgb.b;//b
				}
				else {
					d[0]   = 0;//r
					d[1]   = 0;//g
					d[2]   = 0;//b
				}

				ctx.putImageData(id, col, row);
				//console.log(iteration);
			}
		}
		ajoutLegende(ctx, width, height, x_mean, y_mean, scale, max);
	}

	return [h_min, h_max, b_min, b_max, iteration_min, iteration_max];
}

function ajoutLegende(ctx, width, height, x_mean, y_mean, scale, max) {
    if (document.getElementById("ajouterLegende").checked) {
        ctx.font = Math.floor(width / 30) + "px Georgia";
        ctx.textAlign = "right";
        ctx.fillStyle = "white";
        ctx.fillText("max_iterations : " + max, width * 29 / 30, height * 24 / 28);
        ctx.fillText("scale : " + scale.toPrecision(3), width * 29 / 30, height * 25 / 28);
        ctx.fillText("x_mean : " + x_mean.toPrecision(3), width * 29 / 30, height * 26 / 28);
        ctx.fillText("y_mean : " + y_mean.toPrecision(3), width * 29 / 30, height * 27 / 28);
    }
}

function HSVtoRGB(h, s, v) {
	var r, g, b, i, f, p, q, t;
	if (arguments.length === 1) {
		s = h.s, v = h.v, h = h.h;
	}
	i = Math.floor(h * 6);
	f = h * 6 - i;
	p = v * (1 - s);
	q = v * (1 - f * s);
	t = v * (1 - (1 - f) * s);
	switch (i % 6) {
		case 0: r = v, g = t, b = p; break;
		case 1: r = q, g = v, b = p; break;
		case 2: r = p, g = v, b = t; break;
		case 3: r = p, g = q, b = v; break;
		case 4: r = t, g = p, b = v; break;
		case 5: r = v, g = p, b = q; break;
	}
	return {
		r: Math.round(r * 255),
		g: Math.round(g * 255),
		b: Math.round(b * 255)
	};
}<commit_msg>refactoring fonction de calcul nb d'itérations<commit_after>function draw(x_mean, y_mean, scale) {
    var canvas = document.getElementById('fractale');
	if (canvas.getContext) {
        canvas.width = 200;
        canvas.height = 200;
        drawDetaille(x_mean, y_mean, scale, 1000);
    }
}

function drawPrecise(x_mean, y_mean, scale) {
    var canvas = document.getElementById('fractale');
	if (canvas.getContext) {
        canvas.width = parseInt(document.getElementById("width").value);
        canvas.height = parseInt(document.getElementById("height").value);
        nbMaxIter = parseInt(document.getElementById("max").value);
        drawDetaille(x_mean, y_mean, scale, nbMaxIter);
    }
}

function drawDetaille(x_mean, y_mean, scale, max){
	var canvas = document.getElementById('fractale');
	if (canvas.getContext){
		var ctx = canvas.getContext('2d');
		var width = canvas.width;
		var height = canvas.height;

		var id = ctx.createImageData(1,1); // only do this once per page
		var d  = id.data;       			// only do this once per page
		d[0]   = 0;//r
		d[1]   = 0;//g
		d[2]   = 0;//b
		d[3]   = 255;//a: transparency, 0..255

		 // = -0.77568377;
		 // = 0.13646737;
		 // = 0.01;

		var h_min = 1, h_max = 0, b_min = 1, b_max = 0, iteration_min = max, iteration_max = 0;

		for (var col = 0; col < width; col+=15) {
			for (var row = 0; row < height; row+=15) {
				var iteration = itereZ(col, row, scale, x_mean, y_mean, width, height, max);
				if (iteration < max) {
					iteration_min = Math.min(iteration, iteration_min);
					iteration_max = Math.max(iteration, iteration_max);
					var h = iteration/max;
					h_min = Math.min(h, h_min);
					h_max = Math.max(h, h_max);
					var b = iteration/(iteration+8);
					b_min = Math.min(b, b_min);
					b_max = Math.max(b, b_max);
				}
				//console.log(iteration);
			}
		}

		for (var row = 0; row < height; row++) {
			for (var col = 0; col < width; col++) {
				var iteration = itereZ(col, row, scale, x_mean, y_mean, width, height, max);
				if (iteration < max) {
					var h0 = iteration/max;
					var h = (h0-(h_max+h_min)/2)/(h_max-h_min)+1/2;
					var s   = 1;
					var b0 = iteration/(iteration+8);
                    //ici, on cherche à eviter d'avoir une brillance trop faible
                    var b  = (b0-(b_max+b_min)/2)*0.8/(b_max-b_min)+1.2/2;
					var hsbToRgb = HSVtoRGB(h, s, b);
					d[0] = hsbToRgb.r;//r
					d[1] = hsbToRgb.g;//g
					d[2] = hsbToRgb.b;//b
				}
				else {
					d[0]   = 0;//r
					d[1]   = 0;//g
					d[2]   = 0;//b
				}

				ctx.putImageData(id, col, row);
				//console.log(iteration);
			}
		}
		ajoutLegende(ctx, width, height, x_mean, y_mean, scale, max);
	}

	return [h_min, h_max, b_min, b_max, iteration_min, iteration_max];
}

function itereZ(col, row, scale, x_mean, y_mean, width, height, max) {
    var c_re = (scale/2.0)*(col - width/2.0)*4.0/width + x_mean;
    var c_im = (scale/2.0)*(height/2.0 - row)*4.0/width + y_mean;
    var x = 0, y = 0;
    var iteration = 0;
    while (x*x+y*y <= 4 && iteration < max) {
        var x_new = x*x - y*y + c_re;
        y = 2*x*y + c_im;
        x = x_new;
        iteration++;
    }
    return iteration;
}

function ajoutLegende(ctx, width, height, x_mean, y_mean, scale, max) {
    if (document.getElementById("ajouterLegende").checked) {
        ctx.font = Math.floor(width / 30) + "px Georgia";
        ctx.textAlign = "right";
        ctx.fillStyle = "white";
        ctx.fillText("max_iterations : " + max, width * 29 / 30, height * 24 / 28);
        ctx.fillText("scale : " + scale.toPrecision(3), width * 29 / 30, height * 25 / 28);
        ctx.fillText("x_mean : " + x_mean.toPrecision(3), width * 29 / 30, height * 26 / 28);
        ctx.fillText("y_mean : " + y_mean.toPrecision(3), width * 29 / 30, height * 27 / 28);
    }
}

function HSVtoRGB(h, s, v) {
	var r, g, b, i, f, p, q, t;
	if (arguments.length === 1) {
		s = h.s, v = h.v, h = h.h;
	}
	i = Math.floor(h * 6);
	f = h * 6 - i;
	p = v * (1 - s);
	q = v * (1 - f * s);
	t = v * (1 - (1 - f) * s);
	switch (i % 6) {
		case 0: r = v, g = t, b = p; break;
		case 1: r = q, g = v, b = p; break;
		case 2: r = p, g = v, b = t; break;
		case 3: r = p, g = q, b = v; break;
		case 4: r = t, g = p, b = v; break;
		case 5: r = v, g = p, b = q; break;
	}
	return {
		r: Math.round(r * 255),
		g: Math.round(g * 255),
		b: Math.round(b * 255)
	};
}<|endoftext|>


<commit_before>#!/usr/bin/env node

var jotto = require('../');
var chalk = require('chalk');
var fs = require('graceful-fs');
var humanize = require('humanize-number');
var filter = require('lodash.filter');
var keys = require('lodash.keys');
var minimist = require('minimist');
var noRepeatedLetters = require('no-repeated-letters');
var printf = require('printf');
var sowpodsFive = require('sowpods-five');
var sowpodsSix = require('sowpods-six');

var argv = minimist(process.argv.slice(2), {
  alias: {
    h: 'help',
    v: 'version'
  }
});

if (argv.version) {
  process.stdout.write(require('../package.json').version);
  process.stdout.write('\n');
  return;
}
else if (argv.help) {
  fs.createReadStream(__dirname + '/usage.txt').pipe(process.stdout);
  return;
}

var previousGuesses = {};

if (!process.stdin.isTTY) {
  var temp = '';

  process.stdin.on('data', function(chunk) {
    temp += chunk;
  });

  process.stdin.on('end', function() {
    previousGuesses = JSON.parse(temp);
    next();
  });
}
else {
  next();
}

function next() {
  var words = sowpodsFive;
  var guesses = keys(previousGuesses);
  if (guesses && guesses[0]) {
    words = guesses[0].length === 6 ? sowpodsSix : sowpodsFive;
  }

  console.log();
  console.log(printf('%22s : %6s words', chalk.cyan('Imported'), humanize(words.length)));

  words = filter(words, noRepeatedLetters);
  console.log(printf('%22s : %6s words', chalk.cyan('Using'), humanize(words.length)));

  var possibleWords = jotto.narrowDownPossibleWords(words, previousGuesses);
  console.log(printf('%22s : %6s words', chalk.cyan('Possible'), humanize(possibleWords.length)));

  var guess = jotto.bestGuess(words, possibleWords);
  console.log(printf('%22s : %6s', chalk.cyan('Best guess'), chalk.bold.green(guess)));

  if (possibleWords.length < 6 && possibleWords.length > 1) {
    console.log(printf('%22s : %s', chalk.cyan('Words'), possibleWords.join(', ')));
  }
}
<commit_msg>bin: use `process.exit` instead of `return`<commit_after>#!/usr/bin/env node

var jotto = require('../');
var chalk = require('chalk');
var fs = require('graceful-fs');
var humanize = require('humanize-number');
var filter = require('lodash.filter');
var keys = require('lodash.keys');
var minimist = require('minimist');
var noRepeatedLetters = require('no-repeated-letters');
var printf = require('printf');
var process = require('process');
var sowpodsFive = require('sowpods-five');
var sowpodsSix = require('sowpods-six');

var argv = minimist(process.argv.slice(2), {
  alias: {
    h: 'help',
    v: 'version'
  }
});

if (argv.version) {
  process.stdout.write(require('../package.json').version);
  process.stdout.write('\n');
  process.exit(0);
}
else if (argv.help) {
  fs.createReadStream(__dirname + '/usage.txt').pipe(process.stdout);
  process.exit(0);
}

var previousGuesses = {};

if (!process.stdin.isTTY) {
  var temp = '';

  process.stdin.on('data', function(chunk) {
    temp += chunk;
  });

  process.stdin.on('end', function() {
    previousGuesses = JSON.parse(temp);
    next();
  });
}
else {
  next();
}

function next() {
  var words = sowpodsFive;
  var guesses = keys(previousGuesses);
  if (guesses && guesses[0]) {
    words = guesses[0].length === 6 ? sowpodsSix : sowpodsFive;
  }

  console.log();
  console.log(printf('%22s : %6s words', chalk.cyan('Imported'), humanize(words.length)));

  words = filter(words, noRepeatedLetters);
  console.log(printf('%22s : %6s words', chalk.cyan('Using'), humanize(words.length)));

  var possibleWords = jotto.narrowDownPossibleWords(words, previousGuesses);
  console.log(printf('%22s : %6s words', chalk.cyan('Possible'), humanize(possibleWords.length)));

  var guess = jotto.bestGuess(words, possibleWords);
  console.log(printf('%22s : %6s', chalk.cyan('Best guess'), chalk.bold.green(guess)));

  if (possibleWords.length < 6 && possibleWords.length > 1) {
    console.log(printf('%22s : %s', chalk.cyan('Words'), possibleWords.join(', ')));
  }
}
<|endoftext|>


<commit_before>/*
 *  SonosBridge.js
 *
 *  David Janes
 *  IOTDB.org
 *  2015-04-03
 *
 *  Copyright [2013-2015] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict";

var iotdb = require('iotdb');
var _ = iotdb._;
var bunyan = iotdb.bunyan;

var sonos = require('sonos');

var logger = bunyan.createLogger({
    name: 'homestar-sonos',
    module: 'SonosBridge',
});

var mode_play = _.ld.expand("iot-attribute:media.mode.play");
var mode_pause = _.ld.expand("iot-attribute:media.mode.pause");
var mode_stop = _.ld.expand("iot-attribute:media.mode.stop");

/**
 *  EXEMPLAR and INSTANCE
 *

 *  No subclassing needed! The following functions are
 *  injected _after_ this is created, and before .discover and .connect
 *

 *
discovered - tell IOTDB that we're talking to a new Thing
 *
pulled - got new data
 *
connected - this is connected to a Thing
 *
disconnnected - this has been disconnected from a Thing
 *

 */
var SonosBridge = function (initd, native) {
    var self = this;

    self.initd = _.defaults(initd,
        iotdb.keystore().get("bridges/SonosBridge/initd"), {
            poll: 30
        }
    );
    self.native = native;

    if (self.native) {
        self.native.uuid = "00000000-0000-0000-0000-000000000000";
        self.queue = _.queue("SonosBridge");
        self.stated = {};
    }
};

SonosBridge.prototype = new iotdb.Bridge();

SonosBridge.prototype.name = function () {
    return "SonosBridge";
};

/* --- lifecycle --- */

/**
 *  EXEMPLAR.
 *  Discover Hue
 *

 *
look for Things (using self.bridge data to initialize)
 *
find / create a native that does the talking
 *
create an SonosBridge(native)
 *
call self.discovered(bridge) with it
 */
SonosBridge.prototype.discover = function () {
    var self = this;

    logger.info({
        method: "discover"
    }, "called");

    sonos.search(function (native) {
        self.discovered(new SonosBridge(self.initd, native));
    });
};

/**
 *  INSTANCE
 *  This is called when the Bridge is no longer needed. When
 */
SonosBridge.prototype.connect = function (connectd) {
    var self = this;
    if (!self.native) {
        return;
    }

    self._setup_polling();
    self.pull();
};

SonosBridge.prototype._setup_polling = function () {
    var self = this;
    if (!self.initd.poll) {
        return;
    }

    var timer = setInterval(function () {
        if (!self.native) {
            clearInterval(timer);
            return;
        }

        self.pull();
    }, self.initd.poll * 1000);
};

SonosBridge.prototype._forget = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    logger.info({
        method: "_forget"
    }, "called");

    self.native = null;
    self.pulled();
};

/**
 *  INSTANCE and EXEMPLAR (during shutdown).
 *  This is called when the Bridge is no longer needed.
 */
SonosBridge.prototype.disconnect = function () {
    var self = this;
    if (!self.native || !self.native) {
        return;
    }

    self._forget();
};

/* --- data --- */

/**
 *  INSTANCE.
 *  Send data to whatever you're taking to.
 */
SonosBridge.prototype.push = function (pushd) {
    var self = this;
    if (!self.native) {
        return;
    }

    logger.info({
        method: "push",
        pushd: pushd,
    }, "push");

    if (pushd.mute !== undefined) {
        self._push_mute(pushd.mute);
    }

    if (pushd.volume !== undefined) {
        self._push_volume(pushd.volume);
    }

    if (pushd.next) {
        self._push_next();
    }

    if (pushd.previous) {
        self._push_previous();
    }

    if (pushd.mode === mode_play) {
        self._push_mode_play();
    } else if (pushd.mode === mode_pause) {
        self._push_mode_pause();
    } else if (pushd.mode === mode_stop) {
        self._push_mode_stop();
    }
};

SonosBridge.prototype._push_volume = function (volume) {
    var self = this;

    self.queue.add({
        id: "_push_volume",
        run: function (queue, qitem) {
            self.native.setVolume(volume, function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_volume/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        volume: volume,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mute = function (mute) {
    var self = this;

    self.queue.add({
        id: "_push_mute",
        run: function (queue, qitem) {
            self.native.setMuted(mute, function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mute/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mute: mute,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mode_play = function () {
    var self = this;

    self.queue.add({
        id: "_push_mode",
        run: function (queue, qitem) {
            self.native.play(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mode_play/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mode: mode_play,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mode_pause = function () {
    var self = this;

    self.queue.add({
        id: "_push_mode",
        run: function (queue, qitem) {
            self.native.pause(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mode_pause/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mode: mode_pause,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mode_stop = function () {
    var self = this;

    self.queue.add({
        id: "_push_mode",
        run: function (queue, qitem) {
            self.native.stop(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mode_stop/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mode: mode_stop,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_next = function () {
    var self = this;

    self.queue.add({
        id: "push-next",
        run: function (queue, qitem) {
            self.native.next(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_next/callback",
                        error: error,
                    }, "Sonos error");
                }
            });
        }
    });
};

SonosBridge.prototype._push_previous = function () {
    var self = this;

    self.queue.add({
        id: "push-previous",
        run: function (queue, qitem) {
            self.native.previous(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_previous/callback",
                        error: error,
                    }, "Sonos error");
                }
            });
        }
    });
};

/**
 *  INSTANCE.
 *  Pull data from whatever we're talking to. You don't
 *  have to implement this if it doesn't make sense
 */
SonosBridge.prototype.pull = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    self._pull_volume();
    self._pull_mute();
    self._pull_state();
};

SonosBridge.prototype._pull_volume = function () {
    var self = this;

    self.queue.add({
        id: "_pull_volume",
        run: function (queue, qitem) {
            self.native.getVolume(function (error, volume) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_pull_volume/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        volume: volume,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._pull_mute = function () {
    var self = this;

    self.queue.add({
        id: "_pull_mute",
        run: function (queue, qitem) {
            self.native.getMuted(function (error, mute) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_pull_mute/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mute: mute,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._pull_state = function () {
    var self = this;

    self.queue.add({
        id: "_pull_state",
        run: function (queue, qitem) {
            self.native.getCurrentState(function (error, state) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_pull_state/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    logger.debug({
                        method: "_pull_state/callback",
                        error: error,
                        state: state,
                    }, "XXX - have the state but don't know what to do with it just yet");
                }
            });
        }
    });
};

/* --- state --- */

/**
 *  INSTANCE.
 *  Return the metadata - compact form can be used.
 *  Does not have to work when not reachable
 *

 *  Really really useful things are:
 *

 *
iot:thing required - a unique ID
 *
iot:device suggested if linking multiple things together
 *
schema:name
 *
schema:manufacturer
 *
schema:model
 */
SonosBridge.prototype.meta = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    return {
        "iot:thing": _.id.thing_urn.unique("Sonos", self.native.uuid),
        "schema:name": self.native.name || "Sonos",
        "schema:manufacturer": "http://www.sonos.com/",
    };
};

/**
 *  INSTANCE.
 *  Return True if this is reachable. You
 *  do not need to worry about connect / disconnect /
 *  shutdown states, they will be always checked first.
 */
SonosBridge.prototype.reachable = function () {
    return this.native !== null;
};

/**
 *  INSTANCE.
 *  Configure an express web page to configure this Bridge.
 *  Return the name of the Bridge, which may be
 *  listed and displayed to the user.
 */
SonosBridge.prototype.configure = function (app) {};

/* --- injected: THIS CODE WILL BE REMOVED AT RUNTIME, DO NOT MODIFY  --- */
SonosBridge.prototype.discovered = function (bridge) {
    throw new Error("SonosBridge.discovered not implemented");
};

SonosBridge.prototype.pulled = function (pulld) {
    throw new Error("SonosBridge.pulled not implemented");
};

/*
 *  API
 */
exports.Bridge = SonosBridge;
<commit_msg>remove old documentation dups<commit_after>/*
 *  SonosBridge.js
 *
 *  David Janes
 *  IOTDB.org
 *  2015-04-03
 *
 *  Copyright [2013-2015] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict";

var iotdb = require('iotdb');
var _ = iotdb._;
var bunyan = iotdb.bunyan;

var sonos = require('sonos');

var logger = bunyan.createLogger({
    name: 'homestar-sonos',
    module: 'SonosBridge',
});

var mode_play = _.ld.expand("iot-attribute:media.mode.play");
var mode_pause = _.ld.expand("iot-attribute:media.mode.pause");
var mode_stop = _.ld.expand("iot-attribute:media.mode.stop");

/**
 *  See {iotdb.bridge.Bridge#Bridge} for documentation.
 *

 *  @param {object|undefined} native
 *  only used for instances, should be
 */
var SonosBridge = function (initd, native) {
    var self = this;

    self.initd = _.defaults(initd,
        iotdb.keystore().get("bridges/SonosBridge/initd"), {
            poll: 30
        }
    );
    self.native = native;

    if (self.native) {
        self.native.uuid = "00000000-0000-0000-0000-000000000000";
        self.queue = _.queue("SonosBridge");
        self.stated = {};
    }
};

SonosBridge.prototype = new iotdb.Bridge();

SonosBridge.prototype.name = function () {
    return "SonosBridge";
};

/* --- lifecycle --- */

/**
 *  See {iotdb.bridge.Bridge#XXX} for documentation.
 */
SonosBridge.prototype.discover = function () {
    var self = this;

    logger.info({
        method: "discover"
    }, "called");

    sonos.search(function (native) {
        self.discovered(new SonosBridge(self.initd, native));
    });
};

/**
 *  See {iotdb.bridge.Bridge#XXX} for documentation.
 */
SonosBridge.prototype.connect = function (connectd) {
    var self = this;
    if (!self.native) {
        return;
    }

    self._setup_polling();
    self.pull();
};

SonosBridge.prototype._setup_polling = function () {
    var self = this;
    if (!self.initd.poll) {
        return;
    }

    var timer = setInterval(function () {
        if (!self.native) {
            clearInterval(timer);
            return;
        }

        self.pull();
    }, self.initd.poll * 1000);
};

SonosBridge.prototype._forget = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    logger.info({
        method: "_forget"
    }, "called");

    self.native = null;
    self.pulled();
};

/**
 *  See {iotdb.bridge.Bridge#XXX} for documentation.
 */
SonosBridge.prototype.disconnect = function () {
    var self = this;
    if (!self.native || !self.native) {
        return;
    }

    self._forget();
};

/* --- data --- */

/**
 *  See {iotdb.bridge.Bridge#XXX} for documentation.
 */
SonosBridge.prototype.push = function (pushd) {
    var self = this;
    if (!self.native) {
        return;
    }

    logger.info({
        method: "push",
        pushd: pushd,
    }, "push");

    if (pushd.mute !== undefined) {
        self._push_mute(pushd.mute);
    }

    if (pushd.volume !== undefined) {
        self._push_volume(pushd.volume);
    }

    if (pushd.next) {
        self._push_next();
    }

    if (pushd.previous) {
        self._push_previous();
    }

    if (pushd.mode === mode_play) {
        self._push_mode_play();
    } else if (pushd.mode === mode_pause) {
        self._push_mode_pause();
    } else if (pushd.mode === mode_stop) {
        self._push_mode_stop();
    }
};

SonosBridge.prototype._push_volume = function (volume) {
    var self = this;

    self.queue.add({
        id: "_push_volume",
        run: function (queue, qitem) {
            self.native.setVolume(volume, function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_volume/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        volume: volume,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mute = function (mute) {
    var self = this;

    self.queue.add({
        id: "_push_mute",
        run: function (queue, qitem) {
            self.native.setMuted(mute, function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mute/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mute: mute,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mode_play = function () {
    var self = this;

    self.queue.add({
        id: "_push_mode",
        run: function (queue, qitem) {
            self.native.play(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mode_play/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mode: mode_play,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mode_pause = function () {
    var self = this;

    self.queue.add({
        id: "_push_mode",
        run: function (queue, qitem) {
            self.native.pause(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mode_pause/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mode: mode_pause,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_mode_stop = function () {
    var self = this;

    self.queue.add({
        id: "_push_mode",
        run: function (queue, qitem) {
            self.native.stop(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_mode_stop/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mode: mode_stop,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._push_next = function () {
    var self = this;

    self.queue.add({
        id: "push-next",
        run: function (queue, qitem) {
            self.native.next(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_next/callback",
                        error: error,
                    }, "Sonos error");
                }
            });
        }
    });
};

SonosBridge.prototype._push_previous = function () {
    var self = this;

    self.queue.add({
        id: "push-previous",
        run: function (queue, qitem) {
            self.native.previous(function (error, data) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_push_previous/callback",
                        error: error,
                    }, "Sonos error");
                }
            });
        }
    });
};

/**
 *  See {iotdb.bridge.Bridge#XXX} for documentation.
 */
SonosBridge.prototype.pull = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    self._pull_volume();
    self._pull_mute();
    self._pull_state();
};

SonosBridge.prototype._pull_volume = function () {
    var self = this;

    self.queue.add({
        id: "_pull_volume",
        run: function (queue, qitem) {
            self.native.getVolume(function (error, volume) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_pull_volume/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        volume: volume,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._pull_mute = function () {
    var self = this;

    self.queue.add({
        id: "_pull_mute",
        run: function (queue, qitem) {
            self.native.getMuted(function (error, mute) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_pull_mute/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    self.pulled({
                        mute: mute,
                    });
                }
            });
        }
    });
};

SonosBridge.prototype._pull_state = function () {
    var self = this;

    self.queue.add({
        id: "_pull_state",
        run: function (queue, qitem) {
            self.native.getCurrentState(function (error, state) {
                self.queue.finished(qitem);

                if (error) {
                    logger.error({
                        method: "_pull_state/callback",
                        error: error,
                    }, "Sonos error");
                } else {
                    logger.debug({
                        method: "_pull_state/callback",
                        error: error,
                        state: state,
                    }, "XXX - have the state but don't know what to do with it just yet");
                }
            });
        }
    });
};

/* --- state --- */

/**
 *  See {iotdb.bridge.Bridge#XXX} for documentation.
 */
SonosBridge.prototype.meta = function () {
    var self = this;
    if (!self.native) {
        return;
    }

    return {
        "iot:thing": _.id.thing_urn.unique("Sonos", self.native.uuid),
        "schema:name": self.native.name || "Sonos",
        "schema:manufacturer": "http://www.sonos.com/",
    };
};

/**
 *  See {iotdb.bridge.Bridge#XXX} for documentation.
 */
SonosBridge.prototype.reachable = function () {
    return this.native !== null;
};

/**
 *  See {iotdb.bridge.Bridge#XXX} for documentation.
 */
SonosBridge.prototype.configure = function (app) {};

/* --- injected: THIS CODE WILL BE REMOVED AT RUNTIME, DO NOT MODIFY  --- */
SonosBridge.prototype.discovered = function (bridge) {
    throw new Error("SonosBridge.discovered not implemented");
};

SonosBridge.prototype.pulled = function (pulld) {
    throw new Error("SonosBridge.pulled not implemented");
};

/*
 *  API
 */
exports.Bridge = SonosBridge;
<|endoftext|>


<commit_before>import { Model } from 'objection'

export function mergeSchemas(...schemas) {
  return schemas.reduce(
    (mergedSchema, schema) => ({
      ...mergedSchema,
      ...schema,
      required: [...mergedSchema.required, ...schema.required],
      properties: {
        ...mergedSchema.properties,
        ...schema.properties,
      },
    }),
    {
      required: [],
      properties: {},
    },
  )
}

export default class BaseModel extends Model {
  // Uses http://json-schema.org/latest/json-schema-validation.html
  static jsonSchema = {
    type: 'object',
    required: [],
    properties: {
      id: {
        type: ['integer', 'string'],
      },
      createdAt: {
        type: 'string',
      },
      updatedAt: {
        type: 'string',
      },
    },
  }

  // Centralize the models.
  static modelPaths = [__dirname]

  // http://vincit.github.io/objection.js/#defaulteageralgorithm
  static defaultEagerAlgorithm = Model.JoinEagerAlgorithm

  $beforeInsert() {
    if (!this.createdAt) {
      this.createdAt = new Date().toISOString()
    }

    this.updatedAt = new Date().toISOString()
  }

  $beforeUpdate() {
    this.updatedAt = new Date().toISOString()
  }

  async reload() {
    const model = await this.$query()
    Object.assign(this, model)
    return this
  }
}
<commit_msg>fix: switch default eager algo to WhereIn<commit_after>import { Model } from 'objection'

export function mergeSchemas(...schemas) {
  return schemas.reduce(
    (mergedSchema, schema) => ({
      ...mergedSchema,
      ...schema,
      required: [...mergedSchema.required, ...schema.required],
      properties: {
        ...mergedSchema.properties,
        ...schema.properties,
      },
    }),
    {
      required: [],
      properties: {},
    },
  )
}

export default class BaseModel extends Model {
  // Uses http://json-schema.org/latest/json-schema-validation.html
  static jsonSchema = {
    type: 'object',
    required: [],
    properties: {
      id: {
        type: ['integer', 'string'],
      },
      createdAt: {
        type: 'string',
      },
      updatedAt: {
        type: 'string',
      },
    },
  }

  // Centralize the models.
  static modelPaths = [__dirname]

  // https://vincit.github.io/objection.js/api/model/static-properties.html#static-defaulteageralgorithm
  static defaultEagerAlgorithm = Model.WhereInEagerAlgorithm

  $beforeInsert() {
    if (!this.createdAt) {
      this.createdAt = new Date().toISOString()
    }

    this.updatedAt = new Date().toISOString()
  }

  $beforeUpdate() {
    this.updatedAt = new Date().toISOString()
  }

  async reload() {
    const model = await this.$query()
    Object.assign(this, model)
    return this
  }
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

var clivas = require('clivas')
var cp = require('child_process')
var fs = require('fs')
var minimist = require('minimist')
var moment = require('moment')
var networkAddress = require('network-address')
var path = require('path')
var prettysize = require('prettysize')
var WebTorrent = require('../')

process.title = 'WebTorrent'

process.on('exit', function (code) {
  if (code !== 0) {
    clivas.line('{red:ERROR:} If you think this is a bug in webtorrent, report it!')
    console.log('=====>                                               <=====')
    console.log('=====>  https://github.com/feross/webtorrent/issues  <=====')
    console.log('=====>                                               <=====')
  }
})

var argv = minimist(process.argv.slice(2), {
  alias: {
    p: 'port',
    b: 'blocklist',
    t: 'subtitles',
    l: 'list',
    i: 'index',
    n: 'no-quit',
    r: 'remove',
    o: 'out',
    q: 'quiet',
    h: 'help',
    v: 'version'
  },
  boolean: [ // options that are always boolean
    'airplay',
    'chromecast',
    'mplayer',
    'mpv',
    'vlc',
    'xbmc',
    'list',
    'no-quit',
    'remove',
    'quiet',
    'help',
    'version'
  ],
  default: {
    port: 9000
  }
})

if (argv.version) {
  console.log(require('../package.json').version)
  process.exit(0)
}

var torrentId = argv._[0]

if (argv.help || !torrentId) {
  fs.readFileSync(path.join(__dirname, 'ascii-logo.txt'), 'utf8')
    .split('\n')
    .forEach(function (line) {
      clivas.line('{bold:' + line.substring(0, 20) + '}{red:' + line.substring(20) + '}')
    })

  console.log(function () {/*
  Usage:
      webtorrent <options> <torrent-uri>

      Download the torrent from:
          * magnet uri
          * http url to .torrent file
          * filesystem path to .torrent file
          * info hash (hex string)

  Streaming options:
      --airplay               Apple TV
      --chromecast            Chromecast
      --mplayer               MPlayer
      --mpv                   MPV
      --omx [jack]            omx [default: hdmi]
      --vlc                   VLC
      --xbmc                  XBMC

  Options:
      -o, --out [path]        set download destination [default: /tmp/webtorrent]
      -l, --list              list files in torrent (with indexes)
      -i, --index [index]     stream a particular file from torrent (by index)

      -p, --port [number]     change the http port [default: 9000]
      -b, --blocklist [path]  use the specified blocklist
      -t, --subtitles [file]  load subtitles file
      -n, --no-quit           do not quit webtorrent on vlc exit
      -r, --remove            remove downloaded files on exit

      -q, --quiet             print nothing to stdout
      -v, --version           print the current version

  Please report bugs!  https://github.com/feross/webtorrent/issues

    */}.toString().split(/\n/).slice(1, -1).join('\n'))
  process.exit(0)
}

if (process.env.DEBUG) {
  argv.quiet = argv.q = true
}

var VLC_ARGS = process.env.DEBUG
  ? '-q --play-and-exit'
  : '--play-and-exit --extraintf=http:logger --verbose=2 --file-logging --logfile=vlc-log.txt'
var MPLAYER_EXEC = 'mplayer -ontop -really-quiet -noidx -loop 0'
var MPV_EXEC = 'mpv --ontop --really-quiet --loop=no'
var OMX_EXEC = 'omxplayer -r -o ' + (typeof argv.omx === 'string')
  ? argv.omx
  : 'hdmi'

if (argv.subtitles) {
  VLC_ARGS += ' --sub-file=' + argv.subtitles
  MPLAYER_EXEC += ' -sub ' + argv.subtitles
  MPV_EXEC += ' --sub-file=' + argv.subtitles
  OMX_EXEC += ' --subtitles ' + argv.subtitles
}

function error (err) {
  clivas.line('{red:ERROR:} ' + (err.message || err))
}

function errorAndExit (err) {
  error(err)
  process.exit(1)
}

var started = Date.now()
function getRuntime () {
  return Math.floor((Date.now() - started) / 1000)
}

var client = new WebTorrent({
  blocklist: argv.blocklist
})
.on('error', errorAndExit)

if (argv.remove) {
  process.on('SIGINT', remove)
  process.on('SIGTERM', remove)
}

function remove (cb) {
  process.removeListener('SIGINT', remove)
  process.removeListener('SIGTERM', remove)
  client.destroy(cb)
}

var torrent = client.add(torrentId, (argv.out ? { tmp: argv.out } : {}))

torrent.on('infoHash', function () {
  function updateMetadata () {
    var numPeers = torrent.swarm.numPeers
    clivas.clear()
    clivas.line('{green:fetching torrent metadata from} {bold:'+numPeers+'} {green:peers}')
  }

  if (!argv.quiet && !argv.list) {
    torrent.swarm.on('wire', updateMetadata)
    torrent.on('metadata', function () {
      torrent.swarm.removeListener('wire', updateMetadata)
    })
    updateMetadata()
  }
})

var filename, swarm, wires, server

if (argv.list) torrent.once('ready', onReady)
else {
  server = torrent.createServer()
  server.listen(argv.port, function () {
    if (torrent.ready) onReady()
    else torrent.once('ready', onReady)
  })
}

function onReady () {
  filename = torrent.name
  swarm = torrent.swarm
  wires = torrent.swarm.wires

  // if no index specified, use largest file
  var index = (typeof argv.index === 'number')
    ? argv.index
    : torrent.files.indexOf(torrent.files.reduce(function (a, b) {
      return a.length > b.length ? a : b
    }))
  torrent.files[index].select()

  if (argv.list) {
    torrent.files.forEach(function (file, i) {
      clivas.line('{3+bold:' + i + '} : {magenta:' + file.name + '}')
    })
    process.exit(0)
  }

  torrent.on('verifying', function (data) {
    if (argv.quiet) return
    clivas.clear()
    clivas.line(
      '{green:verifying existing torrent} {bold:'+Math.floor(data.percentDone)+'%} ' +
      '({bold:'+Math.floor(data.percentVerified)+'%} {green:passed verification})'
    )
  })

  torrent.on('done', function () {
    if (!argv.quiet) {
      // TODO: expose this data from bittorrent-swarm
      var numActiveWires = torrent.swarm.wires.reduce(function (num, wire) {
        return num + (wire.downloaded > 0)
      }, 0)
      clivas.line('torrent downloaded {green:successfully} from {bold:'+numActiveWires+'/'+torrent.swarm.wires.length+'} {green:peers} in {bold:'+getRuntime()+'s}!')
    }

    if (argv.remove) {
      remove(maybeExit)
    } else {
      maybeExit()
    }

    function maybeExit () {
      if (!server) {
        process.exit(0)
      }
    }
  })

  var cmd, player
  var href = 'http://' + networkAddress() + ':' + argv.port + '/' + index
  var playerName = argv.airplay ? 'Airplay'
    : argv.chromecast ? 'Chromecast'
    : argv.xbmc ? 'XBMC'
    : argv.vlc ? 'VLC'
    : argv.mplayer ? 'MPlayer'
    : argv.mpv ? 'mpv'
    : argv.omx ? 'OMXPlayer'
    : null

  if (argv.vlc && process.platform === 'win32') {
    var registry = require('windows-no-runnable').registry
    var key
    if (process.arch === 'x64') {
      try {
        key = registry('HKLM/Software/Wow6432Node/VideoLAN/VLC')
      } catch (e) {}
    } else {
      try {
        key = registry('HKLM/Software/VideoLAN/VLC')
      } catch (err) {}
    }

    if (key) {
      var vlcPath = key.InstallDir.value + path.sep + 'vlc'
      VLC_ARGS = VLC_ARGS.split(' ')
      VLC_ARGS.unshift(href)
      cp.execFile(vlcPath, VLC_ARGS, errorAndExit)
    }
  } else if (argv.vlc) {
    var root = '/Applications/VLC.app/Contents/MacOS/VLC'
    var home = (process.env.HOME || '') + root
    cmd = 'vlc ' + href + ' ' + VLC_ARGS + ' || ' +
      root + ' ' + href + ' ' + VLC_ARGS + ' || ' +
      home + ' ' + href + ' ' + VLC_ARGS
  } else if (argv.mplayer) {
    cmd = MPLAYER_EXEC + ' ' + href
  } else if (argv.mpv) {
    cmd = MPV_EXEC + ' ' + href
  } else if (argv.omx) {
    cmd = OMX_EXEC + ' ' + href
  }

  if (cmd) {
    player = cp.exec(cmd, errorAndExit)
      .on('exit', function () {
        if (!argv['no-quit']) process.exit(0)
      })
  }

  if (argv.airplay) {
    var airplay = require('airplay-js')
    airplay.createBrowser()
      .on('deviceOn', function (device) {
        device.play(href, 0, function () {})
      })
      .start()
    // TODO: handle case where user closes airplay. do same thing as when VLC is closed
  }

  if (argv.chromecast) {
    var chromecast = require('chromecast-js')
    new chromecast.Browser()
      .on('deviceOn', function (device) {
        device.connect()
        device.on('connected', function () {
          device.play(href)
        })
      })
  }

  if (argv.xbmc) {
    var xbmc = require('nodebmc')
    new xbmc.Browser()
      .on('deviceOn', function (device) {
          device.play(href, function () {})
      })
  }

  var hotswaps = 0
  torrent.on('hotswap', function () {
    hotswaps += 1
  })

  if (!argv.quiet) {
    process.stdout.write(new Buffer('G1tIG1sySg==', 'base64')) // clear for drawing

    setInterval(draw, 500)
  }

  function active (wire) {
    return !wire.peerChoking
  }

  function bytes (num) {
    return prettysize(num)
  }

  function draw () {
    var unchoked = wires.filter(active)
    var linesremaining = clivas.height
    var peerslisted = 0
    var speed = swarm.downloadSpeed()
    var estimatedSecondsRemaining = Math.max(0, torrent.length - swarm.downloaded) / (speed > 0 ? speed : -1)
    var estimate = moment.duration(estimatedSecondsRemaining, 'seconds').humanize()

    clivas.clear()

    if (playerName)
      clivas.line('{green:Streaming to} {bold:' + playerName + '}')
    if (server)
      clivas.line('{green:server running at} {bold:' + href + '}')

    clivas.line('')
    clivas.line('{green:downloading:} {bold:' + filename + '}')
    clivas.line(
      '{green:speed: }{bold:' + bytes(speed) + '/s}  ' +
      '{green:downloaded:} {bold:' + bytes(swarm.downloaded) + '}' +
      '/{bold:' + bytes(torrent.length) + '}  ' +
      '{green:uploaded:} {bold:' + bytes(swarm.uploaded) + '}  ' +
      '{green:peers:} {bold:' + unchoked.length + '/' + wires.length + '}  ' +
      '{green:hotswaps:} {bold:' + hotswaps + '}'
    )
    clivas.line(
      '{green:time remaining:} {bold:' + estimate + ' remaining}  ' +
      '{green:total time:} {bold:' + getRuntime() + 's}  ' +
      '{green:queued peers:} {bold:' + swarm.numQueued + '}  ' +
      '{green:blocked:} {bold:' + torrent.numBlockedPeers + '}'
    )
    clivas.line('{80:}')
    linesremaining -= 8

    wires.every(function (wire) {
      var tags = []
      if (wire.peerChoking) tags.push('choked')
      clivas.line(
        '{25+magenta:' + wire.remoteAddress + '} {10:'+bytes(wire.downloaded)+'} ' +
        '{10+cyan:' + bytes(wire.downloadSpeed()) + '/s} ' +
        '{15+grey:' + tags.join(', ') + '}'
      )
      peerslisted++
      return linesremaining - peerslisted > 4
    })
    linesremaining -= peerslisted

    if (wires.length > peerslisted) {
      clivas.line('{80:}')
      clivas.line('... and '+(wires.length - peerslisted)+' more')
    }

    clivas.line('{80:}')
    clivas.flush(true)
  }
}
<commit_msg>Removed `--remove` and `--no-quit`; replaced with inference. Resolves issue #181.<commit_after>#!/usr/bin/env node

var clivas = require('clivas')
var cp = require('child_process')
var fs = require('fs')
var minimist = require('minimist')
var moment = require('moment')
var networkAddress = require('network-address')
var path = require('path')
var prettysize = require('prettysize')
var WebTorrent = require('../')

process.title = 'WebTorrent'

process.on('exit', function (code) {
  if (code !== 0) {
    clivas.line('{red:ERROR:} If you think this is a bug in webtorrent, report it!')
    console.log('=====>                                               <=====')
    console.log('=====>  https://github.com/feross/webtorrent/issues  <=====')
    console.log('=====>                                               <=====')
  }
})

var argv = minimist(process.argv.slice(2), {
  alias: {
    p: 'port',
    b: 'blocklist',
    t: 'subtitles',
    l: 'list',
    i: 'index',
    o: 'out',
    q: 'quiet',
    h: 'help',
    v: 'version'
  },
  boolean: [ // options that are always boolean
    'airplay',
    'chromecast',
    'mplayer',
    'mpv',
    'vlc',
    'xbmc',
    'list',
    'quiet',
    'help',
    'version'
  ],
  default: {
    port: 9000
  }
})

if (argv.version) {
  console.log(require('../package.json').version)
  done()
}

var torrentId = argv._[0]

if (argv.help || !torrentId) {
  fs.readFileSync(path.join(__dirname, 'ascii-logo.txt'), 'utf8')
    .split('\n')
    .forEach(function (line) {
      clivas.line('{bold:' + line.substring(0, 20) + '}{red:' + line.substring(20) + '}')
    })

  console.log(function () {/*
  Usage:
      webtorrent <options> <torrent-uri>

      Download the torrent from:
          * magnet uri
          * http url to .torrent file
          * filesystem path to .torrent file
          * info hash (hex string)

  Streaming options:
      --airplay               Apple TV
      --chromecast            Chromecast
      --mplayer               MPlayer
      --mpv                   MPV
      --omx [jack]            omx [default: hdmi]
      --vlc                   VLC
      --xbmc                  XBMC

  Options:
      -o, --out [path]        set download destination [default: /tmp/webtorrent]
      -l, --list              list files in torrent (with indexes)
      -i, --index [index]     stream a particular file from torrent (by index)

      -p, --port [number]     change the http port [default: 9000]
      -b, --blocklist [path]  use the specified blocklist
      -t, --subtitles [file]  load subtitles file

      -q, --quiet             print nothing to stdout
      -v, --version           print the current version

  Please report bugs!  https://github.com/feross/webtorrent/issues

    */}.toString().split(/\n/).slice(1, -1).join('\n'))
  done()
}

if (process.env.DEBUG) {
  argv.quiet = argv.q = true
}

var VLC_ARGS = process.env.DEBUG
  ? '-q --play-and-exit'
  : '--play-and-exit --extraintf=http:logger --verbose=2 --file-logging --logfile=vlc-log.txt'
var MPLAYER_EXEC = 'mplayer -ontop -really-quiet -noidx -loop 0'
var MPV_EXEC = 'mpv --ontop --really-quiet --loop=no'
var OMX_EXEC = 'omxplayer -r -o ' + (typeof argv.omx === 'string')
  ? argv.omx
  : 'hdmi'

if (argv.subtitles) {
  VLC_ARGS += ' --sub-file=' + argv.subtitles
  MPLAYER_EXEC += ' -sub ' + argv.subtitles
  MPV_EXEC += ' --sub-file=' + argv.subtitles
  OMX_EXEC += ' --subtitles ' + argv.subtitles
}

function error (err) {
  clivas.line('{red:ERROR:} ' + (err.message || err))
}

function errorAndExit (err) {
  error(err)
  process.exit(1)
}

var started = Date.now()
function getRuntime () {
  return Math.floor((Date.now() - started) / 1000)
}

var client = new WebTorrent({
  blocklist: argv.blocklist
})
.on('error', errorAndExit)

if (!argv.out) { // If no output file has been specified
  process.on('SIGINT', remove)
  process.on('SIGTERM', remove)
}

function remove (cb) {
  process.removeListener('SIGINT', remove)
  process.removeListener('SIGTERM', remove)
  client.destroy(cb)
}

var torrent = client.add(torrentId, (argv.out ? { tmp: argv.out } : {}))

torrent.on('infoHash', function () {
  function updateMetadata () {
    var numPeers = torrent.swarm.numPeers
    clivas.clear()
    clivas.line('{green:fetching torrent metadata from} {bold:'+numPeers+'} {green:peers}')
  }

  if (!argv.quiet && !argv.list) {
    torrent.swarm.on('wire', updateMetadata)
    torrent.on('metadata', function () {
      torrent.swarm.removeListener('wire', updateMetadata)
    })
    updateMetadata()
  }
})

var filename, swarm, wires, server, serving

if (argv.list) torrent.once('ready', onReady)
else {
  server = torrent.createServer()
  server.listen(argv.port, function () {
    if (torrent.ready) onReady()
    else torrent.once('ready', onReady)
  }).once('connection', function () {
      serving = true
  })
}
function done () {
  if (!serving) {
    process.exit(0)
  }
}

function onReady () {
  filename = torrent.name
  swarm = torrent.swarm
  wires = torrent.swarm.wires

  // if no index specified, use largest file
  var index = (typeof argv.index === 'number')
    ? argv.index
    : torrent.files.indexOf(torrent.files.reduce(function (a, b) {
      return a.length > b.length ? a : b
    }))
  torrent.files[index].select()

  if (argv.list) {
    torrent.files.forEach(function (file, i) {
      clivas.line('{3+bold:' + i + '} : {magenta:' + file.name + '}')
    })
    done()
  }

  torrent.on('verifying', function (data) {
    if (argv.quiet) return
    clivas.clear()
    clivas.line(
      '{green:verifying existing torrent} {bold:'+Math.floor(data.percentDone)+'%} ' +
      '({bold:'+Math.floor(data.percentVerified)+'%} {green:passed verification})'
    )
  })

  torrent.on('done', function () {
    if (!argv.quiet) {
      // TODO: expose this data from bittorrent-swarm
      var numActiveWires = torrent.swarm.wires.reduce(function (num, wire) {
        return num + (wire.downloaded > 0)
      }, 0)
      clivas.line('torrent downloaded {green:successfully} from {bold:'+numActiveWires+'/'+torrent.swarm.wires.length+'} {green:peers} in {bold:'+getRuntime()+'s}!')
    }
    done()
  })

  var cmd, player
  var href = 'http://' + networkAddress() + ':' + argv.port + '/' + index
  var playerName = argv.airplay ? 'Airplay'
    : argv.chromecast ? 'Chromecast'
    : argv.xbmc ? 'XBMC'
    : argv.vlc ? 'VLC'
    : argv.mplayer ? 'MPlayer'
    : argv.mpv ? 'mpv'
    : argv.omx ? 'OMXPlayer'
    : null

  if (argv.vlc && process.platform === 'win32') {
    var registry = require('windows-no-runnable').registry
    var key
    if (process.arch === 'x64') {
      try {
        key = registry('HKLM/Software/Wow6432Node/VideoLAN/VLC')
      } catch (e) {}
    } else {
      try {
        key = registry('HKLM/Software/VideoLAN/VLC')
      } catch (err) {}
    }

    if (key) {
      var vlcPath = key.InstallDir.value + path.sep + 'vlc'
      VLC_ARGS = VLC_ARGS.split(' ')
      VLC_ARGS.unshift(href)
      cp.execFile(vlcPath, VLC_ARGS, errorAndExit)
    }
  } else if (argv.vlc) {
    var root = '/Applications/VLC.app/Contents/MacOS/VLC'
    var home = (process.env.HOME || '') + root
    cmd = 'vlc ' + href + ' ' + VLC_ARGS + ' || ' +
      root + ' ' + href + ' ' + VLC_ARGS + ' || ' +
      home + ' ' + href + ' ' + VLC_ARGS
  } else if (argv.mplayer) {
    cmd = MPLAYER_EXEC + ' ' + href
  } else if (argv.mpv) {
    cmd = MPV_EXEC + ' ' + href
  } else if (argv.omx) {
    cmd = OMX_EXEC + ' ' + href
  }

  if (cmd) {
    player = cp.exec(cmd, errorAndExit)
      .on('exit', function () {
        done()
      })
  }

  if (argv.airplay) {
    var airplay = require('airplay-js')
    airplay.createBrowser()
      .on('deviceOn', function (device) {
        device.play(href, 0, function () {})
      })
      .start()
    // TODO: handle case where user closes airplay. do same thing as when VLC is closed
  }

  if (argv.chromecast) {
    var chromecast = require('chromecast-js')
    new chromecast.Browser()
      .on('deviceOn', function (device) {
        device.connect()
        device.on('connected', function () {
          device.play(href)
        })
      })
  }

  if (argv.xbmc) {
    var xbmc = require('nodebmc')
    new xbmc.Browser()
      .on('deviceOn', function (device) {
          device.play(href, function () {})
      })
  }

  var hotswaps = 0
  torrent.on('hotswap', function () {
    hotswaps += 1
  })

  if (!argv.quiet) {
    process.stdout.write(new Buffer('G1tIG1sySg==', 'base64')) // clear for drawing

    setInterval(draw, 500)
  }

  function active (wire) {
    return !wire.peerChoking
  }

  function bytes (num) {
    return prettysize(num)
  }

  function draw () {
    var unchoked = wires.filter(active)
    var linesremaining = clivas.height
    var peerslisted = 0
    var speed = swarm.downloadSpeed()
    var estimatedSecondsRemaining = Math.max(0, torrent.length - swarm.downloaded) / (speed > 0 ? speed : -1)
    var estimate = moment.duration(estimatedSecondsRemaining, 'seconds').humanize()

    clivas.clear()

    if (playerName)
      clivas.line('{green:Streaming to} {bold:' + playerName + '}')
    if (server)
      clivas.line('{green:server running at} {bold:' + href + '}')

    clivas.line('')
    clivas.line('{green:downloading:} {bold:' + filename + '}')
    clivas.line(
      '{green:speed: }{bold:' + bytes(speed) + '/s}  ' +
      '{green:downloaded:} {bold:' + bytes(swarm.downloaded) + '}' +
      '/{bold:' + bytes(torrent.length) + '}  ' +
      '{green:uploaded:} {bold:' + bytes(swarm.uploaded) + '}  ' +
      '{green:peers:} {bold:' + unchoked.length + '/' + wires.length + '}  ' +
      '{green:hotswaps:} {bold:' + hotswaps + '}'
    )
    clivas.line(
      '{green:time remaining:} {bold:' + estimate + ' remaining}  ' +
      '{green:total time:} {bold:' + getRuntime() + 's}  ' +
      '{green:queued peers:} {bold:' + swarm.numQueued + '}  ' +
      '{green:blocked:} {bold:' + torrent.numBlockedPeers + '}'
    )
    clivas.line('{80:}')
    linesremaining -= 8

    wires.every(function (wire) {
      var tags = []
      if (wire.peerChoking) tags.push('choked')
      clivas.line(
        '{25+magenta:' + wire.remoteAddress + '} {10:'+bytes(wire.downloaded)+'} ' +
        '{10+cyan:' + bytes(wire.downloadSpeed()) + '/s} ' +
        '{15+grey:' + tags.join(', ') + '}'
      )
      peerslisted++
      return linesremaining - peerslisted > 4
    })
    linesremaining -= peerslisted

    if (wires.length > peerslisted) {
      clivas.line('{80:}')
      clivas.line('... and '+(wires.length - peerslisted)+' more')
    }

    clivas.line('{80:}')
    clivas.flush(true)
  }
}
<|endoftext|>