<commit_before>var Transform = require('readable-stream').Transform;
var inherits = require('inherits');

inherits(Tokenize, Transform);
module.exports = Tokenize;

var codes = {
    lt: '<'.charCodeAt(0),
    gt: '>'.charCodeAt(0),
    slash: '/'.charCodeAt(0),
    dquote: '"'.charCodeAt(0),
    squote: "'".charCodeAt(0)
};

var strings = {
    endScript: Buffer('</script'),
    comment: Buffer('<!--'),
    endComment: Buffer('-->'),
    cdata: Buffer('<![CDATA['),
    endCdata: Buffer(']]>')
};

function Tokenize () {
    if (!(this instanceof Tokenize)) return new Tokenize;
    Transform.call(this);
    this._readableState.objectMode = true;
    this.state = 'text';
    this.quoteState = null;
    this.raw = null;
    this.buffers = [];
    this._last = [];
}

Tokenize.prototype._transform = function (buf, enc, next) {
    var offset = 0;
    for (var i = 0; i < buf.length; i++) {
        var b = buf[i];
        this._last.push(b);
        if (this._last.length > 9) this._last.shift();

        if (this.raw) {
            var parts = this._testRaw(buf, offset, i);
            if (parts) {
                this.push([ 'text', parts[0] ]);

                if (this.raw === strings.endComment
                || this.raw === strings.endCdata) {
                    this.state = 'text';
                    this.buffers = [];
                    this.push([ 'close', parts[1] ]);
                }
                else {
                    this.state = 'open';
                    this.buffers = [ parts[1] ];
                }

                this.raw = null;
                offset = i + 1;
            }
        }
        else if (this.state === 'text' && b === codes.lt
        && !/\s+/.test(String.fromCharCode(buf[i+1]))) {
            if (i > 0 && i - offset > 0) {
                this.buffers.push(buf.slice(offset, i));
            }
            offset = i;
            this.state = 'open';
            this._pushState('text');
        }
        else if (
            this.state === 'open' &&
            (!this.quoteState || this.quoteState === 'double') &&
            b === codes.dquote
        ) {
            if (this.quoteState) this.quoteState = null;
            else this.quoteState = 'double';
        }
        else if (
            this.state === 'open' &&
            (!this.quoteState || this.quoteState === 'single') &&
            b === codes.squote
        ) {
            if (this.quoteState) this.quoteState = null;
            else this.quoteState = 'single';
        }
        else if (this.state === 'open' && b === codes.gt && !this.quoteState) {
            if (i > 0) this.buffers.push(buf.slice(offset, i + 1));
            offset = i + 1;
            this.state = 'text';

            if (this._getChar(1) === codes.slash) {
                this._pushState('close');
            }
            else {
                var tag = this._getTag();
                if (tag === 'script') this.raw = strings.endScript;
                this._pushState('open');
            }
        }
        else if (this.state === 'open' && compare(this._last, strings.comment)) {
            this.buffers.push(buf.slice(offset, i + 1));
            offset = i + 1;
            this.state = 'text';
            this.raw = strings.endComment;
            this._pushState('open');
        }
        else if (this.state === 'open' && compare(this._last, strings.cdata)) {
            this.buffers.push(buf.slice(offset, i + 1));
            offset = i + 1;
            this.state = 'text';
            this.raw = strings.endCdata;
            this._pushState('open');
        }
    }
    if (offset < buf.length) this.buffers.push(buf.slice(offset));
    next();
};

Tokenize.prototype._flush = function (next) {
    if (this.state === 'text') this._pushState('text');
    this.push(null);
    next();
};

Tokenize.prototype._pushState = function (ev) {
    if (this.buffers.length === 0) return;
    var buf = Buffer.concat(this.buffers);
    this.buffers = [];
    this.push([ ev, buf ]);
};

Tokenize.prototype._getChar = function (i) {
    var offset = 0;
    for (var j = 0; j < this.buffers.length; j++) {
        var buf = this.buffers[j];
        if (offset + buf.length > i) {
            return buf[i - offset];
        }
        offset += buf;
    }
};

Tokenize.prototype._getTag = function () {
    var offset = 0;
    var tag = '';
    for (var j = 0; j < this.buffers.length; j++) {
        var buf = this.buffers[j];
        for (var k = 0; k < buf.length; k++) {
            if (offset === 0 && k === 0) continue;
            var c = String.fromCharCode(buf[k]);
            if (/[^\w-!\[\]]/.test(c)) {
                return tag.toLowerCase();
            }
            else tag += c;
        }
        offset += buf.length;
    }
};

Tokenize.prototype._testRaw = function (buf, offset, index) {
    var raw = this.raw, last = this._last;
    if (!compare(last, raw)) return;

    this.buffers.push(buf.slice(offset, index + 1));
    var buf = Buffer.concat(this.buffers);
    var k = buf.length - raw.length;
    return [ buf.slice(0, k), buf.slice(k) ];
};

function compare (a, b) {
    if (a.length < b.length) return false;
    for (var i=a.length-1, j=b.length-1; i >= 0 && j >= 0; i--, j--) {
        if (lower(a[i]) !== lower(b[j])) return false;
    }
    return true;
}

function lower (n) {
    if (n >= 65 && n <= 90) return n + 32;
    return n;
}
<commit_msg>fix for lt boundary case<commit_after>var Transform = require('readable-stream').Transform;
var inherits = require('inherits');

inherits(Tokenize, Transform);
module.exports = Tokenize;

var codes = {
    lt: '<'.charCodeAt(0),
    gt: '>'.charCodeAt(0),
    slash: '/'.charCodeAt(0),
    dquote: '"'.charCodeAt(0),
    squote: "'".charCodeAt(0)
};

var strings = {
    endScript: Buffer('</script'),
    comment: Buffer('<!--'),
    endComment: Buffer('-->'),
    cdata: Buffer('<![CDATA['),
    endCdata: Buffer(']]>')
};

function Tokenize () {
    if (!(this instanceof Tokenize)) return new Tokenize;
    Transform.call(this);
    this._readableState.objectMode = true;
    this.state = 'text';
    this.quoteState = null;
    this.raw = null;
    this.buffers = [];
    this._last = [];
}

Tokenize.prototype._transform = function (buf, enc, next) {
    var i = 0;
    var offset = 0;

    if (this._prev) {
        buf = Buffer.concat([ this._prev, buf ]);
        i = this._prev.length - 1;
        offset = this._offset;
        this._prev = null;
        this._offset = 0;
    }

    for (; i < buf.length; i++) {
        var b = buf[i];
        this._last.push(b);
        if (this._last.length > 9) this._last.shift();

        if (this.raw) {
            var parts = this._testRaw(buf, offset, i);
            if (parts) {
                this.push([ 'text', parts[0] ]);

                if (this.raw === strings.endComment
                || this.raw === strings.endCdata) {
                    this.state = 'text';
                    this.buffers = [];
                    this.push([ 'close', parts[1] ]);
                }
                else {
                    this.state = 'open';
                    this.buffers = [ parts[1] ];
                }

                this.raw = null;
                offset = i + 1;
            }
        }
        else if (this.state === 'text' && b === codes.lt
        && i === buf.length - 1) {
            this._prev = buf;
            this._offset = offset;
            return next();
        }
        else if (this.state === 'text' && b === codes.lt
        && !/\s+/.test(String.fromCharCode(buf[i+1]))) {
            if (i > 0 && i - offset > 0) {
                this.buffers.push(buf.slice(offset, i));
            }
            offset = i;
            this.state = 'open';
            this._pushState('text');
        }
        else if (
            this.state === 'open' &&
            (!this.quoteState || this.quoteState === 'double') &&
            b === codes.dquote
        ) {
            if (this.quoteState) this.quoteState = null;
            else this.quoteState = 'double';
        }
        else if (
            this.state === 'open' &&
            (!this.quoteState || this.quoteState === 'single') &&
            b === codes.squote
        ) {
            if (this.quoteState) this.quoteState = null;
            else this.quoteState = 'single';
        }
        else if (this.state === 'open' && b === codes.gt && !this.quoteState) {
            if (i > 0) this.buffers.push(buf.slice(offset, i + 1));
            offset = i + 1;
            this.state = 'text';

            if (this._getChar(1) === codes.slash) {
                this._pushState('close');
            }
            else {
                var tag = this._getTag();
                if (tag === 'script') this.raw = strings.endScript;
                this._pushState('open');
            }
        }
        else if (this.state === 'open' && compare(this._last, strings.comment)) {
            this.buffers.push(buf.slice(offset, i + 1));
            offset = i + 1;
            this.state = 'text';
            this.raw = strings.endComment;
            this._pushState('open');
        }
        else if (this.state === 'open' && compare(this._last, strings.cdata)) {
            this.buffers.push(buf.slice(offset, i + 1));
            offset = i + 1;
            this.state = 'text';
            this.raw = strings.endCdata;
            this._pushState('open');
        }
    }
    if (offset < buf.length) this.buffers.push(buf.slice(offset));
    next();
};

Tokenize.prototype._flush = function (next) {
    if (this.state === 'text') this._pushState('text');
    this.push(null);
    next();
};

Tokenize.prototype._pushState = function (ev) {
    if (this.buffers.length === 0) return;
    var buf = Buffer.concat(this.buffers);
    this.buffers = [];
    this.push([ ev, buf ]);
};

Tokenize.prototype._getChar = function (i) {
    var offset = 0;
    for (var j = 0; j < this.buffers.length; j++) {
        var buf = this.buffers[j];
        if (offset + buf.length > i) {
            return buf[i - offset];
        }
        offset += buf;
    }
};

