<commit_before>//TODO: Add copyright
//TODO: Test for large trees
//integrate https://square.github.io/crossfilter/ or similar for working with large data? not sure how tree generation/reading would work with it.
; (function (base, $, undefined) {
    base.CM = base.CM || {};
    var CM = base.CM;

    var docReady = $.Deferred();
    $(docReady.resolve);

    //$.wait = function (ms) {
    //    var dfd = $.Deferred();
    //    setTimeout(function () { dfd.resolve(); }, ms);
    //    return dfd;
    //};

    var cacheData = {};
    var delimiter = '/';//because we are using it later, we must always have one. Apparenly we can even have null keys, so use \x00 if we don't want a delimiter? I don't know if a c# key can contain a null.
    //var id_i = 0;//need hash function or something

    var CacheNode = function (key, text, id) {
        this.Key = key;
        this.Text = text;
        this.Children = {};//Nodes
        this.Values = [];//Values
        this.Id = id;
        this.ob_Checked = ko.observable(false);
    };

    var CacheValue = function (key, text, id) {
        this.Key = key;
        this.Text = text;
        this.Id = id;
    };

    CM.SortCacheKey = function (node1, node2) {
        var key1 = node1.Key;
        var key2 = node2.Key;

        //What order do we want?
        if (key1 < key2) return -1;
        if (key1 > key2) return 1;
        return 0;
    };

    CM.FindCacheKey = function (key, op_prefix) {
        op_prefix = op_prefix || false;
        return function (node) {
            if (op_prefix)
                return node.Key.indexOf(key) === 0;
            return node.Key === key;
        };
    };

    //var CacheRoot = {
    //    Children: {},
    //    Values: []
    //};

    CM.CopyrightYear = function () {
        return new Date().getUTCFullYear();
    };

    CM.Sort = function (array, op_sorter) {
        if ($.isFunction(op_sorter))
            return array.sort(op_sorter);
        return array.sort();
    };

    CM.Refresh = function () {
        $('.refresh-loading').removeClass('hidden');

        $.get('api/v1/cache')//'refresh' url? include freemem/other stats?
        .done(function (data) {
            cacheData.ob_Entries(data.Entries);
        });

        //TODO: Inline refresh (observables?)
        //document.location.reload();
    };

    CM.ClearRefreshSpinner = function () {
        $('.refresh-loading').addClass('hidden');
    };

    CM.GoBack = function () {
        document.location.href = './';
        //try {
        //    history.go(-1);
        //}
        //catch (e) { }
        //$.wait(100).then(function () {
        //    document.location = './';
        //});
    };

    CM.SetDelimiter = function (data) {
        //delimiter will already be set via two way input binding, this would also be caused by a refresh (use same button text?)
        //trigger re-draw of tree
        cacheData.ob_Delimiter(data.Delimiter);
    };

    CM.EnterDelimiter = function (data, e) {
        if (e.which === 13) {
            cacheData.ob_Delimiter(data.Delimiter);
        }
        return true;
    };

    CM.DeleteNode = function (key, op_prefix) {
        op_prefix = op_prefix || false;

        //Need to somehow keep checked state on redraw
        //Not sure how much I like spawning a new function for each one. Make each level a seperate observable? eww
        return function () {
            if (!op_prefix && (!cacheData.ConfirmDeleteKey || confirm('Are you sure you want to delete this cache value?\n\nKey: ' + key))) {
                $.post('api/v1/delete', { Key: key })
                .done(function (data) {
                    if (data.Success) {
                        //delete
                        cacheData.ob_Entries.remove(CM.FindCacheKey(key))
                    } else {
                        //error
                    }
                });
            } else if (op_prefix && (!cacheData.ConfirmDeletePrefix || confirm('Are you sure you want to delete everything with this prefix?\n\nPrefix: ' + key))) {
                $.post('api/v1/delete', { Key: key, Prefix: true })
                .done(function (data) {
                    if (data.Success) {
                        //delete
                        cacheData.ob_Entries.remove(CM.FindCacheKey(key, true))
                    } else {
                        //error
                    }
                });
            }
        };
    };

    CM.ObjectAsArray = function (object) {
        var properties = [];

        for (child in object) {
            if (object.hasOwnProperty(child)) {
                properties.push(object[child]);
            }
        }

        return properties;
    };

    var parseQuery = function (op_lowercase) {
        op_lowercase = op_lowercase || false;
        var query = document.location.search.substr(1);
        var parts = query.split('&');
        var parameters = {};
        for (var i = 0; i < parts.length; i++) {
            //If the value contains ='s, e.g. base64, we want to keep them.
            var param = parts[i].split('=');
            var key = param.shift();
            var value = param.join('=');

            if (op_lowercase)
                key = key.toLowerCase();

            parameters[key] = value;
        }
        return parameters;
    };

    //TODO:
    //what about empties , e.g. blah//blah
    //or keys that end with the delimiter?

    //Can this be done as a recursive ko template?
    //var drawCacheNode = function ($container, data) {
    //    var leafs = $('

').appendTo($container);

    //    var children = data.Children;
    //    for (child in children) {
    //        if (children.hasOwnProperty(child)) {
    //            var node = children[child];
    //            var id = 'item-' + id_i++;
    //            var branch = $('
<button type="button" class="btn btn-xs btn-link text-bold" data-action="delete" data-type="branch" data-key="' + node.Key + '" style="margin-right: 4px;"></button><input type="checkbox" class="expand" id="' + id + '" />' + node.Text + ' ' + delimiter + '
').appendTo(leafs);//use btn styling on label?//<button type="button" class="btn btn-xs btn-link"></button>
    //            drawCacheNode(branch, node);//AHHHH
    //        }
    //    }

    //    var values = (data.Values || []).sort();
    //    for (var i = 0; i < values.length; i++) {
    //        var value = values[i];
    //        $('
<button type="button" class="btn btn-xs btn-link" data-action="delete" data-type="leaf" data-key="' + value.Key + '" style="margin-right: 4px;"></button>' + value.Text + '
)').appendTo(leafs);
    //    }
    //}

    //Keep open state on data change/reload?

    //update stat count? it would only be accurate as of load time though.
    //make count based on loaded data instead of seperate call?
    //var deleteCacheNode = function ($node) {
    //    if ($node.siblings('li').length > 0) {
    //        $node.remove();
    //    } else {
    //        var $next = $node.parents('li');
    //        if ($next.length > 0) {
    //            deleteCacheNode($next);//ewwww
    //        } else {
    //            $node.remove();//at root level
    //        }
    //    }
    //};

    //String.prototype.getHashCode = function () {
    //    //From Java (apparently), find better one?
    //    var hash = 0;
    //    if (this.length == 0) return hash;
    //    for (i = 0; i < this.length; i++) {
    //        char = this.charCodeAt(i);
    //        hash = ((hash << 5) - hash) + char;
    //        hash = hash & hash; // Convert to 32bit integer
    //    }
    //    return hash;
    //}

    var params = parseQuery(true);//save in local storage instead?

    //TODO: Put wrappers around ajax so we can do things like error handling, busy indicator (tokens?)
    $.when($.get('api/v1/combined'), docReady)
    .done(function (combined) {
        var data = combined[0];

        //TODO: Escape non-printable character?
        data.Delimiter = params['delimiter'] || data.Delimiter || delimiter;
        data.ob_Delimiter = ko.observable(data.Delimiter);
        data.ob_Entries = ko.observableArray(data.Entries);
        data.ob_EntryTree = ko.computed(function () {
            //Can we template directly off the array somehow instead of building our tree here?
            //TODO: need to somehow keep checked state
            var CacheRoot = {
                Children: {},
                Values: []
            };

            var id_i = 0;//need hash function or something
            //Build our tree, any advantage to doing it server side?
            $.each(data.ob_Entries(), function (i, cache) {
                var key = cache.Key;
                var keyParts = key.split(data.ob_Delimiter() || null).reverse();
                var current = CacheRoot;
                var currentKey = [];
                while (keyParts.length > 1) {
                    var keyPart = keyParts.pop();
                    currentKey.push(keyPart);
                    if (current.Children[keyPart] === undefined)
                        current.Children[keyPart] = new CacheNode(currentKey.join(data.ob_Delimiter()) + data.ob_Delimiter(), keyPart, 'item-' + id_i++);//need to get the subkey up to this point
                    current = current.Children[keyPart];
                }
                current.Values.push(new CacheValue(key, keyParts.pop(), 'item-' + id_i++));//TODO: Prevent duplicates
            });

            return CacheRoot;
        });

        ko.applyBindings(data);//Tree parts lose open state on delete, need to save the state somehow.

        //window.TEST = data;

        cacheData = data;

        //console.log(CacheRoot);
        //drawCacheNode($('#cache-tree'), data.ob_EntryTree());

        //Clear loading indiciator
        $('.content-loading').fadeOut(function() {
            $(this).remove();
        });
    });

    CM.BranchExpand = function (branch) {
        if (branch.ob_Checked() && cacheData.ExpandSingleBranches) {
            var current = branch;
            var children = Object.keys(current.Children);
            while (children.length === 1) {
                current = current.Children[children[0]];
                children = Object.keys(current.Children);
                if (!current.ob_Checked())
                    current.ob_Checked(true);
            }
        }
        return true;
    };

    //Can knockout bind to a checkbox "Checked" event and get the element?
    //Then we won't need this id either.
    //$('#cache-tree')
    //.on('click', '.expand:checked', function () {
    //    if (cacheData.ExpandSingleBranches) {
    //        var $this = $(this);
    //        var $list = $this.siblings('ul').first();
    //        var $leafs = $list.children('li');
    //        if ($leafs.length === 1) {
    //            var $branch = $leafs.first().children('.expand').first();
    //            if ($branch.length > 0 && !$branch.is(':checked')) {
    //                $branch.trigger('click');
    //            }
    //        }
    //    }
    //});
    //.on('click', 'button[data-action="delete"]', function () {
    //    //store as json on the action attribute?
    //    var $this = $(this);
    //    var type = $this.data('type');
    //    var key = $this.data('key');

    //    var confirmDeleteKey = $('#ConfirmDeleteKey').is(':checked');
    //    var confirmDeletePrefix = $('#ConfirmDeletePrefix').is(':checked');

    //    if (type === 'leaf' && (!confirmDeleteKey || confirm('Are you sure you want to delete this cache value?\n\nKey: ' + key))) {
    //        //$.post('api/v1/delete', { Key: key })
    //        //.done(function (data) {
    //        //    console.log(data);
    //        //    if (data.Success) {
    //        cacheData.ob_Entries.remove(CM.FindCacheKey(key))

    //        //deleteCacheNode($this.closest('li'));
    //        //delete
    //        //    } else {
    //        //        //error
    //        //    }
    //        //});
    //    }
    //    else if (type === 'branch' && (!confirmDeletePrefix || confirm('Are you sure you want to delete everything with this prefix?\n\nPrefix: ' + key))) {
    //        //$.post('api/v1/delete', { Key: key, Prefix: true })
    //        //.done(function (data) {
    //        //    console.log(data);
    //        //    if (data.Success) {
    //        cacheData.ob_Entries.remove(CM.FindCacheKey(key, true))

    //        //deleteCacheNode($this.closest('li'));
    //        //delete
    //        //    } else {
    //        //        error
    //        //    }
    //        //});
    //    }
    //})
}(window, window.jQuery));<commit_msg>Disable taking settings from url for now.<commit_after>//TODO: Add copyright
//TODO: Test for large trees
//integrate https://square.github.io/crossfilter/ or similar for working with large data? not sure how tree generation/reading would work with it.
; (function (base, $, undefined) {
    base.CM = base.CM || {};
    var CM = base.CM;

    var docReady = $.Deferred();
    $(docReady.resolve);

    //$.wait = function (ms) {
    //    var dfd = $.Deferred();
    //    setTimeout(function () { dfd.resolve(); }, ms);
    //    return dfd;
    //};

    var cacheData = {};
    var delimiter = '/';//because we are using it later, we must always have one. Apparenly we can even have null keys, so use \x00 if we don't want a delimiter? I don't know if a c# key can contain a null.
    //var id_i = 0;//need hash function or something

    var CacheNode = function (key, text, id) {
        this.Key = key;
        this.Text = text;
        this.Children = {};//Nodes
        this.Values = [];//Values
        this.Id = id;
        this.ob_Checked = ko.observable(false);
    };

    var CacheValue = function (key, text, id) {
        this.Key = key;
        this.Text = text;
        this.Id = id;
    };

    CM.SortCacheKey = function (node1, node2) {
        var key1 = node1.Key;
        var key2 = node2.Key;

        //What order do we want?
        if (key1 < key2) return -1;
        if (key1 > key2) return 1;
        return 0;
    };

    CM.FindCacheKey = function (key, op_prefix) {
        op_prefix = op_prefix || false;
        return function (node) {
            if (op_prefix)
                return node.Key.indexOf(key) === 0;
            return node.Key === key;
        };
    };

    //var CacheRoot = {
    //    Children: {},
    //    Values: []
    //};

    CM.CopyrightYear = function () {
        return new Date().getUTCFullYear();
    };

    CM.Sort = function (array, op_sorter) {
        if ($.isFunction(op_sorter))
            return array.sort(op_sorter);
        return array.sort();
    };

    CM.Refresh = function () {
        $('.refresh-loading').removeClass('hidden');

        $.get('api/v1/cache')//'refresh' url? include freemem/other stats?
        .done(function (data) {
            cacheData.ob_Entries(data.Entries);
        });

        //TODO: Inline refresh (observables?)
        //document.location.reload();
    };

    CM.ClearRefreshSpinner = function () {
        $('.refresh-loading').addClass('hidden');
    };

    CM.GoBack = function () {
        document.location.href = './';
        //try {
        //    history.go(-1);
        //}
        //catch (e) { }
        //$.wait(100).then(function () {
        //    document.location = './';
        //});
    };

    CM.SetDelimiter = function (data) {
        //delimiter will already be set via two way input binding, this would also be caused by a refresh (use same button text?)
        //trigger re-draw of tree
        cacheData.ob_Delimiter(data.Delimiter);
    };

    CM.EnterDelimiter = function (data, e) {
        if (e.which === 13) {
            cacheData.ob_Delimiter(data.Delimiter);
        }
        return true;
    };

    CM.DeleteNode = function (key, op_prefix) {
        op_prefix = op_prefix || false;

        //Need to somehow keep checked state on redraw
        //Not sure how much I like spawning a new function for each one. Make each level a seperate observable? eww
        return function () {
            if (!op_prefix && (!cacheData.ConfirmDeleteKey || confirm('Are you sure you want to delete this cache value?\n\nKey: ' + key))) {
                $.post('api/v1/delete', { Key: key })
                .done(function (data) {
                    if (data.Success) {
                        //delete
                        cacheData.ob_Entries.remove(CM.FindCacheKey(key))
                    } else {
                        //error
                    }
                });
            } else if (op_prefix && (!cacheData.ConfirmDeletePrefix || confirm('Are you sure you want to delete everything with this prefix?\n\nPrefix: ' + key))) {
                $.post('api/v1/delete', { Key: key, Prefix: true })
                .done(function (data) {
                    if (data.Success) {
                        //delete
                        cacheData.ob_Entries.remove(CM.FindCacheKey(key, true))
                    } else {
                        //error
                    }
                });
            }
        };
    };

    CM.ObjectAsArray = function (object) {
        var properties = [];

        for (child in object) {
            if (object.hasOwnProperty(child)) {
                properties.push(object[child]);
            }
        }

        return properties;
    };

    var parseQuery = function (op_lowercase) {
        op_lowercase = op_lowercase || false;
        var query = document.location.search.substr(1);
        var parts = query.split('&');
        var parameters = {};
        for (var i = 0; i < parts.length; i++) {
            //If the value contains ='s, e.g. base64, we want to keep them.
            var param = parts[i].split('=');
            var key = param.shift();
            var value = param.join('=');

            if (op_lowercase)
                key = key.toLowerCase();

            parameters[key] = value;
        }
        return parameters;
    };

    //TODO:
    //what about empties , e.g. blah//blah
    //or keys that end with the delimiter?

    //Can this be done as a recursive ko template?
    //var drawCacheNode = function ($container, data) {
    //    var leafs = $('

').appendTo($container);

    //    var children = data.Children;
    //    for (child in children) {
    //        if (children.hasOwnProperty(child)) {
    //            var node = children[child];
    //            var id = 'item-' + id_i++;
    //            var branch = $('
<button type="button" class="btn btn-xs btn-link text-bold" data-action="delete" data-type="branch" data-key="' + node.Key + '" style="margin-right: 4px;"></button><input type="checkbox" class="expand" id="' + id + '" />' + node.Text + ' ' + delimiter + '
').appendTo(leafs);//use btn styling on label?//<button type="button" class="btn btn-xs btn-link"></button>
    //            drawCacheNode(branch, node);//AHHHH
    //        }
    //    }

    //    var values = (data.Values || []).sort();
    //    for (var i = 0; i < values.length; i++) {
    //        var value = values[i];
    //        $('
<button type="button" class="btn btn-xs btn-link" data-action="delete" data-type="leaf" data-key="' + value.Key + '" style="margin-right: 4px;"></button>' + value.Text + '
)').appendTo(leafs);
    //    }
    //}

    //Keep open state on data change/reload?

    //update stat count? it would only be accurate as of load time though.
    //make count based on loaded data instead of seperate call?
    //var deleteCacheNode = function ($node) {
    //    if ($node.siblings('li').length > 0) {
    //        $node.remove();
    //    } else {
    //        var $next = $node.parents('li');
    //        if ($next.length > 0) {
    //            deleteCacheNode($next);//ewwww
    //        } else {
    //            $node.remove();//at root level
    //        }
    //    }
    //};

    //String.prototype.getHashCode = function () {
    //    //From Java (apparently), find better one?
    //    var hash = 0;
    //    if (this.length == 0) return hash;
    //    for (i = 0; i < this.length; i++) {
    //        char = this.charCodeAt(i);
    //        hash = ((hash << 5) - hash) + char;
    //        hash = hash & hash; // Convert to 32bit integer
    //    }
    //    return hash;
    //}

    //var params = parseQuery(true);//save in local storage instead?

    //TODO: Put wrappers around ajax so we can do things like error handling, busy indicator (tokens?)
    $.when($.get('api/v1/combined'), docReady)
    .done(function (combined) {
        var data = combined[0];

        //TODO: Escape non-printable character?
        //data.Delimiter = params['delimiter'] || data.Delimiter || delimiter;
        data.ob_Delimiter = ko.observable(data.Delimiter);
        data.ob_Entries = ko.observableArray(data.Entries);
        data.ob_EntryTree = ko.computed(function () {
            //Can we template directly off the array somehow instead of building our tree here?
            //TODO: need to somehow keep checked state
            var CacheRoot = {
                Children: {},
                Values: []
            };

            var id_i = 0;//need hash function or something
            //Build our tree, any advantage to doing it server side?
            $.each(data.ob_Entries(), function (i, cache) {
                var key = cache.Key;
                var keyParts = key.split(data.ob_Delimiter() || null).reverse();
                var current = CacheRoot;
                var currentKey = [];
                while (keyParts.length > 1) {
                    var keyPart = keyParts.pop();
                    currentKey.push(keyPart);
                    if (current.Children[keyPart] === undefined)
                        current.Children[keyPart] = new CacheNode(currentKey.join(data.ob_Delimiter()) + data.ob_Delimiter(), keyPart, 'item-' + id_i++);//need to get the subkey up to this point
                    current = current.Children[keyPart];
                }
                current.Values.push(new CacheValue(key, keyParts.pop(), 'item-' + id_i++));//TODO: Prevent duplicates
            });

            return CacheRoot;
        });

        ko.applyBindings(data);//Tree parts lose open state on delete, need to save the state somehow.

        //window.TEST = data;

        cacheData = data;

        //console.log(CacheRoot);
        //drawCacheNode($('#cache-tree'), data.ob_EntryTree());

        //Clear loading indiciator
        $('.content-loading').fadeOut(function() {
            $(this).remove();
        });
    });

    CM.BranchExpand = function (branch) {
        if (branch.ob_Checked() && cacheData.ExpandSingleBranches) {
            var current = branch;
            var children = Object.keys(current.Children);
            while (children.length === 1) {
                current = current.Children[children[0]];
                children = Object.keys(current.Children);
                if (!current.ob_Checked())
                    current.ob_Checked(true);
            }
        }
        return true;
    };

    //Can knockout bind to a checkbox "Checked" event and get the element?
    //Then we won't need this id either.
    //$('#cache-tree')
    //.on('click', '.expand:checked', function () {
    //    if (cacheData.ExpandSingleBranches) {
    //        var $this = $(this);
    //        var $list = $this.siblings('ul').first();
    //        var $leafs = $list.children('li');
    //        if ($leafs.length === 1) {
    //            var $branch = $leafs.first().children('.expand').first();
    //            if ($branch.length > 0 && !$branch.is(':checked')) {
    //                $branch.trigger('click');
    //            }
    //        }
    //    }
    //});
    //.on('click', 'button[data-action="delete"]', function () {
    //    //store as json on the action attribute?
    //    var $this = $(this);
    //    var type = $this.data('type');
    //    var key = $this.data('key');

    //    var confirmDeleteKey = $('#ConfirmDeleteKey').is(':checked');
    //    var confirmDeletePrefix = $('#ConfirmDeletePrefix').is(':checked');

    //    if (type === 'leaf' && (!confirmDeleteKey || confirm('Are you sure you want to delete this cache value?\n\nKey: ' + key))) {
    //        //$.post('api/v1/delete', { Key: key })
    //        //.done(function (data) {
    //        //    console.log(data);
    //        //    if (data.Success) {
    //        cacheData.ob_Entries.remove(CM.FindCacheKey(key))

    //        //deleteCacheNode($this.closest('li'));
    //        //delete
    //        //    } else {
    //        //        //error
    //        //    }
    //        //});
    //    }
    //    else if (type === 'branch' && (!confirmDeletePrefix || confirm('Are you sure you want to delete everything with this prefix?\n\nPrefix: ' + key))) {
    //        //$.post('api/v1/delete', { Key: key, Prefix: true })
    //        //.done(function (data) {
    //        //    console.log(data);
    //        //    if (data.Success) {
    //        cacheData.ob_Entries.remove(CM.FindCacheKey(key, true))

    //        //deleteCacheNode($this.closest('li'));
    //        //delete
    //        //    } else {
    //        //        error
    //        //    }
    //        //});
    //    }
    //})
}(window, window.jQuery));<|endoftext|>


