<commit_before>/*
  @license
  crowdutil

  The MIT License (MIT)

  Copyright (c) 2014 Yasuhiro Okuno

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
 */
(function(){var a,b;a=function(a){a.parameters(["-D","--directory"],"target directory [optional]"),a.options(["-v","--verbose"],"verbose mode")},b=function(b){var c,d;c=require("operetta").Operetta,d=new c,d.command("test-connect","test connection to selected Directory",function(c){c.banner="crowdutil: test-connect\ntest connection to selected directory.\n\n",a(c),c.start(function(a){b(a)?require("./test-connection").run(a):logger.error("initialization failed")})}),d.command("create-user","create user in selected Directory",function(c){c.banner="crowdutil: test-connect\ncreate user in selected directory\n\n",a(c),c.parameters(["-f","--first"],"user's first name"),c.parameters(["-l","--last"],"user's last name"),c.parameters(["-d","--dispname"],"user's display name [optional]"),c.parameters(["-e","--email"],"user's email address"),c.parameters(["-u","--uid"],"user's login ID"),c.parameters(["-p","--pass"],"user's password [optional]"),c.start(function(a){b(a)?require("./create-user").run(a):logger.error("initialization failed")})}),d.command("create-group","create group in selected Directory",function(c){c.banner="crowdutil: test-connect\ncreate group in selected directory.\n\n",a(c),c.parameters(["-n","--name"],"group name"),c.parameters(["-d","--desc"],"description of the group"),c.start(function(a){b(a)?require("./create-group").run(a):logger.error("initialization failed")})}),d.command("add-to-groups","add users to groups",function(c){c.banner="crowdutil: test-connect\nadd list of users to list of groups.\n\n",a(c),c.parameters(["-g","--group"],"comma separated list of groups to add users to"),c.parameters(["-u","--uid"],"comma separated list of users to add to groups"),c.start(function(a){b(a)?require("./add-to-groups").run(a):logger.error("initialization failed")})}),d.command("rm-from-groups","remove users from groups",function(c){c.banner="crowdutil: test-connect\nremove list of users from list of groups.\n\n",a(c),c.parameters(["-g","--group"],"comma separated list of groups to remove users from"),c.parameters(["-u","--uid"],"comma separated list of users to remove from groups"),c.start(function(a){b(a)?require("./rm-from-groups").run(a):logger.error("initialization failed")})}),d.command("empty-groups","empty the specified group",function(c){c.banner="crowdutil: test-connect\nremove all direct members from the list of groups.\nIf no -f option is supplied, you must answer 'yes' to proceed.\n\n",a(c),c.parameters(["-g","--group"],"comma separated list of groups to empty out"),c.options(["-f","--force"],"force emptying the group"),c.start(function(a){b(a)?require("./empty-groups").run(a):logger.error("initialization failed")})}),d.command("batch-exec","execute according to batch file",function(c){c.banner="crowdutil: batch-exec\nexecute according to given batch file.\n\n",a(c),c.parameters(["-b","--batch"],"path to the batch file to execute"),c.start(function(a){b(cfg,a)?require("./batch-exec").run(a):logger.error("initialization failed")})}),d.command("create-config","create a sample config file",function(a){a.banner="crowdutil: create-config\ncreate a sample config file.\n\n",a.parameters(["-o","--out"],"output filename (default to crowdutil.json). stdout to print"),a.options(["-f","--force"],"force overwriting file."),a.start(function(a){require("./create-config").run(a)})}),d.banner="crowdutil. Atlassian Crowd utility command line tool\n\n",d.options(["-V","--version"],"display version info"),d.on("-V",function(){var a;a=require("../../../package.json"),console.log(a.name+" version "+a.version)}),d.start()},exports.start=b}).call(this);<commit_msg>missed build<commit_after>/*
  @license
  crowdutil

  The MIT License (MIT)

  Copyright (c) 2014 Yasuhiro Okuno

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
 */
(function(){var a,b;a=function(a){a.parameters(["-D","--directory"],"target directory [optional]"),a.options(["-v","--verbose"],"verbose mode")},b=function(b){var c,d;c=require("operetta").Operetta,d=new c,d.command("test-connect","test connection to selected Directory",function(c){c.banner="crowdutil: test-connect\ntest connection to selected directory.\n\n",a(c),c.start(function(a){b(a)?require("./test-connection").run(a):logger.error("initialization failed")})}),d.command("create-user","create user in selected Directory",function(c){c.banner="crowdutil: test-connect\ncreate user in selected directory\n\n",a(c),c.parameters(["-f","--first"],"user's first name"),c.parameters(["-l","--last"],"user's last name"),c.parameters(["-d","--dispname"],"user's display name [optional]"),c.parameters(["-e","--email"],"user's email address"),c.parameters(["-u","--uid"],"user's login ID"),c.parameters(["-p","--pass"],"user's password [optional]"),c.start(function(a){b(a)?require("./create-user").run(a):logger.error("initialization failed")})}),d.command("create-group","create group in selected Directory",function(c){c.banner="crowdutil: test-connect\ncreate group in selected directory.\n\n",a(c),c.parameters(["-n","--name"],"group name"),c.parameters(["-d","--desc"],"description of the group"),c.start(function(a){b(a)?require("./create-group").run(a):logger.error("initialization failed")})}),d.command("add-to-groups","add users to groups",function(c){c.banner="crowdutil: test-connect\nadd list of users to list of groups.\n\n",a(c),c.parameters(["-g","--group"],"comma separated list of groups to add users to"),c.parameters(["-u","--uid"],"comma separated list of users to add to groups"),c.start(function(a){b(a)?require("./add-to-groups").run(a):logger.error("initialization failed")})}),d.command("rm-from-groups","remove users from groups",function(c){c.banner="crowdutil: test-connect\nremove list of users from list of groups.\n\n",a(c),c.parameters(["-g","--group"],"comma separated list of groups to remove users from"),c.parameters(["-u","--uid"],"comma separated list of users to remove from groups"),c.start(function(a){b(a)?require("./rm-from-groups").run(a):logger.error("initialization failed")})}),d.command("empty-groups","empty the specified group",function(c){c.banner="crowdutil: test-connect\nremove all direct members from the list of groups.\nIf no -f option is supplied, you must answer 'yes' to proceed.\n\n",a(c),c.parameters(["-g","--group"],"comma separated list of groups to empty out"),c.options(["-f","--force"],"force emptying the group"),c.start(function(a){b(a)?require("./empty-groups").run(a):logger.error("initialization failed")})}),d.command("batch-exec","execute according to batch file",function(c){c.banner="crowdutil: batch-exec\nexecute according to given batch file.\n\n",a(c),c.parameters(["-b","--batch"],"path to the batch file to execute"),c.start(function(a){b(a)?require("./batch-exec").run(a):logger.error("initialization failed")})}),d.command("create-config","create a sample config file",function(a){a.banner="crowdutil: create-config\ncreate a sample config file.\n\n",a.parameters(["-o","--out"],"output filename (default to crowdutil.json). stdout to print"),a.options(["-f","--force"],"force overwriting file."),a.start(function(a){require("./create-config").run(a)})}),d.banner="crowdutil. Atlassian Crowd utility command line tool\n\n",d.options(["-V","--version"],"display version info"),d.on("-V",function(){var a;a=require("../../../package.json"),console.log(a.name+" version "+a.version)}),d.start()},exports.start=b}).call(this);<|endoftext|>


<commit_before>'use strict';

const St = imports.gi.St;
const Main = imports.ui.main;
const GnomeDesktop = imports.gi.GnomeDesktop;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Util = imports.misc.util;
const Config = imports.misc.config;

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Me.imports.convenience;

const log_this = Convenience.log_this;
const version_data = Convenience.version_data;
const isGnome40 = Convenience.isGnome40;

let text, button, label;
let clock, clock_signal_id;
let settings;

let signals = [];

let shellMinorVersion36 = parseInt(version_data[1]) < 36;

let format_params = {
    hour: '2-digit',
    minute: '2-digit',
    hour12: false
}
let time_text = 'UTC';

function init() {
    settings = Convenience.getSettings();

    clock = new GnomeDesktop.WallClock();
    button = new St.Bin({
        style_class: 'panel-button',
        reactive: true,
        can_focus: false,
        x_expand: true,
        y_expand: false,
        y_align: !isGnome40 && shellMinorVersion36 ? St.Align.MIDDLE : St.Align.END,
        track_hover: true
    });

    label = new St.Label({
        opacity: 200
    });

    button.set_child(label);
    log_this(Config.PACKAGE_VERSION);
}

function enable() {
    log_this(`enabling...`);

    signals[0] = settings.connect('changed::show-seconds', Lang.bind(this, setSecondsDisplayed));
    signals[1] = settings.connect('changed::time-text', Lang.bind(this, setTimeText));
    signals[2] = settings.connect('changed::show-date', Lang.bind(this, setDateDisplayed));
    signals[3] = settings.connect('changed::light-opacity', Lang.bind(this, setLightOpacity));

    signals[4] = button.connect('button-press-event', showMenu);

    setSecondsDisplayed();
    setTimeText();
    setDateDisplayed();
    setLightOpacity();

    update_time();
    signals[5] = clock.connect('notify::clock', Lang.bind(this, this.update_time));
    Main.panel._centerBox.insert_child_at_index(button, 1);
    log_this(`enabled.`);
}

function disable() {
    log_this(`disabling...`);

    settings.disconnect(signals[0]);
    settings.disconnect(signals[1]);
    settings.disconnect(signals[2]);
    settings.disconnect(signals[3]);
    button.disconnect(signals[4]);

    Main.panel._centerBox.remove_child(button);
    clock.disconnect(signals[5]);
    log_this(`disabled.`);
}

function update_time() {
    var now = new Date();
    var utc = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds());
    label.set_text(new Intl.DateTimeFormat('default', format_params).format(utc) + ' ' + time_text);
}

function setSecondsDisplayed() {
    let secondsDisplayed = settings.get_boolean('show-seconds');
    if (secondsDisplayed) {
        format_params['second'] = '2-digit';
    } else {
        delete format_params['second'];
    }
    update_time();
}

function setTimeText() {
    time_text = settings.get_string('time-text');
    update_time();
}

function setDateDisplayed() {
    let dateDisplayed = settings.get_boolean('show-date');
    if (dateDisplayed) {
        format_params['weekday'] = 'short';
        format_params['month'] = 'short';
        format_params['day'] = 'numeric';
    } else {
        delete format_params['weekday'];
        delete format_params['month'];
        delete format_params['day'];
    }
    update_time();
}

function setLightOpacity() {
    label.opacity = settings.get_boolean('light-opacity') ? 255 : 200;
    update_time();
}

function showMenu() {
    Util.spawn([
        "gnome-shell-extension-prefs",
        Me.uuid
    ]);
}
<commit_msg>More code order<commit_after>'use strict';

const St = imports.gi.St;
const Main = imports.ui.main;
const GnomeDesktop = imports.gi.GnomeDesktop;
const Lang = imports.lang;
const Shell = imports.gi.Shell;
const Util = imports.misc.util;
const Config = imports.misc.config;

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Convenience = Me.imports.convenience;