Tokenize.prototype._getTag = function () {
    var offset = 0;
    var tag = '';
    for (var j = 0; j < this.buffers.length; j++) {
        var buf = this.buffers[j];
        for (var k = 0; k < buf.length; k++) {
            if (offset === 0 && k === 0) continue;
            var c = String.fromCharCode(buf[k]);
            if (/[^\w-!\[\]]/.test(c)) {
                return tag.toLowerCase();
            }
            else tag += c;
        }
        offset += buf.length;
    }
};

Tokenize.prototype._testRaw = function (buf, offset, index) {
    var raw = this.raw, last = this._last;
    if (!compare(last, raw)) return;

    this.buffers.push(buf.slice(offset, index + 1));
    var buf = Buffer.concat(this.buffers);
    var k = buf.length - raw.length;
    return [ buf.slice(0, k), buf.slice(k) ];
};

function compare (a, b) {
    if (a.length < b.length) return false;
    for (var i=a.length-1, j=b.length-1; i >= 0 && j >= 0; i--, j--) {
        if (lower(a[i]) !== lower(b[j])) return false;
    }
    return true;
}

function lower (n) {
    if (n >= 65 && n <= 90) return n + 32;
    return n;
}
<|endoftext|>


<commit_before>'use strict';

/*
 * Copyright 2014 Next Century Corporation
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

angular.module('neonDemo.directives')
.directive('countBy', ['ConnectionService', function(connectionService) {
    return {
        templateUrl: 'partials/directives/countby.html',
        restrict: 'EA',
        scope: {
        },
        link: function($scope, el) {
            el.addClass('countByDirective');

            $scope.countField = "";
            $scope.count = 0;
            $scope.fields = [];
            $scope.tableId = 'query-results-' + uuid();
            $scope.filterKey = "countby-" + uuid();
            $scope.filterSet = undefined;

            var $tableDiv = $(el).find('.count-by-grid');
            $tableDiv.attr("id", $scope.tableId);

            /**
             * Updates the size of the table to fill the available space in the directive's area.
             * @method updateSize
             * @private
             */
            var updateSize = function() {
                $('#' + $scope.tableId).height(el.height() - $(el).find('.count-by-header').outerHeight(true));
                if($scope.table) {
                    $scope.table.refreshLayout();
                }
            };

            /**
             * Initializes the name of the directive's scope variables
             * and the Neon Messenger used to monitor data change events.
             * @method initialize
             */
            $scope.initialize = function() {
                // Setup our messenger.
                $scope.messenger = new neon.eventing.Messenger();

                $scope.messenger.events({
                    activeDatasetChanged: onDatasetChanged,
                    filtersChanged: onFiltersChanged
                });

                $scope.$watch('countField', function() {
                    $scope.queryForData();
                });

                $scope.$on('$destroy', function() {
                    $scope.messenger.removeEvents();
                    if($scope.filterSet) {
                        $scope.messenger.removeFilter($scope.filterKey);
                    }
                });

                el.resize(function() {
                    updateSize();
                });

                // The header is resized whenever filtering is set or cleared.
                el.find('.count-by-header').resize(function() {
                    updateSize();
                });
            };

            function createOptions(data) {
                var options = {
                    data: data.data,
                    columns: createColumns(data.data),
                    gridOptions: {
                        forceFitColumns: true,
                        enableColumnReorder: true,
                        forceSyncScrolling: true
                    }
                };

                return options;
            }

            var createColumns = function(data) {
                var columns = tables.createColumns(data);
                for(var i = 0; i < columns.length; ++i) {
                    // Since forceFitColumns is enabled, setting this width will force the columns to use as much
                    // space as possible, which is necessary to keep the first column (dig) as small as possible.
                    columns[i].width = $tableDiv.outerWidth();
                }

                if(neon.DIG_ENABLED) {
                    var digColumn = {
                        name: "",
                        field: "dig",
                        width: "15",
                        cssClass: "centered",
                        ignoreClicks: true
                    };
                    columns.splice(0, 0, digColumn);
                }

                return columns;
            };

            /**
             * Saves the given field and value as the current filter.
             * @param {String} The filter field
             * @param {String} The filter value
             */
            var handleSetFilter = function(field, value) {
                $scope.filterSet = {
                    key: field,
                    value: value
                };
            };

            /**
             * Clears the current filter.
             */
            var clearFilter = function() {
                $scope.filterSet = undefined;
            };

            /**
             * Event handler for filter changed events issued over Neon's messaging channels.
             * @method onFiltersChanged
             * @private
             */
            var onFiltersChanged = function() {
                $scope.queryForData();
            };

            /**
             * Event handler for dataset changed events issued over Neon's messaging channels.
             * @param {Object} message A Neon dataset changed message.
             * @param {String} message.database The database that was selected.
             * @param {String} message.table The table within the database that was selected.
             * @method onDatasetChanged
             * @private
             */
            var onDatasetChanged = function(message) {
                XDATA.activityLogger.logSystemActivity('CountBy- received neon dataset changed event');
                $scope.databaseName = message.database;
                $scope.tableName = message.table;

                // if there is no active connection, try to make one.
                connectionService.connectToDataset(message.datastore, message.hostname, message.database, message.table);
                $scope.displayActiveDataset();
            };

            /**
             * Displays data for any currently active datasets.
             * @method displayActiveDataset
             */
            $scope.displayActiveDataset = function() {
                var connection = connectionService.getActiveConnection();
                if(connection) {
                    connectionService.loadMetadata(function() {
                        var info = connectionService.getActiveDataset();
                        $scope.databaseName = info.database;
                        $scope.tableName = info.table;
                        connection.getFieldNames($scope.tableName, function(results) {
                            $scope.$apply(function() {
                                $scope.fields = results;
                                $scope.queryForData();
                            });
                        });
                        $scope.queryForData();
                    });
                }
            };

            /**
             * Triggers a Neon query that pull the a number of records that match the current Neon connection
             * and filter set.  The query will be limited by the record number and sorted by the field
             * selected in this directive's form.  This directive includes support for a show-data directive attribute
             * that binds to a scope variable and controls table display.  If the bound variable evaulates to false,
             * no data table is generated.  queryForData will not issue a query until the directive thinks it needs to
             * poll for data and should show data.
             * Resets internal "need to query" state to false.
             * @method queryForData
             */
            $scope.queryForData = function() {
                if(!$scope.countField) {
                    return;
                }

                var connection = connectionService.getActiveConnection();
                if(connection) {
                    var query = $scope.buildQuery();

                    XDATA.activityLogger.logSystemActivity('CountBy - query for data');
                    connection.executeQuery(query, function(queryResults) {
                        XDATA.activityLogger.logSystemActivity('CountBy - received data');
                        $scope.$apply(function() {
                            $scope.updateData(queryResults);
                            XDATA.activityLogger.logSystemActivity('CountBy - rendered data');
                        });
                    });
                }
            };

            $scope.stripIdField = function(dataObject) {
                var data = dataObject.data;

                var cleanData = [];
                for(var i = 0; i < data.length; i++) {
                    var row = {};
                    row[$scope.countField] = data[i][$scope.countField];
                    row.count = data[i].count;
                    cleanData.push(row);
                }
                dataObject.data = cleanData;
                return dataObject;
            };

            $scope.addDigUrlColumnData = function(data) {
                data.data.forEach(function(row) {
                    var field = $scope.countField;
                    var value = row[$scope.countField];
                    var query = $scope.countField + "=" + row[$scope.countField];
                    var element = "<form action=\"" + neon.DIG_SERVER + "/list\" method=\"get\" target=\"" + query + "\">" +
                        "<input type=\"hidden\" name=\"field\" value=\"" + field + "\">" +
                        "<input type=\"hidden\" name=\"value\" value=\"" + value + "\">" +
                        "<button class=\"hidden-button\" type=\"submit\" title=\"" + query + "\">" +
                        "</button></form>";
                    row.dig = element;
                });
                return data;
            };

            /**
             * Saves the given field and value as the current filter for the
             * dashboard and this widget.
             * @param {String} The filter field
             * @param {String} The filter value
             */
            $scope.setFilter = function(field, value) {
                var connection = connectionService.getActiveConnection();
                if($scope.messenger && connection) {
                    var filterClause = neon.query.where(field, '=', value);
                    var filter = new neon.query.Filter().selectFrom($scope.databaseName, $scope.tableName).where(filterClause);
                    if(!$scope.filterSet) {
                        $scope.messenger.addFilter($scope.filterKey, filter, function() {
                            handleSetFilter(field, value);
                        });
                    } else {
                        $scope.messenger.replaceFilter($scope.filterKey, filter, function() {
                            handleSetFilter(field, value);
                        });
                    }
                }
            };

            /**
             * Adds an onClick listener for selecting the rows in the table that
             * sets a filter on the data in the selected row.
             */
            $scope.addOnClickListener = function() {
                $scope.table.addOnClickListener(function(columns, row) {
                    var columnIndex = neon.DIG_ENABLED ? 1 : 0;
                    var field = columns[columnIndex].field;

                    // If the user clicks on the filtered row/cell, clear the filter.
                    if($scope.filterSet !== undefined) {
                        if($scope.filterSet.key === field && $scope.filterSet.value === row[field]) {
                            $scope.clearFilter();
                            return;
                        }
                    }

                    $tableDiv.addClass("filtered");
                    $scope.setFilter(field, row[field]);
                });
            };

            /**
             * Updates the data bound to the table managed by this directive.  This will trigger a change in
             * the chart's visualization.
             * @param {Object} queryResults Results returned from a Neon query.
             * @param {Array} queryResults.data The aggregate numbers for the heat chart cells.
             * @method updateData
             */
            $scope.updateData = function(queryResults) {
                var cleanData = $scope.stripIdField(queryResults);

                // If the table is recreated while sorting is set, we must redo the sorting on the new table.
                var sortInfo = $scope.table ? $scope.table.sortInfo_ : {};

                $scope.tableOptions = createOptions(cleanData);

                // Add the DIG URLs after the table options have been created because it already includes the column.
                if(neon.DIG_ENABLED) {
                    cleanData = $scope.addDigUrlColumnData(cleanData);
                }

                $scope.count = cleanData.data.length;
                $scope.table = new tables.Table("#" + $scope.tableId, $scope.tableOptions).draw();
                $scope.addOnClickListener();
                updateSize();

                if(sortInfo.hasOwnProperty("field") && sortInfo.hasOwnProperty("sortAsc")) {
                    $scope.table.sortColumnAndChangeGlyph(sortInfo);
                }

                // If the table is recreated while a filter is set, we must re-select the filtered row/cells.
                if($scope.filterSet !== undefined) {
                    $scope.table.setActiveCellIfMatchExists($scope.filterSet.key, $scope.filterSet.value);
                }
            };

            /**
             * Builds a query to pull a limited set of records that match any existing filter sets.
             * @return neon.query.Query
             * @method buildQuery
             */
            $scope.buildQuery = function() {
                var query = new neon.query.Query().selectFrom($scope.databaseName, $scope.tableName)
                .groupBy($scope.countField);

                // The widget displays its own ignored rows with 0.5 opacity.
                query.ignoreFilters([$scope.filterKey]);
                query.aggregate(neon.query.COUNT, '*', 'count');

                return query;
            };

            /**
             * Removes the current filter from the dashboard and this widget.
             */
            $scope.clearFilter = function() {
                if($scope.messenger) {
                    $scope.messenger.removeFilter($scope.filterKey, function() {
                        $tableDiv.removeClass("filtered");
                        $scope.table.deselect();
                        clearFilter();
                    });
                }
            };

            neon.ready(function() {
                $scope.initialize();
                $scope.displayActiveDataset();
            });
        }
    };
}]);
<commit_msg>NEON-1357 Added error handling in the CountBy visualization.<commit_after>'use strict';