<commit_before>import ms from 'ms';

export function handleError (err) {
  if (403 === err.status) {
    error('Authentication error. Run `now -L` or `now --login` to log-in again.');
  } else if (429 === err.status) {
    if (null != err.retryAfter) {
      error('Rate limit exceeded error. Try again in ' +
          ms(err.retryAfter * 1000, { long: true }) +
          ', or upgrade your account: https://zeit.co/now#pricing');
    } else {
      error('Rate limit exceeded error. Please try later.');
    }
  } else if (err.userError) {
    error(err.message);
  } else if (500 === err.status) {
    error('Unexpected server error. Please retry.');
  } else {
    error(`Unexpected error. Please try later. (${err.message})`);
  }
}

export function error (err) {
  console.error(`> \u001b[31mError!\u001b[39m ${err}`);
}
<commit_msg>error: prevent ansi escapes for colors in stdout<commit_after>import ms from 'ms';
import chalk from 'chalk';

export function handleError (err) {
  if (403 === err.status) {
    error('Authentication error. Run `now -L` or `now --login` to log-in again.');
  } else if (429 === err.status) {
    if (null != err.retryAfter) {
      error('Rate limit exceeded error. Try again in ' +
          ms(err.retryAfter * 1000, { long: true }) +
          ', or upgrade your account: https://zeit.co/now#pricing');
    } else {
      error('Rate limit exceeded error. Please try later.');
    }
  } else if (err.userError) {
    error(err.message);
  } else if (500 === err.status) {
    error('Unexpected server error. Please retry.');
  } else {
    error(`Unexpected error. Please try later. (${err.message})`);
  }
}