const log_this = Convenience.log_this;
const version_data = Convenience.version_data;
const isGnome40 = Convenience.isGnome40;

let text, button, label;
let clock, clock_signal_id;
let settings;

let signals = [];

let shellMinorVersion36 = parseInt(version_data[1]) < 36;

let format_params = {
    hour: '2-digit',
    minute: '2-digit',
    hour12: false
}
let time_text = 'UTC';

function init() {
    settings = Convenience.getSettings();

    clock = new GnomeDesktop.WallClock();
    button = new St.Bin({
        style_class: 'panel-button',
        reactive: true,
        can_focus: false,
        x_expand: true,
        y_expand: false,
        y_align: !isGnome40 && shellMinorVersion36 ? St.Align.MIDDLE : St.Align.END,
        track_hover: true
    });

    label = new St.Label({
        opacity: 200
    });

    button.set_child(label);
    log_this(Config.PACKAGE_VERSION);
}

function enable() {
    log_this(`enabling...`);

    signals[0] = settings.connect('changed::show-seconds', Lang.bind(this, setSecondsDisplayed));
    signals[1] = settings.connect('changed::time-text', Lang.bind(this, setTimeText));
    signals[2] = settings.connect('changed::show-date', Lang.bind(this, setDateDisplayed));
    signals[3] = settings.connect('changed::light-opacity', Lang.bind(this, setLightOpacity));

    signals[4] = button.connect('button-press-event', showMenu);

    setSecondsDisplayed();
    setTimeText();
    setDateDisplayed();
    setLightOpacity();

    update_time();

    signals[5] = clock.connect('notify::clock', Lang.bind(this, this.update_time));

    Main.panel._centerBox.insert_child_at_index(button, 1);

    log_this(`enabled.`);
}

function disable() {
    log_this(`disabling...`);

    settings.disconnect(signals[0]);
    settings.disconnect(signals[1]);
    settings.disconnect(signals[2]);
    settings.disconnect(signals[3]);
    button.disconnect(signals[4]);

    Main.panel._centerBox.remove_child(button);
    clock.disconnect(signals[5]);
    log_this(`disabled.`);
}

function update_time() {
    var now = new Date();
    var utc = new Date(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), now.getUTCHours(), now.getUTCMinutes(), now.getUTCSeconds());
    label.set_text(new Intl.DateTimeFormat('default', format_params).format(utc) + ' ' + time_text);
}

function setSecondsDisplayed() {
    let secondsDisplayed = settings.get_boolean('show-seconds');
    if (secondsDisplayed) {
        format_params['second'] = '2-digit';
    } else {
        delete format_params['second'];
    }
    update_time();
}

function setTimeText() {
    time_text = settings.get_string('time-text');
    update_time();
}

function setDateDisplayed() {
    let dateDisplayed = settings.get_boolean('show-date');
    if (dateDisplayed) {
        format_params['weekday'] = 'short';
        format_params['month'] = 'short';
        format_params['day'] = 'numeric';
    } else {
        delete format_params['weekday'];
        delete format_params['month'];
        delete format_params['day'];
    }
    update_time();
}

function setLightOpacity() {
    label.opacity = settings.get_boolean('light-opacity') ? 255 : 200;
    update_time();
}

function showMenu() {
    Util.spawn([
        "gnome-shell-extension-prefs",
        Me.uuid
    ]);
}
<|endoftext|>