/*
 * Copyright 2014 Next Century Corporation
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

angular.module('neonDemo.directives')
.directive('countBy', ['ConnectionService', function(connectionService) {
    return {
        templateUrl: 'partials/directives/countby.html',
        restrict: 'EA',
        scope: {
        },
        link: function($scope, el) {
            el.addClass('countByDirective');

            $scope.countField = "";
            $scope.count = 0;
            $scope.fields = [];
            $scope.tableId = 'query-results-' + uuid();
            $scope.filterKey = "countby-" + uuid();
            $scope.filterSet = undefined;
            $scope.errorMessage = undefined;

            var $tableDiv = $(el).find('.count-by-grid');
            $tableDiv.attr("id", $scope.tableId);

            /**
             * Updates the size of the table to fill the available space in the directive's area.
             * @method updateSize
             * @private
             */
            var updateSize = function() {
                // Subtract an additional 2 pixels from the table height to account for the its border.
                $('#' + $scope.tableId).height(el.height() - $(el).find('.count-by-header').outerHeight(true) - 2);
                if($scope.table) {
                    $scope.table.refreshLayout();
                }
            };

            /**
             * Initializes the name of the directive's scope variables
             * and the Neon Messenger used to monitor data change events.
             * @method initialize
             */
            $scope.initialize = function() {
                // Setup our messenger.
                $scope.messenger = new neon.eventing.Messenger();

                $scope.messenger.events({
                    activeDatasetChanged: onDatasetChanged,
                    filtersChanged: onFiltersChanged
                });

                $scope.$watch('countField', function() {
                    $scope.queryForData();
                });

                $scope.$on('$destroy', function() {
                    $scope.messenger.removeEvents();
                    if($scope.filterSet) {
                        $scope.messenger.removeFilter($scope.filterKey);
                    }
                });

                el.resize(function() {
                    updateSize();
                    if($scope.errorMessage) {
                        error.resizeErrorMessage(el, $scope.errorMessage);
                    }
                });

                // The header is resized whenever filtering is set or cleared.
                el.find('.count-by-header').resize(function() {
                    updateSize();
                });
            };

            function createOptions(data) {
                var options = {
                    data: data.data,
                    columns: createColumns(data.data),
                    gridOptions: {
                        forceFitColumns: true,
                        enableColumnReorder: true,
                        forceSyncScrolling: true
                    }
                };

                return options;
            }

            var createColumns = function(data) {
                var columns = tables.createColumns(data);
                for(var i = 0; i < columns.length; ++i) {
                    // Since forceFitColumns is enabled, setting this width will force the columns to use as much
                    // space as possible, which is necessary to keep the first column (dig) as small as possible.
                    columns[i].width = $tableDiv.outerWidth();
                }

                if(neon.DIG_ENABLED) {
                    var digColumn = {
                        name: "",
                        field: "dig",
                        width: "15",
                        cssClass: "centered",
                        ignoreClicks: true
                    };
                    columns.splice(0, 0, digColumn);
                }

                return columns;
            };

            /**
             * Saves the given field and value as the current filter.
             * @param {String} The filter field
             * @param {String} The filter value
             */
            var handleSetFilter = function(field, value) {
                $scope.filterSet = {
                    key: field,
                    value: value
                };
            };

            /**
             * Clears the current filter.
             */
            var clearFilter = function() {
                $scope.filterSet = undefined;
            };

            /**
             * Event handler for filter changed events issued over Neon's messaging channels.
             * @method onFiltersChanged
             * @private
             */
            var onFiltersChanged = function() {
                $scope.queryForData();
            };

            /**
             * Event handler for dataset changed events issued over Neon's messaging channels.
             * @param {Object} message A Neon dataset changed message.
             * @param {String} message.database The database that was selected.
             * @param {String} message.table The table within the database that was selected.
             * @method onDatasetChanged
             * @private
             */
            var onDatasetChanged = function(message) {
                XDATA.activityLogger.logSystemActivity('CountBy- received neon dataset changed event');
                $scope.databaseName = message.database;
                $scope.tableName = message.table;

                // if there is no active connection, try to make one.
                connectionService.connectToDataset(message.datastore, message.hostname, message.database, message.table);
                $scope.displayActiveDataset();
            };

            /**
             * Displays data for any currently active datasets.
             * @method displayActiveDataset
             */
            $scope.displayActiveDataset = function() {
                var connection = connectionService.getActiveConnection();
                if(connection) {
                    connectionService.loadMetadata(function() {
                        var info = connectionService.getActiveDataset();
                        $scope.databaseName = info.database;
                        $scope.tableName = info.table;
                        connection.getFieldNames($scope.tableName, function(results) {
                            $scope.$apply(function() {
                                $scope.fields = results;
                                $scope.queryForData();
                            });
                        });
                        $scope.queryForData();
                    });
                }
            };

            /**
             * Triggers a Neon query that pull the a number of records that match the current Neon connection
             * and filter set.  The query will be limited by the record number and sorted by the field
             * selected in this directive's form.  This directive includes support for a show-data directive attribute
             * that binds to a scope variable and controls table display.  If the bound variable evaulates to false,
             * no data table is generated.  queryForData will not issue a query until the directive thinks it needs to
             * poll for data and should show data.
             * Resets internal "need to query" state to false.
             * @method queryForData
             */
            $scope.queryForData = function() {
                if(!$scope.countField) {
                    return;
                }

                if($scope.errorMessage) {
                    error.hideErrorMessage($scope.errorMessage);
                    $scope.errorMessage = undefined;
                }

                var connection = connectionService.getActiveConnection();
                if(connection) {
                    var query = $scope.buildQuery();

                    XDATA.activityLogger.logSystemActivity('CountBy - query for data');
                    connection.executeQuery(query, function(queryResults) {
                        $scope.$apply(function() {
                            if(queryResults.errorCode) {
                                XDATA.activityLogger.logSystemActivity('CountBy - received error');
                                $scope.errorMessage = error.showErrorMessage(el, queryResults.errorCode, queryResults.stackTrace);
                            }
                            else {
                                XDATA.activityLogger.logSystemActivity('CountBy - received data');
                            }
                            $scope.updateData(queryResults);
                            XDATA.activityLogger.logSystemActivity('CountBy - rendered data');
                        });
                    });
                }
            };

            $scope.stripIdField = function(dataObject) {
                var data = dataObject.data;

                var cleanData = [];
                for(var i = 0; i < data.length; i++) {
                    var row = {};
                    row[$scope.countField] = data[i][$scope.countField];
                    row.count = data[i].count;
                    cleanData.push(row);
                }
                dataObject.data = cleanData;
                return dataObject;
            };

            $scope.addDigUrlColumnData = function(data) {
                data.data.forEach(function(row) {
                    var field = $scope.countField;
                    var value = row[$scope.countField];
                    var query = $scope.countField + "=" + row[$scope.countField];
                    var element = "<form action=\"" + neon.DIG_SERVER + "/list\" method=\"get\" target=\"" + query + "\">" +
                        "<input type=\"hidden\" name=\"field\" value=\"" + field + "\">" +
                        "<input type=\"hidden\" name=\"value\" value=\"" + value + "\">" +
                        "<button class=\"hidden-button\" type=\"submit\" title=\"" + query + "\">" +
                        "</button></form>";
                    row.dig = element;
                });
                return data;
            };

            /**
             * Saves the given field and value as the current filter for the
             * dashboard and this widget.
             * @param {String} The filter field
             * @param {String} The filter value
             */
            $scope.setFilter = function(field, value) {
                var connection = connectionService.getActiveConnection();
                if($scope.messenger && connection) {
                    var filterClause = neon.query.where(field, '=', value);
                    var filter = new neon.query.Filter().selectFrom($scope.databaseName, $scope.tableName).where(filterClause);
                    if(!$scope.filterSet) {
                        $scope.messenger.addFilter($scope.filterKey, filter, function() {
                            handleSetFilter(field, value);
                        });
                    } else {
                        $scope.messenger.replaceFilter($scope.filterKey, filter, function() {
                            handleSetFilter(field, value);
                        });
                    }
                }
            };

            /**
             * Adds an onClick listener for selecting the rows in the table that
             * sets a filter on the data in the selected row.
             */
            $scope.addOnClickListener = function() {
                $scope.table.addOnClickListener(function(columns, row) {
                    var columnIndex = neon.DIG_ENABLED ? 1 : 0;
                    var field = columns[columnIndex].field;

                    // If the user clicks on the filtered row/cell, clear the filter.
                    if($scope.filterSet !== undefined) {
                        if($scope.filterSet.key === field && $scope.filterSet.value === row[field]) {
                            $scope.clearFilter();
                            return;
                        }
                    }

                    $tableDiv.addClass("filtered");
                    $scope.setFilter(field, row[field]);
                });
            };

            /**
             * Updates the data bound to the table managed by this directive.  This will trigger a change in
             * the chart's visualization.
             * @param {Object} queryResults Results returned from a Neon query.
             * @param {Array} queryResults.data The aggregate numbers for the heat chart cells.
             * @method updateData
             */
            $scope.updateData = function(queryResults) {
                var cleanData = $scope.stripIdField(queryResults);

                // If the table is recreated while sorting is set, we must redo the sorting on the new table.
                var sortInfo = $scope.table ? $scope.table.sortInfo_ : {};

                $scope.tableOptions = createOptions(cleanData);

                // Add the DIG URLs after the table options have been created because it already includes the column.
                if(neon.DIG_ENABLED) {
                    cleanData = $scope.addDigUrlColumnData(cleanData);
                }

                $scope.count = cleanData.data.length;
                $scope.table = new tables.Table("#" + $scope.tableId, $scope.tableOptions).draw();
                $scope.addOnClickListener();
                updateSize();

                if(sortInfo.hasOwnProperty("field") && sortInfo.hasOwnProperty("sortAsc")) {
                    $scope.table.sortColumnAndChangeGlyph(sortInfo);
                }

                // If the table is recreated while a filter is set, we must re-select the filtered row/cells.
                if($scope.filterSet !== undefined) {
                    $scope.table.setActiveCellIfMatchExists($scope.filterSet.key, $scope.filterSet.value);
                }
            };

            /**
             * Builds a query to pull a limited set of records that match any existing filter sets.
             * @return neon.query.Query
             * @method buildQuery
             */
            $scope.buildQuery = function() {
                var query = new neon.query.Query().selectFrom($scope.databaseName, $scope.tableName)
                .groupBy($scope.countField);

                // The widget displays its own ignored rows with 0.5 opacity.
                query.ignoreFilters([$scope.filterKey]);
                query.aggregate(neon.query.COUNT, '*', 'count');

                return query;
            };

            /**
             * Removes the current filter from the dashboard and this widget.
             */
            $scope.clearFilter = function() {
                if($scope.messenger) {
                    $scope.messenger.removeFilter($scope.filterKey, function() {
                        $tableDiv.removeClass("filtered");
                        $scope.table.deselect();
                        clearFilter();
                    });
                }
            };

            neon.ready(function() {
                $scope.initialize();
                $scope.displayActiveDataset();
            });
        }
    };
}]);
<|endoftext|>