export function error (err) {
  console.error(`> ${chalk.red('Error!')} ${err}`);
}
<|endoftext|>


<commit_before>/*
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you 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 the following location:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

var ssoSessions = (function () {
    var urls = {
        destroy: {
            all: '/cas/statistics/ssosessions/destroySsoSessions',
            single: '/cas/statistics/ssosessions/destroySsoSession'
        },
        getSessions: '/cas/statistics/ssosessions/getSsoSessions'
    };

    var createDataTable = function() {
        $('#ssoSessions').DataTable( {
            "order": [[ 3, "desc" ]],
            "initComplete": function(settings, json) {

                if (!json || json.activeSsoSessions.length == 0) {
                    $('#loadingMessage').hide();
                    $('#no-cas-sessions').show();
                } else {
                    updateAdminPanels( json );

                    $('#loadingMessage').hide();
                    $("#no-cas-sessions").hide();
                    $("#cas-sessions").show();
                }
            },
            "language": {
                //"infoEmpty": "No active sessions were found",
                "emptyTable": "No sessions found",
                "zeroRecords": "No matching sessions found"
            },
            "processing": true,
            "ajax": {
                "url": '/cas/statistics/ssosessions/getSsoSessions',
                "dataSrc": "activeSsoSessions"
            },

            columnDefs: [
                {
                    "targets": 0,
                    "className":      'details-control',
                    "orderable":      false,
                    "data":           null,
                    "defaultContent": ''
                },
                {
                    "targets": 1,
                    "data": 'is_proxied',
                    'className': 'col-xs-1',
                    "render" : function ( data, type, full, meta ) {
                        if ( data === true) {
                            return 'Proxy';
                        } else {
                            return ' ';
                        }
                    }
                },
                {
                    "targets": 2,
                    "data": 'authenticated_principal',
                    "className": 'col-xs-2',
                    "render": function ( data, type, full, meta ) {
                        return type === 'display' && data.length > 20 ?
                        ''+data.substr( 0, 18 )+'...' :
                        data;
                    }
                },
                {
                    "targets": 3,
                    "data": 'ticket_granting_ticket',
                    "className": 'col-xs-3',
                    "render": function ( data, type, full, meta ) {
                        return type === 'display' && data.length > 20 ?
                        ''+data.substr( 0, 18 )+'...' :
                        data;
                    }
                },
                {
                    "targets": 4,
                    "data": 'authentication_date',
                    "className": 'col-xs-3',
                    "render": function ( data, type, full, meta ) {
                        var timeStamp = new Date( data );
                        return timeStamp.toFormattedString();
                    }
                },
                {
                    "targets": 5,
                    "data": 'number_of_uses',
                    "className": 'col-xs-2'
                },
                {
                    "targets": 6,
                    "data": "ticket_granting_ticket",
                    "className": 'col-xs-1',
                    "render": function (data, type, full, meta ) {
                        return '<button class="btn btn-xs btn-danger" type="button" value="' + data + '">Destroy</button>';
                    },
                    "orderable": false
                },
            ]
        } );
    };

    var addEventHandlers = function() {

        /**
         * The Bulk remove button
         */
        $('#removeAllSessionsButton').on('click', function(e) {
            e.preventDefault();
            removeSession(this.value);
        });

        /**
         * Individual removal button
         */
        $(document).on('click', '#ssoSessions tbody tr td:last-child button.btn-danger', function (e) {
            e.preventDefault();
            removeSession( this.value );
        });

        /**
         * The filter buttons
         */
        $('#filterButtons .btn').click(function() {

            var filter = $(this).data('filter');
            var table = $('#ssoSessions').DataTable();

            // Create Filter RegEx:
            if ( filter == 'proxied') {
                var filterRegex = '^Proxy$';
                var deleteValue = 'PROXIED';
                var btnText = 'Remove xx Proxied Sessions';
            } else if ( filter == 'non-proxied') {
                var filterRegex = '^ $';
                var deleteValue = 'DIRECT';
                var btnText = 'Remove xx Non-Proxied Sessions';
            } else {
                var filterRegex = '';
                var deleteValue = 'ALL';
                var btnText = 'Remove All Sessions';
            }

            var searchTerm = table.column( 1 ).search(filterRegex, true, false).draw();

            $('#removeAllSessionsButton').val( deleteValue ).html(btnText.replace('xx', searchTerm.page.info().recordsDisplay ))
        });

        // Add event listener for opening and closing details
        $(document).on('click', '#ssoSessions tbody td.details-control', function () {
            var table = $('#ssoSessions').DataTable();
            var tr = $(this).closest('tr');
            var row = table.row( tr );

            if ( row.child.isShown() ) {
                // This row is already open - close it
                row.child.hide();
                tr.removeClass('shown');
            }
            else {
                // Open this row
                row.child( format(row.data()), 'info' ).show();
                tr.addClass('shown');
            }
        } );

    };

    // initialization *******
    ( function init () {
        addEventHandlers();
        createDataTable();
    })();

    // Public Methods
    return {
        /**
         * Not used
         */
    };
})();
<commit_msg>Changed the Authentication Date column to use the authentication_date_formatted field instead of authentication_date and then formatting it.<commit_after>/*
 * Licensed to Apereo under one or more contributor license
 * agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership.
 * Apereo licenses this file to you 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 the following location:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

var ssoSessions = (function () {
    var urls = {
        destroy: {
            all: '/cas/statistics/ssosessions/destroySsoSessions',
            single: '/cas/statistics/ssosessions/destroySsoSession'
        },
        getSessions: '/cas/statistics/ssosessions/getSsoSessions'
    };

    var createDataTable = function() {
        $('#ssoSessions').DataTable( {
            "order": [[ 3, "desc" ]],
            "initComplete": function(settings, json) {

                if (!json || json.activeSsoSessions.length == 0) {
                    $('#loadingMessage').hide();
                    $('#no-cas-sessions').show();
                } else {
                    updateAdminPanels( json );

                    $('#loadingMessage').hide();
                    $("#no-cas-sessions").hide();
                    $("#cas-sessions").show();
                }
            },
            "language": {
                //"infoEmpty": "No active sessions were found",
                "emptyTable": "No sessions found",
                "zeroRecords": "No matching sessions found"
            },
            "processing": true,
            "ajax": {
                "url": '/cas/statistics/ssosessions/getSsoSessions',
                "dataSrc": "activeSsoSessions"
            },

            columnDefs: [
                {
                    "targets": 0,
                    "className":      'details-control',
                    "orderable":      false,
                    "data":           null,
                    "defaultContent": ''
                },
                {
                    "targets": 1,
                    "data": 'is_proxied',
                    'className': 'col-xs-1',
                    "render" : function ( data, type, full, meta ) {
                        if ( data === true) {
                            return 'Proxy';
                        } else {
                            return ' ';
                        }
                    }
                },
                {
                    "targets": 2,
                    "data": 'authenticated_principal',
                    "className": 'col-xs-2',
                    "render": function ( data, type, full, meta ) {
                        return type === 'display' && data.length > 20 ?
                        ''+data.substr( 0, 18 )+'...' :
                        data;
                    }
                },
                {
                    "targets": 3,
                    "data": 'ticket_granting_ticket',
                    "className": 'col-xs-3',
                    "render": function ( data, type, full, meta ) {
                        return type === 'display' && data.length > 20 ?
                        ''+data.substr( 0, 18 )+'...' :
                        data;
                    }
                },
                {
                    "targets": 4,
                    "data": 'authentication_date_formatted',
                    "className": 'col-xs-3'
                },
                {
                    "targets": 5,
                    "data": 'number_of_uses',
                    "className": 'col-xs-2'
                },
                {
                    "targets": 6,
                    "data": "ticket_granting_ticket",
                    "className": 'col-xs-1',
                    "render": function (data, type, full, meta ) {
                        return '<button class="btn btn-xs btn-danger" type="button" value="' + data + '">Destroy</button>';
                    },
                    "orderable": false
                },
            ]
        } );
    };

    var addEventHandlers = function() {

        /**
         * The Bulk remove button
         */
        $('#removeAllSessionsButton').on('click', function(e) {
            e.preventDefault();
            removeSession(this.value);
        });

        /**
         * Individual removal button
         */
        $(document).on('click', '#ssoSessions tbody tr td:last-child button.btn-danger', function (e) {
            e.preventDefault();
            removeSession( this.value );
        });

        /**
         * The filter buttons
         */
        $('#filterButtons .btn').click(function() {

            var filter = $(this).data('filter');
            var table = $('#ssoSessions').DataTable();

            // Create Filter RegEx:
            if ( filter == 'proxied') {
                var filterRegex = '^Proxy$';
                var deleteValue = 'PROXIED';
                var btnText = 'Remove xx Proxied Sessions';
            } else if ( filter == 'non-proxied') {
                var filterRegex = '^ $';
                var deleteValue = 'DIRECT';
                var btnText = 'Remove xx Non-Proxied Sessions';
            } else {
                var filterRegex = '';
                var deleteValue = 'ALL';
                var btnText = 'Remove All Sessions';
            }

            var searchTerm = table.column( 1 ).search(filterRegex, true, false).draw();

            $('#removeAllSessionsButton').val( deleteValue ).html(btnText.replace('xx', searchTerm.page.info().recordsDisplay ))
        });

        // Add event listener for opening and closing details
        $(document).on('click', '#ssoSessions tbody td.details-control', function () {
            var table = $('#ssoSessions').DataTable();
            var tr = $(this).closest('tr');
            var row = table.row( tr );

            if ( row.child.isShown() ) {
                // This row is already open - close it
                row.child.hide();
                tr.removeClass('shown');
            }
            else {
                // Open this row
                row.child( format(row.data()), 'info' ).show();
                tr.addClass('shown');
            }
        } );

    };

    // initialization *******
    ( function init () {
        addEventHandlers();
        createDataTable();
    })();

    // Public Methods
    return {
        /**
         * Not used
         */
    };
})();
<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const fs = require('fs');
const electron = require('electron');
const BrowserWindow = electron.BrowserWindow;
const app = electron.app;
const ipc = electron.ipcMain;
const log = require('../../log.js');
const logLevels = require('../../enums/logLevels.js');
const notify = require('./../electron-notify');
const eventEmitter = require('./../../eventEmitter');