<commit_before>(function () {
    var acapela = require('acapela');
    var extract = require('extract-zip');
    var request = require('request');
    var rimraf = require('rimraf');
    var fs = require('fs');
    var path = require('path');

    var tts = {
        exec: function () {
        },
        enabled: false
    };

    if (acapela) {
        tts.enabled = true;
        tts.acapela = acapela;
        var speaker = {
            listen: function (callback) {
                speaker.listeners = speaker.listeners || [];
                speaker.listeners.push(callback);
                if (!speaker.pinging) {
                    speaker.pinging = true;
                    setTimeout(speaker.ping, 100);
                }
            },
            ping: function () {
                // There is a callback on the native speak method, but I'm not smart
                // enough to figure out how to trigger a javascript callback from
                // a c callback, so I poll instead. Don't judge.
                var res = acapela.isSpeaking();
                if (res) {
                    setTimeout(speaker.ping, 50);
                } else {
                    speaker.pinging = false;
                    while (speaker.listeners && speaker.listeners.length > 0) {
                        var cb = speaker.listeners.shift();
                        cb();
                    }
                }
            }
        };
        var downloader = {
            download_file_to_location(url, file_path, progress) {
                var size = 0;
                request({
                    uri: url
                }, function (err, res, body) {
                  if(err) {
                    console.log("error downloading " + url);
                    console.log(err);
                    progress(null, null, "error downloading " + url);
                  } else {
                    console.log("got a response");
                    progress(null, null, "got a response");
                  }
                }).on('data', function (data) {
                    size = size + data.length;
                    progress(size, false, null);
                }).pipe(fs.createWriteStream(file_path)).on('close', function () {
                    console.log("writing to " + file_path)
                    progress(0, true, null);
                });
            },
            download_file: function(url, expected_size, percent_pre, percent_amount, done) {
                downloader.download_file_to_location(url, downloader.tmp_file, function (size, complete, error) {
                  if(error) {
                    console.log(error);
                  } else if(complete) {
                    done();
                  } else {
                    downloader.watcher({
                      percent: percent_pre + Math.min(1.0, size / expected_size) * percent_amount,
                      done: false
                    });
                  }
                });
            },
            assert_directory: function(dir, done) {
                fs.stat(dir, function(err, stats) {
                    if(err && err.errno === 34) {
                        fs.mkdir(dir, function() {
                            done();
                        });
                    } else {
                        done();
                    }
                });
            },
            unzip_file_to_location: function(file_path, dir, progress) {
                var entries = 0;
                downloader.assert_directory(dir, function () {
                    console.log("unzipping to ", path.resolve(dir));
                    extract(downloader.tmp_file, {
                        dir: path.resolve(dir), onEntry: function () {
                            entries++;
                            progress(entries, false, null);
                        }
                    }, function (err) {
                        if (err) {
                            console.log("unzip error", err);
                        }
                        fs.unlink(downloader.tmp_file);
                        progress(0, true, null);
                    });
                });
            },
            unzip_file: function(language_dir, n_entries, percent_pre, percent_amount, done) {
                downloader.unzip_file_to_location(downloader.tmp_file, './data/' + language_dir, function(entries, complete, error) {
                  if(error) {
                    console.log(error);
                  } else if(complete) {
                    done();
                  } else {
                    downloader.watcher({
                      percent: percent_pre + (Math.min(1.0, (entries / n_entries)) * percent_amount),
                      done: false
                    });
                  }
                });
            },
            download_voice: function (opts) {
                var dir_id = opts.voice_id.replace(/^acap:/, '');
                var language_dir = opts.language_dir;
                downloader.tmp_file = 'tmp_download' + Math.round(Math.random() * 99999) + '.zip';
                downloader.watcher = downloader.watcher || function() { };

                fs.unlink(downloader.tmp_file, function () {
                    var download_language = function () {
                        console.log('downloading language...');
                        downloader.download_file(opts.language_url, (5 * 1024 * 1024), 0, 0.10, unzip_language);
                    };
                    var unzip_language = function() {
                        console.log('unzipping language...');
                        downloader.unzip_file(language_dir, 10, 0.10, 0.05, download_voice);
                    };
                    var download_voice = function() {
                        console.log('downloading voice...');
                        downloader.download_file(opts.voice_url, (50 * 1024 * 1024), 0.15, 0.65, unzip_voice);
                    };
                    var unzip_voice = function() {
                        console.log('unzipping voice...');
                        downloader.unzip_file(language_dir, 20, 0.85, 0.15, done);
                    };
                    var done = function() {
                        downloader.watcher({
                            percent: 1.0,
                            done: true
                        });
                    };

                    download_language();
                });
            },
            delete_voice: function(opts) {
                var dir_id = opts.voice_id.replace(/^acap:/, '');
                var found_dir = null;
                fs.readdir('./data/' + opts.language_dir, function(err, list) {
                    for(var idx = 0; idx < list.length; idx++) {
                        var fn = list[idx];
                        var re = new RegExp(dir_id + "[^A-Za-z]", 'i');
                        if(fn.match(re)) {
                            found_dir = fn;
                        }
                    }
                    if (found_dir) {
                        rimraf('./data/' + opts.language_dir + '/' + found_dir, function () {
                            if (opts.success) {
                                opts.success();
                            }
                        });
                    } else {
                        if (opts.success) {
                            opts.success({ message: "no matching directory found" });
                        }
                    }
                });
            },
            watch: function (callback) {
                downloader.watcher = callback;
            }
        };
        tts.exec = function (method, opts) {
            opts = opts || {};
            if (method == 'speakText') {
                speaker.listen(opts.success);
                if (!tts.voice_id_map) {
                    tts.getAvailableVoices();
                }
                if (tts.voice_id_map && tts.voice_id_map[opts.voice_id]) {
                    opts.voice_key = tts.voice_id_map[opts.voice_id];
                    acapela.openVoice(opts.voice_key);
                }
                if (opts.volume) {
                    opts.volume = Math.min(Math.max(0, opts.volume * 100), 150);
                }
                if (opts.rate) {
                    opts.rate = Math.min(Math.max(30, opts.rate * 100), 300);
                }
                if (opts.pitch) {
                    opts.pitch = Math.min(Math.max(50, opts.pitch * 100), 150);
                }
                opts.success = function (res) { };
            }
            var res = acapela[method](opts);
            if (res && res.ready !== false) {
                if (opts.success) {
                    opts.success(res);
                }
            } else {
                if (opts.error) {
                    opts.error({ error: "negative response to " + method });
                }
            }
        }
        var keys = ['init', 'status', 'getAvailableVoices', 'downloadVoice', 'deleteVoice', 'speakText', 'stopSpeakingText'];
        for (var idx = 0; idx < keys.length; idx++) {
            (function (method) {
                tts[method] = function (opts) {
                    tts.exec(method, opts);
                }
            })(keys[idx]);
        }
        tts.reload = function(opts) {
          var teardown = tts.exec('teardown');
          var init = tts.exec('init');
          if(opts && opts.success) {
            opts.success({
              teardown: teardown,
              setup: setup
            });
          }
        };
        tts.getAvailableVoices = function (opts) {
            opts = opts || {};
            var raw_list = acapela.getAvailableVoices();
            var new_list = [];
            tts.voice_id_map = {};
            for (var idx = 0; idx < raw_list.length; idx++) {
                var voice = raw_list[idx];
                voice.raw_voice_id = voice.voice_id;
                voice.voice_id = 'acap:' + voice.raw_voice_id.split(/[^A-Za-z-]/)[0];
                tts.voice_id_map[voice.voice_id] = voice.raw_voice_id;
                new_list.push(voice);
            }
            if (opts.success) {
                opts.success(new_list);
            }
        };
        tts.downloadVoice = function (opts) {
            downloader.watch(opts.progress || opts.success);
            downloader.download_voice(opts || {});
        };
        tts.deleteVoice = function (opts) {
            downloader.delete_voice(opts || {});
        };
        tts.download_file = function(url, file_path, progress) {
            downloader.download_file_to_location(url, file_path, progress);
        };
        tts.unzip_file = function(file_path, dir_path, progress) {
            downloader.unzip_file_to_location(file_path, dir_path, progress);
        };
    }

    module.exports = tts;
})();<commit_msg>logging cleanup<commit_after>(function () {
    var acapela = require('acapela');
    var extract = require('extract-zip');
    var request = require('request');
    var rimraf = require('rimraf');
    var fs = require('fs');
    var path = require('path');

    var tts = {
        exec: function () {
        },
        enabled: false
    };

    if (acapela) {
        tts.enabled = true;
        tts.acapela = acapela;
        var speaker = {
            listen: function (callback) {
                speaker.listeners = speaker.listeners || [];
                speaker.listeners.push(callback);
                if (!speaker.pinging) {
                    speaker.pinging = true;
                    setTimeout(speaker.ping, 100);
                }
            },
            ping: function () {
                // There is a callback on the native speak method, but I'm not smart
                // enough to figure out how to trigger a javascript callback from
                // a c callback, so I poll instead. Don't judge.
                var res = acapela.isSpeaking();
                if (res) {
                    setTimeout(speaker.ping, 50);
                } else {
                    speaker.pinging = false;
                    while (speaker.listeners && speaker.listeners.length > 0) {
                        var cb = speaker.listeners.shift();
                        cb();
                    }
                }
            }
        };
        var downloader = {
            download_file_to_location(url, file_path, progress) {
                var size = 0;
                request({
                    uri: url
                }, function (err, res, body) {
                  if(err) {
                    console.log("error downloading " + url);
                    console.log(err);
                    progress(null, null, "error downloading " + url);
                  } else {
                    console.log("got a response");
                    progress(null, null, "got a response");
                  }
                }).on('data', function (data) {
                    size = size + data.length;
                    progress(size, false, null);
                }).pipe(fs.createWriteStream(file_path)).on('close', function () {
                    progress(0, true, null);
                });
            },
            download_file: function(url, expected_size, percent_pre, percent_amount, done) {
                downloader.download_file_to_location(url, downloader.tmp_file, function (size, complete, error) {
                  if(error) {
                    console.log(error);
                  } else if(complete) {
                    done();
                  } else {
                    downloader.watcher({
                      percent: percent_pre + Math.min(1.0, size / expected_size) * percent_amount,
                      done: false
                    });
                  }
                });
            },
            assert_directory: function(dir, done) {
                fs.stat(dir, function(err, stats) {
                    if(err && err.errno === 34) {
                        fs.mkdir(dir, function() {
                            done();
                        });
                    } else {
                        done();
                    }
                });
            },
            unzip_file_to_location: function(file_path, dir, progress) {
                var entries = 0;
                downloader.assert_directory(dir, function () {
                    extract(downloader.tmp_file, {
                        dir: path.resolve(dir), onEntry: function () {
                            entries++;
                            progress(entries, false, null);
                        }
                    }, function (err) {
                        if (err) {
                            console.log("unzip error", err);
                        }
                        fs.unlink(downloader.tmp_file);
                        progress(0, true, null);
                    });
                });
            },
            unzip_file: function(language_dir, n_entries, percent_pre, percent_amount, done) {
                downloader.unzip_file_to_location(downloader.tmp_file, './data/' + language_dir, function(entries, complete, error) {
                  if(error) {
                    console.log(error);
                  } else if(complete) {
                    done();
                  } else {
                    downloader.watcher({
                      percent: percent_pre + (Math.min(1.0, (entries / n_entries)) * percent_amount),
                      done: false
                    });
                  }
                });
            },
            download_voice: function (opts) {
                var dir_id = opts.voice_id.replace(/^acap:/, '');
                var language_dir = opts.language_dir;
                downloader.tmp_file = 'tmp_download' + Math.round(Math.random() * 99999) + '.zip';
                downloader.watcher = downloader.watcher || function() { };

                fs.unlink(downloader.tmp_file, function () {
                    var download_language = function () {
                        console.log('downloading language...');
                        downloader.download_file(opts.language_url, (5 * 1024 * 1024), 0, 0.10, unzip_language);
                    };
                    var unzip_language = function() {
                        console.log('unzipping language...');
                        downloader.unzip_file(language_dir, 10, 0.10, 0.05, download_voice);
                    };
                    var download_voice = function() {
                        console.log('downloading voice...');
                        downloader.download_file(opts.voice_url, (50 * 1024 * 1024), 0.15, 0.65, unzip_voice);
                    };
                    var unzip_voice = function() {
                        console.log('unzipping voice...');
                        downloader.unzip_file(language_dir, 20, 0.85, 0.15, done);
                    };
                    var done = function() {
                        downloader.watcher({
                            percent: 1.0,
                            done: true
                        });
                    };

                    download_language();
                });
            },
            delete_voice: function(opts) {
                var dir_id = opts.voice_id.replace(/^acap:/, '');
                var found_dir = null;
                fs.readdir('./data/' + opts.language_dir, function(err, list) {
                    for(var idx = 0; idx < list.length; idx++) {
                        var fn = list[idx];
                        var re = new RegExp(dir_id + "[^A-Za-z]", 'i');
                        if(fn.match(re)) {
                            found_dir = fn;
                        }
                    }
                    if (found_dir) {
                        rimraf('./data/' + opts.language_dir + '/' + found_dir, function () {
                            if (opts.success) {
                                opts.success();
                            }
                        });
                    } else {
                        if (opts.success) {
                            opts.success({ message: "no matching directory found" });
                        }
                    }
                });
            },
            watch: function (callback) {
                downloader.watcher = callback;
            }
        };
        tts.exec = function (method, opts) {
            opts = opts || {};
            if (method == 'speakText') {
                speaker.listen(opts.success);
                if (!tts.voice_id_map) {
                    tts.getAvailableVoices();
                }
                if (tts.voice_id_map && tts.voice_id_map[opts.voice_id]) {
                    opts.voice_key = tts.voice_id_map[opts.voice_id];
                    acapela.openVoice(opts.voice_key);
                }
                if (opts.volume) {
                    opts.volume = Math.min(Math.max(0, opts.volume * 100), 150);
                }
                if (opts.rate) {
                    opts.rate = Math.min(Math.max(30, opts.rate * 100), 300);
                }
                if (opts.pitch) {
                    opts.pitch = Math.min(Math.max(50, opts.pitch * 100), 150);
                }
                opts.success = function (res) { };
            }
            var res = acapela[method](opts);
            if (res && res.ready !== false) {
                if (opts.success) {
                    opts.success(res);
                }
            } else {
                if (opts.error) {
                    opts.error({ error: "negative response to " + method });
                }
            }
        }
        var keys = ['init', 'status', 'getAvailableVoices', 'downloadVoice', 'deleteVoice', 'speakText', 'stopSpeakingText'];
        for (var idx = 0; idx < keys.length; idx++) {
            (function (method) {
                tts[method] = function (opts) {
                    tts.exec(method, opts);
                }
            })(keys[idx]);
        }
        tts.reload = function (opts) {
          var teardown = tts.exec('teardown');
          var init = tts.exec('init');
          if(opts && opts.success) {
            opts.success({
              teardown: teardown,
              setup: setup
            });
          }
        };
        tts.getAvailableVoices = function (opts) {
            opts = opts || {};
            console.log("getting available voices");
            var raw_list = acapela.getAvailableVoices();
            var new_list = [];
            tts.voice_id_map = {};
            for (var idx = 0; idx < raw_list.length; idx++) {
                var voice = raw_list[idx];
                voice.raw_voice_id = voice.voice_id;
                voice.voice_id = 'acap:' + voice.raw_voice_id.split(/[^A-Za-z-]/)[0];
                tts.voice_id_map[voice.voice_id] = voice.raw_voice_id;
                new_list.push(voice);
            }
            if (opts.success) {
                opts.success(new_list);
            }
        };
        tts.downloadVoice = function (opts) {
            downloader.watch(opts.progress || opts.success);
            downloader.download_voice(opts || {});
        };
        tts.deleteVoice = function (opts) {
            downloader.delete_voice(opts || {});
        };
        tts.download_file = function(url, file_path, progress) {
            downloader.download_file_to_location(url, file_path, progress);
        };
        tts.unzip_file = function(file_path, dir_path, progress) {
            downloader.unzip_file_to_location(file_path, dir_path, progress);
        };
    }

    module.exports = tts;
})();<|endoftext|>


<commit_before>var BackendTplServer = require('backend-tpl-server');
var Mock = require('mockjs');

// 指定后端 Java Web 项目的路径
var backendTplServer = new BackendTplServer('../src/main/webapp');
backendTplServer.start();

// 快速定义一个模版页面路由并给他灌入所需的数据
// 指定要查看哪个页面(这里的 html 即对应后端的模版页面文件)
// 对应访问的 URL: http://localhost:8000/a/b/c/page.html
backendTplServer.url('a/b/c/page.html', {
    id: '@id',
    name: '@cname'
});

// 如果是想控制更多, 可以直接使用 app(express的实例) 来定义路由, 控制视图和数据
backendTplServer.app.get('/abc', function(request, response) {
    var mockData = Mock.mock({
        id: '@id',
        name: '@cname'
    });

    response.render('abc.html', mockData);
});

// JavaBean 模式
// 在模版页面中通过 $!{a.getTitle()} 这样的方式拿数据
backendTplServer.app.get('/javabean', function(request, response) {
    // 公共的数据模型可以抽取到出来, 作为一个文件 require 进来, 防止多处重复定义数据模型的规则
    var data = Mock.mock({
        'a|10-20': [{
            getTitle: function() {
                // Mock.js 会处理方法, 实际得到的是返回值, 因此这里需要返回一个方法
                return function() {
                    return Mock.mock('@ctitle');
                };
            }
        }]
    });

    // 单独修改其中的某个数据
    data.a[0].getUrls = function() {
        return [
            'http://dummyimage.com/112x74,',
            'http://dummyimage.com/112x74,',
            'http://dummyimage.com/112x74,',
            'http://dummyimage.com/112x74,'
        ]
    };

    response.render('home.html', data);
});

// HTTP 接口返回 JSON 数据
backendTplServer.app.post('/json/getPageData', function(request, response) {
    var data = Mock.mock({
        'data|10-20': [{
            title: '@ctitle'
        }]
    });

    response.json(data);
});

// 路由路径和请求方法一起定义了请求的端点，它可以是字符串、字符串模式或者正则表达式
// http://www.expressjs.com.cn/guide/routing.html
// http://forbeslindesay.github.io/express-route-tester/
// https://www.npmjs.com/package/path-to-regexp
//
// backendTplServer.app.get(/json\/\d+/, function(request, response) {
backendTplServer.app.get('/json/\\d+', function(request, response) {
    var data = Mock.mock({
        'a': {
            getTitle: function() {
                return function() {
                    return Mock.mock('@ctitle');
                };
            }
        }
    });

    response.render('detail.html', data);
});<commit_msg>可以在视图层增加 helper 方法用于调试<commit_after>var BackendTplServer = require('backend-tpl-server');
var Mock = require('mockjs');