<commit_before>var amino = require('amino.js');
var data = require('./countries.js');
var onecolor = require('onecolor');

var fs = require('fs');
var cities = JSON.parse(fs.readFileSync(__dirname+'/cities.json').toString());

var w = 1280;//1920;
var h = 768;//1080;
var radius = w/6;

amino.start(function(core, stage) {

    setupFont();

    stage.setSize(w,h);
    var root = new amino.Group();
    stage.setRoot(root);

    //the globe
    var group = new amino.Group();
    root.add(group);

    buildGlobe(group);

    //lower left bar charts
    root.add(createBar1(200,50,15, '#3333ff').x(5).y(500));
    root.add(createBar1(200,50,15, '#ffff33').x(5).y(700).sy(-1));

    makeHeader(root);

    makeFooterSymbols(root);

    //root.add(createParticles().x(w-250).y(h));

    root.add(buildDashboard().y(130));

});

function buildDashboard() {
    var group = new amino.Group();
    function addLine(text, x, y, glyph) {
        group.add(new amino.Rect()
            .x(x+5)
            .y(y-25)
            .w(200)
            .h(32)
            .fill("#ea5036")
            )
        group.add(new amino.Text()
            .text(text)
            .fill("#fcfbcf")
            .fontName('mech')
            .fontSize(30)
            .x(x+10)
            .y(y)
        );
        if(glyph) {
            group.add(new amino.Text()
                .text(glyph)
                .fill("#fcfbcf")
                .fontName('awesome')
                .fontSize(20)
                .x(x+200-25)
                .y(y-2)
            );
        }
    }

    function addSmallLine(text, x, y) {
        group.add(new amino.Text()
            .text(text)
            .fill("#fcfbcf")
            .fontName('mech')
            .fontSize(20)
            .x(x+15)
            .y(y)
        );
    }

    {
        var x = 0;
        addLine("ENDO SYS OS / MAKR PROC",x,0);
        addSmallLine("RDOZ - 25889",x,30);
        addSmallLine("ZODR - 48639",x,50);
        addSmallLine("FEEA - 92651",x,70);
        addSmallLine("DEAD - 02833",x,90);
    }

    {
        var x = 0;
        var y = 130;
        addLine("FOO_MAR.TCX",x,y+0,'\uf071');
        addSmallLine("analysis - 48%",x,y+30);
        addSmallLine("actualizing - 99%",x,y+50);
        addSmallLine("rentrance - 0.02%",x,y+70);
    }

    {
        var x = w-200-10;
        var y = 0;
        addLine("Core Extraction",x,y+0,'\uf0e4');
        addSmallLine("pulverton - 143.888",x,y+30);
        addSmallLine("minotaur - 105%",x,y+50);
        addSmallLine("gravitation 26.8%",x,y+70);
    }

    {
        var x = w-200-10;
        var y = 120;
        addLine("FEED CR55X \\ Analysis",x,y+0);
        addSmallLine("reconst - 48%",x,y+30);
        addSmallLine("fargonite - 99%",x,y+50);
        addSmallLine("sleestack - 0.02%",x,y+70);

    }
    {
        var x = w-200-10;
        var y = 250;
        addLine("$SHIP_CAM$.FXD",x,y+0,'\uf06d');
        addSmallLine("fracturizing - 128%",x,y+30);
        addSmallLine("detox - 43%",x,y+50);
        addSmallLine("xantos 45% 8%",x,y+70);
    }
    {
        var x = w-200-10;
        var y = 350;
        addLine("XenoPhage",x,y+0,'\uf126');
        addSmallLine("scent analysis - 128%",x,y+30);
        addSmallLine("oxygenize - 43%",x,y+50);
        addSmallLine("heliotrop **",x,y+70);
    }

    return group;
}

function makeFooterSymbols(root) {
    for(var i=0; i<7; i++)  {
        var sun = new amino.Group().x(w/2-300 + i*100).y(h-50).rz(30);
        sun.add(new amino.Text()
            .fontName('awesome').fontSize(80).text('\uf0d8')
            .x(-25).y(25).fill("#fcfbcf")
        );
        var start = Math.random()*90-45;
        var len = Math.random()*5000+5000;

        sun.rz.anim().from(start).to(start+90).dur(len).loop(-1).autoreverse(true).start();
        root.add(sun);
    }

}

function makeHeader(root) {
    root.add(new amino.Rect().fill('#ff0000').w(w).h(100).opacity(0.5));
    root.add(new amino.Text()
        .text('Awesomonium Levels')
        .fontSize(80)
        .fontName('mech')
        .x(20)
        .y(70)
        .fill("#fcfbcf")
        )
    root.add(createBar1(50,100,5, '#fcfbcf').x(500).y(75).rz(-90));
    root.add(new amino.Text()
        .text('Atomization')
        .fontSize(80)
        .fontName('mech')
        .x(w-320)
        .y(70)
        .fill("#fcfbcf")
        )

    //beaker symbol
    root.add(new amino.Text()
        .fontName('awesome').text('\uf0c3').fontSize(80)
        .x(w-85).y(70).fill("#fcfbcf")
        )
}

function buildGlobe(group) {

    var cos = Math.cos;
    var sin = Math.sin;
    var PI = Math.PI;

    function latlon2xyz(lat,lon, rad) {
        var el = lat/180.0*PI;
        var az = lon/180.0*PI;
        var x = rad * cos(el) * sin(az);
        var y = rad * cos(el) * cos(az);
        var z = rad * sin(el);
        return [x,y,z];
    }

    function addCountry(nz) {
        //make the geometry
        for(var i=0; i<nz.borders.length; i++) {
            var border = nz.borders[i];
            var points = [];
            var poly = new amino.Polygon();
            for(var j=0; j<border.length; j++) {
                var point = border[j];
                var pts = latlon2xyz(point.lat,point.lng,radius);
                points.push(pts[0]);
                points.push(pts[1]);
                points.push(pts[2]);
            }
            poly.fill("#80ff80");
            poly.geometry(points);
            poly.dimension(3);
            group.add(poly);
        }
    }

    for(var i=0; i<data.countries.length; i++) {
        addCountry(data.countries[i]);
    }

    // NOTE: on Raspberry pi we can't just make a line.
    // A polygon needs at least two segments.
    function addLine(lat,lon,el, color) {
        var poly = new amino.Polygon();
        var pt1 = latlon2xyz(lat,lon,radius);
        var pt2 = latlon2xyz(lat,lon,radius+el);
        var pt3 = latlon2xyz(lat,lon,radius);
        var points = pt1.concat(pt2).concat(pt3);

        poly.fill(color);
        poly.geometry(points);
        poly.dimension(3);
        group.add(poly);
    }

    //add a line at portland
    cities.features.forEach(function(city) {
        var color = '#ff00ff';
        var hue = city.properties.city.length / 20;
        addLine(city.geometry.coordinates[1],
                city.geometry.coordinates[0],
                100*hue,
                onecolor('red').hue(hue).hex());
    });

    // center
    group.x(w/2).y(h/2);
    //turn earth upright
    group.rx(90);
    group.ry(0);
    group.rz(0);

    // spin it forever
    //core.createPropAnim(group,"rotateZ",0,-360,60*1000).setCount(-1);

}

