Rashid Khan 13 лет назад
Родитель
Сommit
b3052d0c95
41 измененных файлов с 2000 добавлено и 759 удалено
  1. BIN
      common/.DS_Store
  2. 4 0
      common/css/main.css
  3. BIN
      common/lib/.DS_Store
  4. 4 0
      common/lib/LAB.min.js
  5. 5 5
      config.js
  6. 2 29
      index.html
  7. 37 9
      js/app.js
  8. 1 2
      js/directives.js
  9. 0 714
      js/panels.js
  10. 150 0
      js/panels/histogram/module.js
  11. 114 0
      js/panels/map/module.js
  12. 134 0
      js/panels/piequery/module.js
  13. 140 0
      js/panels/pieterms/module.js
  14. 165 0
      js/panels/stackedquery/module.js
  15. 7 0
      scripts/date.js
  16. 7 0
      scripts/load.sh
  17. 2 0
      scripts/node_modules/random-weighted-choice/.npmignore
  18. 3 0
      scripts/node_modules/random-weighted-choice/.travis.yml
  19. 9 0
      scripts/node_modules/random-weighted-choice/Makefile
  20. 75 0
      scripts/node_modules/random-weighted-choice/README.md
  21. 65 0
      scripts/node_modules/random-weighted-choice/lib/random-weighted-choice.js
  22. 4 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/.npmignore
  23. 47 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/History.md
  24. 4 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/Makefile
  25. 130 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/Readme.md
  26. 120 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/debug.component.js
  27. 116 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/debug.js
  28. 19 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/example/app.js
  29. 24 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/example/browser.html
  30. 10 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/example/wildcards.js
  31. 22 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/example/worker.js
  32. 1 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/head.js
  33. 2 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/index.js
  34. 135 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/lib/debug.js
  35. 27 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/package.json
  36. 4 0
      scripts/node_modules/random-weighted-choice/node_modules/debug/tail.js
  37. 31 0
      scripts/node_modules/random-weighted-choice/package.json
  38. 66 0
      scripts/node_modules/random-weighted-choice/test/test.js
  39. 282 0
      scripts/reader.js
  40. 0 0
      scripts/shakespeare.json
  41. 32 0
      scripts/underscore.min.js

BIN
common/.DS_Store


+ 4 - 0
common/css/main.css

@@ -8,4 +8,8 @@
 
 #upload {
   display: inline-block;
+}
+
+[ng\:cloak], [ng-cloak], .ng-cloak {
+  display: none !important;
 }

BIN
common/lib/.DS_Store


Разница между файлами не показана из-за своего большого размера
+ 4 - 0
common/lib/LAB.min.js


+ 5 - 5
config.js

@@ -8,6 +8,9 @@ refresh:        Milliseconds between auto refresh.
 timeformat:     Format for time in histograms (might go away)
 timefield:      Field to use for ISO8601 timestamps (might go away)
 indexpattern:   Timestamping pattern for time based indices, 
+modules:        Panel modules to load. In the future these will be inferred 
+                from your initial dashboard, though if you share dashboards you
+                will probably need to list them all here 
 
 NOTE: No timezone support yet, everything is in UTC at the moment.
 
@@ -17,8 +20,6 @@ shared.json contains an example sharable dashboard. Note the subtle differences
 between dashboard.js and shared.json. Once is a javascript object, the other is
 json.
 
-PLEASE SEE js/
-
 */
 var config = new Settings(
 {
@@ -29,8 +30,7 @@ var config = new Settings(
     timefield:      '@timestamp', 
     //indexpattern:  '"logstash-"yyyy.mm.dd',
     indexpattern:   '"shakespeare"', 
-    modules:        ['histogram','piequery','pieterms','stackedquery','map'], 
-
+    modules:        ['histogram','pieterms','piequery','stackedquery','map'], 
 
     defaultfields:  ['line_text'],
     perpage:        50,
@@ -42,4 +42,4 @@ var config = new Settings(
     indexdefault:   'logstash-*',
     primaryfield:   '_all'
   }
-);
+);

+ 2 - 29
index.html

@@ -17,44 +17,17 @@
   <link rel="stylesheet" href="/common/css/bootstrap-responsive.min.css">
   <link rel="stylesheet" href="/common/css/elasticjs.css">
   <link rel="stylesheet" href="/common/css/datepicker.css">
-  <link rel="stylesheet" href="/common/css/jquery-jvectormap.css">
-
 
   <!-- project dependency libs -->
-  <script src="common/lib/jquery-1.8.0.min.js"></script>
-  <script src="common/lib/modernizr-2.6.1.min.js"></script>
+  <script src="/common/lib/LAB.min.js"></script>
   <script src="common/lib/underscore.min.js"></script>
-  <script src="common/lib/angular.min.js"></script>
-  <script src="common/lib/elastic.min.js"></script>
-  <script src="common/lib/elastic-angular-client.min.js"></script>
-  <script src="common/lib/dateformat.js"></script>
-  <script src="common/lib/jquery.flot.js"></script>
-  <script src="common/lib/jquery.flot.time.js"></script>
-  <script src="common/lib/jquery.flot.stack.js"></script>
-  <script src="common/lib/jquery.flot.pie.js"></script>
-  <script src="common/lib/jquery.jvectormap.min.js"></script>
-  <script src="common/lib/jquery-jvectormap-world-mill-en.js"></script>
-  <script src="common/lib/date.js"></script>
-  <script src="common/lib/datepicker.js"></script>
-
-
   <script src="common/lib/settings.js"></script>
   <script src="config.js"></script>
-  <script src="common/lib/shared.js"></script>
-  <script src="dashboards.js"></script>
-
-    
-  <!-- project specific files -->
   <script src="js/app.js"></script>
-  <script src="js/services.js"></script>
-  <script src="js/controllers.js"></script>
-  <script src="js/filters.js"></script>
-  <script src="js/directives.js"></script>
-  <script src="js/panels.js"></script>
 
 </head>
 
-<body ng-controller="DashCtrl">
+<body ng-controller="DashCtrl" ng-cloak>
   <div class="navbar navbar-fixed-top">
     <div class="navbar-inner">
       <div class="container-fluid">

+ 37 - 9
js/app.js

@@ -12,13 +12,41 @@ var modules = [
   'kibana.panels',
   ]
 
+var scripts = []
+
+var labjs = $LAB
+  .script("common/lib/jquery-1.8.0.min.js").wait()
+  .script("common/lib/modernizr-2.6.1.min.js")
+  .script("common/lib/underscore.min.js")
+  .script("common/lib/angular.min.js")
+  .script("common/lib/elastic.min.js")
+  .script("common/lib/elastic-angular-client.min.js")
+  .script("common/lib/dateformat.js")
+  .script("common/lib/date.js")
+  .script("common/lib/datepicker.js")
+  .script("common/lib/shared.js")
+  .script("js/services.js")
+  .script("js/controllers.js")
+  .script("js/filters.js")
+  .script("js/directives.js")
+  .script("js/panels.js")
+  .script("dashboards.js");
+
+_.each(config.modules, function(v) {
+  labjs = labjs.script('js/panels/'+v+'/module.js').wait()
+  modules.push('kibana.'+v)
+})
+
 /* Application level module which depends on filters, controllers, and services */
-angular.module('kibana', modules).config(['$routeProvider', function($routeProvider) {
-    $routeProvider
-      .when('/dashboard', {
-        templateUrl: 'partials/dashboard.html' 
-      })
-      .otherwise({
-        redirectTo: '/dashboard'
-      });
-  }]);
+labjs.wait(function(){
+  angular.module('kibana', modules).config(['$routeProvider', function($routeProvider) {
+      $routeProvider
+        .when('/dashboard', {
+          templateUrl: 'partials/dashboard.html' 
+        })
+        .otherwise({
+          redirectTo: '/dashboard'
+        });
+    }]);
+
+});

+ 1 - 2
js/directives.js

@@ -12,7 +12,7 @@ angular.module('kibana.directives', [])
           return (attrs.panel && scope.index) ? true : false;
         }, function (ready) {
           if (ready) {
-            $compile("<div "+attrs.panel+" params={{panel}} style='height:{{row.height}}'></div>")(scope).replaceAll(element);
+            element.html($compile("<div "+attrs.panel+" params={{panel}} style='height:{{row.height}}'></div>")(scope))
           }
         });
       }