const { updateConfigField } = require('../../config');

let configurationWindow;
let screens;
let position;
let display;
let sandboxed = false;

let windowConfig = {
    width: 460,
    height: 360,
    show: false,
    modal: true,
    autoHideMenuBar: true,
    resizable: false,
    webPreferences: {
        preload: path.join(__dirname, 'configure-notification-position-preload.js'),
        sandbox: sandboxed,
        nodeIntegration: false
    }
};

app.on('ready', () => {
    screens = electron.screen.getAllDisplays();

    // if display added/removed update the list of screens
    electron.screen.on('display-added', updateScreens);
    electron.screen.on('display-removed', updateScreens);
});

/**
 * Update all the screens
 */
function updateScreens() {
    screens = electron.screen.getAllDisplays();

    // Notifying renderer when a display is added/removed
    if (configurationWindow && screens && screens.length >= 0) {
        configurationWindow.webContents.send('screens', screens);
    }
}

/**
 * Gets the template path
 * @returns {string}
 */
function getTemplatePath() {
    let templatePath = path.join(__dirname, 'configure-notification-position.html');
    try {
        fs.statSync(templatePath).isFile();
    } catch (err) {
        log.send(logLevels.ERROR, 'configure-notification-position: Could not find template ("' + templatePath + '").');
    }
    return 'file://' + templatePath;
}

/**
 * Opens the configuration window for a specific window
 * @param windowName
 */
function openConfigurationWindow(windowName) {
    let allWindows = BrowserWindow.getAllWindows();
    allWindows = allWindows.find((window) => { return window.winName === windowName });

    // if we couldn't find any window matching the window name
    // it will render as a new window
    if (allWindows) {
        windowConfig.parent = allWindows;
    }

    configurationWindow = new BrowserWindow(windowConfig);
    configurationWindow.setVisibleOnAllWorkspaces(true);
    configurationWindow.loadURL(getTemplatePath());

    configurationWindow.once('ready-to-show', () => {
        configurationWindow.show();
    });

    configurationWindow.webContents.on('did-finish-load', () => {
        if (screens && screens.length >= 0) {
            configurationWindow.webContents.send('screens', screens);
        }
        configurationWindow.webContents.send('notificationSettings', {position: position, display: display});
    });

    configurationWindow.on('close', () => {
        destroyWindow();
    });

    configurationWindow.on('closed', () => {
        destroyWindow();
    });
}

/**
 * Destroys a window
 */
function destroyWindow() {
    configurationWindow = null;
}

/**
 * Method to save 'position' & 'display' to the config file
 */
function updateConfig() {
    let settings = {
        position: position,
        display: display
    };
    updateConfigField('notificationSettings', settings);
    updateNotification(position, display);
}

/**
 * Method to update the Notification class with the new 'position' & 'screen'
 * @param mPosition - position to display the notifications
 * ('upper-right, upper-left, lower-right, lower-left')
 * @param mDisplay - id of the selected display
 */
function updateNotification(mPosition, mDisplay) {
    notify.updateConfig({position: mPosition, display: mDisplay});
    notify.reset();
}

ipc.on('close-alert', function () {
    configurationWindow.close();
});

ipc.on('update-config', (event, config) => {

    if (config) {
        if (config.position) {
            position = config.position;
        }
        if (config.display) {
            display = config.display;
        }
    }

    updateConfig();
});

/**
 * Event to read 'Position' & 'Display' from config and
 * updated the configuration view
 */
eventEmitter.on('notificationSettings', (notificationSettings) => {
    position = notificationSettings.position;
    display = notificationSettings.display;
});

module.exports = {
    openConfigurationWindow: openConfigurationWindow
};<commit_msg>Electron-171 - Fixes the Configuration window positioning when multiple monitors are connected<commit_after>'use strict';

const path = require('path');
const fs = require('fs');
const electron = require('electron');
const BrowserWindow = electron.BrowserWindow;
const app = electron.app;
const ipc = electron.ipcMain;
const log = require('../../log.js');
const logLevels = require('../../enums/logLevels.js');
const notify = require('./../electron-notify');
const eventEmitter = require('./../../eventEmitter');

const { updateConfigField } = require('../../config');

let configurationWindow;
let screens;
let position;
let display;
let sandboxed = false;

let windowConfig = {
    width: 460,
    height: 360,
    show: false,
    modal: true,
    autoHideMenuBar: true,
    resizable: false,
    webPreferences: {
        preload: path.join(__dirname, 'configure-notification-position-preload.js'),
        sandbox: sandboxed,
        nodeIntegration: false
    }
};

app.on('ready', () => {
    screens = electron.screen.getAllDisplays();

    // if display added/removed update the list of screens
    electron.screen.on('display-added', updateScreens);
    electron.screen.on('display-removed', updateScreens);
});

/**
 * Update all the screens
 */
function updateScreens() {
    screens = electron.screen.getAllDisplays();

    // Notifying renderer when a display is added/removed
    if (configurationWindow && screens && screens.length >= 0) {
        configurationWindow.webContents.send('screens', screens);
    }
}

/**
 * Gets the template path
 * @returns {string}
 */
function getTemplatePath() {
    let templatePath = path.join(__dirname, 'configure-notification-position.html');
    try {
        fs.statSync(templatePath).isFile();
    } catch (err) {
        log.send(logLevels.ERROR, 'configure-notification-position: Could not find template ("' + templatePath + '").');
    }
    return 'file://' + templatePath;
}

/**
 * Opens the configuration window for a specific window
 * @param windowName
 */
function openConfigurationWindow(windowName) {
    const allWindows = BrowserWindow.getAllWindows();
    const selectedParentWindow = allWindows.find((window) => { return window.winName === windowName });

    // if we couldn't find any window matching the window name
    // it will render as a new window
    if (selectedParentWindow) {
        windowConfig.parent = selectedParentWindow;

        // This is a temporary work around until there
        // is a fix for the modal window in windows from the electron
        const { x, y, width, height } = selectedParentWindow.getBounds();

        const windowWidth = Math.round(width * 0.5);
        const windowHeight = Math.round(height * 0.5);

        // Calculating the center of the window
        // to place the configuration window
        const centerX = x + width / 2.0;
        const centerY = y + height / 2.0;
        windowConfig.x = Math.round(centerX - (windowWidth / 2.0));
        windowConfig.y = Math.round(centerY - (windowHeight / 2.0));
    }

    configurationWindow = new BrowserWindow(windowConfig);
    configurationWindow.setVisibleOnAllWorkspaces(true);
    configurationWindow.loadURL(getTemplatePath());

    configurationWindow.once('ready-to-show', () => {
        configurationWindow.show();
    });

    configurationWindow.webContents.on('did-finish-load', () => {
        if (screens && screens.length >= 0) {
            configurationWindow.webContents.send('screens', screens);
        }
        configurationWindow.webContents.send('notificationSettings', {position: position, display: display});
    });

    configurationWindow.on('close', () => {
        destroyWindow();
    });

    configurationWindow.on('closed', () => {
        destroyWindow();
    });
}

/**
 * Destroys a window
 */
function destroyWindow() {
    configurationWindow = null;
}

/**
 * Method to save 'position' & 'display' to the config file
 */
function updateConfig() {
    let settings = {
        position: position,
        display: display
    };
    updateConfigField('notificationSettings', settings);
    updateNotification(position, display);
}