function createBar1(w,h,count,color) {
    var gr = new amino.Group();
    var rects = [];
    var barw = w/count;
    for(var i=0; i<count; i++) {
        var rect = new amino.Rect()
            .x(i*barw).y(0)
            .w(barw-5)
            .h(30)
            .fill(color)
            ;
        rects.push(rect);
        gr.add(rect);
    }

    function update() {
        rects.forEach(function(rect) {
            rect.h(20+Math.random()*(h-20));
        });
    }

    setInterval(update,100);

    return gr;
}

function frand(min,max) {
    return Math.random()*(max-min) + min;
}

function setupFont() {
    amino.registerFont({
         name:'mech',
         path:__dirname+'/resources/',
         weights: {
              400: {
                   normal:'MechEffects1BB_reg.ttf',
                   italic:'MechEffects1BB_ital.ttf',
              },
         }
    });
}
<commit_msg>turn animation back on<commit_after>var amino = require('amino.js');
var data = require('./countries.js');
var onecolor = require('onecolor');

var fs = require('fs');
var cities = JSON.parse(fs.readFileSync(__dirname+'/cities.json').toString());

var w = 1280;//1920;
var h = 768;//1080;
var radius = w/6;

amino.start(function(core, stage) {

    setupFont();

    stage.setSize(w,h);
    var root = new amino.Group();
    stage.setRoot(root);

    //the globe
    var group = new amino.Group();
    root.add(group);

    buildGlobe(group);

    //lower left bar charts
    root.add(createBar1(200,50,15, '#3333ff').x(5).y(500));
    root.add(createBar1(200,50,15, '#ffff33').x(5).y(700).sy(-1));

    makeHeader(root);

    makeFooterSymbols(root);

    //root.add(createParticles().x(w-250).y(h));

    root.add(buildDashboard().y(130));

});

function buildDashboard() {
    var group = new amino.Group();
    function addLine(text, x, y, glyph) {
        group.add(new amino.Rect()
            .x(x+5)
            .y(y-25)
            .w(200)
            .h(32)
            .fill("#ea5036")
            )
        group.add(new amino.Text()
            .text(text)
            .fill("#fcfbcf")
            .fontName('mech')
            .fontSize(30)
            .x(x+10)
            .y(y)
        );
        if(glyph) {
            group.add(new amino.Text()
                .text(glyph)
                .fill("#fcfbcf")
                .fontName('awesome')
                .fontSize(20)
                .x(x+200-25)
                .y(y-2)
            );
        }
    }

    function addSmallLine(text, x, y) {
        group.add(new amino.Text()
            .text(text)
            .fill("#fcfbcf")
            .fontName('mech')
            .fontSize(20)
            .x(x+15)
            .y(y)
        );
    }

    {
        var x = 0;
        addLine("ENDO SYS OS / MAKR PROC",x,0);
        addSmallLine("RDOZ - 25889",x,30);
        addSmallLine("ZODR - 48639",x,50);
        addSmallLine("FEEA - 92651",x,70);
        addSmallLine("DEAD - 02833",x,90);
    }

    {
        var x = 0;
        var y = 130;
        addLine("FOO_MAR.TCX",x,y+0,'\uf071');
        addSmallLine("analysis - 48%",x,y+30);
        addSmallLine("actualizing - 99%",x,y+50);
        addSmallLine("rentrance - 0.02%",x,y+70);
    }

    {
        var x = w-200-10;
        var y = 0;
        addLine("Core Extraction",x,y+0,'\uf0e4');
        addSmallLine("pulverton - 143.888",x,y+30);
        addSmallLine("minotaur - 105%",x,y+50);
        addSmallLine("gravitation 26.8%",x,y+70);
    }

    {
        var x = w-200-10;
        var y = 120;
        addLine("FEED CR55X \\ Analysis",x,y+0);
        addSmallLine("reconst - 48%",x,y+30);
        addSmallLine("fargonite - 99%",x,y+50);
        addSmallLine("sleestack - 0.02%",x,y+70);

    }
    {
        var x = w-200-10;
        var y = 250;
        addLine("$SHIP_CAM$.FXD",x,y+0,'\uf06d');
        addSmallLine("fracturizing - 128%",x,y+30);
        addSmallLine("detox - 43%",x,y+50);
        addSmallLine("xantos 45% 8%",x,y+70);
    }
    {
        var x = w-200-10;
        var y = 350;
        addLine("XenoPhage",x,y+0,'\uf126');
        addSmallLine("scent analysis - 128%",x,y+30);
        addSmallLine("oxygenize - 43%",x,y+50);
        addSmallLine("heliotrop **",x,y+70);
    }

    return group;
}

function makeFooterSymbols(root) {
    for(var i=0; i<7; i++)  {
        var sun = new amino.Group().x(w/2-300 + i*100).y(h-50).rz(30);
        sun.add(new amino.Text()
            .fontName('awesome').fontSize(80).text('\uf0d8')
            .x(-25).y(25).fill("#fcfbcf")
        );
        var start = Math.random()*90-45;
        var len = Math.random()*5000+5000;

        sun.rz.anim().from(start).to(start+90).dur(len).loop(-1).autoreverse(true).start();
        root.add(sun);
    }

}

function makeHeader(root) {
    root.add(new amino.Rect().fill('#ff0000').w(w).h(100).opacity(0.5));
    root.add(new amino.Text()
        .text('Awesomonium Levels')
        .fontSize(80)
        .fontName('mech')
        .x(20)
        .y(70)
        .fill("#fcfbcf")
        )
    root.add(createBar1(50,100,5, '#fcfbcf').x(500).y(75).rz(-90));
    root.add(new amino.Text()
        .text('Atomization')
        .fontSize(80)
        .fontName('mech')
        .x(w-320)
        .y(70)
        .fill("#fcfbcf")
        )

    //beaker symbol
    root.add(new amino.Text()
        .fontName('awesome').text('\uf0c3').fontSize(80)
        .x(w-85).y(70).fill("#fcfbcf")
        )
}

function buildGlobe(group) {

    var cos = Math.cos;
    var sin = Math.sin;
    var PI = Math.PI;

    function latlon2xyz(lat,lon, rad) {
        var el = lat/180.0*PI;
        var az = lon/180.0*PI;
        var x = rad * cos(el) * sin(az);
        var y = rad * cos(el) * cos(az);
        var z = rad * sin(el);
        return [x,y,z];
    }

    function addCountry(nz) {
        //make the geometry
        for(var i=0; i<nz.borders.length; i++) {
            var border = nz.borders[i];
            var points = [];
            var poly = new amino.Polygon();
            for(var j=0; j<border.length; j++) {
                var point = border[j];
                var pts = latlon2xyz(point.lat,point.lng,radius);
                points.push(pts[0]);
                points.push(pts[1]);
                points.push(pts[2]);
            }
            poly.fill("#80ff80");
            poly.geometry(points);
            poly.dimension(3);
            group.add(poly);
        }
    }

    for(var i=0; i<data.countries.length; i++) {
        addCountry(data.countries[i]);
    }

    // NOTE: on Raspberry pi we can't just make a line.
    // A polygon needs at least two segments.
    function addLine(lat,lon,el, color) {
        var poly = new amino.Polygon();
        var pt1 = latlon2xyz(lat,lon,radius);
        var pt2 = latlon2xyz(lat,lon,radius+el);
        var pt3 = latlon2xyz(lat,lon,radius);
        var points = pt1.concat(pt2).concat(pt3);

        poly.fill(color);
        poly.geometry(points);
        poly.dimension(3);
        group.add(poly);
    }

    //add a line at portland
    cities.features.forEach(function(city) {
        var color = '#ff00ff';
        var hue = city.properties.city.length / 20;
        addLine(city.geometry.coordinates[1],
                city.geometry.coordinates[0],
                100*hue,
                onecolor('red').hue(hue).hex());
    });

    // center
    group.x(w/2).y(h/2);
    //turn earth upright
    group.rx(90);
    group.ry(0);
    group.rz(0);

    // spin it forever
    group.rz.anim().from(0).to(360).dur(60*1000).loop(-1).start();
    //core.createPropAnim(group,"rotateZ",0,-360,60*1000).setCount(-1);

}

function createBar1(w,h,count,color) {
    var gr = new amino.Group();
    var rects = [];
    var barw = w/count;
    for(var i=0; i<count; i++) {
        var rect = new amino.Rect()
            .x(i*barw).y(0)
            .w(barw-5)
            .h(30)
            .fill(color)
            ;
        rects.push(rect);
        gr.add(rect);
    }

    function update() {
        rects.forEach(function(rect) {
            rect.h(20+Math.random()*(h-20));
        });
    }

    setInterval(update,100);

    return gr;
}

function frand(min,max) {
    return Math.random()*(max-min) + min;
}

function setupFont() {
    amino.registerFont({
         name:'mech',
         path:__dirname+'/resources/',
         weights: {
              400: {
                   normal:'MechEffects1BB_reg.ttf',
                   italic:'MechEffects1BB_ital.ttf',
              },
         }
    });
}
<|endoftext|>