// 指定后端 Java Web 项目的路径
var backendTplServer = new BackendTplServer('../src/main/webapp');
backendTplServer.start();

// 可以在视图层增加 helper 方法用于调试
// <textarea>$!{__helper.toJSON($var)}</textarea>
var __helper = {
    toJSON: function(value) {
        return JSON.stringify(value, null, 4);
    }
};

// 快速定义一个模版页面路由并给他灌入所需的数据
// 指定要查看哪个页面(这里的 html 即对应后端的模版页面文件)
// 对应访问的 URL: http://localhost:8000/a/b/c/page.html
backendTplServer.url('a/b/c/page.html', {
    id: '@id',
    name: '@cname'
});

// 如果是想控制更多, 可以直接使用 app(express的实例) 来定义路由, 控制视图和数据
backendTplServer.app.get('/abc', function(request, response) {
    var data = Mock.mock({
        id: '@id',
        name: '@cname'
    });

    data.__helper = __helper;

    response.render('abc.html', data);
});

// JavaBean 模式
// 在模版页面中通过 $!{a.getTitle()} 这样的方式拿数据
backendTplServer.app.get('/javabean', function(request, response) {
    // 公共的数据模型可以抽取到出来, 作为一个文件 require 进来, 防止多处重复定义数据模型的规则
    var data = Mock.mock({
        'a|10-20': [{
            getTitle: function() {
                // Mock.js 会处理方法, 实际得到的是返回值, 因此这里需要返回一个方法
                return function() {
                    return Mock.mock('@ctitle');
                };
            }
        }]
    });

    // 单独修改其中的某个数据
    data.a[0].getUrls = function() {
        return [
            'http://dummyimage.com/112x74,',
            'http://dummyimage.com/112x74,',
            'http://dummyimage.com/112x74,',
            'http://dummyimage.com/112x74,'
        ]
    };

    response.render('home.html', data);
});

// HTTP 接口返回 JSON 数据
backendTplServer.app.post('/json/getPageData', function(request, response) {
    var data = Mock.mock({
        'data|10-20': [{
            title: '@ctitle'
        }]
    });

    response.json(data);
});

// 路由路径和请求方法一起定义了请求的端点，它可以是字符串、字符串模式或者正则表达式
// http://www.expressjs.com.cn/guide/routing.html
// http://forbeslindesay.github.io/express-route-tester/
// https://www.npmjs.com/package/path-to-regexp
//
// backendTplServer.app.get(/json\/\d+/, function(request, response) {
backendTplServer.app.get('/json/\\d+', function(request, response) {
    var data = Mock.mock({
        'a': {
            getTitle: function() {
                return function() {
                    return Mock.mock('@ctitle');
                };
            }
        }
    });

    response.render('detail.html', data);
});<|endoftext|>


<commit_before>'use strict';
var BaseEvent = require('broker').events.ApplicationEvent;
var logger = require('hoist-logger');
var util = require('util');
var BBPromise = require('bluebird');
var Model = require('hoist-model');
var Session = Model.Session;
var AppUser = Model.AppUser;
var Organisation = Model.Organisation;
var Application = Model.Application;
var path = require('path');
var _ = require('lodash');
var kueProxy = require('../kue_proxy');
var moment = require('moment');

function ApplicationEvent(properties) {
  BaseEvent.call(this, properties);
  _.bindAll(this);
}

util.inherits(ApplicationEvent, BaseEvent);

ApplicationEvent.QueueName = 'application_event';
ApplicationEvent.prototype.getModuleDescription = function (moduleName, application) {
  return BBPromise.try(function () {
    var module = null;
    var settings = application.settings[this.environment];
    if (settings) {
      module = _.find(settings.modules, function (moduleDesc) {
        return moduleDesc.name === moduleName;
      });
    }
    return module;
  }, [], this);
};
ApplicationEvent.prototype.getContext = function (application) {
  var context = {};
  var pipeline = [];
  context.applicationId = this.applicationId;
  context.environment = this.environment;
  if (this.sessionId) {
    pipeline.push(Session.findOneAsync({
        _id: this.sessionId
      })
      .then(function (session) {
        if (session) {
          context.sessionId = session._id;
          if (session.appUser) {
            return AppUser.findOneAsync({
              _id: session.appUser
            }).then(function (appUser) {
              if (appUser) {
                context.user = appUser.toObject();
              }
            });
          }
        }
      }));
  }

  context.application = application.toObject();

  return BBPromise.all(pipeline).then(function () {
    return context;
  });
};
ApplicationEvent.prototype.getEventDescription = function (application) {
  var environment = this.environment || 'live';
  var settings = application.settings[environment];
  return settings.on[this.eventName];
};
ApplicationEvent.prototype.registerJobComplete = function (id) {
  if (this.timeouts[id]) {
    this.decrementJob(id);
    require('kue').Job.get(id, function (err, job) {
      if (err) {
        return;
      }
      job.remove(function (err) {
        if (err) {
          throw err;
        }
        logger.info(util.format('removed completed job #%d', job.id));
      });
    });
  }
};
ApplicationEvent.prototype.registerJobFailed = function (id) {
  console.log('job failed', arguments);
  if (this.timeouts[id]) {
    this.decrementJob(id);
    require('kue').Job.log(id, function (err, logs) {
      console.log(logs);
    });
  }
};
ApplicationEvent.prototype.decrementJob = function (id) {
  clearTimeout(this.timeouts[id]);
  this.executionCount--;
  if (this.executionCount < 1) {
    clearInterval(this.pingInterval);
    kueProxy.get().removeListener('job failed', this.registerJobFailed);
    kueProxy.get().removeListener('job complete', this.registerJobComplete);
    this.emit('done');
  }
};
ApplicationEvent.prototype.process = function (callback) {
  return Application.findOneAsync({
      _id: this.applicationId
    })
    .bind(this)
    .then(function (application) {
      return Organisation.findOneAsync({
        _id: application.organisation
      }).bind(this).then(function (org) {

        var eventDescription = this.getEventDescription(application);

        var modules = eventDescription.modules;

        if (!modules || modules.length < 1) {
          this.emit('done');
          return;
        }
        this.timeouts = {};
        this.pingInterval = setInterval(_.bind(function () {
          logger.debug('emitting ping');
          this.emit('ping');
        }, this), 30000);
        this.executionCount = modules.length;
        kueProxy.get().on('job failed', this.registerJobFailed);
        kueProxy.get().on('job complete', this.registerJobComplete);
        return BBPromise.all(_.map(modules, _.bind(function (moduleName) {
            return this.getModuleDescription(moduleName, application);
          }, this)))
          .bind(this)
          .then(function (moduleDescriptions) {
            var lastDeployTimestamp = moment(application.lastDeploy[this.environment]);
            var applicationDeployFolder = path.join(org.gitFolder, application.gitRepo, lastDeployTimestamp.format('X'));
            return BBPromise.all(_.map(moduleDescriptions, _.bind(function (moduleDescription) {
              return this.getContext(application)
                .bind(this)
                .then(function (context) {
                  var jobData = {
                    application: context.application,
                    user: context.user,
                    environment: context.environment,
                    event: this.toJSON(),
                    applicationPath: applicationDeployFolder,
                    modulePath: moduleDescription.src,
                    moduleName: moduleDescription.name,
                    module: moduleDescription,
                    title: 'running module ' + moduleDescription.name
                  };
                  var job = kueProxy.get().create('RunModule', jobData)
                    .save(_.bind(function (err) {
                      if (err) {
                        logger.alert(err);
                        logger.error(err, 'unable to save execution job');
                      }
                      //execution should be done in two mins
                      this.timeouts[job.id] = setTimeout(function () {
                        var delayedError = new Error('RunModule job id ' + job.id + ' seems to be stuck on queue');
                        logger.alert(delayedError);
                        logger.error(delayedError);
                      }, 120000);
                    }, this));

                });
            }, this)));
          });

      });
    }).nodeify(callback);
};
module.exports = ApplicationEvent;
<commit_msg>cope with no module linked to event<commit_after>'use strict';
var BaseEvent = require('broker').events.ApplicationEvent;
var logger = require('hoist-logger');
var util = require('util');
var BBPromise = require('bluebird');
var Model = require('hoist-model');
var Session = Model.Session;
var AppUser = Model.AppUser;
var Organisation = Model.Organisation;
var Application = Model.Application;
var path = require('path');
var _ = require('lodash');
var kueProxy = require('../kue_proxy');
var moment = require('moment');

function ApplicationEvent(properties) {
  BaseEvent.call(this, properties);
  _.bindAll(this);
}

util.inherits(ApplicationEvent, BaseEvent);

ApplicationEvent.QueueName = 'application_event';
ApplicationEvent.prototype.getModuleDescription = function (moduleName, application) {
  return BBPromise.try(function () {
    var module = null;
    var settings = application.settings[this.environment];
    if (settings) {
      module = _.find(settings.modules, function (moduleDesc) {
        return moduleDesc.name === moduleName;
      });
    }
    return module;
  }, [], this);
};
ApplicationEvent.prototype.getContext = function (application) {
  var context = {};
  var pipeline = [];
  context.applicationId = this.applicationId;
  context.environment = this.environment;
  if (this.sessionId) {
    pipeline.push(Session.findOneAsync({
        _id: this.sessionId
      })
      .then(function (session) {
        if (session) {
          context.sessionId = session._id;
          if (session.appUser) {
            return AppUser.findOneAsync({
              _id: session.appUser
            }).then(function (appUser) {
              if (appUser) {
                context.user = appUser.toObject();
              }
            });
          }
        }
      }));
  }

  context.application = application.toObject();

  return BBPromise.all(pipeline).then(function () {
    return context;
  });
};
ApplicationEvent.prototype.getEventDescription = function (application) {
  var environment = this.environment || 'live';
  var settings = application.settings[environment];
  return settings.on[this.eventName];
};
ApplicationEvent.prototype.registerJobComplete = function (id) {
  if (this.timeouts[id]) {
    this.decrementJob(id);
    require('kue').Job.get(id, function (err, job) {
      if (err) {
        return;
      }
      job.remove(function (err) {
        if (err) {
          throw err;
        }
        logger.info(util.format('removed completed job #%d', job.id));
      });
    });
  }
};
ApplicationEvent.prototype.registerJobFailed = function (id) {
  console.log('job failed', arguments);
  if (this.timeouts[id]) {
    this.decrementJob(id);
    require('kue').Job.log(id, function (err, logs) {
      console.log(logs);
    });
  }
};
ApplicationEvent.prototype.decrementJob = function (id) {
  clearTimeout(this.timeouts[id]);
  this.executionCount--;
  if (this.executionCount < 1) {
    clearInterval(this.pingInterval);
    kueProxy.get().removeListener('job failed', this.registerJobFailed);
    kueProxy.get().removeListener('job complete', this.registerJobComplete);
    this.emit('done');
  }
};
ApplicationEvent.prototype.process = function (callback) {
  return Application.findOneAsync({
      _id: this.applicationId
    })
    .bind(this)
    .then(function (application) {
      return Organisation.findOneAsync({
        _id: application.organisation
      }).bind(this).then(function (org) {

        var eventDescription = this.getEventDescription(application);
        if(!eventDescription){
          this.emit('done');
          return;
        }
        var modules = eventDescription.modules;
        if (!modules || modules.length < 1) {
          this.emit('done');
          return;
        }
        this.timeouts = {};
        this.pingInterval = setInterval(_.bind(function () {
          logger.debug('emitting ping');
          this.emit('ping');
        }, this), 30000);
        this.executionCount = modules.length;
        kueProxy.get().on('job failed', this.registerJobFailed);
        kueProxy.get().on('job complete', this.registerJobComplete);
        return BBPromise.all(_.map(modules, _.bind(function (moduleName) {
            return this.getModuleDescription(moduleName, application);
          }, this)))
          .bind(this)
          .then(function (moduleDescriptions) {
            var lastDeployTimestamp = moment(application.lastDeploy[this.environment]);
            var applicationDeployFolder = path.join(org.gitFolder, application.gitRepo, lastDeployTimestamp.format('X'));
            return BBPromise.all(_.map(moduleDescriptions, _.bind(function (moduleDescription) {
              return this.getContext(application)
                .bind(this)
                .then(function (context) {
                  var jobData = {
                    application: context.application,
                    user: context.user,
                    environment: context.environment,
                    event: this.toJSON(),
                    applicationPath: applicationDeployFolder,
                    modulePath: moduleDescription.src,
                    moduleName: moduleDescription.name,
                    module: moduleDescription,
                    title: 'running module ' + moduleDescription.name
                  };
                  var job = kueProxy.get().create('RunModule', jobData)
                    .save(_.bind(function (err) {
                      if (err) {
                        logger.alert(err);
                        logger.error(err, 'unable to save execution job');
                      }
                      //execution should be done in two mins
                      this.timeouts[job.id] = setTimeout(function () {
                        var delayedError = new Error('RunModule job id ' + job.id + ' seems to be stuck on queue');
                        logger.alert(delayedError);
                        logger.error(delayedError);
                      }, 120000);
                    }, this));

                });
            }, this)));
          });

      });
    }).nodeify(callback);
};
module.exports = ApplicationEvent;
<|endoftext|>