/**
 * Method to update the Notification class with the new 'position' & 'screen'
 * @param mPosition - position to display the notifications
 * ('upper-right, upper-left, lower-right, lower-left')
 * @param mDisplay - id of the selected display
 */
function updateNotification(mPosition, mDisplay) {
    notify.updateConfig({position: mPosition, display: mDisplay});
    notify.reset();
}

ipc.on('close-alert', function () {
    configurationWindow.close();
});

ipc.on('update-config', (event, config) => {

    if (config) {
        if (config.position) {
            position = config.position;
        }
        if (config.display) {
            display = config.display;
        }
    }

    updateConfig();
});

/**
 * Event to read 'Position' & 'Display' from config and
 * updated the configuration view
 */
eventEmitter.on('notificationSettings', (notificationSettings) => {
    position = notificationSettings.position;
    display = notificationSettings.display;
});

module.exports = {
    openConfigurationWindow: openConfigurationWindow
};<|endoftext|>


<commit_before>const assetUrl = {
    name: 'assetUrl',
    env: null,
    bucket: null,
    prefix: null,
    cloudfront: false,

    plugContext(options) {
        if (!this.rehydrated) {
            this.env = options.env;
            this.siteUrl = options.siteUrl;

            if (options.aws) {
                this.useAws = true;
                this.bucket = options.aws.bucket;
                this.prefix = options.aws.prefix;
                this.folder = options.aws.folder;
                this.cloudfront = options.aws.cloudfront;
                this.bypassCdn = options.aws.bypassCdn;
                this.urlHash = options.aws.urlHash;
            }
        }

        const useAws = this.useAws;
        const env = this.env;
        const siteUrl = this.siteUrl;
        const bucket = this.bucket;
        const prefix = this.prefix;
        const folder = this.folder;
        const cloudfront = this.cloudfront;
        const bypassCdn = this.bypassCdn;
        const urlHash = this.urlHash;

        let urlBase;

        if (cloudfront && !bypassCdn) {
            urlBase = `${cloudfront}${urlHash}/`;
        } else {
            urlBase = `http://${bucket}.s3.amazonaws.com/${prefix}/${folder}/`;
        }

        const slashRegex = /([^:])\/{1,}/g;

        // Returns a context plugin
        return {
            plugComponentContext(componentContext) {
                return Object.assign(componentContext, {
                    assetUrl(path) {
                        if (env === 'local' || !useAws) {
                            return path;
                        }

                        if (path.indexOf('http') === 0 || path.indexOf(urlBase) === 0) {
                            return path;
                        }

                        const cleanPath = (path.slice(0, 1) === '/') ? path.slice(1) : path;

                        // Prepend the urlBase and remove any incidences of multiple
                        // slashes after the initial http://
                        return (`${urlBase}${cleanPath}`).replace(slashRegex, '$1/');
                    },
                    siteUrl() { return siteUrl; },
                });
            },
        };
    },

    dehydrate() {
        return {
            env: this.env,
            siteUrl: this.siteUrl,
            bucket: this.bucket,
            prefix: this.prefix,
            folder: this.folder,
            cloudfront: this.cloudfront,
            bypassCdn: this.bypassCdn,
            urlHash: this.urlHash,
        };
    },

    rehydrate(state) {
        this.env = state.env;
        this.siteUrl = state.siteUrl;
        this.bucket = state.bucket;
        this.prefix = state.prefix;
        this.folder = state.folder;
        this.cloudfront = state.cloudfront;
        this.bypassCdn = state.bypassCdn;
        this.urlHash = state.urlHash;
        this.rehydrated = true;
        this.useAws = state.useAws;
    },
};

export default assetUrl;
<commit_msg>Respect `aws` usage setting<commit_after>const assetUrl = {
    name: 'assetUrl',
    env: null,
    bucket: null,
    prefix: null,
    cloudfront: false,

    plugContext(options) {
        if (!this.rehydrated) {
            this.env = options.env;
            this.siteUrl = options.siteUrl;

            if (options.aws) {
                this.useAws = options.aws.useAws;
                this.bucket = options.aws.bucket;
                this.prefix = options.aws.prefix;
                this.folder = options.aws.folder;
                this.cloudfront = options.aws.cloudfront;
                this.bypassCdn = options.aws.bypassCdn;
                this.urlHash = options.aws.urlHash;
            }
        }

        const useAws = this.useAws;
        const env = this.env;
        const siteUrl = this.siteUrl;
        const bucket = this.bucket;
        const prefix = this.prefix;
        const folder = this.folder;
        const cloudfront = this.cloudfront;
        const bypassCdn = this.bypassCdn;
        const urlHash = this.urlHash;

        let urlBase;

        if (cloudfront && !bypassCdn) {
            urlBase = `${cloudfront}${urlHash}/`;
        } else {
            urlBase = `http://${bucket}.s3.amazonaws.com/${prefix}/${folder}/`;
        }

        const slashRegex = /([^:])\/{1,}/g;

        // Returns a context plugin
        return {
            plugComponentContext(componentContext) {
                return Object.assign(componentContext, {
                    assetUrl(path) {
                        if (env === 'local' || !useAws) {
                            return path;
                        }

                        if (path.indexOf('http') === 0 || path.indexOf(urlBase) === 0) {
                            return path;
                        }

                        const cleanPath = (path.slice(0, 1) === '/') ? path.slice(1) : path;

                        // Prepend the urlBase and remove any incidences of multiple
                        // slashes after the initial http://
                        return (`${urlBase}${cleanPath}`).replace(slashRegex, '$1/');
                    },
                    siteUrl() { return siteUrl; },
                });
            },
        };
    },

    dehydrate() {
        return {
            env: this.env,
            siteUrl: this.siteUrl,
            bucket: this.bucket,
            prefix: this.prefix,
            folder: this.folder,
            cloudfront: this.cloudfront,
            bypassCdn: this.bypassCdn,
            urlHash: this.urlHash,
        };
    },

    rehydrate(state) {
        this.env = state.env;
        this.siteUrl = state.siteUrl;
        this.bucket = state.bucket;
        this.prefix = state.prefix;
        this.folder = state.folder;
        this.cloudfront = state.cloudfront;
        this.bypassCdn = state.bypassCdn;
        this.urlHash = state.urlHash;
        this.rehydrated = true;
        this.useAws = state.useAws;
    },
};

export default assetUrl;
<|endoftext|>


<commit_before>var main    = require('redis');

var Redis = function () {
  this.cmds   = [];
  this.calls  = [];
  this.replys = {};
  this.is_fin = false;
  this.data   = {}; // Data to be stored by user.
};

function log() {
  console['log'].apply(console, arguments);
}

Redis.client = main.createClient(5100);

// process.on('exit', function () {
  // log('Closing redis.');
  // Redis.client.quit();
// });

Redis.new = function () {
  return (new Redis);
};

Redis.prototype.on_fin = function (func) {

  if (arguments.length === 0) {
    if (this.is_fin)
      throw new Error('Can not call on_fin event multiple times.');
    if (!this.fin)
      return null;
    var fin_result = this.fin(this.replys, this);
    this.fin = null;
    this.is_fin = (this.cmds.length === 0);
    return fin_result;
  }

  if (this.fin)
    throw new Error('Can only add a fin function once.');
  this.fin = func;
  return this.fin;
};

Redis.prototype.add = function( cmd_id, r_func_name, raw_args, on_fin, on_err ) {
  var me      = this;
  var args    = raw_args.slice();
  var cont    = true;
  var func    = function (err, reply) {

    me.replys[cmd_id] = {
      success : !err,
      reply   : reply,
      cmd     : r_func_name,
      args    : raw_args
    };

    if (err) {
      if (on_err)
        cont = on_err(err, reply, me);
      else
        log('Redis err:', err, 'Reply: ', reply, 'cmd: ', r_func_name, 'args: ', raw_args, 'id: ', cmd_id);

      if (!cont)
        return cont;
    }

    if (on_fin)
      on_fin(reply, me);

    me.cmds.pop();
    if (me.cmds.length === 0) {
      me.on_fin();
    }
    me.exec();
  };

  args.push(func);
  me.cmds.push(cmd_id);
  me.calls.push([r_func_name, args]);
};

Redis.prototype.exec = function (fin) {
  var c  = null;
  var me = this;

  if (fin)
    this.on_fin(fin);

  while((c = this.calls.pop()) || c) {
    var meth = Redis.client[c[0]];
    if (!meth)
      throw new Error('Unknown method: ' + c[0]);
    Redis.client[c[0]].apply(Redis.client, c[1]);
  }
};

exports.Redis = Redis;

<commit_msg>Added: .read_records_from_list<commit_after>var main    = require('redis')
,   _base   = require('okdoki/lib/base');

var error = _base.error
, warn    = _base.warn
, log     = _base.log;

var Redis = function () {
  this.cmds   = [];
  this.calls  = [];
  this.replys = {};
  this.is_fin = false;
  this.data   = {}; // Data to be stored by user.
};

function log() {
  console['log'].apply(console, arguments);
}

Redis.client = main.createClient(5100);

Redis.read_records_from_list = function (key, on_fin) {
  Redis.client.llen(key, function (err, l) {
    if (err) error(err);
    if (!l || l < 1)
      return on_fin([]);

    var ids_multi = Redis.client.multi();
    while(l > 0) {
      ids_multi.lpop(key);
      l -= 1;
    }

    ids_multi.exec(function (err, raw_ids) {
      if (err) error(err);

      var ids = _.compact( raw_ids || [] );
      if (ids.length < 1)
        return on_fin([]);

      var r_multi = Redis.client.multi();
      _.each(ids, function (id) {
        r_multi.hgetall(id);
      });
      r_multi.exec(function (err, raw_records) {
        if (err) error(err);
        var records = [];
        _.each((raw_records || []), function (rec, i) {
          if (!rec)
            return;
          records.push([ ids[i], rec ]);
        });

        return on_fin(records);
      });
    });
  });
};

// process.on('exit', function () {
  // log('Closing redis.');
  // Redis.client.quit();
// });

Redis.new = function () {
  return (new Redis);
};

Redis.prototype.on_fin = function (func) {

  if (arguments.length === 0) {
    if (this.is_fin)
      throw new Error('Can not call on_fin event multiple times.');
    if (!this.fin)
      return null;
    var fin_result = this.fin(this.replys, this);
    this.fin = null;
    this.is_fin = (this.cmds.length === 0);
    return fin_result;
  }

  if (this.fin)
    throw new Error('Can only add a fin function once.');
  this.fin = func;
  return this.fin;
};