<commit_before>CD3.Behaviors({
  'body:ajax:after': {
    '.action_form':       function(e, element){
                            if (element.getAttribute('data-disable') !== 'false'){
                              element.addClassName('loading');
                              element.getElements().invoke('disable');
                            }
                          },
    '.edit':              function(e, element){
                            element.addClassName('loading');
                          }
  },
  '#sections':            function(){
                            Taskar.Sections.Ordering(this);
                            Taskar.Sections.NewSection(this);
                          },
  '#section_title':       Taskar.Sections.Title,
  '#sections_show':       Taskar.Sections.Actions,
  '#tasks_index':         Taskar.Sections.Actions,
  '#section_aside':       Taskar.Sections.Aside.initialize,
  '#user_card':           Taskar.Sections.NewStatus,
  '#tasks':               Taskar.Sections.TaskList,
  '#tasks_show':          Taskar.Sections.Comments,
  '#feedback':            Taskar.Sections.Feedback,
  'body':                 Taskar.Dnd.Sortable.AjaxSave,
  '#live_search':         Taskar.UI.LiveSearch.Form,
  'li.tasks_stats ul':    Taskar.Graphics.createPieChart,
  '#statuses_list:ajax:delete': function(e){ Taskar.FX.dropOut(e.findElement('li'), function(e){e.element.remove()}); },
  '#tasks_show:ajax:put': {
    '.archive': function(e){
      var task = e.findElement('.task');
      if (task){
        if (task.hasClassName('archived')){
          task.removeClassName('archived');
          task.down('.checkbox').writeAttribute('data-disabled', null);
        } else {
          task.addClassName('archived');
          task.down('.checkbox').writeAttribute('data-disabled', 'true');
        }
      }
    }
  },
  '#scroll_to_top:click': function(e){
                            e.stop();

                            var id      = this.getAttribute('href').split('#').last(),
                                element = $(id);

                            element && new Taskar.FX.ScrollTo(element, function(){ location.hash = id; });
                          }
});<commit_msg>toggle new_comment form on archive changes<commit_after>CD3.Behaviors({
  'body:ajax:after': {
    '.action_form':       function(e, element){
                            if (element.getAttribute('data-disable') !== 'false'){
                              element.addClassName('loading');
                              element.getElements().invoke('disable');
                            }
                          },
    '.edit':              function(e, element){
                            element.addClassName('loading');
                          }
  },
  '#sections':            function(){
                            Taskar.Sections.Ordering(this);
                            Taskar.Sections.NewSection(this);
                          },
  '#section_title':       Taskar.Sections.Title,
  '#sections_show':       Taskar.Sections.Actions,
  '#tasks_index':         Taskar.Sections.Actions,
  '#section_aside':       Taskar.Sections.Aside.initialize,
  '#user_card':           Taskar.Sections.NewStatus,
  '#tasks':               Taskar.Sections.TaskList,
  '#tasks_show':          Taskar.Sections.Comments,
  '#feedback':            Taskar.Sections.Feedback,
  'body':                 Taskar.Dnd.Sortable.AjaxSave,
  '#live_search':         Taskar.UI.LiveSearch.Form,
  'li.tasks_stats ul':    Taskar.Graphics.createPieChart,
  '#statuses_list:ajax:delete': function(e){ Taskar.FX.dropOut(e.findElement('li'), function(e){e.element.remove()}); },
  '#tasks_show:ajax:put': {
    '.archive': function(e){
      var task = e.findElement('.task');
      if (task){
        var newComment = $('new_comment');
        if (task.hasClassName('archived')){
          task.removeClassName('archived');
          task.down('.checkbox').writeAttribute('data-disabled', null);
          newComment && newComment.slideDown();
        } else {
          task.addClassName('archived');
          task.down('.checkbox').writeAttribute('data-disabled', 'true');
          newComment && newComment.slideUp();
        }
      }
    }
  },
  '#scroll_to_top:click': function(e){
                            e.stop();

                            var id      = this.getAttribute('href').split('#').last(),
                                element = $(id);

                            element && new Taskar.FX.ScrollTo(element, function(){ location.hash = id; });
                          }
});<|endoftext|>


<commit_before>/**
* Require stub for browser.
* Prepend this script in head.
* Set `data-module="name"` attribute on script tag to define module name to register (or it will be parsed as src file name).
*/

//TODO: wrap requirements into scopes