@@ -23,7 +23,6 @@ angular.module('kibana.directives', [])
   return {
     restrict: 'A',
     link: function(scope, elem, attrs) {
-      console.log(elem);
       function file_selected(evt) {
         var files = evt.target.files; // FileList object
 

+ 0 - 714
js/panels.js

@@ -71,718 +71,4 @@
               of queries in your queries array
   show:       array of what to show, (eg ['bars','lines','points']) 
 */
-
-
 angular.module('kibana.panels', [])
-.directive('histogram', function() {
-  return {
-    restrict: 'A',
-    link: function(scope, elem, attrs) {
-
-      // Specify defaults for ALL directives
-      var _d = {
-        query   : "*",
-        interval: secondsToHms(calculate_interval(scope.from,scope.to,40,0)/1000),
-        color   : "#27508C",
-        show    : ['bars']
-      }
-
-      // Set ready flag and fill parameters (REQUIRED IN EVERY PANEL)
-      scope.$watch(function () {
-        return (attrs.params && scope.index) ? true : false;
-      }, function (ready) {
-        scope.ready = ready;
-        if(ready) {
-          scope.params = JSON.parse(attrs.params);
-          _.each(_d, function(v, k) {
-            scope.params[k] = _.isUndefined(scope.params[k]) 
-              ? _d[k] : scope.params[k];
-          });
-        }
-      });
-
-      // Also get the data if time frame changes.
-      // (REQUIRED IN EVERY PANEL)
-      scope.$watch(function() { 
-        return angular.toJson([scope.from, scope.to, scope.ready]) 
-      }, function(){
-        if(scope.ready)
-          if (_.isUndefined(attrs.params.interval))
-            scope.params.interval = secondsToHms(
-              calculate_interval(scope.from,scope.to,50,0)/1000),
-          get_data(scope,elem,attrs);
-      });
-
-      // Re-rending the panel if it is resized,
-      scope.$watch('data', function() {
-          render_panel(scope,elem,attrs);
-      });
-
-      // Or if the model changes
-      angular.element(window).bind('resize', function(){
-          render_panel(scope,elem,attrs);
-      });
-
-      // Function for getting data
-      function get_data(scope,elem,attrs) {
-        var params = scope.params;
-        var ejs = scope.ejs;
-        var request = ejs.Request().indices(scope.index);
-        
-        // Build the question part of the query
-        var query = ejs.FilteredQuery(
-          ejs.QueryStringQuery(params.query || '*'),
-          ejs.RangeFilter(config.timefield)
-            .from(scope.from)
-            .to(scope.to)
-            .cache(false)
-          );
-
-        // Then the insert into facet and make the request
-        var results = request
-          .facet(ejs.DateHistogramFacet('histogram')
-            .field(config.timefield)
-            .interval(params.interval)
-            .facetFilter(ejs.QueryFilter(query))
-          )
-          .doSearch();
-
-        // Populate scope when we have results
-        results.then(function(results) {
-          scope.hits = results.hits.total;
-          scope.data = results.facets.histogram.entries;
-        });
-      }
-
-      // Function for rendering panel
-      function render_panel(scope,elem,attrs) {
-        // Parse our params object
-        var params = scope.params;
-
-        // Determine format
-        var show = _.isUndefined(params.show) ? {
-            bars: true, lines: false, points: false
-          } : {
-            lines:  _.indexOf(params.show,'lines') < 0 ? false : true,
-            bars:   _.indexOf(params.show,'bars') < 0 ? false : true,
-            points: _.indexOf(params.show,'points') < 0 ? false : true,
-          }
-
-        // Push null values at beginning and end of timeframe
-        scope.graph = [
-          [scope.from.getTime(), null],[scope.to.getTime(), null]];
-
-        // Create FLOT value array 
-        _.each(scope.data, function(v, k) {
-          scope.graph.push([v['time'],v['count']])
-        });
-
-        // Set barwidth based on specified interval
-        var barwidth = interval_to_seconds(params.interval)*1000
-
-        // Populate element
-        $.plot(elem, [{
-          label: _.isUndefined(params.label) ? params.query: params.label, 
-          data: scope.graph
-        }], {
-          legend: { 
-            position: "nw", 
-            labelFormatter: function(label, series) {
-              return '<span class="legend">' + label + ' / ' + params.interval 
-                + '</span>';
-            }
-          },
-          series: {
-            lines:  { show: show.lines, fill: false },
-            bars:   { show: show.bars,  fill: 1, barWidth: barwidth/1.8 },
-            points: { show: show.points },
-            color: params.color,
-            shadowSize: 1
-          },
-          yaxis: { min: 0, color: "#000" },
-          xaxis: {
-            mode: "time",
-            timeformat: "%H:%M:%S<br>%m-%d",
-            label: "Datetime",
-            color: "#000",
-          },
-          grid: {
-            backgroundColor: '#fff',
-            borderWidth: 0,
-            borderColor: '#eee',
-            color: "#eee",
-            hoverable: true,
-          }
-        });
-        //elem.show();
-      }
-    }
-  };
-})
-.directive('pieterms', function() {
-  return {
-    restrict: 'A',
-    link: function(scope, elem, attrs) {
-
-      // Specify defaults for ALL directives
-      var _d = {
-        size    : 5,
-        query   : "*",
-        exclude : [],
-        donut   : false, 
-        tilt    : false,
-        legend  : true,
-      }
-
-      // Set ready flag and fill parameters (REQUIRED IN EVERY PANEL)
-      scope.$watch(function () {
-        return (attrs.params && scope.index) ? true : false;
-      }, function (ready) {
-        scope.ready = ready;
-        if(ready) {
-          scope.params = JSON.parse(attrs.params);
-          _.each(_d, function(v, k) {
-            scope.params[k] = _.isUndefined(scope.params[k]) 
-              ? _d[k] : scope.params[k];
-          });
-        }
-      });
-
-      // Also get the data if time frame changes.
-      // (REQUIRED IN EVERY PANEL)
-      scope.$watch(function() { 
-        return angular.toJson([scope.from, scope.to, scope.ready]) 
-      }, function(){
-        if(scope.ready)
-          get_data(scope,elem,attrs);
-      });
-
-      // Re-rending the panel if it is resized,
-      scope.$watch('data', function() {
-          render_panel(scope,elem,attrs);
-      });
-
-      // Or if the model changes
-      angular.element(window).bind('resize', function(){
-          render_panel(scope,elem,attrs);
-      });
-
-      // Function for getting data
-      function get_data(scope,elem,attrs) {
-        var params = scope.params;
-        var ejs = scope.ejs;
-        var request = ejs.Request().indices(scope.index);
-        
-        // Build the question part of the query
-        var query = ejs.FilteredQuery(
-          ejs.QueryStringQuery(params.query || '*'),
-          ejs.RangeFilter(config.timefield)
-            .from(scope.from)
-            .to(scope.to)
-            .cache(false)
-          );
-
-        // Then the insert into facet and make the request
-        var results = request
-          .facet(ejs.TermsFacet('termpie')
-            .field(params.field)
-            .size(params['size'])
-            .exclude(params.exclude)
-            .facetFilter(ejs.QueryFilter(query))
-          )
-          .doSearch();
-
-        // Populate scope when we have results
-        results.then(function(results) {
-          scope.hits = results.hits.total;
-          scope.data = results.facets.termpie.terms;
-        });
-      }
-
-      // Function for rendering panel
-      function render_panel(scope,elem,attrs) {
-        // Parse our params object
-        var params = scope.params;
-
-        // Create graph array
-        scope.graph = [];
-        _.each(scope.data, function(v, k) {
-          if(!_.isUndefined(params.only) && _.indexOf(params.only,v['term']) < 0)
-            return
-
-          var point = {
-            label : v['term'],
-            data  : v['count']
-          }
-
-          if(!_.isUndefined(params.colors))
-            point.color = params.colors[_.indexOf(params.only,v['term'])] 
-
-          scope.graph.push(point)
-        });
-
-        var pie = {
-          series: {
-            pie: {
-              innerRadius: params.donut ? 0.4 : 0,
-              tilt: params.tilt ? 0.45 : 1,
-              radius: 1,
-              show: true,
-              combine: {
-                color: '#999',
-                label: 'The Rest'
-              },
-              label: { 
-                show: true,
-                radius: 2/3,
-                formatter: function(label, series){
-                  return '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">'+
-                    label+'<br/>'+Math.round(series.percent)+'%</div>';
-                },
-                threshold: 0.1 
-              }
-            }
-          },
-          //grid: { hoverable: true, clickable: true },
-          legend: { show: params.legend }
-        };
-
-        // Populate element
-        $.plot(elem, scope.graph, pie);
-        //elem.show();
-      }
-    }
-  };
-})
-.directive('piequery', function() {
-  return {
-    restrict: 'A',
-    link: function(scope, elem, attrs) {
-
-      // Specify defaults for ALL directives
-      var _d = {
-        queries : ["*"],
-        donut   : false, 
-        tilt    : false,
-        legend  : true,
-      }
-
-      // Set ready flag and fill parameters (REQUIRED IN EVERY PANEL)
-      scope.$watch(function () {
-        return (attrs.params && scope.index) ? true : false;
-      }, function (ready) {
-        scope.ready = ready;
-        if(ready) {
-          scope.params = JSON.parse(attrs.params);
-          _.each(_d, function(v, k) {
-            scope.params[k] = _.isUndefined(scope.params[k]) 
-              ? _d[k] : scope.params[k];
-          });
-        }
-      });
-
-      // Also get the data if time frame changes.
-      // (REQUIRED IN EVERY PANEL)
-      scope.$watch(function() { 
-        return angular.toJson([scope.from, scope.to, scope.ready]) 
-      }, function(){
-        if(scope.ready)
-          get_data(scope,elem,attrs);
-      });
-
-      // Re-rending the panel if it is resized,
-      scope.$watch('data', function() {
-          render_panel(scope,elem,attrs);
-      });
-
-      // Or if the model changes
-      angular.element(window).bind('resize', function(){
-          render_panel(scope,elem,attrs);
-      });
-
-      // Function for getting data
-      function get_data(scope,elem,attrs) {
-        var params = scope.params;
-        var ejs = scope.ejs;
-        var request = ejs.Request().indices(scope.index);
-        
-
-        var queries = [];
-        // Build the question part of the query
-        _.each(params.queries, function(v) {
-          queries.push(ejs.FilteredQuery(
-            ejs.QueryStringQuery(v || '*'),
-            ejs.RangeFilter(config.timefield)
-              .from(scope.from)
-              .to(scope.to)
-              .cache(false))
-          )
-        });
-
-        _.each(queries, function(v) {
-          request = request.facet(ejs.QueryFacet(_.indexOf(queries,v))
-            .query(v)
-            .facetFilter(ejs.QueryFilter(v))
-          )
-        })
-        // Then the insert into facet and make the request
-        var results = request.doSearch();
-
-        // Populate scope when we have results
-        results.then(function(results) {
-          scope.hits = results.hits.total;
-          scope.data = results.facets;
-        });
-      }
-
-      // Function for rendering panel
-      function render_panel(scope,elem,attrs) {
-        // Parse our params object
-        var params = scope.params;
-
-        // Create graph array
-        scope.graph = [];
-        _.each(scope.data, function(v, k) {
-          var point = {
-            label : params.queries[k],
-            data  : v['count']
-          }
-          if(!_.isUndefined(params.colors))
-            point.color = params.colors[k%params.colors.length];
-          scope.graph.push(point)
-        });
-
-        // Populate element
-        $.plot(elem, scope.graph, {
-            series: {
-              pie: {
-                innerRadius: params.donut ? 0.4 : 0,
-                tilt: params.tilt ? 0.45 : 1,
-                radius: 1,
-                show: true,
-                combine: {
-                  color: '#999',
-                  label: 'The Rest'
-                },
-                label: { 
-                  show: true,
-                  radius: 2/3,
-                  formatter: function(label, series){
-                    return '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">'+
-                      label+'<br/>'+Math.round(series.percent)+'%</div>';
-                  },
-                  threshold: 0.1 
-                }
-              }
-            },
-            //grid: { hoverable: true, clickable: true },
-            legend: { show: params.legend }
-          });
-        //elem.show();
-      }
-    }
-  };
-})
-.directive('stackedquery', function() {
-  return {
-    restrict: 'A',
-    link: function(scope, elem, attrs) {
-
-      // Specify defaults for ALL directives
-      var _d = {
-        queries : ["*"],
-        interval: secondsToHms(calculate_interval(scope.from,scope.to,40,0)/1000),
-        colors  : ["#BF3030","#1D7373","#86B32D","#A98A21","#411F73"],
-        show    : ['bars']
-      }
-
-      // Set ready flag and fill parameters (REQUIRED IN EVERY PANEL)
-      scope.$watch(function () {
-        return (attrs.params && scope.index) ? true : false;
-      }, function (ready) {
-        scope.ready = ready;
-        if(ready) {
-          scope.params = JSON.parse(attrs.params);
-          _.each(_d, function(v, k) {
-            scope.params[k] = _.isUndefined(scope.params[k]) 
-              ? _d[k] : scope.params[k];
-          });
-        }
-      });
-
-      // Also get the data if time frame changes.
-      // (REQUIRED IN EVERY PANEL)
-      scope.$watch(function() { 
-        return angular.toJson([scope.from, scope.to, scope.ready]) 
-      }, function(){
-        if(scope.ready)
-          if (_.isUndefined(attrs.params.interval))
-            scope.params.interval = secondsToHms(
-              calculate_interval(scope.from,scope.to,50,0)/1000),
-          get_data(scope,elem,attrs);
-      });
-
-      // Re-rending the panel if it is resized,
-      scope.$watch('data', function() {
-          render_panel(scope,elem,attrs);
-      });
-
-      // Or if the model changes
-      angular.element(window).bind('resize', function(){
-          render_panel(scope,elem,attrs);
-      });
-
-      // Function for getting data
-      function get_data(scope,elem,attrs) {
-        var params = scope.params;
-        var ejs = scope.ejs;
-        var request = ejs.Request().indices(scope.index);
-        
-        // Build the question part of the query
-        var queries = [];
-        _.each(params.queries, function(v) {
-          queries.push(ejs.FilteredQuery(
-            ejs.QueryStringQuery(v || '*'),
-            ejs.RangeFilter(config.timefield)
-              .from(scope.from)
-              .to(scope.to)
-              .cache(false))
-          )
-        });
-
-        // Build the facet part
-        _.each(queries, function(v) {
-          request = request
-            .facet(ejs.DateHistogramFacet(_.indexOf(queries,v))
-              .field(config.timefield)
-              .interval(params.interval)
-              .facetFilter(ejs.QueryFilter(v))
-            )
-        })
-
-        // Then run it
-        var results = request.doSearch();
-
-        // Populate scope when we have results
-        results.then(function(results) {
-          scope.hits = results.hits.total;
-          scope.data = results.facets;
-        });
-      }
-
-      // Function for rendering panel
-      function render_panel(scope,elem,attrs) {
-        // Parse our params object
-        var params = scope.params;
-
-        // Determine format
-        var show = _.isUndefined(params.show) ? {
-            bars: true, lines: false, points: false, fill: false
-          } : {
-            lines:  _.indexOf(params.show,'lines') < 0 ? false : true,
-            bars:   _.indexOf(params.show,'bars') < 0 ? false : true,
-            points: _.indexOf(params.show,'points') < 0 ? false : true,
-            fill:   _.indexOf(params.show,'fill') < 0 ? false : true
-          }
-
-        scope.graph = [];
-        // Push null values at beginning and end of timeframe
-        _.each(scope.data, function(v, k) {
-          var series = {};
-          var data = [[scope.from.getTime(), null]];
-          _.each(v.entries, function(v, k) {
-            data.push([v['time'],v['count']])
-          });
-          data.push([scope.to.getTime(), null])
-          series.data = {
-            label: params.queries[k], 
-            data: data, 
-            color: params.colors[k%params.colors.length]
-          };
-          scope.graph.push(series.data)
-        });
-
-        // Set barwidth based on specified interval
-        var barwidth = interval_to_seconds(params.interval)*1000
-
-        // Populate element
-        $.plot(elem, scope.graph, {
-          legend: { 
-            position: "nw", 
-            labelFormatter: function(label, series) {
-              return '<span class="legend">' + label + ' / ' + params.interval 
-                + '</span>';
-            }
-          },
-          series: {
-            stack:  0,
-            lines:  { show: show.lines, fill: show.fill },
-            bars:   { show: show.bars,  fill: 1, barWidth: barwidth/1.8 },
-            points: { show: show.points },
-            color: params.color,
-            shadowSize: 1
-          },
-          yaxis: { min: 0, color: "#000" },
-          xaxis: {
-            mode: "time",
-            timeformat: "%H:%M:%S<br>%m-%d",
-            label: "Datetime",
-            color: "#000",
-          },
-          grid: {
-            backgroundColor: '#fff',
-            borderWidth: 0,
-            borderColor: '#eee',
-            color: "#eee",
-            hoverable: true,
-          }
-        });
-        //elem.show();
-      }
-    }
-  };
-})
-.directive('map', function() {
-  return {
-    restrict: 'A',
-    link: function(scope, elem, attrs) {
-
-      // Specify defaults for ALL directives
-      var _d = {
-        queries : ["*"],
-        interval: secondsToHms(calculate_interval(scope.from,scope.to,40,0)/1000),
-        colors  : ["#BF3030","#1D7373","#86B32D","#A98A21","#411F73"],
-        show    : ['bars'],
-        size    : 100,
-        exclude : []
-      }
-
-      // Set ready flag and fill parameters (REQUIRED IN EVERY PANEL)
-      scope.$watch(function () {
-        return (attrs.params && scope.index) ? true : false;
-      }, function (ready) {
-        scope.ready = ready;
-        if(ready) {
-          scope.params = JSON.parse(attrs.params);
-          _.each(_d, function(v, k) {
-            scope.params[k] = _.isUndefined(scope.params[k]) 
-              ? _d[k] : scope.params[k];
-          });
-        }
-      });
-
-      // Also get the data if time frame changes.
-      // (REQUIRED IN EVERY PANEL)
-      scope.$watch(function() { 
-        return angular.toJson([scope.from, scope.to, scope.ready]) 
-      }, function(){
-        if(scope.ready)
-          if (_.isUndefined(attrs.params.interval))
-            scope.params.interval = secondsToHms(
-              calculate_interval(scope.from,scope.to,50,0)/1000),
-          get_data(scope,elem,attrs);
-      });
-
-      // Re-rending the panel if it is resized,
-      scope.$watch('data', function() {
-          render_panel(scope,elem,attrs);
-      });
-
-      // Or if the model changes
-      angular.element(window).bind('resize', function(){
-          render_panel(scope,elem,attrs);
-      });
-
-      // Function for getting data
-      function get_data(scope,elem,attrs) {
-        var params = scope.params;
-        var ejs = scope.ejs;
-        var request = ejs.Request().indices(scope.index);
-        
-        // Build the question part of the query
-        var query = ejs.FilteredQuery(
-          ejs.QueryStringQuery(params.query || '*'),
-          ejs.RangeFilter(config.timefield)
-            .from(scope.from)
-            .to(scope.to)
-            .cache(false)
-          );
-
-        // Then the insert into facet and make the request
-        var results = request
-          .facet(ejs.TermsFacet('worldmap')
-            .field(params.field)
-            .size(params['size'])
-            .exclude(params.exclude)
-            .facetFilter(ejs.QueryFilter(query))
-          )
-          .doSearch();
-
-        // Populate scope when we have results
-        results.then(function(results) {
-          scope.hits = results.hits.total;
-          scope.data = results.facets.worldmap.terms;
-        });
-      }
-
-      // Function for rendering panel
-      function render_panel(scope,elem,attrs) {
-        // Parse our params object
-        var params = scope.params;
-
-        // Determine format
-        var show = _.isUndefined(params.show) ? {
-            bars: true, lines: false, points: false, fill: false
-          } : {
-            lines:  _.indexOf(params.show,'lines') < 0 ? false : true,
-            bars:   _.indexOf(params.show,'bars') < 0 ? false : true,
-            points: _.indexOf(params.show,'points') < 0 ? false : true,
-            fill:   _.indexOf(params.show,'fill') < 0 ? false : true
-          }
-
-        scope.graph = [];
-        // Push null values at beginning and end of timeframe
-        _.each(scope.data, function(v, k) {
-          var series = {};
-          var data = [[scope.from.getTime(), null]];
-          _.each(v.entries, function(v, k) {
-            data.push([v['time'],v['count']])
-          });
-          data.push([scope.to.getTime(), null])
-          series.data = {
-            label: params.queries[k], 
-            data: data, 
-            color: params.colors[k%params.colors.length]
-          };
-          scope.graph.push(series.data)
-        });
-
-        // Set barwidth based on specified interval
-        var barwidth = interval_to_seconds(params.interval)*1000
-        var values = {}
-        _.each(scope.data, function(v) {
-          values[v.term.toUpperCase()] = v.count;
-        });
-        console.log(values)
-
-        // Populate element
-        $('.jvectormap-label,.jvectormap-zoomin,.jvectormap-zoomout').remove();
-        elem.text('');
-        elem.vectorMap({  
-          map: 'world_mill_en',
-          regionStyle: {initial: {fill: '#eee'}},
-          zoomOnScroll: false,
-          backgroundColor: '#fff',
-          series: {
-            regions: [{
-              values: values,
-              scale: ['#C8EEFF', '#0071A4'],
-              normalizeFunction: 'polynomial'
-            }]
-          }
-        });
-        //elem.show();
-      }
-    }
-  };
-});

+ 150 - 0
js/panels/histogram/module.js

@@ -0,0 +1,150 @@
+labjs = labjs.script("common/lib/jquery.flot.js")
+  .script("common/lib/jquery.flot.time.js")
+
+angular.module('kibana.histogram', [])
+.directive('histogram', function() {
+  return {
+    restrict: 'A',
+    link: function(scope, elem, attrs) {
+
+      // Specify defaults for ALL directives
+      var _d = {
+        query   : "*",
+        interval: secondsToHms(calculate_interval(scope.from,scope.to,40,0)/1000),
+        color   : "#27508C",
+        show    : ['bars']
+      }
+
+      // Set ready flag and fill parameters (REQUIRED IN EVERY PANEL)
+      scope.$watch(function () {
+        return (attrs.params && scope.index) ? true : false;
+      }, function (ready) {
+        scope.ready = ready;
+        if(ready) {
+          scope.params = JSON.parse(attrs.params);
+          _.each(_d, function(v, k) {
+            scope.params[k] = _.isUndefined(scope.params[k]) 
+              ? _d[k] : scope.params[k];
+          });
+        }
+      });
+
+      // Also get the data if time frame changes.
+      // (REQUIRED IN EVERY PANEL)
+      scope.$watch(function() { 
+        return angular.toJson([scope.from, scope.to, scope.ready]) 
+      }, function(){
+        if(scope.ready)
+          if (_.isUndefined(attrs.params.interval))
+            scope.params.interval = secondsToHms(
+              calculate_interval(scope.from,scope.to,50,0)/1000),
+          get_data(scope,elem,attrs);
+      });
+
+      // Re-rending the panel if it is resized,
+      scope.$watch('data', function() {
+        if(scope.ready)
+          render_panel(scope,elem,attrs);
+      });
+
+      // Or if the model changes
+      angular.element(window).bind('resize', function(){
+          render_panel(scope,elem,attrs);
+      });
+
+      // Function for getting data
+      function get_data(scope,elem,attrs) {
+        var params = scope.params;
+        var ejs = scope.ejs;
+        var request = ejs.Request().indices(scope.index);
+        
+        // Build the question part of the query
+        var query = ejs.FilteredQuery(
+          ejs.QueryStringQuery(params.query || '*'),
+          ejs.RangeFilter(config.timefield)
+            .from(scope.from)
+            .to(scope.to)
+            .cache(false)
+          );
+
+        // Then the insert into facet and make the request
+        var results = request
+          .facet(ejs.DateHistogramFacet('histogram')
+            .field(config.timefield)
+            .interval(params.interval)
+            .facetFilter(ejs.QueryFilter(query))
+          )
+          .doSearch();
+
+        // Populate scope when we have results
+        results.then(function(results) {
+          scope.hits = results.hits.total;
+          scope.data = results.facets.histogram.entries;
+        });
+      }
+
+      // Function for rendering panel
+      function render_panel(scope,elem,attrs) {
+        // Parse our params object
+        var params = scope.params;
+
+        // Determine format
+        var show = _.isUndefined(params.show) ? {
+            bars: true, lines: false, points: false
+          } : {
+            lines:  _.indexOf(params.show,'lines') < 0 ? false : true,
+            bars:   _.indexOf(params.show,'bars') < 0 ? false : true,
+            points: _.indexOf(params.show,'points') < 0 ? false : true,
+          }
+
+        // Push null values at beginning and end of timeframe
+        scope.graph = [
+          [scope.from.getTime(), null],[scope.to.getTime(), null]];
+
+        // Create FLOT value array 
+        _.each(scope.data, function(v, k) {
+          scope.graph.push([v['time'],v['count']])
+        });
+
+        // Set barwidth based on specified interval
+        var barwidth = interval_to_seconds(params.interval)*1000
+
+        // Populate element
+        $.plot(elem, [{
+          label: _.isUndefined(params.label) ? params.query: params.label, 
+          data: scope.graph
+        }], {
+          legend: { 
+            position: "nw", 
+            labelFormatter: function(label, series) {
+              return '<span class="legend">' + label + ' / ' + params.interval 
+                + '</span>';
+            }
+          },
+          series: {
+            lines:  { show: show.lines, fill: false },
+            bars:   { show: show.bars,  fill: 1, barWidth: barwidth/1.8 },
+            points: { show: show.points },
+            color: params.color,
+            shadowSize: 1
+          },
+          yaxis: { min: 0, color: "#000" },
+          xaxis: {
+            mode: "time",
+            timeformat: "%H:%M:%S<br>%m-%d",
+            label: "Datetime",
+            color: "#000",
+          },
+          grid: {
+            backgroundColor: '#fff',
+            borderWidth: 0,
+            borderColor: '#eee',
+            color: "#eee",
+            hoverable: true,
+          }
+        });
+        //elem.show();
+      }
+    }
+  };
+})

+ 114 - 0
js/panels/map/module.js

@@ -0,0 +1,114 @@
+labjs = labjs.script("common/lib/jquery.jvectormap.min.js")
+  .script("common/lib/jquery-jvectormap-world-mill-en.js")
+
+angular.module('kibana.map', [])
+.directive('map', function() {
+  return {
+    restrict: 'A',
+    link: function(scope, elem, attrs) {
+
+      // Specify defaults for ALL directives
+      var _d = {
+        queries : ["*"],
+        interval: secondsToHms(calculate_interval(scope.from,scope.to,40,0)/1000),
+        colors  : ["#BF3030","#1D7373","#86B32D","#A98A21","#411F73"],
+        show    : ['bars'],
+        size    : 100,
+        exclude : []
+      }
+
+      // Set ready flag and fill parameters (REQUIRED IN EVERY PANEL)
+      scope.$watch(function () {
+        return (attrs.params && scope.index) ? true : false;
+      }, function (ready) {
+        scope.ready = ready;
+        if(ready) {
+          scope.params = JSON.parse(attrs.params);
+          _.each(_d, function(v, k) {
+            scope.params[k] = _.isUndefined(scope.params[k]) 
+              ? _d[k] : scope.params[k];
+          });
+        }
+      });
+
+      // Also get the data if time frame changes.
+      // (REQUIRED IN EVERY PANEL)
+      scope.$watch(function() { 
+        return angular.toJson([scope.from, scope.to, scope.ready]) 
+      }, function(){
+        if(scope.ready)
+          get_data(scope,elem,attrs);
+      });
+
+      // Re-rending panel if data changes
+      scope.$watch('data', function() {
+        if(scope.ready)
+          render_panel(scope,elem,attrs);
+      });
+
+      // Or if the window is resized
+      angular.element(window).bind('resize', function(){
+          render_panel(scope,elem,attrs);
+      });
+
+      // Function for getting data
+      function get_data(scope,elem,attrs) {
+        var params = scope.params;
+        var ejs = scope.ejs;
+        var request = ejs.Request().indices(scope.index);
+        
+        // Build the question part of the query
+        var query = ejs.FilteredQuery(
+          ejs.QueryStringQuery(params.query || '*'),
+          ejs.RangeFilter(config.timefield)
+            .from(scope.from)
+            .to(scope.to)
+            .cache(false)
+          );
+
+        // Then the insert into facet and make the request
+        var results = request
+          .facet(ejs.TermsFacet('worldmap')
+            .field(params.field)
+            .size(params['size'])
+            .exclude(params.exclude)
+            .facetFilter(ejs.QueryFilter(query))
+          )
+          .doSearch();
+
+        // Populate scope when we have results
+        results.then(function(results) {
+          scope.hits = results.hits.total;
+          scope.data = {};
+          _.each(results.facets.worldmap.terms, function(v) {
+            scope.data[v.term.toUpperCase()] = v.count;
+          });
+        });
+      }
+
+      // Function for rendering panel
+      function render_panel(scope,elem,attrs) {
+        // Parse our params object
+        var params = scope.params;
+
+        // Populate element
+        $('.jvectormap-label,.jvectormap-zoomin,.jvectormap-zoomout').remove();
+        elem.text('');
+        elem.vectorMap({  
+          map: 'world_mill_en',
+          regionStyle: {initial: {fill: '#ddd'}},
+          zoomOnScroll: false,
+          backgroundColor: '#fff',
+          series: {
+            regions: [{
+              values: scope.data,
+              scale: ['#C8EEFF', '#0071A4'],
+              normalizeFunction: 'polynomial'
+            }]
+          }
+        });
+        //elem.show();
+      }
+    }
+  };
+});

+ 134 - 0
js/panels/piequery/module.js

@@ -0,0 +1,134 @@
+labjs = labjs.script("common/lib/jquery.flot.js")
+  .script("common/lib/jquery.flot.pie.js")
+
+angular.module('kibana.piequery', [])
+.directive('piequery', function() {
+  return {
+    restrict: 'A',
+    link: function(scope, elem, attrs) {
+
+      // Specify defaults for ALL directives
+      var _d = {
+        queries : ["*"],
+        donut   : false, 
+        tilt    : false,
+        legend  : true,
+      }
+
+      // Set ready flag and fill parameters (REQUIRED IN EVERY PANEL)
+      scope.$watch(function () {
+        return (attrs.params && scope.index) ? true : false;
+      }, function (ready) {
+        scope.ready = ready;
+        if(ready) {
+          scope.params = JSON.parse(attrs.params);
+          _.each(_d, function(v, k) {
+            scope.params[k] = _.isUndefined(scope.params[k]) 
+              ? _d[k] : scope.params[k];
+          });
+        }
+      });
+
+      // Also get the data if time frame changes.
+      // (REQUIRED IN EVERY PANEL)
+      scope.$watch(function() { 
+        return angular.toJson([scope.from, scope.to, scope.ready]) 
+      }, function(){
+        if(scope.ready)
+          get_data(scope,elem,attrs);
+      });
+
+      // Re-rending the panel if it is resized,
+      scope.$watch('data', function() {
+        if(scope.ready)
+          render_panel(scope,elem,attrs);
+      });
+
+      // Or if the model changes
+      angular.element(window).bind('resize', function(){
+          render_panel(scope,elem,attrs);
+      });
+
+      // Function for getting data
+      function get_data(scope,elem,attrs) {
+        var params = scope.params;
+        var ejs = scope.ejs;
+        var request = ejs.Request().indices(scope.index);
+        
+
+        var queries = [];
+        // Build the question part of the query
+        _.each(params.queries, function(v) {
+          queries.push(ejs.FilteredQuery(
+            ejs.QueryStringQuery(v || '*'),
+            ejs.RangeFilter(config.timefield)
+              .from(scope.from)
+              .to(scope.to)
+              .cache(false))
+          )
+        });
+
+        _.each(queries, function(v) {
+          request = request.facet(ejs.QueryFacet(_.indexOf(queries,v))
+            .query(v)
+            .facetFilter(ejs.QueryFilter(v))
+          )
+        })
+        // Then the insert into facet and make the request
+        var results = request.doSearch();
+
+        // Populate scope when we have results
+        results.then(function(results) {
+          scope.hits = results.hits.total;
+          scope.data = results.facets;
+        });
+      }
+
+      // Function for rendering panel
+      function render_panel(scope,elem,attrs) {
+        // Parse our params object
+        var params = scope.params;
+
+        // Create graph array
+        scope.graph = [];
+        _.each(scope.data, function(v, k) {
+          var point = {
+            label : params.queries[k],
+            data  : v['count']
+          }
+          if(!_.isUndefined(params.colors))
+            point.color = params.colors[k%params.colors.length];
+          scope.graph.push(point)
+        });
+
+        // Populate element
+        $.plot(elem, scope.graph, {
+            series: {
+              pie: {
+                innerRadius: params.donut ? 0.4 : 0,
+                tilt: params.tilt ? 0.45 : 1,
+                radius: 1,
+                show: true,
+                combine: {
+                  color: '#999',
+                  label: 'The Rest'
+                },
+                label: { 
+                  show: true,
+                  radius: 2/3,
+                  formatter: function(label, series){
+                    return '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">'+
+                      label+'<br/>'+Math.round(series.percent)+'%</div>';
+                  },
+                  threshold: 0.1 
+                }
+              }
+            },
+            //grid: { hoverable: true, clickable: true },
+            legend: { show: params.legend }
+          });
+        //elem.show();
+      }
+    }
+  };
+})

+ 140 - 0
js/panels/pieterms/module.js

@@ -0,0 +1,140 @@
+labjs = labjs.script("common/lib/jquery.flot.js")
+  .script("common/lib/jquery.flot.pie.js")
+
+angular.module('kibana.pieterms', [])
+.directive('pieterms', function() {
+  return {
+    restrict: 'A',
+    link: function(scope, elem, attrs) {
+
+      // Specify defaults for ALL directives
+      var _d = {
+        size    : 5,
+        query   : "*",
+        exclude : [],
+        donut   : false, 
+        tilt    : false,
+        legend  : true,
+      }
+
+      // Set ready flag and fill parameters (REQUIRED IN EVERY PANEL)
+      scope.$watch(function () {
+        return (attrs.params && scope.index) ? true : false;
+      }, function (ready) {
+        scope.ready = ready;
+        if(ready) {
+          scope.params = JSON.parse(attrs.params);
+          _.each(_d, function(v, k) {
+            scope.params[k] = _.isUndefined(scope.params[k]) 
+              ? _d[k] : scope.params[k];
+          });
+        }
+      });
+
+      // Also get the data if time frame changes.
+      // (REQUIRED IN EVERY PANEL)
+      scope.$watch(function() { 
+        return angular.toJson([scope.from, scope.to, scope.ready]) 
+      }, function(){
+        if(scope.ready)
+          get_data(scope,elem,attrs);
+      });
+
+      // Re-rending the panel if it is resized,
+      scope.$watch('data', function() {
+        if(scope.ready)
+          render_panel(scope,elem,attrs);
+      });
+
+      // Or if the model changes
+      angular.element(window).bind('resize', function(){
+          render_panel(scope,elem,attrs);
+      });
+
+      // Function for getting data
+      function get_data(scope,elem,attrs) {
+        var params = scope.params;
+        var ejs = scope.ejs;
+        var request = ejs.Request().indices(scope.index);
+        
+        // Build the question part of the query
+        var query = ejs.FilteredQuery(
+          ejs.QueryStringQuery(params.query || '*'),
+          ejs.RangeFilter(config.timefield)
+            .from(scope.from)
+            .to(scope.to)
+            .cache(false)
+          );
+
+        // Then the insert into facet and make the request
+        var results = request
+          .facet(ejs.TermsFacet('termpie')
+            .field(params.field)
+            .size(params['size'])
+            .exclude(params.exclude)
+            .facetFilter(ejs.QueryFilter(query))
+          )
+          .doSearch();
+
+        // Populate scope when we have results
+        results.then(function(results) {
+          scope.hits = results.hits.total;
+          scope.data = results.facets.termpie.terms;
+        });
+      }
+
+      // Function for rendering panel
+      function render_panel(scope,elem,attrs) {
+        // Parse our params object
+        var params = scope.params;
+
+        // Create graph array
+        scope.graph = [];
+        _.each(scope.data, function(v, k) {
+          if(!_.isUndefined(params.only) && _.indexOf(params.only,v['term']) < 0)
+            return
+
+          var point = {
+            label : v['term'],
+            data  : v['count']
+          }
+
+          if(!_.isUndefined(params.colors))
+            point.color = params.colors[_.indexOf(params.only,v['term'])] 
+
+          scope.graph.push(point)
+        });
+
+        var pie = {
+          series: {
+            pie: {
+              innerRadius: params.donut ? 0.4 : 0,
+              tilt: params.tilt ? 0.45 : 1,
+              radius: 1,
+              show: true,
+              combine: {
+                color: '#999',
+                label: 'The Rest'
+              },
+              label: { 
+                show: true,
+                radius: 2/3,
+                formatter: function(label, series){
+                  return '<div style="font-size:8pt;text-align:center;padding:2px;color:white;">'+
+                    label+'<br/>'+Math.round(series.percent)+'%</div>';
+                },
+                threshold: 0.1 
+              }
+            }
+          },
+          //grid: { hoverable: true, clickable: true },
+          legend: { show: params.legend }
+        };
+
+        // Populate element
+        $.plot(elem, scope.graph, pie);
+        //elem.show();
+      }
+    }
+  };
+})

+ 165 - 0
js/panels/stackedquery/module.js

@@ -0,0 +1,165 @@
+labjs = labjs.script("common/lib/jquery.flot.js")
+  .script("common/lib/jquery.flot.time.js")
+  .script("common/lib/jquery.flot.stack.js")
+
+angular.module('kibana.stackedquery', [])
+.directive('stackedquery', function() {
+  return {
+    restrict: 'A',
+    link: function(scope, elem, attrs) {
+
+      // Specify defaults for ALL directives
+      var _d = {
+        queries : ["*"],
+        interval: secondsToHms(calculate_interval(scope.from,scope.to,40,0)/1000),
+        colors  : ["#BF3030","#1D7373","#86B32D","#A98A21","#411F73"],
+        show    : ['bars']
+      }
+
+      // Set ready flag and fill parameters (REQUIRED IN EVERY PANEL)
+      scope.$watch(function () {
+        return (attrs.params && scope.index) ? true : false;
+      }, function (ready) {
+        scope.ready = ready;
+        if(ready) {
+          scope.params = JSON.parse(attrs.params);
+          _.each(_d, function(v, k) {
+            scope.params[k] = _.isUndefined(scope.params[k]) 
+              ? _d[k] : scope.params[k];
+          });
+        }
+      });
+
+      // Also get the data if time frame changes.
+      // (REQUIRED IN EVERY PANEL)
+      scope.$watch(function() { 
+        return angular.toJson([scope.from, scope.to, scope.ready]) 
+      }, function(){
+        if(scope.ready)
+          if (_.isUndefined(attrs.params.interval))
+            scope.params.interval = secondsToHms(
+              calculate_interval(scope.from,scope.to,50,0)/1000),
+          get_data(scope,elem,attrs);
+      });
+
+      // Re-rending the panel if it is resized,
+      scope.$watch('data', function() {
+        if(scope.ready)
+          render_panel(scope,elem,attrs);
+      });
+
+      // Or if the model changes
+      angular.element(window).bind('resize', function(){
+          render_panel(scope,elem,attrs);
+      });
+
+      // Function for getting data
+      function get_data(scope,elem,attrs) {
+        var params = scope.params;
+        var ejs = scope.ejs;
+        var request = ejs.Request().indices(scope.index);
+        
+        // Build the question part of the query
+        var queries = [];
+        _.each(params.queries, function(v) {
+          queries.push(ejs.FilteredQuery(
+            ejs.QueryStringQuery(v || '*'),
+            ejs.RangeFilter(config.timefield)
+              .from(scope.from)
+              .to(scope.to)
+              .cache(false))
+          )
+        });
+
+        // Build the facet part
+        _.each(queries, function(v) {
+          request = request
+            .facet(ejs.DateHistogramFacet(_.indexOf(queries,v))
+              .field(config.timefield)
+              .interval(params.interval)
+              .facetFilter(ejs.QueryFilter(v))
+            )
+        })
+
+        // Then run it
+        var results = request.doSearch();
+
+        // Populate scope when we have results
+        results.then(function(results) {
+          scope.hits = results.hits.total;
+          scope.data = results.facets;
+        });
+      }
+
+      // Function for rendering panel
+      function render_panel(scope,elem,attrs) {
+        // Parse our params object
+        var params = scope.params;
+
+        // Determine format
+        var show = _.isUndefined(params.show) ? {
+            bars: true, lines: false, points: false, fill: false
+          } : {
+            lines:  _.indexOf(params.show,'lines') < 0 ? false : true,
+            bars:   _.indexOf(params.show,'bars') < 0 ? false : true,
+            points: _.indexOf(params.show,'points') < 0 ? false : true,
+            fill:   _.indexOf(params.show,'fill') < 0 ? false : true
+          }
+
+        scope.graph = [];
+        // Push null values at beginning and end of timeframe
+        _.each(scope.data, function(v, k) {
+          var series = {};
+          var data = [[scope.from.getTime(), null]];
+          _.each(v.entries, function(v, k) {
+            data.push([v['time'],v['count']])
+          });
+          data.push([scope.to.getTime(), null])
+          series.data = {
+            label: params.queries[k], 
+            data: data, 
+            color: params.colors[k%params.colors.length]
+          };
+          scope.graph.push(series.data)
+        });
+
+        // Set barwidth based on specified interval
+        var barwidth = interval_to_seconds(params.interval)*1000
+
+        // Populate element
+        $.plot(elem, scope.graph, {
+          legend: { 
+            position: "nw", 
+            labelFormatter: function(label, series) {
+              return '<span class="legend">' + label + ' / ' + params.interval 
+                + '</span>';
+            }
+          },
+          series: {
+            stack:  0,
+            lines:  { show: show.lines, fill: show.fill },
+            bars:   { show: show.bars,  fill: 1, barWidth: barwidth/1.8 },
+            points: { show: show.points },
+            color: params.color,
+            shadowSize: 1
+          },
+          yaxis: { min: 0, color: "#000" },
+          xaxis: {
+            mode: "time",
+            timeformat: "%H:%M:%S<br>%m-%d",
+            label: "Datetime",
+            color: "#000",
+          },
+          grid: {
+            backgroundColor: '#fff',
+            borderWidth: 0,
+            borderColor: '#eee',
+            color: "#eee",
+            hoverable: true,
+          }
+        });
+        //elem.show();
+      }
+    }
+  };
+})

Разница между файлами не показана из-за своего большого размера
+ 7 - 0
scripts/date.js


+ 7 - 0
scripts/load.sh

@@ -0,0 +1,7 @@
+#!/usr/bin/env bash
+echo "Generating bulk indexable shakespeare lines with timestamp 3 hours in the past and 5 hours into the future"
+node reader.js > indexme.json
+echo "Performing bulk indexing into localhost:9200"
+curl -XPUT localhost:9200/_bulk --data-binary @indexme.json;echo
+echo
+echo "If tons of JSON just scrolled above, I've probably successfully loaded over 100,000 lines of shakespeare into localhost:9200/shakespeare"

+ 2 - 0
scripts/node_modules/random-weighted-choice/.npmignore

@@ -0,0 +1,2 @@
+*.sublime-*
+node_modules

+ 3 - 0
scripts/node_modules/random-weighted-choice/.travis.yml

@@ -0,0 +1,3 @@
+language: node_js
+node_js:
+    - 0.8

+ 9 - 0
scripts/node_modules/random-weighted-choice/Makefile

@@ -0,0 +1,9 @@
+test:
+	@NODE_ENV=test ./node_modules/.bin/mocha
+
+test-w:
+	@NODE_ENV=test ./node_modules/.bin/mocha \
+	  --growl \
+	  --watch
+
+.PHONY: test test-w

+ 75 - 0
scripts/node_modules/random-weighted-choice/README.md

@@ -0,0 +1,75 @@
+# Random Weighted Choice
+
+[![Build Status](https://secure.travis-ci.org/parmentf/random-weighted-choice.png?branch=master)](http://travis-ci.org/parmentf/random-weighted-choice)
+
+Node.js module to make a random choice among weighted elements of table.
+
+## Installation
+
+With [npm](http://npmjs.org) do:
+
+    $ npm install random-weighted-choice
+
+
+## Examples
+
+Although you can add several times the same id
+
+    var rwc = require('random-weighted-choice');
+    var table = [
+        { weight: 1, id: "item1"} // Element 1
+      , { weight: 1, id: "item2"} // Element 2
+      , { weight: 4, id: "item3"} // Element with a 4 times likelihood
+      , { weight: 2, id: "item1"} // Element 1, weight added with 2 => 3
+    ];
+    var choosenItem = rwc(table);
+    var choosenUnlikely = rwc(table, 100); // The last shall be first
+    var choosenDeterministically = rwc(table, 0);
+
+It is better to not use the same twice, if you want a temperature other than
+the default one (50).
+
+    var rwc = require('random-weighted-choice');
+    var table = [
+        { weight: 1, id: "item1"} // Element 1
+      , { weight: 1, id: "item2"} // Element 2
+      , { weight: 4, id: "item3"} // Element with a 4 times likelihood
+      , { weight: 2, id: "item4"} // Element 4
+      , { weight: 2, id: "item5"}
+    ];
+    var choosenItem = rwc(table);
+    var choosenUnlikely = rwc(table, 100); // The last shall be first
+    var choosenDeterministically = rwc(table, 0);
+
+Without temperature (second parameter) or a 50 value, likelihoods are:
+
+    { item1: 10%, item2: 10%, item3: 40%, item4: 20%, item5: 20% }
+
+With a temperature value of 100:
+
+    { item1: 30%, item2: 30%, item3: 0%, item4: 20%, item5: 20% }
+
+With a temperature value of 0, modified weights are:
+
+    { item1: 0, item2: 0, item3: 8, item4: 2, item5: 2 }
+
+## Usage
+
+### random-weighted-choice(Array table, Number temperature = 50)
+
+Return the ``id`` of the chosen item from ``table``.
+
+The ``table`` parameter should contain an Array. Each item of that Array must
+bean object, with at least ``weight`` and ``id`` property.
+
+Weight values are relative to each other. They are integers.
+
+When the sum of the weight values is ``null``, ``null`` is returned (can't choose).
+
+When the Array is empty, ``null`` is returned.
+
+More explanations on how it works on [Everything2](http://everything2.com/title/Blackboard+temperature).
+
+## Also
+
+* https://github.com/Schoonology/weighted

+ 65 - 0
scripts/node_modules/random-weighted-choice/lib/random-weighted-choice.js

@@ -0,0 +1,65 @@
+/*jshint node:true, laxcomma:true */
+"use strict";
+
+var debug = require('debug')('rwc');
+
+var RandomWeightedChoice = function (table, temperature, randomFunction, influence) {
+  influence = influence || 2; // Seems fine, difficult to tune
+  if (typeof(temperature)=="undefined") temperature =  50; // in [0,100], 50 is neutral
+  temperature = temperature | 50;
+  debug('temperature', temperature);
+  var T = (temperature - 50) / 50;
+  if (typeof(randomFunction)=="undefined") randomFunction = Math.random;
+
+  var nb = table.length;
+  if(!nb) return null; // No item given.
+
+  var total = 0;
+  table.forEach(function(element, index) {
+    total += element.weight;
+  });
+
+  var avg = total / nb;
+  debug('total', total);
+  debug('nb', nb);
+  debug('avg', avg);
+
+  // Compute amplified urgencies (depending on temperature)
+  var ur = {};
+  var urgencySum = 0;
+  table.forEach(function(element, index) {
+    var urgency = element.weight + T * influence * (avg - element.weight);
+    if (urgency < 0) urgency = 0;
+    urgencySum += urgency;
+    ur[element.id] = (ur[element.id] || 0 ) + urgency;
+  });
+
+  var cumulatedUrgencies = {};
+  var currentUrgency = 0;
+  Object.keys(ur).forEach(function(id, index) {
+    currentUrgency += ur[id];
+    cumulatedUrgencies[id] = currentUrgency;
+  });
+
+  if(urgencySum < 1) return null; // No weight given
+
+  // Choose
+  var choice = randomFunction() * urgencySum;
+
+  debug('ur', ur);
+  debug('cumulatedUrgencies', cumulatedUrgencies);
+  debug('urgencySum', urgencySum);
+  debug('choice', choice);
+
+  var ids = Object.keys(cumulatedUrgencies);
+  for(var i=0; i<ids.length; i++) {
+    var id = ids[i];
+    var urgency = cumulatedUrgencies[id];
+    if(choice <= urgency) {
+      debug('return', id);
+      return id;
+    }    
+  }
+};
+
+module.exports = RandomWeightedChoice;

+ 4 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/.npmignore

@@ -0,0 +1,4 @@
+support
+test
+examples
+*.sock

+ 47 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/History.md

@@ -0,0 +1,47 @@
+
+0.7.0 / 2012-05-04 
+==================
+
+  * Added .component to package.json
+  * Added debug.component.js build
+
+0.6.0 / 2012-03-16 
+==================
+
+  * Added support for "-" prefix in DEBUG [Vinay Pulim]
+  * Added `.enabled` flag to the node version [TooTallNate] 
+
+0.5.0 / 2012-02-02 
+==================
+
+  * Added: humanize diffs. Closes #8
+  * Added `debug.disable()` to the CS variant
+  * Removed padding. Closes #10
+  * Fixed: persist client-side variant again. Closes #9
+
+0.4.0 / 2012-02-01 
+==================
+
+  * Added browser variant support for older browsers [TooTallNate]
+  * Added `debug.enable('project:*')` to browser variant [TooTallNate]
+  * Added padding to diff (moved it to the right)
+
+0.3.0 / 2012-01-26 
+==================
+
+  * Added millisecond diff when isatty, otherwise UTC string
+
+0.2.0 / 2012-01-22 
+==================
+
+  * Added wildcard support
+
+0.1.0 / 2011-12-02 
+==================
+
+  * Added: remove colors unless stderr isatty [TooTallNate]
+
+0.0.1 / 2010-01-03
+==================
+
+  * Initial release

+ 4 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/Makefile

@@ -0,0 +1,4 @@
+
+debug.component.js: head.js debug.js tail.js
+	cat $^ > $@
+

+ 130 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/Readme.md

@@ -0,0 +1,130 @@
+
+# debug
+
+  tiny node.js debugging utility.
+
+## Installation
+
+```
+$ npm install debug
+```
+
+## Example
+
+  This module is modelled after node core's debugging technique, allowing you to enable one or more topic-specific debugging functions, for example core does the following within many modules:
+
+```js
+var debug;
+if (process.env.NODE_DEBUG && /cluster/.test(process.env.NODE_DEBUG)) {
+  debug = function(x) {
+    var prefix = process.pid + ',' +
+        (process.env.NODE_WORKER_ID ? 'Worker' : 'Master');
+    console.error(prefix, x);
+  };
+} else {
+  debug = function() { };
+}
+```
+
+ This concept is extremely simple but it works well. With `debug` you simply invoke the exported function to generate your debug function, passing it a name which will determine if a noop function is returned, or a decorated `console.error`, so all of the `console` format string goodies you're used to work fine. A unique color is selected per-function for visibility.
+ 
+Example _app.js_:
+
+```js
+var debug = require('debug')('http')
+  , http = require('http')
+  , name = 'My App';
+
+// fake app
+
+debug('booting %s', name);
+
+http.createServer(function(req, res){
+  debug(req.method + ' ' + req.url);
+  res.end('hello\n');
+}).listen(3000, function(){
+  debug('listening');
+});
+
+// fake worker of some kind
+
+require('./worker');
+```
+
+Example _worker.js_:
+
+```js
+var debug = require('debug')('worker');
+
+setInterval(function(){
+  debug('doing some work');
+}, 1000);
+```
+
+ The __DEBUG__ environment variable is then used to enable these based on space or comma-delimited names. Here are some examples:
+
+  ![debug http and worker](http://f.cl.ly/items/18471z1H402O24072r1J/Screenshot.png)
+
+  ![debug worker](http://f.cl.ly/items/1X413v1a3M0d3C2c1E0i/Screenshot.png)
+
+## Millisecond diff
+
+  When actively developing an application it can be useful to see when the time spent between one `debug()` call and the next. Suppose for example you invoke `debug()` before requesting a resource, and after as well, the "+NNNms" will show you how much time was spent between calls.
+
+  ![](http://f.cl.ly/items/2i3h1d3t121M2Z1A3Q0N/Screenshot.png)
+
+  When stdout is not a TTY, `Date#toUTCString()` is used, making it more useful for logging the debug information as shown below:
+  
+  ![](http://f.cl.ly/items/112H3i0e0o0P0a2Q2r11/Screenshot.png)
+
+## Conventions
+
+ If you're using this in one or more of your libraries, you _should_ use the name of your library so that developers may toggle debugging as desired without guessing names. If you have more than one debuggers you _should_ prefix them with your library name and use ":" to separate features. For example "bodyParser" from Connect would then be "connect:bodyParser". 
+
+## Wildcards
+
+  The "*" character may be used as a wildcard. Suppose for example your library has debuggers named "connect:bodyParser", "connect:compress", "connect:session", instead of listing all three with `DEBUG=connect:bodyParser,connect.compress,connect:session`, you may simply do `DEBUG=connect:*`, or to run everything using this module simply use `DEBUG=*`.
+
+  You can also exclude specific debuggers by prefixing them with a "-" character.  For example, `DEBUG=* -connect:*` would include all debuggers except those starting with "connect:".
+
+## Browser support
+
+ Debug works in the browser as well, currently persisted by `localStorage`. For example if you have `worker:a` and `worker:b` as shown below, and wish to debug both type `debug.enable('worker:*')` in the console and refresh the page, this will remain until you disable with `debug.disable()`. 
+
+```js
+a = debug('worker:a');
+b = debug('worker:b');
+
+setInterval(function(){
+  a('doing some work');
+}, 1000);
+
+setInterval(function(){
+  a('doing some work');
+}, 1200);
+```
+
+## License 
+
+(The MIT License)
+
+Copyright (c) 2011 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 120 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/debug.component.js

@@ -0,0 +1,120 @@
+;(function(){
+
+/**
+ * Create a debugger with the given `name`.
+ *
+ * @param {String} name
+ * @return {Type}
+ * @api public
+ */
+
+function debug(name) {
+  if (!debug.enabled(name)) return function(){};
+
+  return function(fmt){
+    var curr = new Date;
+    var ms = curr - (debug[name] || curr);
+    debug[name] = curr;
+
+    fmt = name
+      + ' '
+      + fmt
+      + ' +' + debug.humanize(ms);
+
+    // This hackery is required for IE8
+    // where `console.log` doesn't have 'apply'
+    window.console
+      && console.log
+      && Function.prototype.apply.call(console.log, console, arguments);
+  }
+}
+
+/**
+ * The currently active debug mode names.
+ */
+
+debug.names = [];
+debug.skips = [];
+
+/**
+ * Enables a debug mode by name. This can include modes
+ * separated by a colon and wildcards.
+ *
+ * @param {String} name
+ * @api public
+ */
+
+debug.enable = function(name) {
+  localStorage.debug = name;
+
+  var split = (name || '').split(/[\s,]+/)
+    , len = split.length;
+
+  for (var i = 0; i < len; i++) {
+    name = split[i].replace('*', '.*?');
+    if (name[0] === '-') {
+      debug.skips.push(new RegExp('^' + name.substr(1) + '$'));
+    }
+    else {
+      debug.names.push(new RegExp('^' + name + '$'));
+    }
+  }
+};
+
+/**
+ * Disable debug output.
+ *
+ * @api public
+ */
+
+debug.disable = function(){
+  debug.enable('');
+};
+
+/**
+ * Humanize the given `ms`.
+ *
+ * @param {Number} m
+ * @return {String}
+ * @api private
+ */
+
+debug.humanize = function(ms) {
+  var sec = 1000
+    , min = 60 * 1000
+    , hour = 60 * min;
+
+  if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
+  if (ms >= min) return (ms / min).toFixed(1) + 'm';
+  if (ms >= sec) return (ms / sec | 0) + 's';
+  return ms + 'ms';
+};
+
+/**
+ * Returns true if the given mode name is enabled, false otherwise.
+ *
+ * @param {String} name
+ * @return {Boolean}
+ * @api public
+ */
+
+debug.enabled = function(name) {
+  for (var i = 0, len = debug.skips.length; i < len; i++) {
+    if (debug.skips[i].test(name)) {
+      return false;
+    }
+  }
+  for (var i = 0, len = debug.names.length; i < len; i++) {
+    if (debug.names[i].test(name)) {
+      return true;
+    }
+  }
+  return false;
+};
+
+// persist
+
+if (window.localStorage) debug.enable(localStorage.debug);
+  module.exports = debug;
+
+})();

+ 116 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/debug.js

@@ -0,0 +1,116 @@
+
+/**
+ * Create a debugger with the given `name`.
+ *
+ * @param {String} name
+ * @return {Type}
+ * @api public
+ */
+
+function debug(name) {
+  if (!debug.enabled(name)) return function(){};
+
+  return function(fmt){
+    var curr = new Date;
+    var ms = curr - (debug[name] || curr);
+    debug[name] = curr;
+
+    fmt = name
+      + ' '
+      + fmt
+      + ' +' + debug.humanize(ms);
+
+    // This hackery is required for IE8
+    // where `console.log` doesn't have 'apply'
+    window.console
+      && console.log
+      && Function.prototype.apply.call(console.log, console, arguments);
+  }
+}
+
+/**
+ * The currently active debug mode names.
+ */
+
+debug.names = [];
+debug.skips = [];
+
+/**
+ * Enables a debug mode by name. This can include modes
+ * separated by a colon and wildcards.
+ *
+ * @param {String} name
+ * @api public
+ */
+
+debug.enable = function(name) {
+  localStorage.debug = name;
+
+  var split = (name || '').split(/[\s,]+/)
+    , len = split.length;
+
+  for (var i = 0; i < len; i++) {
+    name = split[i].replace('*', '.*?');
+    if (name[0] === '-') {
+      debug.skips.push(new RegExp('^' + name.substr(1) + '$'));
+    }
+    else {
+      debug.names.push(new RegExp('^' + name + '$'));
+    }
+  }
+};
+
+/**
+ * Disable debug output.
+ *
+ * @api public
+ */
+
+debug.disable = function(){
+  debug.enable('');
+};
+
+/**
+ * Humanize the given `ms`.
+ *
+ * @param {Number} m
+ * @return {String}
+ * @api private
+ */
+
+debug.humanize = function(ms) {
+  var sec = 1000
+    , min = 60 * 1000
+    , hour = 60 * min;
+
+  if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
+  if (ms >= min) return (ms / min).toFixed(1) + 'm';
+  if (ms >= sec) return (ms / sec | 0) + 's';
+  return ms + 'ms';
+};
+
+/**
+ * Returns true if the given mode name is enabled, false otherwise.
+ *
+ * @param {String} name
+ * @return {Boolean}
+ * @api public
+ */
+
+debug.enabled = function(name) {
+  for (var i = 0, len = debug.skips.length; i < len; i++) {
+    if (debug.skips[i].test(name)) {
+      return false;
+    }
+  }
+  for (var i = 0, len = debug.names.length; i < len; i++) {
+    if (debug.names[i].test(name)) {
+      return true;
+    }
+  }
+  return false;
+};
+
+// persist
+
+if (window.localStorage) debug.enable(localStorage.debug);

+ 19 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/example/app.js

@@ -0,0 +1,19 @@
+
+var debug = require('../')('http')
+  , http = require('http')
+  , name = 'My App';
+
+// fake app
+
+debug('booting %s', name);
+
+http.createServer(function(req, res){
+  debug(req.method + ' ' + req.url);
+  res.end('hello\n');
+}).listen(3000, function(){
+  debug('listening');
+});
+
+// fake worker of some kind
+
+require('./worker');

+ 24 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/example/browser.html

@@ -0,0 +1,24 @@
+<html>
+  <head>
+    <title>debug()</title>
+    <script src="../debug.js"></script>
+    <script>
+      // type debug.enable('*') in
+      // the console and refresh :)
+
+      a = debug('worker:a');
+      b = debug('worker:b');
+
+      setInterval(function(){
+        a('doing some work');
+      }, 1000);
+
+      setInterval(function(){
+        a('doing some work');
+      }, 1200);
+    </script>
+  </head>
+  <body>
+    
+  </body>
+</html>

+ 10 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/example/wildcards.js

@@ -0,0 +1,10 @@
+
+var debug = {
+  foo: require('../')('test:foo'),
+  bar: require('../')('test:bar'),
+  baz: require('../')('test:baz')
+};
+
+debug.foo('foo')
+debug.bar('bar')
+debug.baz('baz')

+ 22 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/example/worker.js

@@ -0,0 +1,22 @@
+
+// DEBUG=* node example/worker
+// DEBUG=worker:* node example/worker
+// DEBUG=worker:a node example/worker
+// DEBUG=worker:b node example/worker
+
+var a = require('../')('worker:a')
+  , b = require('../')('worker:b');
+
+function work() {
+  a('doing lots of uninteresting work');
+  setTimeout(work, Math.random() * 1000);
+}
+
+work();
+
+function workb() {
+  b('doing some work');
+  setTimeout(workb, Math.random() * 2000);
+}
+
+workb();

+ 1 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/head.js

@@ -0,0 +1 @@
+;(function(){

+ 2 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/index.js

@@ -0,0 +1,2 @@
+
+module.exports = require('./lib/debug');

+ 135 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/lib/debug.js

@@ -0,0 +1,135 @@
+
+/**
+ * Module dependencies.
+ */
+
+var tty = require('tty');
+
+/**
+ * Expose `debug()` as the module.
+ */
+
+module.exports = debug;
+
+/**
+ * Enabled debuggers.
+ */
+
+var names = []
+  , skips = [];
+
+(process.env.DEBUG || '')
+  .split(/[\s,]+/)
+  .forEach(function(name){
+    name = name.replace('*', '.*?');
+    if (name[0] === '-') {
+      skips.push(new RegExp('^' + name.substr(1) + '$'));
+    } else {
+      names.push(new RegExp('^' + name + '$'));
+    }
+  });
+
+/**
+ * Colors.
+ */
+
+var colors = [6, 2, 3, 4, 5, 1];
+
+/**
+ * Previous debug() call.
+ */
+
+var prev = {};
+
+/**
+ * Previously assigned color.
+ */
+
+var prevColor = 0;
+
+/**
+ * Is stdout a TTY? Colored output is disabled when `true`.
+ */
+
+var isatty = tty.isatty(2);
+
+/**
+ * Select a color.
+ *
+ * @return {Number}
+ * @api private
+ */
+
+function color() {
+  return colors[prevColor++ % colors.length];
+}
+
+/**
+ * Humanize the given `ms`.
+ *
+ * @param {Number} m
+ * @return {String}
+ * @api private
+ */
+
+function humanize(ms) {
+  var sec = 1000
+    , min = 60 * 1000
+    , hour = 60 * min;
+
+  if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
+  if (ms >= min) return (ms / min).toFixed(1) + 'm';
+  if (ms >= sec) return (ms / sec | 0) + 's';
+  return ms + 'ms';
+}
+
+/**
+ * Create a debugger with the given `name`.
+ *
+ * @param {String} name
+ * @return {Type}
+ * @api public
+ */
+
+function debug(name) {
+  function disabled(){}
+  disabled.enabled = false;
+
+  var match = skips.some(function(re){
+    return re.test(name);
+  });
+
+  if (match) return disabled;
+
+  match = names.some(function(re){
+    return re.test(name);
+  });
+
+  if (!match) return disabled;
+  var c = color();
+
+  function colored(fmt) {
+    var curr = new Date;
+    var ms = curr - (prev[name] || curr);
+    prev[name] = curr;
+
+    fmt = '  \033[9' + c + 'm' + name + ' '
+      + '\033[3' + c + 'm\033[90m'
+      + fmt + '\033[3' + c + 'm'
+      + ' +' + humanize(ms) + '\033[0m';
+
+    console.error.apply(this, arguments);
+  }
+
+  function plain(fmt) {
+    fmt = new Date().toUTCString()
+      + ' ' + name + ' ' + fmt;
+    console.error.apply(this, arguments);
+  }
+
+  colored.enabled = plain.enabled = true;
+
+  return isatty
+    ? colored
+    : plain;
+}

Разница между файлами не показана из-за своего большого размера
+ 27 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/package.json


+ 4 - 0
scripts/node_modules/random-weighted-choice/node_modules/debug/tail.js

@@ -0,0 +1,4 @@
+
+  module.exports = debug;
+
+})();

Разница между файлами не показана из-за своего большого размера
+ 31 - 0
scripts/node_modules/random-weighted-choice/package.json


+ 66 - 0
scripts/node_modules/random-weighted-choice/test/test.js

@@ -0,0 +1,66 @@
+/*jshint node:true, laxcomma:true */
+/*global describe:true, it:true */
+"use strict";
+
+var debug = require('debug')('rwc:test');
+var assert = require('assert');
+
+var rwc = require('../lib/random-weighted-choice');
+
+var randomCounter = 0;
+var randomValues = [0,0.19,0.5,0.7,0.9];
+var randomMock = function(values, reset) {
+  if(typeof(values)=="undefined") values = randomValues;
+  if (typeof(reset)=="undefined") reset = false;
+  if (reset) randomCounter = 0;
+  return values[randomCounter++];
+};
+
+
+describe('Temperature 50', function () {
+  var table = [
+        { weight: 1, id: "item1"} // Element 1
+      , { weight: 1, id: "item2"} // Element 2
+      , { weight: 4, id: "item3"} // Element with a 4 times likelihood
+      , { weight: 2, id: "item4"} // Element 4
+      , { weight: 2, id: "item5"}
+    ];
+
+  it('should return "item1"', function (){
+    assert.equal('item1', rwc(table,null,randomMock));
+  });
+  it('should return "item2"', function (){
+    assert.equal('item2', rwc(table,null,randomMock));
+  });
+  it('should return "item3"', function (){
+    assert.equal('item3', rwc(table,null,randomMock));
+  });
+  it('should return "item4"', function (){
+    assert.equal('item4', rwc(table,null,randomMock));
+  });
+  it('should return "item5"', function (){
+    assert.equal('item5', rwc(table,null,randomMock));
+  });
+});
+
+
+describe('Empty table', function () {
+  it('should return null', function () {
+    assert.equal(null, rwc([]));
+  });
+});
+
+
+describe('One element', function () {
+  it('should return the element', function () {
+    assert.equal('a', rwc([{weight:1, id: 'a'}]));
+  });
+});
+
+describe('No weight', function () {
+  it('should return null', function () {
+    assert.equal(null, rwc([{weight:0, id: 'a'}]));
+  });
+});
+
+module.exports.random = randomMock;

+ 282 - 0
scripts/reader.js

@@ -0,0 +1,282 @@
+require("./date.js")
+var rwc = require('random-weighted-choice');
+_ = require("./underscore.min.js")
+fs = require('fs')
+
+fs.readFile('shakespeare.json', 'utf8', function (err,data) {
+  i = 0;
+  if (err) {
+    return console.log(err);
+  }
+  var obj = JSON.parse(data);
+  _.each(obj, function (o) {
+    setTimeout(print_obj(o), 10000) //wait ten seconds before continuing
+  });
+
+  function getRandomInRange(from, to, fixed) {
+    return (Math.random() * (to - from) + from).toFixed(fixed) * 1;
+  }
+
+  function print_obj(o) {
+    var countries = get_countries();
+    var randomnumber=Math.floor(Math.random()*28800000)
+    var command = {index:{_index: "shakespeare", _type: "line", _id: i}};
+    o['@timestamp'] = new Date((new Date()).getTime() -9000000 + randomnumber);
+    o.geo = [getRandomInRange(-90, 90, 3),getRandomInRange(-180, 180, 3)]
+    o.country = rwc(countries);
+    console.log(JSON.stringify(command))
+    console.log(JSON.stringify(o));
+    i = i + 1;
+  }
+
+  function get_countries() {
+    return [{id:"CN",weight:1330044000},
+{id:"IN",weight:1173108018},
+{id:"US",weight:610232863},
+{id:"ID",weight:242968342},
+{id:"BR",weight:201103330},
+{id:"PK",weight:184404791},
+{id:"BD",weight:156118464},
+{id:"NG",weight:154000000},
+{id:"RU",weight:140702000},
+{id:"JP",weight:127288000},
+{id:"MX",weight:112468855},
+{id:"PH",weight:99900177},
+{id:"VN",weight:89571130},
+{id:"ET",weight:88013491},
+{id:"DE",weight:81802257},
+{id:"EG",weight:80471869},
+{id:"TR",weight:77804122},
+{id:"IR",weight:76923300},
+{id:"CD",weight:70916439},
+{id:"TH",weight:67089500},
+{id:"FR",weight:64768389},
+{id:"GB",weight:62348447},
+{id:"IT",weight:60340328},
+{id:"MM",weight:53414374},
+{id:"ZA",weight:49000000},
+{id:"KR",weight:48422644},
+{id:"ES",weight:46505963},
+{id:"UA",weight:45415596},
+{id:"CO",weight:44205293},
+{id:"TZ",weight:41892895},
+{id:"AR",weight:41343201},
+{id:"KE",weight:40046566},
+{id:"PL",weight:38500000},
+{id:"SD",weight:35000000},
+{id:"DZ",weight:34586184},
+{id:"CA",weight:33679000},
+{id:"UG",weight:33398682},
+{id:"MA",weight:31627428},
+{id:"PE",weight:29907003},
+{id:"IQ",weight:29671605},
+{id:"AF",weight:29121286},
+{id:"NP",weight:28951852},
+{id:"MY",weight:28274729},
+{id:"UZ",weight:27865738},
+{id:"VE",weight:27223228},
+{id:"SA",weight:25731776},
+{id:"GH",weight:24339838},
+{id:"YE",weight:23495361},
+{id:"KP",weight:22912177},
+{id:"TW",weight:22894384},
+{id:"SY",weight:22198110},
+{id:"MZ",weight:22061451},
+{id:"RO",weight:21959278},
+{id:"AU",weight:21515754},
+{id:"LK",weight:21513990},
+{id:"MG",weight:21281844},
+{id:"CI",weight:21058798},
+{id:"CM",weight:19294149},
+{id:"CL",weight:16746491},
+{id:"NL",weight:16645000},
+{id:"BF",weight:16241811},
+{id:"NE",weight:15878271},
+{id:"MW",weight:15447500},
+{id:"KZ",weight:15340000},
+{id:"EC",weight:14790608},
+{id:"KH",weight:14453680},
+{id:"ML",weight:13796354},
+{id:"GT",weight:13550440},
+{id:"ZM",weight:13460305},
+{id:"AO",weight:13068161},
+{id:"SN",weight:12323252},
+{id:"ZW",weight:11651858},
+{id:"CU",weight:11423000},
+{id:"RW",weight:11055976},
+{id:"GR",weight:11000000},
+{id:"CS",weight:10829175},
+{id:"PT",weight:10676000},
+{id:"TN",weight:10589025},
+{id:"TD",weight:10543464},
+{id:"CZ",weight:10476000},
+{id:"BE",weight:10403000},
+{id:"GN",weight:10324025},
+{id:"SO",weight:10112453},
+{id:"BO",weight:9947418},
+{id:"HU",weight:9930000},
+{id:"BI",weight:9863117},
+{id:"DO",weight:9823821},
+{id:"BY",weight:9685000},
+{id:"HT",weight:9648924},
+{id:"BJ",weight:9056010},
+{id:"SE",weight:9045000},
+{id:"AZ",weight:8303512},
+{id:"SS",weight:8260490},
+{id:"AT",weight:8205000},
+{id:"HN",weight:7989415},
+{id:"CH",weight:7581000},
+{id:"TJ",weight:7487489},
+{id:"IL",weight:7353985},
+{id:"RS",weight:7344847},
+{id:"BG",weight:7148785},
+{id:"HK",weight:6898686},
+{id:"TG",weight:6587239},
+{id:"LY",weight:6461454},
+{id:"JO",weight:6407085},
+{id:"PY",weight:6375830},
+{id:"LA",weight:6368162},
+{id:"PG",weight:6064515},
+{id:"SV",weight:6052064},
+{id:"NI",weight:5995928},
+{id:"ER",weight:5792984},
+{id:"KG",weight:5508626},
+{id:"DK",weight:5484000},
+{id:"SK",weight:5455000},
+{id:"SL",weight:5245695},
+{id:"FI",weight:5244000},
+{id:"NO",weight:5009150},
+{id:"AE",weight:4975593},
+{id:"TM",weight:4940916},
+{id:"CF",weight:4844927},
+{id:"SG",weight:4701069},
+{id:"GE",weight:4630000},
+{id:"IE",weight:4622917},
+{id:"BA",weight:4590000},
+{id:"CR",weight:4516220},
+{id:"HR",weight:4491000},
+{id:"MD",weight:4324000},
+{id:"NZ",weight:4252277},
+{id:"LB",weight:4125247},
+{id:"PR",weight:3916632},
+{id:"PS",weight:3800000},
+{id:"LR",weight:3685076},
+{id:"LT",weight:3565000},
+{id:"UY",weight:3477000},
+{id:"PA",weight:3410676},
+{id:"MR",weight:3205060},
+{id:"MN",weight:3086918},
+{id:"CG",weight:3039126},
+{id:"AL",weight:2986952},
+{id:"AM",weight:2968000},
+{id:"OM",weight:2967717},
+{id:"JM",weight:2847232},
+{id:"KW",weight:2789132},
+{id:"LV",weight:2217969},
+{id:"NA",weight:2128471},
+{id:"MK",weight:2061000},
+{id:"BW",weight:2029307},
+{id:"SI",weight:2007000},
+{id:"LS",weight:1919552},
+{id:"XK",weight:1800000},
+{id:"GM",weight:1593256},
+{id:"GW",weight:1565126},
+{id:"GA",weight:1545255},
+{id:"SZ",weight:1354051},
+{id:"MU",weight:1294104},
+{id:"EE",weight:1291170},
+{id:"TT",weight:1228691},
+{id:"TL",weight:1154625},
+{id:"CY",weight:1102677},
+{id:"GQ",weight:1014999},
+{id:"FJ",weight:875983},
+{id:"QA",weight:840926},
+{id:"RE",weight:776948},
+{id:"KM",weight:773407},
+{id:"GY",weight:748486},
+{id:"DJ",weight:740528},
+{id:"BH",weight:738004},
+{id:"BT",weight:699847},
+{id:"ME",weight:666730},
+{id:"SB",weight:559198},
+{id:"CV",weight:508659},
+{id:"LU",weight:497538},
+{id:"SR",weight:492829},
+{id:"MO",weight:449198},
+{id:"GP",weight:443000},
+{id:"MQ",weight:432900},
+{id:"MT",weight:403000},
+{id:"MV",weight:395650},
+{id:"BN",weight:395027},
+{id:"BZ",weight:314522},
+{id:"IS",weight:308910},
+{id:"BS",weight:301790},
+{id:"BB",weight:285653},
+{id:"EH",weight:273008},
+{id:"PF",weight:270485},
+{id:"VU",weight:221552},
+{id:"NC",weight:216494},
+{id:"GF",weight:195506},
+{id:"WS",weight:192001},
+{id:"ST",weight:175808},
+{id:"LC",weight:160922},
+{id:"GU",weight:159358},
+{id:"YT",weight:159042},
+{id:"CW",weight:141766},
+{id:"AN",weight:136197},
+{id:"TO",weight:122580},
+{id:"VI",weight:108708},
+{id:"GD",weight:107818},
+{id:"FM",weight:107708},
+{id:"VC",weight:104217},
+{id:"KI",weight:92533},
+{id:"JE",weight:90812},
+{id:"SC",weight:88340},
+{id:"AG",weight:86754},
+{id:"AD",weight:84000},
+{id:"IM",weight:75049},
+{id:"DM",weight:72813},
+{id:"AW",weight:71566},
+{id:"MH",weight:65859},
+{id:"BM",weight:65365},
+{id:"GG",weight:65228},
+{id:"AS",weight:57881},
+{id:"GL",weight:56375},
+{id:"MP",weight:53883},
+{id:"KN",weight:49898},
+{id:"FO",weight:48228},
+{id:"KY",weight:44270},
+{id:"SX",weight:37429},
+{id:"MF",weight:35925},
+{id:"LI",weight:35000},
+{id:"MC",weight:32965},
+{id:"SM",weight:31477},
+{id:"GI",weight:27884},
+{id:"AX",weight:26711},
+{id:"VG",weight:21730},
+{id:"CK",weight:21388},
+{id:"TC",weight:20556},
+{id:"PW",weight:19907},
+{id:"BQ",weight:18012},
+{id:"WF",weight:16025},
+{id:"AI",weight:13254},
+{id:"TV",weight:10472},
+{id:"NR",weight:10065},
+{id:"MS",weight:9341},
+{id:"BL",weight:8450},
+{id:"SH",weight:7460},
+{id:"PM",weight:7012},
+{id:"IO",weight:4000},
+{id:"FK",weight:2638},
+{id:"SJ",weight:2550},
+{id:"NU",weight:2166},
+{id:"NF",weight:1828},
+{id:"CX",weight:1500},
+{id:"TK",weight:1466},
+{id:"VA",weight:921},
+{id:"CC",weight:628},
+{id:"TF",weight:140},
+{id:"PN",weight:46},
+{id:"GS",weight:30}];
+  }
+});

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
scripts/shakespeare.json


+ 32 - 0
scripts/underscore.min.js

@@ -0,0 +1,32 @@
+// Underscore.js 1.3.3
+// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
+// Underscore is freely distributable under the MIT license.
+// Portions of Underscore are inspired or borrowed from Prototype,
+// Oliver Steele's Functional, and John Resig's Micro-Templating.
+// For all details and documentation:
+// http://documentcloud.github.com/underscore
+(function(){function r(a,c,d){if(a===c)return 0!==a||1/a==1/c;if(null==a||null==c)return a===c;a._chain&&(a=a._wrapped);c._chain&&(c=c._wrapped);if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return!1;switch(e){case "[object String]":return a==""+c;case "[object Number]":return a!=+a?c!=+c:0==a?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source==
+c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if("object"!=typeof a||"object"!=typeof c)return!1;for(var f=d.length;f--;)if(d[f]==a)return!0;d.push(a);var f=0,g=!0;if("[object Array]"==e){if(f=a.length,g=f==c.length)for(;f--&&(g=f in a==f in c&&r(a[f],c[f],d)););}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return!1;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c,h)&&!f--)break;
+g=!f}}d.pop();return g}var s=this,I=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,J=k.unshift,l=p.toString,K=p.hasOwnProperty,y=k.forEach,z=k.map,A=k.reduce,B=k.reduceRight,C=k.filter,D=k.every,E=k.some,q=k.indexOf,F=k.lastIndexOf,p=Array.isArray,L=Object.keys,t=Function.prototype.bind,b=function(a){return new m(a)};"undefined"!==typeof exports?("undefined"!==typeof module&&module.exports&&(exports=module.exports=b),exports._=b):s._=b;b.VERSION="1.3.3";var j=b.each=b.forEach=function(a,
+c,d){if(a!=null)if(y&&a.forEach===y)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e<f;e++){if(e in a&&c.call(d,a[e],e,a)===o)break}else for(e in a)if(b.has(a,e)&&c.call(d,a[e],e,a)===o)break};b.map=b.collect=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.map===z)return a.map(c,b);j(a,function(a,g,h){e[e.length]=c.call(b,a,g,h)});if(a.length===+a.length)e.length=a.length;return e};b.reduce=b.foldl=b.inject=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(A&&
+a.reduce===A){e&&(c=b.bind(c,e));return f?a.reduce(c,d):a.reduce(c)}j(a,function(a,b,i){if(f)d=c.call(e,d,a,b,i);else{d=a;f=true}});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(B&&a.reduceRight===B){e&&(c=b.bind(c,e));return f?a.reduceRight(c,d):a.reduceRight(c)}var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect=function(a,
+c,b){var e;G(a,function(a,g,h){if(c.call(b,a,g,h)){e=a;return true}});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(C&&a.filter===C)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(D&&a.every===D)return a.every(c,b);j(a,function(a,g,h){if(!(e=e&&c.call(b,
+a,g,h)))return o});return!!e};var G=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(E&&a.some===E)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;if(q&&a.indexOf===q)return a.indexOf(c)!=-1;return b=G(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck=
+function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a)&&a[0]===+a[0])return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b<e.computed&&
+(e={value:a,computed:b})});return e.value};b.shuffle=function(a){var b=[],d;j(a,function(a,f){d=Math.floor(Math.random()*(f+1));b[f]=b[d];b[d]=a});return b};b.sortBy=function(a,c,d){var e=b.isFunction(c)?c:function(a){return a[c]};return b.pluck(b.map(a,function(a,b,c){return{value:a,criteria:e.call(d,a,b,c)}}).sort(function(a,b){var c=a.criteria,d=b.criteria;return c===void 0?1:d===void 0?-1:c<d?-1:c>d?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};
+j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e<f;){var g=e+f>>1;d(a[g])<d(c)?e=g+1:f=g}return e};b.toArray=function(a){return!a?[]:b.isArray(a)||b.isArguments(a)?i.call(a):a.toArray&&b.isFunction(a.toArray)?a.toArray():b.values(a)};b.size=function(a){return b.isArray(a)?a.length:b.keys(a).length};b.first=b.head=b.take=function(a,b,d){return b!=null&&!d?i.call(a,0,b):a[0]};b.initial=function(a,b,d){return i.call(a,
+0,a.length-(b==null||d?1:b))};b.last=function(a,b,d){return b!=null&&!d?i.call(a,Math.max(a.length-b,0)):a[a.length-1]};b.rest=b.tail=function(a,b,d){return i.call(a,b==null||d?1:b)};b.compact=function(a){return b.filter(a,function(a){return!!a})};b.flatten=function(a,c){return b.reduce(a,function(a,e){if(b.isArray(e))return a.concat(c?e:b.flatten(e));a[a.length]=e;return a},[])};b.without=function(a){return b.difference(a,i.call(arguments,1))};b.uniq=b.unique=function(a,c,d){var d=d?b.map(a,d):a,
+e=[];a.length<3&&(c=true);b.reduce(d,function(d,g,h){if(c?b.last(d)!==g||!d.length:!b.include(d,g)){d.push(g);e.push(a[h])}return d},[]);return e};b.union=function(){return b.uniq(b.flatten(arguments,true))};b.intersection=b.intersect=function(a){var c=i.call(arguments,1);return b.filter(b.uniq(a),function(a){return b.every(c,function(c){return b.indexOf(c,a)>=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1),true);return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=
+i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e<c;e++)d[e]=b.pluck(a,""+e);return d};b.indexOf=function(a,c,d){if(a==null)return-1;var e;if(d){d=b.sortedIndex(a,c);return a[d]===c?d:-1}if(q&&a.indexOf===q)return a.indexOf(c);d=0;for(e=a.length;d<e;d++)if(d in a&&a[d]===c)return d;return-1};b.lastIndexOf=function(a,b){if(a==null)return-1;if(F&&a.lastIndexOf===F)return a.lastIndexOf(b);for(var d=a.length;d--;)if(d in a&&a[d]===b)return d;return-1};b.range=function(a,b,d){if(arguments.length<=
+1){b=a||0;a=0}for(var d=arguments[2]||1,e=Math.max(Math.ceil((b-a)/d),0),f=0,g=Array(e);f<e;){g[f++]=a;a=a+d}return g};var H=function(){};b.bind=function(a,c){var d,e;if(a.bind===t&&t)return t.apply(a,i.call(arguments,1));if(!b.isFunction(a))throw new TypeError;e=i.call(arguments,2);return d=function(){if(!(this instanceof d))return a.apply(c,e.concat(i.call(arguments)));H.prototype=a.prototype;var b=new H,g=a.apply(b,e.concat(i.call(arguments)));return Object(g)===g?g:b}};b.bindAll=function(a){var c=
+i.call(arguments,1);c.length==0&&(c=b.functions(a));j(c,function(c){a[c]=b.bind(a[c],a)});return a};b.memoize=function(a,c){var d={};c||(c=b.identity);return function(){var e=c.apply(this,arguments);return b.has(d,e)?d[e]:d[e]=a.apply(this,arguments)}};b.delay=function(a,b){var d=i.call(arguments,2);return setTimeout(function(){return a.apply(null,d)},b)};b.defer=function(a){return b.delay.apply(b,[a,1].concat(i.call(arguments,1)))};b.throttle=function(a,c){var d,e,f,g,h,i,j=b.debounce(function(){h=
+g=false},c);return function(){d=this;e=arguments;f||(f=setTimeout(function(){f=null;h&&a.apply(d,e);j()},c));g?h=true:i=a.apply(d,e);j();g=true;return i}};b.debounce=function(a,b,d){var e;return function(){var f=this,g=arguments;d&&!e&&a.apply(f,g);clearTimeout(e);e=setTimeout(function(){e=null;d||a.apply(f,g)},b)}};b.once=function(a){var b=false,d;return function(){if(b)return d;b=true;return d=a.apply(this,arguments)}};b.wrap=function(a,b){return function(){var d=[a].concat(i.call(arguments,0));
+return b.apply(this,d)}};b.compose=function(){var a=arguments;return function(){for(var b=arguments,d=a.length-1;d>=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=L||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&
+c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.pick=function(a){var c={};j(b.flatten(i.call(arguments,1)),function(b){b in a&&(c[b]=a[b])});return c};b.defaults=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=
+function(a){if(a==null)return true;if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=function(a){return l.call(a)=="[object Arguments]"};b.isArguments(arguments)||(b.isArguments=function(a){return!(!a||!b.has(a,"callee"))});b.isFunction=function(a){return l.call(a)=="[object Function]"};
+b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isFinite=function(a){return b.isNumber(a)&&isFinite(a)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,
+b){return K.call(a,b)};b.noConflict=function(){s._=I;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e<a;e++)b.call(d,e)};b.escape=function(a){return(""+a).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;").replace(/\//g,"&#x2F;")};b.result=function(a,c){if(a==null)return null;var d=a[c];return b.isFunction(d)?d.call(a):d};b.mixin=function(a){j(b.functions(a),function(c){M(c,b[c]=a[c])})};var N=0;b.uniqueId=
+function(a){var b=N++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var u=/.^/,n={"\\":"\\","'":"'",r:"\r",n:"\n",t:"\t",u2028:"\u2028",u2029:"\u2029"},v;for(v in n)n[n[v]]=v;var O=/\\|'|\r|\n|\t|\u2028|\u2029/g,P=/\\(\\|'|r|n|t|u2028|u2029)/g,w=function(a){return a.replace(P,function(a,b){return n[b]})};b.template=function(a,c,d){d=b.defaults(d||{},b.templateSettings);a="__p+='"+a.replace(O,function(a){return"\\"+n[a]}).replace(d.escape||
+u,function(a,b){return"'+\n_.escape("+w(b)+")+\n'"}).replace(d.interpolate||u,function(a,b){return"'+\n("+w(b)+")+\n'"}).replace(d.evaluate||u,function(a,b){return"';\n"+w(b)+"\n;__p+='"})+"';\n";d.variable||(a="with(obj||{}){\n"+a+"}\n");var a="var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n"+a+"return __p;\n",e=new Function(d.variable||"obj","_",a);if(c)return e(c,b);c=function(a){return e.call(this,a,b)};c.source="function("+(d.variable||"obj")+"){\n"+a+"}";return c};
+b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var x=function(a,c){return c?b(a).chain():a},M=function(a,c){m.prototype[a]=function(){var a=i.call(arguments);J.call(a,this._wrapped);return x(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return x(d,
+this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return x(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain=true;return this};m.prototype.value=function(){return this._wrapped}}).call(this);

Некоторые файлы не были показаны из-за большого количества измененных файлов