Redis.prototype.add = function( cmd_id, r_func_name, raw_args, on_fin, on_err ) {
  var me      = this;
  var args    = raw_args.slice();
  var cont    = true;
  var func    = function (err, reply) {

    me.replys[cmd_id] = {
      success : !err,
      reply   : reply,
      cmd     : r_func_name,
      args    : raw_args
    };

    if (err) {
      if (on_err)
        cont = on_err(err, reply, me);
      else
        log('Redis err:', err, 'Reply: ', reply, 'cmd: ', r_func_name, 'args: ', raw_args, 'id: ', cmd_id);

      if (!cont)
        return cont;
    }

    if (on_fin)
      on_fin(reply, me);

    me.cmds.pop();
    if (me.cmds.length === 0) {
      me.on_fin();
    }
    me.exec();
  };

  args.push(func);
  me.cmds.push(cmd_id);
  me.calls.push([r_func_name, args]);
};

Redis.prototype.exec = function (fin) {
  var c  = null;
  var me = this;

  if (fin)
    this.on_fin(fin);

  while((c = this.calls.pop()) || c) {
    var meth = Redis.client[c[0]];
    if (!meth)
      throw new Error('Unknown method: ' + c[0]);
    Redis.client[c[0]].apply(Redis.client, c[1]);
  }
};

exports.Redis = Redis;

<|endoftext|>


<commit_before>function carleonMpdController ($scope, $q, $window, $translatePartialLoader, $translate, $interval, angharadConfig, carleonFactory, carleonMpdFactory, sagremorService, sagremorParams, toaster) {
    var ctrl = this;

    this.mpd = {};
    this.playlists = [];
    this.selectedPlaylist = false;
    this._interval = null;
    this.hasFocus = true;

    function init() {
		var promises = [
			carleonMpdFactory.getMpdStatus(ctrl.element.name),
			carleonMpdFactory.getMpdPlaylists(ctrl.element.name)
		];

		$q.all(promises).then(function (responses) {
			ctrl.mpd = responses[0];
			ctrl.playlists = responses[1];
			if (ctrl.mpd.state === "play" || ctrl.mpd.state === "pause") {
				startRefreshStatusInterval();
			}
		}, function () {
			toaster.pop("error", $translate.instant("carleon_mpd"), $translate.instant("carleon_mpd_load_error", {name: ctrl.element.name}));
		});
    }

    function startRefreshStatusInterval() {
		ctrl._interval = $interval(function () {
			if (ctrl.hasFocus) {
				ctrl.refreshStatus();
			}
		}, 1000 * 10);
	}

    this.refreshStatus = function() {
		carleonMpdFactory.getMpdStatus(ctrl.element.name).then(function (response) {
			ctrl.mpd = response;
			if ((ctrl.mpd.state === "play" || ctrl.mpd.state === "pause") && ctrl._interval == null) {
				startRefreshStatusInterval();
			} else if (ctrl._interval != null && ctrl.mpd.state !== "play" && ctrl.mpd.state !== "pause") {
				$interval.cancel(ctrl._interval);
				ctrl._interval = null;
			}
		}, function () {
			toaster.pop("error", $translate.instant("carleon_mpd"), $translate.instant("carleon_mpd_load_error", {name: ctrl.element.name}));
		});
	};

    this.displayVolume = function () {
		return ctrl.mpd.volume + "%";
	};

	this.setVolume = function (delta) {
		var newVolume = ctrl.mpd.volume + delta;
		if (newVolume >= 0 && newVolume <= 100) {
			carleonMpdFactory.setMpdVolume(ctrl.element.name, newVolume).then(function () {
				ctrl.mpd.volume = newVolume;
			}, function () {
				toaster.pop("error", $translate.instant("carleon_mpd"), $translate.instant("carleon_mpd_volume_error"));
			});
		}
	};

	this.displayVolumeCommand = function (delta) {
		return (delta>0?"+":"") + delta + " %"
	};

	this.setAction = function (action) {
		carleonMpdFactory.setMpdAction(ctrl.element.name, action).then(function () {
			ctrl.refreshStatus();
		}, function () {
			toaster.pop("error", $translate.instant("carleon_mpd"), $translate.instant("carleon_mpd_volume_error"));
		});
	};

	this.loadPlaylist = function () {
		if (!!ctrl.selectedPlaylist) {
			carleonMpdFactory.loadMpdPlaylist(ctrl.element.name, ctrl.selectedPlaylist).then(function () {
				ctrl.refreshStatus();
			}, function () {
				toaster.pop("error", $translate.instant("carleon_mpd"), $translate.instant("carleon_mpd_load_playlist_error"));
			});
		}
	};

	$scope.$on("refreshCarleonServices", function () {
		ctrl.refreshStatus();
	});

	$scope.$on("$destroy", function() {
		$interval.cancel(ctrl._interval);
		ctrl._interval = null;
	});

	$window.onblur = function() {
		ctrl.hasFocus = false;
	};

	$window.onfocus = function() {
		ctrl.hasFocus = true;
	};

    init();
}

angular.module("sagremorApp").component("serviceMpd", {
    templateUrl: "components/carleonMpd/carleonMpd.template.html",
    controller: carleonMpdController,
    bindings: {
        element: "="
    }
})
.factory("carleonMpdFactory", function($http, $uibModal, $translate, toaster, angharadConfig, angharadBackendService, sagremorConfirm, sharedData) {
    var urlBase = angharadConfig.baseUrl + angharadConfig.prefixCarleon;
    var carleonMpdFactory = {};

	/* Mpd service */
    carleonMpdFactory.getMpdServiceList = function () {
        return angharadBackendService.httpRequest("GET", urlBase + "service-mpd/");
    };

    carleonMpdFactory.getMpdService = function (name) {
        return angharadBackendService.httpRequest("GET", urlBase + "service-mpd/" + name);
    };

    carleonMpdFactory.addMpdService = function (mpdService) {
        return angharadBackendService.httpRequest("POST", urlBase + "service-mpd/", mpdService);
    };

    carleonMpdFactory.setMpdService = function (name, mpdService) {
        return angharadBackendService.httpRequest("PUT", urlBase + "service-mpd/" + name, mpdService);
    };

    carleonMpdFactory.removeMpdService = function (name) {
        return angharadBackendService.httpRequest("DELETE", urlBase + "service-mpd/" + name);
    };

    carleonMpdFactory.getMpdStatus = function (name) {
        return angharadBackendService.httpRequest("GET", urlBase + "service-mpd/" + name + "/status");
    };

    carleonMpdFactory.getMpdPlaylists = function (name) {
        return angharadBackendService.httpRequest("GET", urlBase + "service-mpd/" + name + "/playlists");
    };

    carleonMpdFactory.setMpdAction = function (name, action) {
        return angharadBackendService.httpRequest("PUT", urlBase + "service-mpd/" + name + "/action/" + action);
    };

    carleonMpdFactory.loadMpdPlaylist = function (name, playlist) {
        return angharadBackendService.httpRequest("PUT", urlBase + "service-mpd/" + name + "/playlist/" + playlist);
    };

    carleonMpdFactory.setMpdVolume = function (name, volume) {
        return angharadBackendService.httpRequest("PUT", urlBase + "service-mpd/" + name + "/volume/" + volume);
    };

	carleonMpdFactory.addService = function () {
		var modalInstance = $uibModal.open({
			animation: true,
			templateUrl: "components/carleonMpd/carleonMpd.modal.html",
			controller: "carleonMpdModalCtrl",
			controllerAs: "carleonMpdModalCtrl",
			size: "md",
			resolve: {
				mpd: function () {
					return null;
				}
			}
		});
	};

	carleonMpdFactory.editService = function (service) {
		var modalInstance = $uibModal.open({
			animation: true,
			templateUrl: "components/carleonMpd/carleonMpd.modal.html",
			controller: "carleonMpdModalCtrl",
			controllerAs: "carleonMpdModalCtrl",
			size: "md",
			resolve: {
				mpd: function () {
					return service;
				}
			}
		});
	};

	carleonMpdFactory.removeService = function (service) {
		return sagremorConfirm.open($translate.instant("carleon_mpd_remove"), $translate.instant("carleon_mpd_confirm")).then(function () {
			return carleonMpdFactory.removeMpdService(service.name).then(function () {
				var injector = sharedData.get("carleonServices", "service-mpd");
				_.remove(injector.element, function (element) {
					return element.name === service.name;
				});
				sharedData.add("carleonServices", "service-mpd", injector);
				toaster.pop("success", $translate.instant("carleon_mpd_remove"), $translate.instant("carleon_mpd_remove_success"));
			}, function () {
				toaster.pop("error", $translate.instant("carleon_mpd_remove"), $translate.instant("carleon_mpd_remove_error"));
			});
		});
	};

    return carleonMpdFactory;

})
.config(function run($translatePartialLoaderProvider) {
	$translatePartialLoaderProvider.addPart("carleonMpd");
})
.run(function(sagGenericInjectorManager, carleonMpdFactory) {
    sagGenericInjectorManager.add({
        type: "service-mpd",
        directive: "service-mpd",
        groupTitle: "carleon_mpd_title",
        service: carleonMpdFactory,
        carleonService: true,
        size: 2,
        leftMenu: {
			title: "carleon_music_title",
			target: "carleonMpd"
		},
		widgetHeight: 4,
		widgetWidth: 3,
		icon: "music",
		commands: {
			action: {
				title: "carleon_mpd_command_action_title",
				parameters: {
					action: "carleon_mpd_command_action_parameter_action_title",
				},
				result: {
					type: "boolean",
					title: "carleon_mpd_command_action_result_title"
				}
			},
			load_playlist: {
				title: "carleon_mpd_command_playlist_title",
				parameters: {
					playlist: "carleon_mpd_command_playlist_parameter_plsylist_title",
				},
				result: {
					type: "boolean",
					title: "carleon_mpd_command_playlist_result_title"
				}
			},
			set_volume: {
				title: "carleon_mpd_command_volume_title",
				parameters: {
					volume: "carleon_mpd_command_volume_parameter_volume_title",
				},
				result: {
					type: "boolean",
					title: "carleon_mpd_command_volume_result_title"
				}
			}
		}
    });
});
<commit_msg>Fix left menu target<commit_after>function carleonMpdController ($scope, $q, $window, $translatePartialLoader, $translate, $interval, angharadConfig, carleonFactory, carleonMpdFactory, sagremorService, sagremorParams, toaster) {
    var ctrl = this;

    this.mpd = {};
    this.playlists = [];
    this.selectedPlaylist = false;
    this._interval = null;
    this.hasFocus = true;

    function init() {
		var promises = [
			carleonMpdFactory.getMpdStatus(ctrl.element.name),
			carleonMpdFactory.getMpdPlaylists(ctrl.element.name)
		];

		$q.all(promises).then(function (responses) {
			ctrl.mpd = responses[0];
			ctrl.playlists = responses[1];
			if (ctrl.mpd.state === "play" || ctrl.mpd.state === "pause") {
				startRefreshStatusInterval();
			}
		}, function () {
			toaster.pop("error", $translate.instant("carleon_mpd"), $translate.instant("carleon_mpd_load_error", {name: ctrl.element.name}));
		});
    }

    function startRefreshStatusInterval() {
		ctrl._interval = $interval(function () {
			if (ctrl.hasFocus) {
				ctrl.refreshStatus();
			}
		}, 1000 * 10);
	}

    this.refreshStatus = function() {
		carleonMpdFactory.getMpdStatus(ctrl.element.name).then(function (response) {
			ctrl.mpd = response;
			if ((ctrl.mpd.state === "play" || ctrl.mpd.state === "pause") && ctrl._interval == null) {
				startRefreshStatusInterval();
			} else if (ctrl._interval != null && ctrl.mpd.state !== "play" && ctrl.mpd.state !== "pause") {
				$interval.cancel(ctrl._interval);
				ctrl._interval = null;
			}
		}, function () {
			toaster.pop("error", $translate.instant("carleon_mpd"), $translate.instant("carleon_mpd_load_error", {name: ctrl.element.name}));
		});
	};

    this.displayVolume = function () {
		return ctrl.mpd.volume + "%";
	};

	this.setVolume = function (delta) {
		var newVolume = ctrl.mpd.volume + delta;
		if (newVolume >= 0 && newVolume <= 100) {
			carleonMpdFactory.setMpdVolume(ctrl.element.name, newVolume).then(function () {
				ctrl.mpd.volume = newVolume;
			}, function () {
				toaster.pop("error", $translate.instant("carleon_mpd"), $translate.instant("carleon_mpd_volume_error"));
			});
		}
	};

	this.displayVolumeCommand = function (delta) {
		return (delta>0?"+":"") + delta + " %"
	};

	this.setAction = function (action) {
		carleonMpdFactory.setMpdAction(ctrl.element.name, action).then(function () {
			ctrl.refreshStatus();
		}, function () {
			toaster.pop("error", $translate.instant("carleon_mpd"), $translate.instant("carleon_mpd_volume_error"));
		});
	};

	this.loadPlaylist = function () {
		if (!!ctrl.selectedPlaylist) {
			carleonMpdFactory.loadMpdPlaylist(ctrl.element.name, ctrl.selectedPlaylist).then(function () {
				ctrl.refreshStatus();
			}, function () {
				toaster.pop("error", $translate.instant("carleon_mpd"), $translate.instant("carleon_mpd_load_playlist_error"));
			});
		}
	};

	$scope.$on("refreshCarleonServices", function () {
		ctrl.refreshStatus();
	});

	$scope.$on("$destroy", function() {
		$interval.cancel(ctrl._interval);
		ctrl._interval = null;
	});

	$window.onblur = function() {
		ctrl.hasFocus = false;
	};

	$window.onfocus = function() {
		ctrl.hasFocus = true;
	};

    init();
}