<commit_before>self.name = 'eventsource.sharedworker.js';

const sourcesByUrl = {};
const sourcesByPort = {};

class Source {
  constructor(url) {
    this.url = url;
    this.eventSource = new EventSource(url);
    this.listening = {};
    this.clients = [];
    this.listen('open');
    this.listen('close');
    this.listen('logout');
    this.listen('notification-count');
    this.listen('stopwatches');
    this.listen('error');
  }

  register(port) {
    if (this.clients.includes(port)) return;

    this.clients.push(port);

    port.postMessage({
      type: 'status',
      message: `registered to ${this.url}`,
    });
  }

  deregister(port) {
    const portIdx = this.clients.indexOf(port);
    if (portIdx < 0) {
      return this.clients.length;
    }
    this.clients.splice(portIdx, 1);
    return this.clients.length;
  }

  close() {
    if (!this.eventSource) return;

    this.eventSource.close();
    this.eventSource = null;
  }

  listen(eventType) {
    if (this.listening[eventType]) return;
    this.listening[eventType] = true;
    this.eventSource.addEventListener(eventType, (event) => {
      this.notifyClients({
        type: eventType,
        data: event.data
      });
    });
  }

  notifyClients(event) {
    for (const client of this.clients) {
      client.postMessage(event);
    }
  }

  status(port) {
    port.postMessage({
      type: 'status',
      message: `url: ${this.url} readyState: ${this.eventSource.readyState}`,
    });
  }
}