(function(global){
if (global.require) {
	throw Error('Turn off `require-stub`: another `require` is on.');
	return;
}

var prefix = 'require-stub-';
var firstRun = !localStorage.getItem(prefix + 'ready');

/** try to look up for script (causes 404 requests) */
require.lookUpModules = true;

/** modules storage */
var modules = require.modules = {};
/** paths-names dict */
var modulePaths = require.modulePaths = {};

/** packages storage: `moduleName:package`, `path:package` */
var packages = {};

/** stack of errors to log */
var errors = [];

/** list of native node modules */
var nativeModules = {
	'assert': true,
	'buffer': true,
	'child_process': true,
	'cluster': true,
	'crypto': false,
	'dns': true,
	'domain': true,
	'events': true,
	'fs': true,
	'http': true,
	'https': true,
	'net': true,
	'os': true,
	'path': true,
	'punycode': true,
	'querystring': true,
	'readline': true,
	'stream': true,
	'string_decoder': true,
	'tls': true,
	'dgram': true,
	'url': true,
	'util': true,
	'vm': true,
	'zlib': true
};

//script run emulation
var fakeCurrentScript, fakeStack = [];

console.groupCollapsed('package.json')

// http://localhost:8000/
var rootPath = getAbsolutePath('/');
// http://localhost:8000/test/
var currPath = getAbsolutePath('');

//reach root (initial) package.json (closest one to the current url)
var selfPkg = requestClosestPkg(getAbsolutePath(''));

if (!selfPkg) console.warn('Can’t find main package.json by `' + rootPath + '` nor by `' +  getAbsolutePath('') + '`.');

console.groupEnd();

/** export function */
global.require = require;

/** require stub */
function require(name){
	if (!name) throw Error('Bad module name `' + name + '`');

	//ignore errorred previous requires
	// if (errors.length) return;

	console.groupCollapsed('require(\'' + name + '\') ', getCurrentScript().src || global.location + '');

	//try to fetch existing module
	var result = getModule(unjs(name.toLowerCase()));
	if (result) {
		console.groupEnd();
		return result;
	}

	//get current script dir
	var currDir = getDir(getAbsolutePath(getCurrentScript().src));

	//if not - try to look up for module
	if (require.lookUpModules) {
		//clean js suffix
		name = unjs(name);

		//try to reach module by path
		//./chai/a.js
		var path = getAbsolutePath(currDir + name + '.js');
		var sourceCode = requestFile(path);

		//./chai/a/index.js
		if (!sourceCode) {
			path = getAbsolutePath(currDir + name + '/index.js');
			sourceCode = requestFile(path);
		}

		//if found - eval script
		if (sourceCode) {
			try {
				evalScript({code: sourceCode, src:path, 'data-module-name': name, 'name': name });
			}catch(e){throw e}
			finally{
				console.groupEnd();
			}
			return getModule(name);
		}

		//if is not found, try to reach dependency from the current script package.json
		var pkg = requestClosestPkg(currDir);
		if (pkg) {
			var pkgDir = pkg._dir;
			console.log('load dependency from', pkgDir + 'package.json');

			//try to reach dependency’s package.json and get path from it
			var depPkg = requestPkg(pkgDir + 'node_modules/' + name + '/');
			if (depPkg) {
				if (!depPkg.main) depPkg.main = 'index.js';
				else depPkg.main = unjs(depPkg.main) + '.js';
				path = depPkg._dir + depPkg.main;
				sourceCode = requestFile(path);
				if (sourceCode) {
					try{
						evalScript({code: sourceCode, src:path, 'data-module-name': name, 'name': name });
					}catch(e){throw e}
					finally{
						console.groupEnd();
					}
					return getModule(name);
				}
			}
		}

		//try to fetch dependency from all the known (registered) packages
		var tPkg;
		for (var pkgName in packages) {
			tPkg = packages[pkgName];
			if (tPkg.name === name) {
				path = tPkg._dir + tPkg.main;
				sourceCode = requestFile(path);
				if (sourceCode) {
					try{
						evalScript({code: sourceCode, src:path, 'data-module-name': name, 'name': name });
					}catch(e){throw e}
					finally{
						console.groupEnd();
					}
					return getModule(name);
				}
			}
		}

		//if is not found - try to fetch from node_modules folder, if any (no need package.json)
		var commonPaths = [
			'node_modules/{{name}}/index.js',
			'node_modules/{{name}}/{{name}}.js',
			'node_modules/{{name}}/main.js',
			'node_modules/{{name}}/lib/{{name}}.js',
			'node_modules/{{name}}/lib/index.js',
			'node_modules/{{name}}/src/{{name}}.js',
			'node_modules/{{name}}/src/index.js',
			'node_modules/{{name}}/dist/{{name}}.js'
		];

		//try relative node_modules folder
		for (var i = 0, path; i < commonPaths.length; i++){
			path = commonPaths[i].replace(/{{name}}/ig, name);
			path = currDir + path;
			sourceCode = requestFile(path);
			if (sourceCode) {
				try{evalScript({code: sourceCode, src:path, 'data-module-name': name, 'name': name });
				}catch(e){throw e}
				finally{
					console.groupEnd();
				}
				return getModule(name);
			}
		}

		//try initial node_modules folder
		for (var i = 0, path; i < commonPaths.length; i++){
			path = commonPaths[i].replace(/{{name}}/ig, name);
			path = currPath + path;
			sourceCode = requestFile(path);
			if (sourceCode) {
				try{evalScript({code: sourceCode, src:path, 'data-module-name': name, 'name': name });
				}catch(e){throw e}
				finally{
					console.groupEnd();
				}
				return getModule(name);
			}
		}

		//try root node_modules folder
		for (var i = 0, path; i < commonPaths.length; i++){
			path = commonPaths[i].replace(/{{name}}/ig, name);
			path = rootPath + path;
			sourceCode = requestFile(path);
			if (sourceCode) {
				try{evalScript({code: sourceCode, src:path, 'data-module-name': name, 'name': name });
				}catch(e){throw e}
				finally{
					console.groupEnd();
				}
				return getModule(name);
			}
		}
	}

	//close require group
	console.groupEnd();

	//force native modules throw error
	if (nativeModules[name]) throw Error('Can’t include native module `' + name + '` in browser');

	//save error to log
	var scriptSrc = getCurrentScript().src;
	scriptSrc = scriptSrc || global.location + '';
	var error = new Error('Can’t find module `' + name + '` in `' + scriptSrc + '`. Possibly the module is not installed. Please, install it or include script on the page.');

	errors.push(error);

	throw error;
}

/** retrieve module from storage by name */
function getModule(name){
	var currDir = getDir(getCurrentScript().src);
	var resolvedName = getAbsolutePath(currDir + name);
	var result = global[name] || global[name[0].toUpperCase() + name.slice(1)] || modules[name] || modules[modulePaths[resolvedName]] || modules[modulePaths[resolvedName+'.js']];

	return result;
}

/** return dir from path */
function getDir(path){
	var arr = path.split(/[\\\/]/);
	arr.pop();
	return arr.join('/') + '/';
}

/** return absolute path */
function getAbsolutePath(path){
	var a = document.createElement('a');
	a.href = path;
	return a.href;
}

/** return file by path */
function requestFile(path){
	// console.log('resolve', path)
	//FIXME: XHR is forbidden without server. Try to resolve via script/image/etc
	try {
		request = new XMLHttpRequest();

		// `false` makes the request synchronous
		request.open('GET', path, false);
		request.send();
	}

	catch (e) {
		return false;
	}

	finally {
		if (request.status === 200) {
			// console.log('SUCCESS', request);
			return request.response;
		}
	}

	return false;
}

/** Return closest package to the path */
function requestClosestPkg(path) {
	var file;
	if (path[path.length - 1] === '/') path = path.slice(0, -1);
	while (path) {
		pkg = requestPkg(path);
		if (pkg) {
			return pkg;
		}
		path = path.slice(0, path.lastIndexOf('/'));
	}
	return false;
}

/**
 * Return package.json parsed by the path requested, or false
 */
function requestPkg(path){
	//return cached pkg
	if (packages[path]) return packages[path];

	if (path[path.length - 1] === '/') path = path.slice(0, -1);
	file = requestFile(path + '/package.json');

	if (file) {
		var result = JSON.parse(file);
		//save path to package.json
		result._dir = path + '/';

		//save package
		var name = result.name || path.slice(path.lastIndexOf('/') + 1);

		//preset pkg name
		if (!result.name) result.name = name;
		if (!result.main) result.main = 'index.js';

		if (!packages[name]){
			packages[name] = result;
			packages[path] = result;
		}

		//save all nested packages
		if (result.dependencies){
			for (var depName in result.dependencies){
				requestPkg(path + '/node_modules/' + depName);
			}
		}
		return result;
	}
	return false;
}

/** eval & create fake script */
function evalScript(obj){
	var name = obj.name;
	// console.group('eval', name)

	//we need to keep fake <script> tags in order to comply with inner require calls, referencing .currentScript and .src attributes
	fakeCurrentScript = obj;
	fakeStack.push(obj);
	fakeCurrentScript.getAttribute = function(name){
		return this[name];
	};
	try {
		eval(obj.code);
	}
	catch (e){
		throw e;
	}
	finally{
		fakeStack.pop();
		fakeCurrentScript = fakeStack[fakeStack.length - 1];
	}

	// console.log('endeval', name, getModule(name))
	// console.groupEnd();
}

/** Export module emulation */
var module = global.module = {};

// Listen to `module.exports` change
Object.defineProperty(module, 'exports', {
	configurable: false,
	enumerable: false,
	get: hookExports,
	set: hookExports
});

//Listen to `exports` change
Object.defineProperty(global, 'exports', {
	configurable: false,
	enumerable: false,
	get: hookExports,
	set: hookExports
});

//any time exports required winthin the new script - create a new module
var lastExports, lastScript, lastModuleName;

/** hook for modules/exports accessors */
function hookExports(v){
	var script = getCurrentScript();

	//if script hasn’t changed - keep current exports
	if (!arguments.length && script === lastScript) return lastExports;

	//if script changed - create a new module with exports
	lastScript = script;
	var moduleName = inferModuleName(script);

	//ignore scripts with undefined moduleName/src
	if (!moduleName) throw Error('Can’t infer module name. Define it via `data-module="name"` attribute on the script.')

	//save new module path
	modulePaths[script.src] = moduleName;
	modulePaths[script.src.toLowerCase()] = moduleName;
	modulePaths[script.getAttribute('src')] = moduleName;

	//@deprecated if module exists - ignore saving
	// if (modules[moduleName]) return modules[moduleName];

	lastModuleName = moduleName;
	lastExports = v || {};

	// console.log('new module', moduleName);
	//else - save a new module (e.g. enot/index.js)
	modules[moduleName] = lastExports;

	//save no-js module name (e.g. enot/index)
	moduleName = unjs(moduleName);
	modules[moduleName] = lastExports;

	//save package name (e.g. enot)
	moduleName = moduleName.split(/[\\\/]/)[0];
	modules[moduleName] = lastExports;

	return lastExports;
}

/** try to retrieve module name from script tag */
function inferModuleName(script){
	//name is clearly defined
	var moduleName = script.getAttribute('data-module-name');

	//return parsed name, if pointed
	if (moduleName) return moduleName.toLowerCase();

	//plugin is in the node_modules
	var path = script.src;

	//catch dirname after last node_modules dirname, if any
	var idx = path.lastIndexOf('node_modules');
	if (idx >= 0){
		path = path.slice(idx);
		var matchResult = /node_modules[\/\\](.+)/.exec(path);
		moduleName = matchResult[1];
	}

	//else take file name as the module name
	if (!moduleName) {
		moduleName = script.getAttribute('src');

		//clear name
		moduleName = moduleName.split(/[\\\/]/).pop().split('.').shift();
	}

	return moduleName.toLowerCase();
}

/** get current script tag, taking into account fake scripts running */
function getCurrentScript(){
	if (fakeCurrentScript) return fakeCurrentScript;

	if (document.currentScript) return document.currentScript;

	var scripts = document.getElementsByTagName('script');
	return scripts[scripts.length - 1];
}

/**
 * Get rid of .js suffix
 */
function unjs(name){
	if (/\.js$/.test(name)) return name.slice(0, -3);
	return name;
}

})(window);<commit_msg>Show files where virtual errors took place<commit_after>/**
* Require stub for browser.
* Prepend this script in head.
* Set `data-module="name"` attribute on script tag to define module name to register (or it will be parsed as src file name).
*/

//TODO: wrap requirements into scopes (seems that it’s ok now - why?)
//TODO: show line numbers of errors
//TODO: save paths to the once found modules