angular.module("sagremorApp").component("serviceMpd", {
    templateUrl: "components/carleonMpd/carleonMpd.template.html",
    controller: carleonMpdController,
    bindings: {
        element: "="
    }
})
.factory("carleonMpdFactory", function($http, $uibModal, $translate, toaster, angharadConfig, angharadBackendService, sagremorConfirm, sharedData) {
    var urlBase = angharadConfig.baseUrl + angharadConfig.prefixCarleon;
    var carleonMpdFactory = {};

	/* Mpd service */
    carleonMpdFactory.getMpdServiceList = function () {
        return angharadBackendService.httpRequest("GET", urlBase + "service-mpd/");
    };

    carleonMpdFactory.getMpdService = function (name) {
        return angharadBackendService.httpRequest("GET", urlBase + "service-mpd/" + name);
    };

    carleonMpdFactory.addMpdService = function (mpdService) {
        return angharadBackendService.httpRequest("POST", urlBase + "service-mpd/", mpdService);
    };

    carleonMpdFactory.setMpdService = function (name, mpdService) {
        return angharadBackendService.httpRequest("PUT", urlBase + "service-mpd/" + name, mpdService);
    };

    carleonMpdFactory.removeMpdService = function (name) {
        return angharadBackendService.httpRequest("DELETE", urlBase + "service-mpd/" + name);
    };

    carleonMpdFactory.getMpdStatus = function (name) {
        return angharadBackendService.httpRequest("GET", urlBase + "service-mpd/" + name + "/status");
    };

    carleonMpdFactory.getMpdPlaylists = function (name) {
        return angharadBackendService.httpRequest("GET", urlBase + "service-mpd/" + name + "/playlists");
    };

    carleonMpdFactory.setMpdAction = function (name, action) {
        return angharadBackendService.httpRequest("PUT", urlBase + "service-mpd/" + name + "/action/" + action);
    };

    carleonMpdFactory.loadMpdPlaylist = function (name, playlist) {
        return angharadBackendService.httpRequest("PUT", urlBase + "service-mpd/" + name + "/playlist/" + playlist);
    };

    carleonMpdFactory.setMpdVolume = function (name, volume) {
        return angharadBackendService.httpRequest("PUT", urlBase + "service-mpd/" + name + "/volume/" + volume);
    };

	carleonMpdFactory.addService = function () {
		var modalInstance = $uibModal.open({
			animation: true,
			templateUrl: "components/carleonMpd/carleonMpd.modal.html",
			controller: "carleonMpdModalCtrl",
			controllerAs: "carleonMpdModalCtrl",
			size: "md",
			resolve: {
				mpd: function () {
					return null;
				}
			}
		});
	};

	carleonMpdFactory.editService = function (service) {
		var modalInstance = $uibModal.open({
			animation: true,
			templateUrl: "components/carleonMpd/carleonMpd.modal.html",
			controller: "carleonMpdModalCtrl",
			controllerAs: "carleonMpdModalCtrl",
			size: "md",
			resolve: {
				mpd: function () {
					return service;
				}
			}
		});
	};

	carleonMpdFactory.removeService = function (service) {
		return sagremorConfirm.open($translate.instant("carleon_mpd_remove"), $translate.instant("carleon_mpd_confirm")).then(function () {
			return carleonMpdFactory.removeMpdService(service.name).then(function () {
				var injector = sharedData.get("carleonServices", "service-mpd");
				_.remove(injector.element, function (element) {
					return element.name === service.name;
				});
				sharedData.add("carleonServices", "service-mpd", injector);
				toaster.pop("success", $translate.instant("carleon_mpd_remove"), $translate.instant("carleon_mpd_remove_success"));
			}, function () {
				toaster.pop("error", $translate.instant("carleon_mpd_remove"), $translate.instant("carleon_mpd_remove_error"));
			});
		});
	};

    return carleonMpdFactory;

})
.config(function run($translatePartialLoaderProvider) {
	$translatePartialLoaderProvider.addPart("carleonMpd");
})
.run(function(sagGenericInjectorManager, carleonMpdFactory) {
    sagGenericInjectorManager.add({
        type: "service-mpd",
        directive: "service-mpd",
        groupTitle: "carleon_mpd_title",
        service: carleonMpdFactory,
        carleonService: true,
        size: 2,
        leftMenu: {
			title: "carleon_music_title",
			target: "music"
		},
		widgetHeight: 4,
		widgetWidth: 3,
		icon: "music",
		commands: {
			action: {
				title: "carleon_mpd_command_action_title",
				parameters: {
					action: "carleon_mpd_command_action_parameter_action_title",
				},
				result: {
					type: "boolean",
					title: "carleon_mpd_command_action_result_title"
				}
			},
			load_playlist: {
				title: "carleon_mpd_command_playlist_title",
				parameters: {
					playlist: "carleon_mpd_command_playlist_parameter_plsylist_title",
				},
				result: {
					type: "boolean",
					title: "carleon_mpd_command_playlist_result_title"
				}
			},
			set_volume: {
				title: "carleon_mpd_command_volume_title",
				parameters: {
					volume: "carleon_mpd_command_volume_parameter_volume_title",
				},
				result: {
					type: "boolean",
					title: "carleon_mpd_command_volume_result_title"
				}
			}
		}
    });
});
<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React from 'react';
import { FormattedMessage, injectIntl } from 'react-intl';
import Dialog from '@material-ui/core/Dialog';
import DialogTitle from '@material-ui/core/MenuItem';

const localMessages = {
  title: { id: 'explorer.querymediapicker.title', defaultMessage: 'Selecting Media' },
  desc: { id: 'explorer.querymediapicker.desc', defaultMessage: 'Media Cloud allows you to search within collections or media sources, or within online news sources directly. You can select media sources or collections in a variety of ways:' },
  option1: { id: 'explorer.querymediapicker.option1', defaultMessage: 'Search within our geographic collections by country' },
  option2: { id: 'explorer.querymediapicker.option2', defaultMessage: 'Pick from our commonly-used list of featured collections' },
  option3: { id: 'explorer.querymediapicker.option3', defaultMessage: 'Pick from any sources or collections you have "starred"' },
  option4: { id: 'explorer.querymediapicker.option4', defaultMessage: 'Search all our individual media sources by name or URL' },
  instructions: { id: 'explorer.querymediapicker.instructions', defaultMessage: 'When you find a source or collection you want to add, click the + button to the right of the description. You can edit your selections (by clicking the X button to remove unwanted selections) in the lower left corner of the dialog window. Click the OK button to add your source selections to your query.' },
};

class QueryPickerLoggedInHeader extends React.Component {
  state = {
    open: false,
  };

  handleClickOpen = () => {
    this.setState({
      open: true,
    });
  };

  render() {
    return (
      <Dialog
        open={this.state.open}
        onClose={this.handleClose}
        aria-labelledby="simple-dialog-title"
      >
        <DialogTitle id="simple-dialog-title"><FormattedMessage {...localMessages.title} /></DialogTitle>

<FormattedMessage {...localMessages.option1} />

<FormattedMessage {...localMessages.option2} />

<FormattedMessage {...localMessages.option3} />

<FormattedMessage {...localMessages.option4} />

      </Dialog>
    );
  }
}