self.onconnect = (e) => {
  for (const port of e.ports) {
    port.addEventListener('message', (event) => {
      if (event.data.type === 'start') {
        const url = event.data.url;
        if (sourcesByUrl[url]) {
          // we have a Source registered to this url
          const source = sourcesByUrl[url];
          source.register(port);
          sourcesByPort[port] = source;
          return;
        }
        let source = sourcesByPort[port];
        if (source) {
          if (source.eventSource && source.url === url) return;

          // How this has happened I don't understand...
          // deregister from that source
          const count = source.deregister(port);
          // Clean-up
          if (count === 0) {
            source.close();
            sourcesByUrl[source.url] = null;
          }
        }
        // Create a new Source
        source = new Source(url);
        source.register(port);
        sourcesByUrl[url] = source;
        sourcesByPort[port] = source;
      } else if (event.data.type === 'listen') {
        const source = sourcesByPort[port];
        source.listen(event.data.eventType);
      } else if (event.data.type === 'close') {
        const source = sourcesByPort[port];

        if (!source) return;

        const count = source.deregister(port);
        if (count === 0) {
          source.close();
          sourcesByUrl[source.url] = null;
          sourcesByPort[port] = null;
        }
      } else if (event.data.type === 'status') {
        const source = sourcesByPort[port];
        if (!source) {
          port.postMessage({
            type: 'status',
            message: 'not connected',
          });
          return;
        }
        source.status(port);
      } else {
        // just send it back
        port.postMessage({
          type: 'error',
          message: `received but don't know how to handle: ${event.data}`,
        });
      }
    });
    port.start();
  }
};
<commit_msg>Remove spurious set name from eventsource.sharedworker.js (#15643)<commit_after>const sourcesByUrl = {};
const sourcesByPort = {};

class Source {
  constructor(url) {
    this.url = url;
    this.eventSource = new EventSource(url);
    this.listening = {};
    this.clients = [];
    this.listen('open');
    this.listen('close');
    this.listen('logout');
    this.listen('notification-count');
    this.listen('stopwatches');
    this.listen('error');
  }

  register(port) {
    if (this.clients.includes(port)) return;

    this.clients.push(port);

    port.postMessage({
      type: 'status',
      message: `registered to ${this.url}`,
    });
  }

  deregister(port) {
    const portIdx = this.clients.indexOf(port);
    if (portIdx < 0) {
      return this.clients.length;
    }
    this.clients.splice(portIdx, 1);
    return this.clients.length;
  }

  close() {
    if (!this.eventSource) return;

    this.eventSource.close();
    this.eventSource = null;
  }

  listen(eventType) {
    if (this.listening[eventType]) return;
    this.listening[eventType] = true;
    this.eventSource.addEventListener(eventType, (event) => {
      this.notifyClients({
        type: eventType,
        data: event.data
      });
    });
  }

  notifyClients(event) {
    for (const client of this.clients) {
      client.postMessage(event);
    }
  }

  status(port) {
    port.postMessage({
      type: 'status',
      message: `url: ${this.url} readyState: ${this.eventSource.readyState}`,
    });
  }
}

self.onconnect = (e) => {
  for (const port of e.ports) {
    port.addEventListener('message', (event) => {
      if (event.data.type === 'start') {
        const url = event.data.url;
        if (sourcesByUrl[url]) {
          // we have a Source registered to this url
          const source = sourcesByUrl[url];
          source.register(port);
          sourcesByPort[port] = source;
          return;
        }
        let source = sourcesByPort[port];
        if (source) {
          if (source.eventSource && source.url === url) return;

          // How this has happened I don't understand...
          // deregister from that source
          const count = source.deregister(port);
          // Clean-up
          if (count === 0) {
            source.close();
            sourcesByUrl[source.url] = null;
          }
        }
        // Create a new Source
        source = new Source(url);
        source.register(port);
        sourcesByUrl[url] = source;
        sourcesByPort[port] = source;
      } else if (event.data.type === 'listen') {
        const source = sourcesByPort[port];
        source.listen(event.data.eventType);
      } else if (event.data.type === 'close') {
        const source = sourcesByPort[port];

        if (!source) return;

        const count = source.deregister(port);
        if (count === 0) {
          source.close();
          sourcesByUrl[source.url] = null;
          sourcesByPort[port] = null;
        }
      } else if (event.data.type === 'status') {
        const source = sourcesByPort[port];
        if (!source) {
          port.postMessage({
            type: 'status',
            message: 'not connected',
          });
          return;
        }
        source.status(port);
      } else {
        // just send it back
        port.postMessage({
          type: 'error',
          message: `received but don't know how to handle: ${event.data}`,
        });
      }
    });
    port.start();
  }
};
<|endoftext|>


<commit_before>import React from "react";
import { MountService } from "foundation-ui";

import ConfigurationMapHeading
  from "#SRC/js/components/ConfigurationMapHeading";
import ConfigurationMapSection
  from "#SRC/js/components/ConfigurationMapSection";

import {
  getSharedIconWithLabel,
  getContainerNameWithIcon
} from "../utils/ServiceConfigDisplayUtil";
import ConfigurationMapTable from "../components/ConfigurationMapTable";

const columns = [
  {
    heading: "Key",
    prop: "key"
  },
  {
    heading: "Value",
    prop: "value"
  },
  {
    heading: "Container",
    prop: "container"
  }
];

const PodEnvironmentVariablesConfigSection = ({ appConfig, onEditClick }) => {
  const { environment = {}, containers = [] } = appConfig;

  if (!environment || !containers) {
    return ;
  }

  let combinedEnv = Object.keys(environment)
    .filter(function(key) {
      return typeof environment[key] === "string";
    })
    .reduce((memo, key) => {
      memo.push({
        key: {key},
        value: environment[key],
        container: getSharedIconWithLabel()
      });

      return memo;
    }, []);

  combinedEnv = containers.reduce((memo, container) => {
    const { environment = {} } = container;

    return Object.keys(environment).reduce((cvMemo, key) => {
      cvMemo.push({
        key: {key},
        value: environment[key],
        container: getContainerNameWithIcon(container)
      });

      return cvMemo;
    }, memo);
  }, combinedEnv);

  if (!combinedEnv.length) {
    return ;
  }

  return (

      <ConfigurationMapHeading level={1}>
        Environment Variables
      </ConfigurationMapHeading>
      <ConfigurationMapSection key="pod-general-section">
        <MountService.Mount
          type="CreateService:ServiceConfigDisplay:Pod:EnvironmentVariables"
          appConfig={this.props.appConfig}
          onEditClick={onEditClick}
        >
          <ConfigurationMapTable
            columnDefaults={{ hideIfEmpty: true }}
            columns={columns}
            data={combinedEnv}
            onEditClick={onEditClick}
            tabViewID="multienvironment"
          />
        </MountService.Mount>
      </ConfigurationMapSection>

  );
};

PodEnvironmentVariablesConfigSection.propTypes = {
  onEditClick: React.PropTypes.func
};

module.exports = PodEnvironmentVariablesConfigSection;
<commit_msg>fix(PodEnvironmentVariablesConfigSection): fix props<commit_after>import React from "react";
import { MountService } from "foundation-ui";

import ConfigurationMapHeading
  from "#SRC/js/components/ConfigurationMapHeading";
import ConfigurationMapSection
  from "#SRC/js/components/ConfigurationMapSection";

import {
  getSharedIconWithLabel,
  getContainerNameWithIcon
} from "../utils/ServiceConfigDisplayUtil";
import ConfigurationMapTable from "../components/ConfigurationMapTable";

const columns = [
  {
    heading: "Key",
    prop: "key"
  },
  {
    heading: "Value",
    prop: "value"
  },
  {
    heading: "Container",
    prop: "container"
  }
];

const PodEnvironmentVariablesConfigSection = ({ appConfig, onEditClick }) => {
  const { environment = {}, containers = [] } = appConfig;

  if (!environment || !containers) {
    return ;
  }

  let combinedEnv = Object.keys(environment)
    .filter(function(key) {
      return typeof environment[key] === "string";
    })
    .reduce((memo, key) => {
      memo.push({
        key: {key},
        value: environment[key],
        container: getSharedIconWithLabel()
      });

      return memo;
    }, []);

  combinedEnv = containers.reduce((memo, container) => {
    const { environment = {} } = container;

    return Object.keys(environment).reduce((cvMemo, key) => {
      cvMemo.push({
        key: {key},
        value: environment[key],
        container: getContainerNameWithIcon(container)
      });

      return cvMemo;
    }, memo);
  }, combinedEnv);

  if (!combinedEnv.length) {
    return ;
  }

  return (

      <ConfigurationMapHeading level={1}>
        Environment Variables
      </ConfigurationMapHeading>
      <ConfigurationMapSection key="pod-general-section">
        <MountService.Mount
          type="CreateService:ServiceConfigDisplay:Pod:EnvironmentVariables"
          appConfig={appConfig}
          onEditClick={onEditClick}
        >
          <ConfigurationMapTable
            columnDefaults={{ hideIfEmpty: true }}
            columns={columns}
            data={combinedEnv}
            onEditClick={onEditClick}
            tabViewID="multienvironment"
          />
        </MountService.Mount>
      </ConfigurationMapSection>

  );
};

PodEnvironmentVariablesConfigSection.propTypes = {
  onEditClick: React.PropTypes.func
};

module.exports = PodEnvironmentVariablesConfigSection;
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import {Emitter} from 'event-kit';

import {WorkdirContextPoolPropType} from '../prop-types';
import CommitDetailContainer from '../containers/commit-detail-container';
import RefHolder from '../models/ref-holder';

export default class CommitDetailItem extends React.Component {
  static propTypes = {
    workdirContextPool: WorkdirContextPoolPropType.isRequired,
    workingDirectory: PropTypes.string.isRequired,
    sha: PropTypes.string.isRequired,
  }

  static uriPattern = 'atom-github://commit-detail?workdir={workingDirectory}&sha={sha}'

  static buildURI(workingDirectory, sha) {
    return `atom-github://commit-detail?workdir=${encodeURIComponent(workingDirectory)}&sha=${encodeURIComponent(sha)}`;
  }

  constructor(props) {
    super(props);

    this.emitter = new Emitter();
    this.isDestroyed = false;
    this.hasTerminatedPendingState = false;
    this.refInitialFocus = new RefHolder();
  }

  terminatePendingState() {
    if (!this.hasTerminatedPendingState) {
      this.emitter.emit('did-terminate-pending-state');
      this.hasTerminatedPendingState = true;
    }
  }

  onDidTerminatePendingState(callback) {
    return this.emitter.on('did-terminate-pending-state', callback);
  }

  destroy = () => {
    /* istanbul ignore else */
    if (!this.isDestroyed) {
      this.emitter.emit('did-destroy');
      this.isDestroyed = true;
    }
  }

  onDidDestroy(callback) {
    return this.emitter.on('did-destroy', callback);
  }

  render() {
    const repository = this.props.workdirContextPool.getContext(this.props.workingDirectory).getRepository();

    return (
      <CommitDetailContainer
        itemType={this.constructor}
        repository={repository}
        {...this.props}
        destroy={this.destroy}
        refInitialFocus={this.refInitialFocus}
      />
    );
  }

  getTitle() {
    return `Commit: ${this.props.sha}`;
  }

  getIconName() {
    return 'git-commit';
  }

  getWorkingDirectory() {
    return this.props.workingDirectory;
  }

  getSha() {
    return this.props.sha;
  }

  serialize() {
    return {
      deserializer: 'CommitDetailStub',
      uri: CommitDetailItem.buildURI(this.props.workingDirectory, this.props.sha),
    };
  }

  focus() {
    this.refInitialFocus.map(focusable => focusable.focus());
  }
}
<commit_msg>Focus refInitialFocus even if it isn't available right away<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import {Emitter} from 'event-kit';

import {WorkdirContextPoolPropType} from '../prop-types';
import CommitDetailContainer from '../containers/commit-detail-container';
import RefHolder from '../models/ref-holder';

export default class CommitDetailItem extends React.Component {
  static propTypes = {
    workdirContextPool: WorkdirContextPoolPropType.isRequired,
    workingDirectory: PropTypes.string.isRequired,
    sha: PropTypes.string.isRequired,
  }

  static uriPattern = 'atom-github://commit-detail?workdir={workingDirectory}&sha={sha}'

  static buildURI(workingDirectory, sha) {
    return `atom-github://commit-detail?workdir=${encodeURIComponent(workingDirectory)}&sha=${encodeURIComponent(sha)}`;
  }

  constructor(props) {
    super(props);

    this.emitter = new Emitter();
    this.isDestroyed = false;
    this.hasTerminatedPendingState = false;
    this.refInitialFocus = new RefHolder();
  }

  terminatePendingState() {
    if (!this.hasTerminatedPendingState) {
      this.emitter.emit('did-terminate-pending-state');
      this.hasTerminatedPendingState = true;
    }
  }

  onDidTerminatePendingState(callback) {
    return this.emitter.on('did-terminate-pending-state', callback);
  }

  destroy = () => {
    /* istanbul ignore else */
    if (!this.isDestroyed) {
      this.emitter.emit('did-destroy');
      this.isDestroyed = true;
    }
  }

  onDidDestroy(callback) {
    return this.emitter.on('did-destroy', callback);
  }

  render() {
    const repository = this.props.workdirContextPool.getContext(this.props.workingDirectory).getRepository();

    return (
      <CommitDetailContainer
        itemType={this.constructor}
        repository={repository}
        {...this.props}
        destroy={this.destroy}
        refInitialFocus={this.refInitialFocus}
      />
    );
  }

  getTitle() {
    return `Commit: ${this.props.sha}`;
  }

  getIconName() {
    return 'git-commit';
  }

  getWorkingDirectory() {
    return this.props.workingDirectory;
  }

  getSha() {
    return this.props.sha;
  }

  serialize() {
    return {
      deserializer: 'CommitDetailStub',
      uri: CommitDetailItem.buildURI(this.props.workingDirectory, this.props.sha),
    };
  }

  focus() {
    this.refInitialFocus.getPromise().then(focusable => focusable.focus());
  }
}
<|endoftext|>


<commit_before>/**
 * DashboardAllTrafficWidget component
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * WordPress dependencies
 */
import { _x } from '@wordpress/i18n';
import { useState, useEffect } from '@wordpress/element';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { FORM_ALL_TRAFFIC_WIDGET, DATE_RANGE_OFFSET, MODULES_ANALYTICS } from '../../../datastore/constants';
import { CORE_FORMS } from '../../../../../googlesitekit/datastore/forms/constants';
import { CORE_SITE } from '../../../../../googlesitekit/datastore/site/constants';
import { CORE_USER } from '../../../../../googlesitekit/datastore/user/constants';
import { Grid, Row, Cell } from '../../../../../material-components/layout';
import { getURLPath } from '../../../../../util/getURLPath';
import whenActive from '../../../../../util/when-active';
import SourceLink from '../../../../../components/SourceLink';
import ReportError from '../../../../../components/ReportError';
import TotalUserCount from './TotalUserCount';
import UserCountGraph from './UserCountGraph';
import DimensionTabs from './DimensionTabs';
import UserDimensionsPieChart from './UserDimensionsPieChart';
import { isZeroReport } from '../../../util';
const { useSelect } = Data;

function DashboardAllTrafficWidget( { Widget, WidgetReportZero } ) {
	const [ firstLoad, setFirstLoad ] = useState( true );
	const [ currentRange, setCurrentRange ] = useState( '' );

	const dateRange = useSelect( ( select ) => select( CORE_USER ).getDateRange() );
	const dimensionName = useSelect( ( select ) => select( CORE_FORMS ).getValue( FORM_ALL_TRAFFIC_WIDGET, 'dimensionName' ) || 'ga:channelGrouping' );
	const dimensionValue = useSelect( ( select ) => select( CORE_FORMS ).getValue( FORM_ALL_TRAFFIC_WIDGET, 'dimensionValue' ) );
	const entityURL = useSelect( ( select ) => select( CORE_SITE ).getCurrentEntityURL() );

	const {
		startDate,
		endDate,
		compareStartDate,
		compareEndDate,
	} = useSelect( ( select ) => select( CORE_USER ).getDateRangeDates( {
		compare: true,
		offsetDays: DATE_RANGE_OFFSET,
	} ) );

	const baseArgs = {
		startDate,
		endDate,
		metrics: [ { expression: 'ga:users' } ],
	};

	const pieArgs = {
		...baseArgs,
		compareStartDate,
		compareEndDate,
		dimensions: [ dimensionName ],
		orderby: {
			fieldName: 'ga:users',
			sortOrder: 'DESCENDING',
		},
		limit: 6,
	};

	const graphArgs = {
		...baseArgs,
		dimensions: [ 'ga:date' ],
	};

	const totalsArgs = {
		...baseArgs,
		compareStartDate,
		compareEndDate,
	};

	if ( entityURL ) {
		pieArgs.url = entityURL;
		graphArgs.url = entityURL;
		totalsArgs.url = entityURL;
	}

	if ( dimensionName && dimensionValue ) {
		graphArgs.dimensionFilters = { [ dimensionName ]: dimensionValue };
		totalsArgs.dimensionFilters = { [ dimensionName ]: dimensionValue };
	}

	const pieChartLoaded = useSelect( ( select ) => select( MODULES_ANALYTICS ).hasFinishedResolution( 'getReport', [ pieArgs ] ) );
	const pieChartError = useSelect( ( select ) => select( MODULES_ANALYTICS ).getErrorForSelector( 'getReport', [ pieArgs ] ) );
	const pieChartReport = useSelect( ( select ) => select( MODULES_ANALYTICS ).getReport( pieArgs ) );

	const userCountGraphLoaded = useSelect( ( select ) => select( MODULES_ANALYTICS ).hasFinishedResolution( 'getReport', [ graphArgs ] ) );
	const userCountGraphError = useSelect( ( select ) => select( MODULES_ANALYTICS ).getErrorForSelector( 'getReport', [ graphArgs ] ) );
	const userCountGraphReport = useSelect( ( select ) => select( MODULES_ANALYTICS ).getReport( graphArgs ) );

	const totalUsersLoaded = useSelect( ( select ) => select( MODULES_ANALYTICS ).hasFinishedResolution( 'getReport', [ totalsArgs ] ) );
	const totalUsersError = useSelect( ( select ) => select( MODULES_ANALYTICS ).getErrorForSelector( 'getReport', [ totalsArgs ] ) );
	const totalUsersReport = useSelect( ( select ) => select( MODULES_ANALYTICS ).getReport( totalsArgs ) );

	let reportType;
	switch ( dimensionName ) {
		case 'ga:country':
			reportType = 'visitors-geo';
			break;
		case 'ga:deviceCategory':
			reportType = 'visitors-mobile-overview';
			break;
		case 'ga:channelGrouping':
		default:
			reportType = 'trafficsources-overview';
			break;
	}

	let reportArgs = {};
	if ( entityURL ) {
		reportArgs = {
			'explorer-table.plotKeys': '[]',
			'_r.drilldown': `analytics.pagePath:${ getURLPath( entityURL ) }`,
		};
	}

	const serviceReportURL = useSelect( ( select ) => select( MODULES_ANALYTICS ).getServiceReportURL( reportType, reportArgs ) );

	useEffect( () => {
		if ( dateRange !== currentRange ) {
			setFirstLoad( true );
			setCurrentRange( dateRange );
		} else if ( pieChartLoaded && totalUsersLoaded && userCountGraphLoaded ) {
			setFirstLoad( false );
		}
	}, [
		pieChartLoaded,
		totalUsersLoaded,
		userCountGraphLoaded,
		dateRange,
		currentRange,
	] );

	if ( pieChartError ) {
		return <ReportError moduleSlug="analytics" error={ pieChartError } />;
	}

	if ( isZeroReport( pieChartReport ) ) {
		return <WidgetReportZero />;
	}

	return (
		<Widget
			className="googlesitekit-widget--footer-v2"
			Footer={ () => (
				<SourceLink
					className="googlesitekit-data-block__source"
					name={ _x( 'Analytics', 'Service name', 'google-site-kit' ) }
					href={ serviceReportURL }
					external
				/>
			) }
			noPadding
		>
			<Grid>
				<Row>
					<Cell
						className="googlesitekit-widget--analyticsAllTraffic__totals"
						lgSize={ 7 }
						mdSize={ 8 }
					>
						<TotalUserCount
							loaded={ totalUsersLoaded && ! firstLoad }
							report={ totalUsersReport }
							error={ totalUsersError }
							dimensionValue={ dimensionValue }
						/>

						<UserCountGraph
							loaded={ userCountGraphLoaded && ! firstLoad }
							error={ userCountGraphError }
							report={ userCountGraphReport }
						/>
					</Cell>

					<Cell
						className="googlesitekit-widget--analyticsAllTraffic__dimensions"
						lgSize={ 5 }
						mdSize={ 8 }
					>
						<DimensionTabs
							loaded={ ! firstLoad }
							dimensionName={ dimensionName }
						/>

						<UserDimensionsPieChart
							dimensionName={ dimensionName }
							dimensionValue={ dimensionValue }
							sourceLink={ serviceReportURL }
							loaded={ pieChartLoaded && ! firstLoad }
							report={ pieChartReport }
						/>
					</Cell>
				</Row>
			</Grid>
		</Widget>
	);
}

export default whenActive( { moduleName: 'analytics' } )( DashboardAllTrafficWidget );
<commit_msg>Add missing moduleSlug prop for WidgetReportZero.<commit_after>/**
 * DashboardAllTrafficWidget component
 *
 * Site Kit by Google, Copyright 2021 Google LLC
 *
 * 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
 *
 *     https://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.
 */

/**
 * WordPress dependencies
 */
import { _x } from '@wordpress/i18n';
import { useState, useEffect } from '@wordpress/element';

/**
 * Internal dependencies
 */
import Data from 'googlesitekit-data';
import { FORM_ALL_TRAFFIC_WIDGET, DATE_RANGE_OFFSET, MODULES_ANALYTICS } from '../../../datastore/constants';
import { CORE_FORMS } from '../../../../../googlesitekit/datastore/forms/constants';
import { CORE_SITE } from '../../../../../googlesitekit/datastore/site/constants';
import { CORE_USER } from '../../../../../googlesitekit/datastore/user/constants';
import { Grid, Row, Cell } from '../../../../../material-components/layout';
import { getURLPath } from '../../../../../util/getURLPath';
import whenActive from '../../../../../util/when-active';
import SourceLink from '../../../../../components/SourceLink';
import ReportError from '../../../../../components/ReportError';
import TotalUserCount from './TotalUserCount';
import UserCountGraph from './UserCountGraph';
import DimensionTabs from './DimensionTabs';
import UserDimensionsPieChart from './UserDimensionsPieChart';
import { isZeroReport } from '../../../util';
const { useSelect } = Data;

function DashboardAllTrafficWidget( { Widget, WidgetReportZero } ) {
	const [ firstLoad, setFirstLoad ] = useState( true );
	const [ currentRange, setCurrentRange ] = useState( '' );

	const dateRange = useSelect( ( select ) => select( CORE_USER ).getDateRange() );
	const dimensionName = useSelect( ( select ) => select( CORE_FORMS ).getValue( FORM_ALL_TRAFFIC_WIDGET, 'dimensionName' ) || 'ga:channelGrouping' );
	const dimensionValue = useSelect( ( select ) => select( CORE_FORMS ).getValue( FORM_ALL_TRAFFIC_WIDGET, 'dimensionValue' ) );
	const entityURL = useSelect( ( select ) => select( CORE_SITE ).getCurrentEntityURL() );

	const {
		startDate,
		endDate,
		compareStartDate,
		compareEndDate,
	} = useSelect( ( select ) => select( CORE_USER ).getDateRangeDates( {
		compare: true,
		offsetDays: DATE_RANGE_OFFSET,
	} ) );

	const baseArgs = {
		startDate,
		endDate,
		metrics: [ { expression: 'ga:users' } ],
	};

	const pieArgs = {
		...baseArgs,
		compareStartDate,
		compareEndDate,
		dimensions: [ dimensionName ],
		orderby: {
			fieldName: 'ga:users',
			sortOrder: 'DESCENDING',
		},
		limit: 6,
	};

	const graphArgs = {
		...baseArgs,
		dimensions: [ 'ga:date' ],
	};

	const totalsArgs = {
		...baseArgs,
		compareStartDate,
		compareEndDate,
	};

	if ( entityURL ) {
		pieArgs.url = entityURL;
		graphArgs.url = entityURL;
		totalsArgs.url = entityURL;
	}

	if ( dimensionName && dimensionValue ) {
		graphArgs.dimensionFilters = { [ dimensionName ]: dimensionValue };
		totalsArgs.dimensionFilters = { [ dimensionName ]: dimensionValue };
	}

	const pieChartLoaded = useSelect( ( select ) => select( MODULES_ANALYTICS ).hasFinishedResolution( 'getReport', [ pieArgs ] ) );
	const pieChartError = useSelect( ( select ) => select( MODULES_ANALYTICS ).getErrorForSelector( 'getReport', [ pieArgs ] ) );
	const pieChartReport = useSelect( ( select ) => select( MODULES_ANALYTICS ).getReport( pieArgs ) );

	const userCountGraphLoaded = useSelect( ( select ) => select( MODULES_ANALYTICS ).hasFinishedResolution( 'getReport', [ graphArgs ] ) );
	const userCountGraphError = useSelect( ( select ) => select( MODULES_ANALYTICS ).getErrorForSelector( 'getReport', [ graphArgs ] ) );
	const userCountGraphReport = useSelect( ( select ) => select( MODULES_ANALYTICS ).getReport( graphArgs ) );

	const totalUsersLoaded = useSelect( ( select ) => select( MODULES_ANALYTICS ).hasFinishedResolution( 'getReport', [ totalsArgs ] ) );
	const totalUsersError = useSelect( ( select ) => select( MODULES_ANALYTICS ).getErrorForSelector( 'getReport', [ totalsArgs ] ) );
	const totalUsersReport = useSelect( ( select ) => select( MODULES_ANALYTICS ).getReport( totalsArgs ) );

	let reportType;
	switch ( dimensionName ) {
		case 'ga:country':
			reportType = 'visitors-geo';
			break;
		case 'ga:deviceCategory':
			reportType = 'visitors-mobile-overview';
			break;
		case 'ga:channelGrouping':
		default:
			reportType = 'trafficsources-overview';
			break;
	}

	let reportArgs = {};
	if ( entityURL ) {
		reportArgs = {
			'explorer-table.plotKeys': '[]',
			'_r.drilldown': `analytics.pagePath:${ getURLPath( entityURL ) }`,
		};
	}

	const serviceReportURL = useSelect( ( select ) => select( MODULES_ANALYTICS ).getServiceReportURL( reportType, reportArgs ) );

	useEffect( () => {
		if ( dateRange !== currentRange ) {
			setFirstLoad( true );
			setCurrentRange( dateRange );
		} else if ( pieChartLoaded && totalUsersLoaded && userCountGraphLoaded ) {
			setFirstLoad( false );
		}
	}, [
		pieChartLoaded,
		totalUsersLoaded,
		userCountGraphLoaded,
		dateRange,
		currentRange,
	] );

	if ( pieChartError ) {
		return <ReportError moduleSlug="analytics" error={ pieChartError } />;
	}

	if ( isZeroReport( pieChartReport ) ) {
		return <WidgetReportZero moduleSlug="analytics" />;
	}

	return (
		<Widget
			className="googlesitekit-widget--footer-v2"
			Footer={ () => (
				<SourceLink
					className="googlesitekit-data-block__source"
					name={ _x( 'Analytics', 'Service name', 'google-site-kit' ) }
					href={ serviceReportURL }
					external
				/>
			) }
			noPadding
		>
			<Grid>
				<Row>
					<Cell
						className="googlesitekit-widget--analyticsAllTraffic__totals"
						lgSize={ 7 }
						mdSize={ 8 }
					>
						<TotalUserCount
							loaded={ totalUsersLoaded && ! firstLoad }
							report={ totalUsersReport }
							error={ totalUsersError }
							dimensionValue={ dimensionValue }
						/>

						<UserCountGraph
							loaded={ userCountGraphLoaded && ! firstLoad }
							error={ userCountGraphError }
							report={ userCountGraphReport }
						/>
					</Cell>

					<Cell
						className="googlesitekit-widget--analyticsAllTraffic__dimensions"
						lgSize={ 5 }
						mdSize={ 8 }
					>
						<DimensionTabs
							loaded={ ! firstLoad }
							dimensionName={ dimensionName }
						/>

						<UserDimensionsPieChart
							dimensionName={ dimensionName }
							dimensionValue={ dimensionValue }
							sourceLink={ serviceReportURL }
							loaded={ pieChartLoaded && ! firstLoad }
							report={ pieChartReport }
						/>
					</Cell>
				</Row>
			</Grid>
		</Widget>
	);
}

export default whenActive( { moduleName: 'analytics' } )( DashboardAllTrafficWidget );
<|endoftext|>


<commit_before>'use strict';

function Floating2DText(w, text, type, world, syntax_checks) {
    this.__init__(w, text, type, world, syntax_checks);
}

const TEMP_SMUDGE_FACTOR = 0.75;

Floating2DText.prototype = {

    material: null,
    dynamic_texture: null,

    tool_tip_text: null,

    _get_text_length: function() {
        return this.dynamic_texture.getTextLength(this.text);
    },

    refresh_for_2D_text: function() {
        if (this.type === TYPE_ICON) {
            // TODO :
            //l('REFRESH THIS ICON!!');
        } else {
            var x_offset = 0;
            if (this.type === TYPE_BUTTON || this.type === TYPE_CHECK_BOX || this.type === TYPE_TITLE || this.type === TYPE_SUPER_TITLE) {
                x_offset = this.texture_width / 2 - this._get_text_length() / 2;
            }
            if (this.current_background_color !== COLOR_TRANSPARENT) {
                this.dynamic_texture.clear(this.current_background_color).drawText(this.text, x_offset, this.font_size * TEMP_SMUDGE_FACTOR, this.current_color, this.current_background_color);
            } else {
                //this.dynamic_texture.clear().drawText(this.text, x_offset, this.font_size * TEMP_SMUDGE_FACTOR, this.current_color, this.current_background_color);
                this.dynamic_texture.clear(this.current_background_color).drawText(this.text, x_offset, this.font_size * TEMP_SMUDGE_FACTOR, this.current_color, this.current_background_color);
            }
            this.dynamic_texture.needsUpdate = true;
        }
    },

    __init__: function(w, text, type, world, syntax_checks) {
        // Inherit from Atachmentable.
        Attachmentable.call(this, world);

        if (is_defined(syntax_checks)) {
            // Inherit from TextSyntax.
            TextSyntax.call(this, syntax_checks);
        }

        // Inherit from FloatingText.
        FloatingText.call(this, text, type, true);

        // Inherit from Animatable.
        Animatable.call(this);

        this.width = w;
        if (type === TYPE_SUPER_TITLE) {
            this.height = 36;
        } else if (type === TYPE_TITLE) {
            this.height = 26;
        } else {
            this.height = 16;
        }

        if (this.type === TYPE_ICON) {
            // TODO : Create a cleaner design in the future.
            if (this.text === CURSOR_TYPE_HORIZONTAL || this.text === CURSOR_TYPE_VERTICAL || this.text === CURSOR_TYPE_HAND || this.text === CURSOR_TYPE_POINTER || this.text === CURSOR_TYPE_LARGER || this.text === CURSOR_TYPE_MOUSE) {
                this.material = new THREE.MeshBasicMaterial({map : MANAGER_TEXTURE.get_texture(TEXTURE_GROUP_CURSOR, this.text), transparent : true});
            } else {
                this.material = new THREE.MeshBasicMaterial({map : MANAGER_TEXTURE.get_texture(TEXTURE_GROUP_ICONS, this.text)});
            }
        } else {
            this.texture_width = get_nearest_power_of_two_for_number(this.width * 2);
            var texture_height = get_nearest_power_of_two_for_number(this.height * 2);
            this.font_size = texture_height;

            this.dynamic_texture = new THREEx.DynamicTexture(this.texture_width, texture_height);
            if (this.type === TYPE_TITLE || this.type === TYPE_CONSTANT || this.type === TYPE_BUTTON) {
                this.dynamic_texture.context.font = 'Bold ' + str(this.font_size) + 'px Arial';
            } else {
                this.dynamic_texture.context.font = str(this.font_size) + 'px Arial';
            }
            this.dynamic_texture.texture.anisotropy = MANAGER_RENDERER.renderer.capabilities.getMaxAnisotropy();

            this.material = new THREE.MeshBasicMaterial({
                map : this.dynamic_texture.texture
            });
        }
        this.material.transparent = true;
        // TODO : DoubleSide is temporary
        this.material.side = THREE.DoubleSide;

        this.create_base_mesh();

        // Inherit from Interactive.
        Interactive.call(this);
        // Inherit from Visibility.
        Visibility.call(this);

        this.final_initialize();
    },

    /*__   __   ___      ___    __
     /  ` |__) |__   /\   |  | /  \ |\ |
     \__, |  \ |___ /~~\  |  | \__/ | \| */
    create_base_mesh: function() {
        this.geometry = new THREE.PlaneGeometry(this.width, this.height);
        this.mesh = new THREE.Mesh(this.geometry, this.material);
        this.object3D.add(this.mesh);
    },

    /*__   ___  __   __        __   __   ___     __        ___                 __
     |__) |__  /__` /  \ |  | |__) /  ` |__     /  ` |    |__   /\  |\ | |  | |__)
     |  \ |___ .__/ \__/ \__/ |  \ \__, |___    \__, |___ |___ /~~\ | \| \__/ |    */
    delete_mesh: function() {
        if (is_defined(this.mesh)) {
            this.object3D.remove(this.mesh);
        }
        if (is_defined(this.geometry)) {
            this.geometry.dispose();
        }
    },

    full_remove: function() {
        if (is_defined(this.mesh)) {
            this.object3D.remove(this.mesh);
            // TODO : UPDATE THREE JS VERSION!
            //this.mesh.dispose();
        }
        if (is_defined(this.geometry)) {
            this.geometry.dispose();
        }
        if (is_defined(this.material)) {
            this.material.dispose();
        }
    },

};

/* ___  __   __      __   __             ___         ___       __   ___
  |__  /  \ |__)    /  ` /  \ |\ | \  / |__  |\ | | |__  |\ | /  ` |__
  |    \__/ |  \    \__, \__/ | \|  \/  |___ | \| | |___ | \| \__, |___ */
function get_new_floating_icon(icon_type, world) {
    return new Floating2DText(16, icon_type, TYPE_ICON, world);
}
<commit_msg>general updating 11<commit_after>'use strict';

function Floating2DText(w, text, type, world, syntax_checks) {
    this.__init__(w, text, type, world, syntax_checks);
}

const TEMP_SMUDGE_FACTOR = 0.75;

Floating2DText.prototype = {

    material: null,
    dynamic_texture: null,

    tool_tip_text: null,

    _get_text_length: function() {
        return this.dynamic_texture.getTextLength(this.text);
    },

    refresh_for_2D_text: function() {
        if (this.type === TYPE_ICON) {
            // TODO :
            //l('REFRESH THIS ICON!!');
        } else {
            var x_offset = 0;
            if (this.type === TYPE_BUTTON || this.type === TYPE_CHECK_BOX || this.type === TYPE_TITLE || this.type === TYPE_SUPER_TITLE) {
                x_offset = this.texture_width / 2 - this._get_text_length() / 2;
            }

            this.dynamic_texture.clear(this.current_background_color).drawText(this.text, x_offset, this.font_size * TEMP_SMUDGE_FACTOR, this.current_color);
            /*
            if (this.current_background_color !== COLOR_TRANSPARENT) {
                this.dynamic_texture.clear(this.current_background_color).drawText(this.text, x_offset, this.font_size * TEMP_SMUDGE_FACTOR, this.current_color, this.current_background_color);
            } else {
                //this.dynamic_texture.clear().drawText(this.text, x_offset, this.font_size * TEMP_SMUDGE_FACTOR, this.current_color, this.current_background_color);
                this.dynamic_texture.clear(this.current_background_color).drawText(this.text, x_offset, this.font_size * TEMP_SMUDGE_FACTOR, this.current_color, this.current_background_color);
            }
            */
            this.dynamic_texture.needsUpdate = true;
        }
    },

    __init__: function(w, text, type, world, syntax_checks) {
        // Inherit from Atachmentable.
        Attachmentable.call(this, world);

        if (is_defined(syntax_checks)) {
            // Inherit from TextSyntax.
            TextSyntax.call(this, syntax_checks);
        }

        // Inherit from FloatingText.
        FloatingText.call(this, text, type, true);

        // Inherit from Animatable.
        Animatable.call(this);

        this.width = w;
        if (type === TYPE_SUPER_TITLE) {
            this.height = 36;
        } else if (type === TYPE_TITLE) {
            this.height = 26;
        } else {
            this.height = 16;
        }

        if (this.type === TYPE_ICON) {
            // TODO : Create a cleaner design in the future.
            if (this.text === CURSOR_TYPE_HORIZONTAL || this.text === CURSOR_TYPE_VERTICAL || this.text === CURSOR_TYPE_HAND || this.text === CURSOR_TYPE_POINTER || this.text === CURSOR_TYPE_LARGER || this.text === CURSOR_TYPE_MOUSE) {
                this.material = new THREE.MeshBasicMaterial({map : MANAGER_TEXTURE.get_texture(TEXTURE_GROUP_CURSOR, this.text), transparent : true});
            } else {
                this.material = new THREE.MeshBasicMaterial({map : MANAGER_TEXTURE.get_texture(TEXTURE_GROUP_ICONS, this.text)});
            }
        } else {
            this.texture_width = get_nearest_power_of_two_for_number(this.width * 2);
            var texture_height = get_nearest_power_of_two_for_number(this.height * 2);
            this.font_size = texture_height;

            this.dynamic_texture = new THREEx.DynamicTexture(this.texture_width, texture_height);
            if (this.type === TYPE_TITLE || this.type === TYPE_CONSTANT || this.type === TYPE_BUTTON) {
                this.dynamic_texture.context.font = 'Bold ' + str(this.font_size) + 'px Arial';
            } else {
                this.dynamic_texture.context.font = str(this.font_size) + 'px Arial';
            }
            this.dynamic_texture.texture.anisotropy = MANAGER_RENDERER.renderer.capabilities.getMaxAnisotropy();

            this.material = new THREE.MeshBasicMaterial({
                map : this.dynamic_texture.texture
            });
        }
        this.material.transparent = true;
        // TODO : DoubleSide is temporary
        this.material.side = THREE.DoubleSide;

        this.create_base_mesh();

        // Inherit from Interactive.
        Interactive.call(this);
        // Inherit from Visibility.
        Visibility.call(this);

        this.final_initialize();
    },

    /*__   __   ___      ___    __
     /  ` |__) |__   /\   |  | /  \ |\ |
     \__, |  \ |___ /~~\  |  | \__/ | \| */
    create_base_mesh: function() {
        this.geometry = new THREE.PlaneGeometry(this.width, this.height);
        this.mesh = new THREE.Mesh(this.geometry, this.material);
        this.object3D.add(this.mesh);
    },

    /*__   ___  __   __        __   __   ___     __        ___                 __
     |__) |__  /__` /  \ |  | |__) /  ` |__     /  ` |    |__   /\  |\ | |  | |__)
     |  \ |___ .__/ \__/ \__/ |  \ \__, |___    \__, |___ |___ /~~\ | \| \__/ |    */
    delete_mesh: function() {
        if (is_defined(this.mesh)) {
            this.object3D.remove(this.mesh);
        }
        if (is_defined(this.geometry)) {
            this.geometry.dispose();
        }
    },

    full_remove: function() {
        if (is_defined(this.mesh)) {
            this.object3D.remove(this.mesh);
            // TODO : UPDATE THREE JS VERSION!
            //this.mesh.dispose();
        }
        if (is_defined(this.geometry)) {
            this.geometry.dispose();
        }
        if (is_defined(this.material)) {
            this.material.dispose();
        }
    },

};

/* ___  __   __      __   __             ___         ___       __   ___
  |__  /  \ |__)    /  ` /  \ |\ | \  / |__  |\ | | |__  |\ | /  ` |__
  |    \__/ |  \    \__, \__/ | \|  \/  |___ | \| | |___ | \| \__, |___ */
function get_new_floating_icon(icon_type, world) {
    return new Floating2DText(16, icon_type, TYPE_ICON, world);
}
<|endoftext|>