(function(global){
if (global.require) {
	throw Error('Turn off `require-stub`: another `require` is on.');
	return;
}

var prefix = 'require-stub-';
var firstRun = !localStorage.getItem(prefix + 'ready');

/** try to look up for script (causes 404 requests) */
require.lookUpModules = true;

/** modules storage */
var modules = require.modules = {};
/** paths-names dict */
var modulePaths = require.modulePaths = {};

/** packages storage: `moduleName:package`, `path:package` */
var packages = {};

/** stack of errors to log */
var errors = [];

/** list of native node modules */
var nativeModules = {
	'assert': true,
	'buffer': true,
	'child_process': true,
	'cluster': true,
	'crypto': false,
	'dns': true,
	'domain': true,
	'events': true,
	'fs': true,
	'http': true,
	'https': true,
	'net': true,
	'os': true,
	'path': true,
	'punycode': true,
	'querystring': true,
	'readline': true,
	'stream': true,
	'string_decoder': true,
	'tls': true,
	'dgram': true,
	'url': true,
	'util': true,
	'vm': true,
	'zlib': true
};

//script run emulation
var fakeCurrentScript, fakeStack = [];

console.groupCollapsed('package.json')

// http://localhost:8000/
var rootPath = getAbsolutePath('/');
// http://localhost:8000/test/
var currPath = getAbsolutePath('');

//reach root (initial) package.json (closest one to the current url)
var selfPkg = requestClosestPkg(getAbsolutePath(''));

if (!selfPkg) console.warn('Can’t find main package.json by `' + rootPath + '` nor by `' +  getAbsolutePath('') + '`.');

console.groupEnd();

/** export function */
global.require = require;

/** require stub */
function require(name){
	if (!name) throw Error('Bad module name `' + name + '`');

	//ignore errorred previous requires
	// if (errors.length) return;

	console.groupCollapsed('require(\'' + name + '\') ', getCurrentScript().src || global.location + '');

	//try to fetch existing module
	var result = getModule(unjs(name.toLowerCase()));
	if (result) {
		console.groupEnd();
		return result;
	}

	//get current script dir
	var currDir = getDir(getAbsolutePath(getCurrentScript().src));

	//if not - try to look up for module
	if (require.lookUpModules) {
		//clean js suffix
		name = unjs(name);

		//try to reach module by path
		//./chai/a.js
		var path = getAbsolutePath(currDir + name + '.js');
		var sourceCode = requestFile(path);

		//./chai/a/index.js
		if (!sourceCode) {
			path = getAbsolutePath(currDir + name + '/index.js');
			sourceCode = requestFile(path);
		}

		//if found - eval script
		if (sourceCode) {
			try {
				evalScript({code: sourceCode, src:path, 'data-module-name': name, 'name': name });
			}catch(e){throw e}
			finally{
				console.groupEnd();
			}
			return getModule(name);
		}

		//if is not found, try to reach dependency from the current script package.json
		var pkg = requestClosestPkg(currDir);
		if (pkg) {
			var pkgDir = pkg._dir;
			console.log('load dependency from', pkgDir + 'package.json');

			//try to reach dependency’s package.json and get path from it
			var depPkg = requestPkg(pkgDir + 'node_modules/' + name + '/');
			if (depPkg) {
				if (!depPkg.main) depPkg.main = 'index.js';
				else depPkg.main = unjs(depPkg.main) + '.js';
				path = depPkg._dir + depPkg.main;
				sourceCode = requestFile(path);
				if (sourceCode) {
					try{
						evalScript({code: sourceCode, src:path, 'data-module-name': name, 'name': name });
					}catch(e){throw e}
					finally{
						console.groupEnd();
					}
					return getModule(name);
				}
			}
		}

		//try to fetch dependency from all the known (registered) packages
		var tPkg;
		for (var pkgName in packages) {
			tPkg = packages[pkgName];
			if (tPkg.name === name) {
				path = tPkg._dir + tPkg.main;
				sourceCode = requestFile(path);
				if (sourceCode) {
					try{
						evalScript({code: sourceCode, src:path, 'data-module-name': name, 'name': name });
					}catch(e){throw e}
					finally{
						console.groupEnd();
					}
					return getModule(name);
				}
			}
		}

		//if is not found - try to fetch from node_modules folder, if any (no need package.json)
		var commonPaths = [
			'node_modules/{{name}}/index.js',
			'node_modules/{{name}}/{{name}}.js',
			'node_modules/{{name}}/main.js',
			'node_modules/{{name}}/lib/{{name}}.js',
			'node_modules/{{name}}/lib/index.js',
			'node_modules/{{name}}/src/{{name}}.js',
			'node_modules/{{name}}/src/index.js',
			'node_modules/{{name}}/dist/{{name}}.js'
		];

		//try relative node_modules folder
		for (var i = 0, path; i < commonPaths.length; i++){
			path = commonPaths[i].replace(/{{name}}/ig, name);
			path = currDir + path;
			sourceCode = requestFile(path);
			if (sourceCode) {
				try{evalScript({code: sourceCode, src:path, 'data-module-name': name, 'name': name });
				}catch(e){throw e}
				finally{
					console.groupEnd();
				}
				return getModule(name);
			}
		}

		//try initial node_modules folder
		for (var i = 0, path; i < commonPaths.length; i++){
			path = commonPaths[i].replace(/{{name}}/ig, name);
			path = currPath + path;
			sourceCode = requestFile(path);
			if (sourceCode) {
				try{evalScript({code: sourceCode, src:path, 'data-module-name': name, 'name': name });
				}catch(e){throw e}
				finally{
					console.groupEnd();
				}
				return getModule(name);
			}
		}

		//try root node_modules folder
		for (var i = 0, path; i < commonPaths.length; i++){
			path = commonPaths[i].replace(/{{name}}/ig, name);
			path = rootPath + path;
			sourceCode = requestFile(path);
			if (sourceCode) {
				try{evalScript({code: sourceCode, src:path, 'data-module-name': name, 'name': name });
				}catch(e){throw e}
				finally{
					console.groupEnd();
				}
				return getModule(name);
			}
		}
	}

	//close require group
	console.groupEnd();

	//force native modules throw error
	if (nativeModules[name]) throw Error('Can’t include native module `' + name + '` in browser');

	//save error to log
	var scriptSrc = getCurrentScript().src;
	scriptSrc = scriptSrc || global.location + '';
	var error = new Error('Can’t find module `' + name + '` in `' + scriptSrc + '`. Possibly the module is not installed. Please, install it or include script on the page.');

	errors.push(error);

	throw error;
}

/** retrieve module from storage by name */
function getModule(name){
	var currDir = getDir(getCurrentScript().src);
	var resolvedName = getAbsolutePath(currDir + name);
	var result = global[name] || global[name[0].toUpperCase() + name.slice(1)] || modules[name] || modules[modulePaths[resolvedName]] || modules[modulePaths[resolvedName+'.js']];

	return result;
}

/** return dir from path */
function getDir(path){
	var arr = path.split(/[\\\/]/);
	arr.pop();
	return arr.join('/') + '/';
}

/** return absolute path */
function getAbsolutePath(path){
	var a = document.createElement('a');
	a.href = path;
	return a.href;
}

/** return file by path */
function requestFile(path){
	// console.log('resolve', path)
	//FIXME: XHR is forbidden without server. Try to resolve via script/image/etc
	try {
		request = new XMLHttpRequest();

		// `false` makes the request synchronous
		request.open('GET', path, false);
		request.send();
	}

	catch (e) {
		return false;
	}

	finally {
		if (request.status === 200) {
			// console.log('SUCCESS', request);
			return request.response;
		}
	}

	return false;
}

/** Return closest package to the path */
function requestClosestPkg(path) {
	var file;
	if (path[path.length - 1] === '/') path = path.slice(0, -1);
	while (path) {
		pkg = requestPkg(path);
		if (pkg) {
			return pkg;
		}
		path = path.slice(0, path.lastIndexOf('/'));
	}
	return false;
}

/**
 * Return package.json parsed by the path requested, or false
 */
function requestPkg(path){
	//return cached pkg
	if (packages[path]) return packages[path];

	if (path[path.length - 1] === '/') path = path.slice(0, -1);
	file = requestFile(path + '/package.json');

	if (file) {
		var result = JSON.parse(file);
		//save path to package.json
		result._dir = path + '/';

		//save package
		var name = result.name || path.slice(path.lastIndexOf('/') + 1);

		//preset pkg name
		if (!result.name) result.name = name;
		if (!result.main) result.main = 'index.js';

		if (!packages[name]){
			packages[name] = result;
			packages[path] = result;
		}

		//save all nested packages
		if (result.dependencies){
			for (var depName in result.dependencies){
				requestPkg(path + '/node_modules/' + depName);
			}
		}
		return result;
	}
	return false;
}

/** eval & create fake script */
function evalScript(obj){
	var name = obj.name;
	// console.group('eval', name)

	//we need to keep fake <script> tags in order to comply with inner require calls, referencing .currentScript and .src attributes
	fakeCurrentScript = obj;
	fakeStack.push(obj);
	fakeCurrentScript.getAttribute = function(name){
		return this[name];
	};
	try {
		eval(obj.code);
	}
	catch (e){
		//add filename
		e.message += '. ' + obj.src
		throw e;
	}
	finally{
		fakeStack.pop();
		fakeCurrentScript = fakeStack[fakeStack.length - 1];
	}

	// console.log('endeval', name, getModule(name))
	// console.groupEnd();
}

/** Export module emulation */
var module = global.module = {};

// Listen to `module.exports` change
Object.defineProperty(module, 'exports', {
	configurable: false,
	enumerable: false,
	get: hookExports,
	set: hookExports
});

//Listen to `exports` change
Object.defineProperty(global, 'exports', {
	configurable: false,
	enumerable: false,
	get: hookExports,
	set: hookExports
});

//any time exports required winthin the new script - create a new module
var lastExports, lastScript, lastModuleName;

/** hook for modules/exports accessors */
function hookExports(v){
	var script = getCurrentScript();

	//if script hasn’t changed - keep current exports
	if (!arguments.length && script === lastScript) return lastExports;

	//if script changed - create a new module with exports
	lastScript = script;
	var moduleName = inferModuleName(script);

	//ignore scripts with undefined moduleName/src
	if (!moduleName) throw Error('Can’t infer module name. Define it via `data-module="name"` attribute on the script.')

	//save new module path
	modulePaths[script.src] = moduleName;
	modulePaths[script.src.toLowerCase()] = moduleName;
	modulePaths[script.getAttribute('src')] = moduleName;

	//@deprecated if module exists - ignore saving
	// if (modules[moduleName]) return modules[moduleName];

	lastModuleName = moduleName;
	lastExports = v || {};

	// console.log('new module', moduleName);
	//else - save a new module (e.g. enot/index.js)
	modules[moduleName] = lastExports;

	//save no-js module name (e.g. enot/index)
	moduleName = unjs(moduleName);
	modules[moduleName] = lastExports;

	//save package name (e.g. enot)
	moduleName = moduleName.split(/[\\\/]/)[0];
	modules[moduleName] = lastExports;

	return lastExports;
}

/** try to retrieve module name from script tag */
function inferModuleName(script){
	//name is clearly defined
	var moduleName = script.getAttribute('data-module-name');

	//return parsed name, if pointed
	if (moduleName) return moduleName.toLowerCase();

	//plugin is in the node_modules
	var path = script.src;

	//catch dirname after last node_modules dirname, if any
	var idx = path.lastIndexOf('node_modules');
	if (idx >= 0){
		path = path.slice(idx);
		var matchResult = /node_modules[\/\\](.+)/.exec(path);
		moduleName = matchResult[1];
	}

	//else take file name as the module name
	if (!moduleName) {
		moduleName = script.getAttribute('src');

		//clear name
		moduleName = moduleName.split(/[\\\/]/).pop().split('.').shift();
	}

	return moduleName.toLowerCase();
}

/** get current script tag, taking into account fake scripts running */
function getCurrentScript(){
	if (fakeCurrentScript) return fakeCurrentScript;

	if (document.currentScript) return document.currentScript;

	var scripts = document.getElementsByTagName('script');
	return scripts[scripts.length - 1];
}

/**
 * Get rid of .js suffix
 */
function unjs(name){
	if (/\.js$/.test(name)) return name.slice(0, -3);
	return name;
}

})(window);<|endoftext|>