QueryPickerLoggedInHeader.propTypes = {
  // from parent
  query: PropTypes.object,
  isDeletable: PropTypes.func.isRequired,
  onColorChange: PropTypes.func.isRequired,
  onDelete: PropTypes.func,
  onLabelEditRequest: PropTypes.func,
  // from composition
  intl: PropTypes.object.isRequired,
};

export default injectIntl(QueryPickerLoggedInHeader);
<commit_msg>Fix incorrect class name<commit_after>import PropTypes from 'prop-types';
import React from 'react';
import { FormattedMessage, injectIntl } from 'react-intl';
import Dialog from '@material-ui/core/Dialog';
import DialogTitle from '@material-ui/core/MenuItem';

const localMessages = {
  title: { id: 'explorer.querymediapicker.title', defaultMessage: 'Selecting Media' },
  desc: { id: 'explorer.querymediapicker.desc', defaultMessage: 'Media Cloud allows you to search within collections or media sources, or within online news sources directly. You can select media sources or collections in a variety of ways:' },
  option1: { id: 'explorer.querymediapicker.option1', defaultMessage: 'Search within our geographic collections by country' },
  option2: { id: 'explorer.querymediapicker.option2', defaultMessage: 'Pick from our commonly-used list of featured collections' },
  option3: { id: 'explorer.querymediapicker.option3', defaultMessage: 'Pick from any sources or collections you have "starred"' },
  option4: { id: 'explorer.querymediapicker.option4', defaultMessage: 'Search all our individual media sources by name or URL' },
  instructions: { id: 'explorer.querymediapicker.instructions', defaultMessage: 'When you find a source or collection you want to add, click the + button to the right of the description. You can edit your selections (by clicking the X button to remove unwanted selections) in the lower left corner of the dialog window. Click the OK button to add your source selections to your query.' },
};

class LearnMorePopup extends React.Component {
  state = {
    open: false,
  };

  handleClickOpen = () => {
    this.setState({
      open: true,
    });
  };

  render() {
    return (
      <Dialog
        open={this.state.open}
        onClose={this.handleClose}
        aria-labelledby="simple-dialog-title"
      >
        <DialogTitle id="simple-dialog-title"><FormattedMessage {...localMessages.title} /></DialogTitle>

<FormattedMessage {...localMessages.option1} />

<FormattedMessage {...localMessages.option2} />

<FormattedMessage {...localMessages.option3} />

<FormattedMessage {...localMessages.option4} />

      </Dialog>
    );
  }
}

LearnMorePopup.propTypes = {
  // from parent
  query: PropTypes.object,
  isDeletable: PropTypes.func.isRequired,
  onColorChange: PropTypes.func.isRequired,
  onDelete: PropTypes.func,
  onLabelEditRequest: PropTypes.func,
  // from composition
  intl: PropTypes.object.isRequired,
};

export default injectIntl(LearnMorePopup);
<|endoftext|>


<commit_before>var logger = require('./logger');
var request = require('request');

/**
 * @param {String} baseUrl
 * @param {Number} clientKey
 */
CMApiClient = function(baseUrl, clientKey) {
  this.baseUrl = baseUrl;
  this.clientKey = clientKey;
};

var _responseHandler = function(error, response, body) {
  if (response.statusCode == 200) {
    logger.debug('Response OK');
  } else {
    logger.error('error: ' + response.statusCode);
    logger.error(body);
  }
};

/**
 * @param {String} streamName
 * @param {Number} start
 * @param {JSON} data
 */
CMApiClient.prototype.publish = function(streamName, start, data) {
  request.post(
    this.baseUrl + '/rpc/CM_Janus_RpcEndpoints.publish',
    {form: {streamName: streamName, clientKey: this.clientKey, start: +start, data: data}},
    _responseHandler
  );
};

/**
 * @param {String} streamName
 */
CMApiClient.prototype.unpublish = function(streamName) {
  request.post(this.baseUrl + '/rpc/CM_Janus_RpcEndpoints.unpublish',
    {form: {streamName: streamName}},
    _responseHandler
  );
};

/**
 * @param {String} streamName
 * @param {Number} start
 * @param {JSON} data
 */
CMApiClient.prototype.subscribe = function(streamName, start, data) {
  request.post(this.baseUrl + '/rpc/CM_Janus_RpcEndpoints.subscribe',
    {form: {streamName: streamName, clientKey: this.clientKey, start: +start, data: data}},
    function(error, response, body) {
      if (response.statusCode == 200) {
        logger.log('Response OK');
      } else {
        logger.error('error: ' + response.statusCode);
        logger.error(body);
      }
    }
  );
};

/**
 * @param {String} streamName
 */
CMApiClient.prototype.unsubscribe = function(streamName) {
  request.post(this.baseUrl + '/rpc/CM_Janus_RpcEndpoints.unsubscribe',
    {form: {streamName: streamName}},
    _responseHandler
  );
};

module.exports = CMApiClient;
<commit_msg>add auth stubs<commit_after>var logger = require('./logger');
var request = require('request');

/**
 * @param {String} baseUrl
 * @param {Number} clientKey
 */
CMApiClient = function(baseUrl, clientKey) {
  this.baseUrl = baseUrl;
  this.clientKey = clientKey;
};

var _responseHandler = function(error, response, body) {
  if (response.statusCode == 200) {
    logger.debug('Response OK');
  } else {
    logger.error('error: ' + response.statusCode);
    logger.error(body);
  }
};

/**
 * @param {String} streamName
 * @param {Number} start
 * @param {JSON} data
 */
CMApiClient.prototype.publish = function(streamName, start, data) {
  request.post(
    this.baseUrl + '/rpc/CM_Janus_RpcEndpoints.publish',
    {form: {streamName: streamName, clientKey: this.clientKey, start: +start, data: data}},
    _responseHandler
  );
};

/**
 * @param {String} streamName
 */
CMApiClient.prototype.unpublish = function(streamName) {
  request.post(this.baseUrl + '/rpc/CM_Janus_RpcEndpoints.unpublish',
    {form: {streamName: streamName}},
    _responseHandler
  );
};

/**
 * @param {String} streamName
 * @param {Number} start
 * @param {JSON} data
 */
CMApiClient.prototype.subscribe = function(streamName, start, data) {
  request.post(this.baseUrl + '/rpc/CM_Janus_RpcEndpoints.subscribe',
    {form: {streamName: streamName, clientKey: this.clientKey, start: +start, data: data}},
    function(error, response, body) {
      if (response.statusCode == 200) {
        logger.log('Response OK');
      } else {
        logger.error('error: ' + response.statusCode);
        logger.error(body);
      }
    }
  );
};

/**
 * @param {String} streamName
 */
CMApiClient.prototype.unsubscribe = function(streamName) {
  request.post(this.baseUrl + '/rpc/CM_Janus_RpcEndpoints.unsubscribe',
    {form: {streamName: streamName}},
    _responseHandler
  );
};

/**
 * @param {String} sessionId
 */
CMApiClient.prototype.authPublish = function(sessionId) {
  request.post(this.baseUrl + '/rpc/CM_Janus_RpcEndpoints.authPublish',
    {form: {sessionId: sessionId}},
    _responseHandler
  );
};

/**
 * @param {String} sessionId
 */
CMApiClient.prototype.authSubscribe = function(sessionId) {
  request.post(this.baseUrl + '/rpc/CM_Janus_RpcEndpoints.authSubscribe',
    {form: {sessionId: sessionId}},
    _responseHandler
  );
};

module.exports = CMApiClient;
<|endoftext|>


<commit_before>'use strict';
const expect = require('chai').expect;
const Excel = require('exceljs');
const ExcelReader = require('../index').ExcelReader;
const fs = require('fs');

let testWorkbooks = {};
describe('Excel Reader', () => {
    before(() => {
        testWorkbooks.singleSheetFirstRowHeader = fs.createReadStream('./util/excels/1sheet-1header.xlsx');
    });
    describe('Sheets', () => {
        it('should error if different number of Sheets', (done) => {
            let workbook = testWorkbooks.singleSheetFirstRowHeader;
            let reader = new ExcelReader(testWorkbooks.singleSheetFirstRowHeader, {
                sheets: [{
                    name: 'Data',
                }, {
                    name: 'Test'
                }]
            })
            reader.eachRow()
            .then(() => {
                done('Reader must exit with an error');
            })
            .catch((err) => {
                expect(err).to.exist();
            });
        });
    });

    describe('Allowed Sheet Names', () => {
        it('should be an array', () => {
        });

        it('should only allow selected sheet names', () => {
        });

        it('should throw error if invalid sheet name is in excel', () => {
        });

        it('should allow any name if allowedNames is null', () => {
        });
    });

    describe('Rows', () => {
        it('should error if header row does not exist in excel', () => {
        });

        it('should only allow specified header rows', () => {
        });

        it('should return each row data based on header row keys', () => {
        });
    });
});<commit_msg>Added additional tests for reading<commit_after>'use strict';
const expect = require('chai').expect;
const Excel = require('exceljs');
const ExcelReader = require('../index').ExcelReader;
const fs = require('fs');

let testWorkbooks = {};
describe('Excel Reader', () => {
    before(() => {
        testWorkbooks.singleSheetFirstRowHeader = fs.createReadStream('./util/excels/1sheet-1header.xlsx');
    });
    describe('Sheets', () => {
        it('should error if different number of Sheets', (done) => {
            let workbook = testWorkbooks.singleSheetFirstRowHeader;
            let reader = new ExcelReader(testWorkbooks.singleSheetFirstRowHeader, {
                sheets: [{
                    name: 'Data',
                }, {
                    name: 'Test'
                }]
            })
            reader.eachRow()
            .then(() => {
                done('Reader must exit with an error');
            })
            .catch((err) => {
                expect(err).to.exist();
            });
        });
    });

    describe('Allowed Sheet Names', () => {
        it('should be an array', () => {
        });

        it('should only allow selected sheet names', () => {
        });

        it('should throw error if invalid sheet name is in excel', () => {
        });

        it('should allow any name if allowedNames is null', () => {
        });
    });

    describe('Rows', () => {
        it('should error if header row does not exist in excel', () => {
        });

        it('should assume default header row', () => {
        });

        it('should take header row from config', () => {
        });

        it('should only allow specified header rows', () => {
        });

        it('should return each row data based on header row keys', () => {
        });
    });
});<|endoftext|>