Full Code of yaronn/blessed-contrib for AI

master ecd48d98c4c6 cached
64 files
184.0 KB
72.2k tokens
116 symbols
1 requests
Download .txt
Repository: yaronn/blessed-contrib
Branch: master
Commit: ecd48d98c4c6
Files: 64
Total size: 184.0 KB

Directory structure:
gitextract_i23csocn/

├── .eslintrc.json
├── .gitignore
├── .npmignore
├── LICENSE.md
├── README.md
├── examples/
│   ├── bar.js
│   ├── carousel.js
│   ├── dashboard-random-colors.js
│   ├── dashboard.js
│   ├── donut.js
│   ├── explorer.js
│   ├── gauge-list.js
│   ├── gauge-stack.js
│   ├── gauge.js
│   ├── grid-no-border.js
│   ├── grid.js
│   ├── inline-data/
│   │   ├── bar.js
│   │   ├── donut.js
│   │   ├── gauge.js
│   │   ├── lcd.js
│   │   ├── map.js
│   │   ├── markdown.js
│   │   ├── multi-line-chart.js
│   │   ├── picture.js
│   │   ├── sparkline.js
│   │   └── table.js
│   ├── lcd.js
│   ├── line-abbreviate.js
│   ├── line-fraction.js
│   ├── line-random-colors.js
│   ├── line-start-above-zero.js
│   ├── line-zoomed-in.js
│   ├── log.js
│   ├── map.js
│   ├── markdown.js
│   ├── marked-terminal.js
│   ├── multi-line-chart.js
│   ├── picture.js
│   ├── sparkline.js
│   ├── stacked-bar.js
│   ├── table-color.js
│   └── table.js
├── index.d.ts
├── index.js
├── lib/
│   ├── layout/
│   │   ├── carousel.js
│   │   └── grid.js
│   ├── server-utils.js
│   ├── utils.js
│   └── widget/
│       ├── canvas.js
│       ├── charts/
│       │   ├── bar.js
│       │   ├── line.js
│       │   └── stacked-bar.js
│       ├── donut.js
│       ├── gauge-list.js
│       ├── gauge.js
│       ├── lcd.js
│       ├── log.js
│       ├── map.js
│       ├── markdown.js
│       ├── picture.js
│       ├── sparkline.js
│       ├── table.js
│       └── tree.js
└── package.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintrc.json
================================================
{
  "env": {
    "es6": true,
    "node": true
  },
  "extends": "eslint:recommended",
  "parserOptions": {
    "ecmaVersion": 2015
  },
  "rules": {
    "brace-style": "error",
    "no-irregular-whitespace":"error",
    "no-octal-escape": "error",
    "no-octal": "error",
    "no-proto":"error",
    "strict":["error", "global"],
    "no-undef":"error",
    "no-use-before-define": "off",
    "indent": ["error", 2],
    "semi": [2, "always"],
    "quotes": [2, "single"]
  }
}


================================================
FILE: .gitignore
================================================
.dccache
node_modules
p.js
p1.js
p2.js
npm-debug.log
log.txt
weather.query


================================================
FILE: .npmignore
================================================
node_modules
p.js
p1.js
p2.js
npm-debug.log
docs
examples

================================================
FILE: LICENSE.md
================================================
## MIT License

Copyright (c) 2015 Yaron Naveh and blessed-contrib contributors

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.


================================================
FILE: README.md
================================================
## blessed-contrib

Build dashboards (or any other application) using ascii/ansi art and javascript.

Friendly to terminals, ssh and developers. Extends [blessed](https://github.com/chjj/blessed) with custom  [drawille](https://github.com/madbence/node-drawille) and other widgets.

You should also [check WOPR](https://github.com/yaronn/wopr): a markup for creating terminal reports, presentations and infographics.


**Contributors:**

Yaron Naveh ([@YaronNaveh](http://twitter.com/YaronNaveh))
Chris ([@xcezzz](https://twitter.com/xcezzz))
Miguel Valadas ([@mvaladas](https://github.com/mvaladas))
Liran Tal ([@lirantal](https://github.com/lirantal))

**Demo ([full size](https://raw.githubusercontent.com/yaronn/blessed-contrib/master/docs/images/term3.gif)):**

<img src="./docs/images/truload.png" alt="term" width="800">

<img src="./docs/images/term3.gif" alt="term" width="800">

([source code](./examples/dashboard.js))

**Running the demo**

    git clone https://github.com/yaronn/blessed-contrib.git
    cd blessed-contrib
    npm install
    node ./examples/dashboard.js

Works on Linux, OS X and Windows. For Windows follow the [pre requisites](http://webservices20.blogspot.co.il/2015/04/running-terminal-dashboards-on-windows.html).

## Installation (to build custom projects)

    npm install blessed blessed-contrib

## Usage

You can use any of the default widgets of [blessed](https://github.com/chjj/blessed) (texts, lists and etc) or the widgets added in blessed-contrib (described below). A [layout](#layouts) is optional but useful for dashboards. The widgets in blessed-contrib follow the same usage pattern:

`````javascript
   var blessed = require('blessed')
     , contrib = require('blessed-contrib')
     , screen = blessed.screen()
     , line = contrib.line(
         { style:
           { line: "yellow"
           , text: "green"
           , baseline: "black"}
         , xLabelPadding: 3
         , xPadding: 5
         , label: 'Title'})
     , data = {
         x: ['t1', 't2', 't3', 't4'],
         y: [5, 1, 7, 5]
      }
   screen.append(line) //must append before setting data
   line.setData([data])

   screen.key(['escape', 'q', 'C-c'], function(ch, key) {
     return process.exit(0);
   });

   screen.render()
`````

See below for a complete list of widgets.


## Widgets

[Line Chart](#line-chart)

[Bar Chart](#bar-chart)

[Stacked Bar Chart](#stacked-bar-chart)

[Map](#map)

[Gauge](#gauge)

[Stacked Gauge](#stacked-gauge)

[Donut](#donut)

[LCD Display](#lcd-display)

[Rolling Log](#rolling-log)

[Picture](#picture)

[Sparkline](#sparkline)

[Table](#table)

[Tree](#tree)

[Markdown](#markdown)

### Line Chart

<img src="./docs/images/line.gif" alt="line" width="400">

`````javascript
   var line = contrib.line(
         { style:
           { line: "yellow"
           , text: "green"
           , baseline: "black"}
         , xLabelPadding: 3
         , xPadding: 5
         , showLegend: true
         , wholeNumbersOnly: false //true=do not show fraction in y axis
         , label: 'Title'})
   var series1 = {
         title: 'apples',
         x: ['t1', 't2', 't3', 't4'],
         y: [5, 1, 7, 5]
      }
   var series2 = {
         title: 'oranges',
         x: ['t1', 't2', 't3', 't4'],
         y: [2, 1, 4, 8]
      }
   screen.append(line) //must append before setting data
   line.setData([series1, series2])
`````
**Examples:** [simple line chart](./examples/line-fraction.js), [multiple lines](./examples/multi-line-chart.js), [256 colors](./examples/line-random-colors.js)

### Bar Chart

<img src="./docs/images/bar.gif" alt="bar" width="250">

`````javascript
    var bar = contrib.bar(
       { label: 'Server Utilization (%)'
       , barWidth: 4
       , barSpacing: 6
       , xOffset: 0
       , maxHeight: 9})
    screen.append(bar) //must append before setting data
    bar.setData(
       { titles: ['bar1', 'bar2']
       , data: [5, 10]})
`````

### Stacked Bar Chart

<img src="./docs/images/stacked-bar.png" alt="stacked-bar" width="250">

`````javascript
    bar = contrib.stackedBar(
       { label: 'Server Utilization (%)'
       , barWidth: 4
       , barSpacing: 6
       , xOffset: 0
       //, maxValue: 15
       , height: "40%"
       , width: "50%"
       , barBgColor: [ 'red', 'blue', 'green' ]})
    screen.append(bar)
    bar.setData(
       { barCategory: ['Q1', 'Q2', 'Q3', 'Q4']
       , stackedCategory: ['US', 'EU', 'AP']
       , data:
          [ [ 7, 7, 5]
          , [8, 2, 0]
          , [0, 0, 0]
          , [2, 3, 2] ]
       })
`````

### Map

<img src="./docs/images/map.gif" alt="map" width="500">

`````javascript
   var map = contrib.map({label: 'World Map'})
   map.addMarker({"lon" : "-79.0000", "lat" : "37.5000", color: "red", char: "X" })
`````


### Gauge

<img src="./docs/images/gauge.gif" alt="gauge" width="170">

`````javascript
   var gauge = contrib.gauge({label: 'Progress', stroke: 'green', fill: 'white'})
   gauge.setPercent(25)
`````

### Stacked Gauge

<img src="./docs/images/stackgauge.gif" alt="stackedgauge">

Either specify each stacked portion with a `percent` and `stroke`...

`````javascript
   var gauge = contrib.gauge({label: 'Stacked '})
   gauge.setStack([{percent: 30, stroke: 'green'}, {percent: 30, stroke: 'magenta'}, {percent: 40, stroke: 'cyan'}])
`````

Or, you can just supply an array of numbers and random colors will be chosen.

`````javascript
   var gauge = contrib.gauge({label: 'Stacked Progress'})
   gauge.setStack([30,30,40])
`````

### Donut

<img src="./docs/images/donut.gif" alt="donut">


`````javascript
   var donut = contrib.donut({
	label: 'Test',
	radius: 8,
	arcWidth: 3,
	remainColor: 'black',
	yPadding: 2,
	data: [
	  {percent: 80, label: 'web1', color: 'green'}
	]
  });
`````

Data passed in uses `percent` and `label` to draw the donut graph. Color is optional and defaults to green.

`````javascript
   donut.setData([
   	{percent: 87, label: 'rcp','color': 'green'},
	{percent: 43, label: 'rcp','color': 'cyan'},
   ]);
`````

Updating the donut is as easy as passing in an array to `setData` using the same array format as in the constructor. Pass in as many objects to the array of data as you want, they will automatically resize and try to fit. However, please note that you will still be restricted to actual screen space.

You can also hardcode a specific numeric into the donut's core display instead of the percentage by passing an `percentAltNumber` property to the data, such as:

`````javascript
   var donut = contrib.donut({
	label: 'Test',
	radius: 8,
	arcWidth: 3,
	remainColor: 'black',
	yPadding: 2,
	data: [
	  {percentAltNumber: 50, percent: 80, label: 'web1', color: 'green'}
	]
  });
`````

See an example of this in one of the donuts settings on `./examples/donut.js`.

### LCD Display

<img src="./docs/images/lcd.gif" alt="lcd">

`````javascript
   var lcd = contrib.lcd(
     { segmentWidth: 0.06 // how wide are the segments in % so 50% = 0.5
     , segmentInterval: 0.11 // spacing between the segments in % so 50% = 0.550% = 0.5
     , strokeWidth: 0.11 // spacing between the segments in % so 50% = 0.5
     , elements: 4 // how many elements in the display. or how many characters can be displayed.
     , display: 321 // what should be displayed before first call to setDisplay
     , elementSpacing: 4 // spacing between each element
     , elementPadding: 2 // how far away from the edges to put the elements
     , color: 'white' // color for the segments
     , label: 'Storage Remaining'})
`````

`````javascript

	lcd.setDisplay(23 + 'G'); // will display "23G"
	lcd.setOptions({}) // adjust options at runtime

`````

Please see the **examples/lcd.js** for an example. The example provides keybindings to adjust the `segmentWidth` and `segmentInterval` and `strokeWidth` in real-time so that you can see how they manipulate the look and feel.


### Rolling Log

<img src="./docs/images/log.gif" alt="log" width="180">

`````javascript
   var log = contrib.log(
      { fg: "green"
      , selectedFg: "green"
      , label: 'Server Log'})
   log.log("new log line")
`````


### Picture

(Also check the new blessed [image implementation](https://github.com/chjj/blessed#image-from-box) which has several benefits over this one.)

<img src="./docs/images/picture.png" alt="log" width="180">

`````javascript
    var pic = contrib.picture(
       { file: './flower.png'
       , cols: 25
       , onReady: ready})
    function ready() {screen.render()}
`````

note: only png images are supported


### Sparkline

<img src="./docs/images/spark.gif" alt="spark" width="180">

`````javascript
   var spark = contrib.sparkline(
     { label: 'Throughput (bits/sec)'
     , tags: true
     , style: { fg: 'blue' }})

   sparkline.setData(
   [ 'Sparkline1', 'Sparkline2'],
   [ [10, 20, 30, 20]
   , [40, 10, 40, 50]])
`````

### Table

<img src="./docs/images/table.gif" alt="table" width="250">

`````javascript
   var table = contrib.table(
     { keys: true
     , fg: 'white'
     , selectedFg: 'white'
     , selectedBg: 'blue'
     , interactive: true
     , label: 'Active Processes'
     , width: '30%'
     , height: '30%'
     , border: {type: "line", fg: "cyan"}
     , columnSpacing: 10 //in chars
     , columnWidth: [16, 12, 12] /*in chars*/ })

   //allow control the table with the keyboard
   table.focus()

   table.setData(
   { headers: ['col1', 'col2', 'col3']
   , data:
      [ [1, 2, 3]
      , [4, 5, 6] ]})
`````

### Tree

<img src="./docs/images/tree.gif" alt="table" width="250">

`````javascript
   var tree = contrib.tree({fg: 'green'})

   //allow control the table with the keyboard
   tree.focus()

   tree.on('select',function(node){
     if (node.myCustomProperty){
       console.log(node.myCustomProperty);
     }
     console.log(node.name);
   }

   // you can specify a name property at root level to display root
   tree.setData(
   { extended: true
   , children:
     {
       'Fruit':
       { children:
         { 'Banana': {}
         , 'Apple': {}
         , 'Cherry': {}
         , 'Exotics': {
             children:
             { 'Mango': {}
             , 'Papaya': {}
             , 'Kiwi': { name: 'Kiwi (not the bird!)', myCustomProperty: "hairy fruit" }
             }}
         , 'Pear': {}}}
     , 'Vegetables':
       { children:
         { 'Peas': {}
         , 'Lettuce': {}
         , 'Pepper': {}}}}})
`````

#### Options

 * keys : Key to expand nodes. Default : ['enter','default']
 * extended : Should nodes be extended/generated by default? Be careful with this setting when using a callback function. Default : false
 * template :
   * extend : Suffix "icon" for closed node. Default : '[+]'
   * retract : Suffix "icon" for opened node. Default : '[-]'
   * lines : Show lines in tree. Default : true

#### Nodes

Every node is a hash and it can have custom properties that can be used in "select" event callback. However, there are several special keys :

* name
  * *Type* : `string`
  * *Desc* : Node name
  * If the node isn't the root and you don't specify the name, will be set to hash key
  * *Example* : <code>{ name: 'Fruit'}</code>
* children
  * *Type* : `hash` or `function(node){ return children }`
  * *Desc* : Node children.
  * The function must return a hash that could have been used as children property
  * If you use a function, the result will be stored in `node.childrenContent` and `children`
  * *Example* :
    * Hash : <code>{'Fruit':{ name: 'Fruit', children:{ 'Banana': {}, 'Cherry': {}}}}</code>
    * Function : see `examples/explorer.js`
* childrenContent
  * *Type* : `hash`
  * *Desc* : Children content for internal usage *DO NOT MODIFY*
  * If `node.children` is a hash, `node.children===node.childrenContent`
  * If `node.children` is a function, it's used to store the `node.children()` result
  * You can read this property, but you should never write it.
  * Usually this will be used to check `if(node.childrenContent)` in your `node.children` function to generate children only once
* extended
  * *Type* : `boolean`
  * *Desc* : Determine if this node is extended
  * No effect when the node have no child
  * Default value for each node will be `treeInstance.options.extended` if the node `extended` option is not set
  * *Example* : <code>{'Fruit':{ name: 'Fruit', extended: true, children:{ 'Banana': {}, 'Cherry': {}}}}</code>

### Markdown

<img src="./docs/images/markdown.png" alt="table">

`````javascript
   var markdown = contrib.markdown()
   markdown.setMarkdown('# Hello \n blessed-contrib renders markdown using `marked-terminal`')
`````

### Colors
You can use 256 colors ([source](./examples/line-random-colors.js)):

`````javascript
  function randomColor() {
    return [Math.random() * 255,Math.random()*255, Math.random()*255]
  }

  line = contrib.line(
  {
    ...
    , style: { line: randomColor(), text: randomColor(), baseline: randomColor() }
  })
`````
   
### Layouts

[Grid](#grid)

[Carousel](#carousel)

### Grid

A grid layout can auto position your elements in a grid layout.
When using a grid, you should not create the widgets, rather specify to the grid which widget to create and with which params.
Each widget can span multiple rows and columns.

`````javascript
   var screen = blessed.screen()

   var grid = new contrib.grid({rows: 12, cols: 12, screen: screen})

   //grid.set(row, col, rowSpan, colSpan, obj, opts)
   var map = grid.set(0, 0, 4, 4, contrib.map, {label: 'World Map'})
   var box = grid.set(4, 4, 4, 4, blessed.box, {content: 'My Box'})

   screen.render()
`````

### Carousel
A carousel layout switches between different views based on time or keyboard activity.
One use case is an office dashboard with rotating views:

`````javascript
    var blessed = require('blessed')
      , contrib = require('./')
      , screen = blessed.screen()

    function page1(screen) {
       var map = contrib.map()
       screen.append(map)
    }

    function page2(screen) {
      var line = contrib.line(
       { width: 80
       , height: 30
       , left: 15
       , top: 12
       , xPadding: 5
       , label: 'Title'
       })

      var data = [ { title: 'us-east',
                 x: ['t1', 't2', 't3', 't4'],
                 y: [0, 0.0695652173913043, 0.11304347826087, 2],
                 style: {
                  line: 'red'
                 }
               }
            ]

      screen.append(line)
      line.setData(data)
    }

    screen.key(['escape', 'q', 'C-c'], function(ch, key) {
      return process.exit(0);
    });

    var carousel = new contrib.carousel( [page1, page2]
                                       , { screen: screen
                                         , interval: 3000 //how often to switch views (set 0 to never swicth automatically)
                                         , controlKeys: true  //should right and left keyboard arrows control view rotation
                                         })
    carousel.start()

`````

## Samples


### Terminal Dashboard

<img src="./docs/images/term3.gif" alt="term" width="800">

**Running the sample**

    git clone https://github.com/yaronn/blessed-contrib.git
    cd blessed-contrib
    npm install
    node ./examples/dashboard.js

**Installation (for a custom dashboard)**

    npm install blessed
    npm install blessed-contrib


**A simple dashboard**

`````javascript
   var blessed = require('blessed')
     , contrib = require('blessed-contrib')
     , screen = blessed.screen()
     , grid = new contrib.grid({rows: 1, cols: 2, screen: screen})

   var line = grid.set(0, 0, 1, 1, contrib.line,
     { style:
       { line: "yellow"
       , text: "green"
       , baseline: "black"}
     , xLabelPadding: 3
     , xPadding: 5
     , label: 'Stocks'})

   var map = grid.set(0, 1, 1, 1, contrib.map, {label: 'Servers Location'})

   var lineData = {
      x: ['t1', 't2', 't3', 't4'],
      y: [5, 1, 7, 5]
   }

   line.setData([lineData])

   screen.key(['escape', 'q', 'C-c'], function(ch, key) {
     return process.exit(0);
   });

   screen.render()
`````

**Rich dashboard**

See [source code](./examples/dashboard.js)

## Troubleshooting
If you see questions marks or some (or all) missign characters try running with these env vars to fix encoding / terminal: 
`````
    $> LANG=en_US.utf8 TERM=xterm-256color node your-code.js 
`````

## License
This library is under the [MIT License](http://opensource.org/licenses/MIT)

## More Information
Created by Yaron Naveh ([twitter](http://twitter.com/YaronNaveh), [blog](http://webservices20.blogspot.com/))


================================================
FILE: examples/bar.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
  , bar = contrib.bar(
       { label: 'Server Utilization (%)'
       , barWidth: 4
       , barSpacing: 6
       , xOffset: 0
       , maxHeight: 9
       , height: "40%"})

screen.append(bar)

bar.setData(
       { titles: ['bar1', 'bar2']
       , data: [5, 10]})

screen.render()

================================================
FILE: examples/carousel.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()

function page1(screen) {  
   var grid = new contrib.grid({rows: 4, cols: 4, screen: screen})

   var line = grid.set(1, 0, 2, 2, contrib.line, 
     { style: 
       { line: "yellow"
       , text: "green"
       , baseline: "black"}
     , xLabelPadding: 3
     , xPadding: 5
     , label: 'Stocks'})

   var map = grid.set(1, 2, 2, 2, contrib.map, {label: 'Servers Location'})

   var box = blessed.box({content: 'click right-left arrows or wait 3 seconds for the next layout in the carousel', top: '80%', left: '10%'})
   screen.append(box)

   var lineData = {
      x: ['t1', 't2', 't3', 't4'],
      y: [5, 1, 7, 5]
   }

   line.setData([lineData]) 
}

function page2(screen) {  
  var line = contrib.line(
   { width: 80
   , height: 30
   , left: 15
   , top: 12  
   , xPadding: 5
   , label: 'Title'
   })

  var data = [ { title: 'us-east',
             x: ['t1', 't2', 't3', 't4'],
             y: [0, 0.0695652173913043, 0.11304347826087, 2],
             style: {
              line: 'red'
             }
           }
        ]

  screen.append(line)
  line.setData(data)

  var box = blessed.box({content: 'click right-left arrows or wait 3 seconds for the next layout in the carousel', top: '80%', left: '10%'})
  screen.append(box)

}

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

var carousel = new contrib.carousel( [page1, page2]
                                   , { screen: screen
                                     , interval: 3000
                                     , controlKeys: true })
carousel.start()


================================================
FILE: examples/dashboard-random-colors.js
================================================
var blessed = require('blessed')
  , contrib = require('../index')

var screen = blessed.screen()

//create layout and widgets

  // Create a random color
  function randomColor() {
    return [Math.random() * 255,Math.random()*255, Math.random()*255]
}

var grid = new contrib.grid({rows: 12, cols: 12, screen: screen})

/**
 * Donut Options
  self.options.radius = options.radius || 14; // how wide is it? over 5 is best
  self.options.arcWidth = options.arcWidth || 4; //width of the donut
  self.options.yPadding = options.yPadding || 2; //padding from the top
 */
var donut = grid.set(8, 8, 4, 2, contrib.donut, 
  {
  label: 'Percent Donut',
  radius: 16,
  arcWidth: 4,
  yPadding: 2,
  data: [{label: 'Storage', percent: 87}]
})

// var latencyLine = grid.set(8, 8, 4, 2, contrib.line, 
//   { style: 
//     { line: "yellow"
//     , text: "green"
//     , baseline: "black"}
//   , xLabelPadding: 3
//   , xPadding: 5
//   , label: 'Network Latency (sec)'})

var gauge = grid.set(8, 10, 2, 2, contrib.gauge, {label: 'Storage', percent: [80,20]})
var gauge_two = grid.set(2, 9, 2, 3, contrib.gauge, {label: 'Deployment Progress', percent: 80})

var sparkline = grid.set(10, 10, 2, 2, contrib.sparkline, 
  { label: 'Throughput (bits/sec)'
  , tags: true
  , style: { fg: 'blue', titleFg: 'white' }})

var bar = grid.set(4, 6, 4, 3, contrib.bar, 
  { label: 'Server Utilization (%)'
  , barWidth: 4
  , barSpacing: 6
  , xOffset: 2
  , maxHeight: 9})

var table =  grid.set(4, 9, 4, 3, contrib.table, 
  { keys: true
  , fg: 'green'
  , label: 'Active Processes'
  , columnSpacing: 1
  , columnWidth: [24, 10, 10]})

/*
 *
 * LCD Options
//these options need to be modified epending on the resulting positioning/size
  options.segmentWidth = options.segmentWidth || 0.06; // how wide are the segments in % so 50% = 0.5
  options.segmentInterval = options.segmentInterval || 0.11; // spacing between the segments in % so 50% = 0.5
  options.strokeWidth = options.strokeWidth || 0.11; // spacing between the segments in % so 50% = 0.5
//default display settings
  options.elements = options.elements || 3; // how many elements in the display. or how many characters can be displayed.
  options.display = options.display || 321; // what should be displayed before anything is set
  options.elementSpacing = options.spacing || 4; // spacing between each element
  options.elementPadding = options.padding || 2; // how far away from the edges to put the elements
//coloring
  options.color = options.color || "white";
*/
var lcdLineOne = grid.set(0,9,2,3, contrib.lcd,
  {
    label: "LCD Test",
    segmentWidth: 0.06,
    segmentInterval: 0.11,
    strokeWidth: 0.1,
    elements: 5,
    display: 3210,
    elementSpacing: 4,
    elementPadding: 2
  }
);

var errorsLine = grid.set(0, 6, 4, 3, contrib.line, 
  { style: 
    { line: randomColor()
    , text: randomColor()
    , baseline: randomColor()}
  , label: 'Errors Rate'
  , maxY: 60
  , showLegend: true })

var transactionsLine = grid.set(0, 0, 6, 6, contrib.line, 
          { showNthLabel: 5
          , maxY: 100
          , label: 'Total Transactions'
          , showLegend: true
          , legend: {width: 10}})

var map = grid.set(6, 0, 6, 6, contrib.map, {label: 'Servers Location'})

var log = grid.set(8, 6, 4, 2, contrib.log, 
  { fg: randomColor()
  , selectedFg: randomColor()
  , label: 'Server Log'})


//dummy data
var servers = ['US1', 'US2', 'EU1', 'AU1', 'AS1', 'JP1']
var commands = ['grep', 'node', 'java', 'timer', '~/ls -l', 'netns', 'watchdog', 'gulp', 'tar -xvf', 'awk', 'npm install']


//set dummy data on gauge
var gauge_percent = 0
setInterval(function() {
  gauge.setData([gauge_percent, 100-gauge_percent]);
  gauge_percent++;
  if (gauge_percent>=100) gauge_percent = 0  
}, 200)

var gauge_percent_two = 0
setInterval(function() {
  gauge_two.setData(gauge_percent_two);
  gauge_percent_two++;
  if (gauge_percent_two>=100) gauge_percent_two = 0  
}, 200);


//set dummy data on bar chart
function fillBar() {
  var arr = []
  for (var i=0; i<servers.length; i++) {
    arr.push(Math.round(Math.random()*10))
  }
  bar.setData({titles: servers, data: arr})
}
fillBar()
setInterval(fillBar, 2000)


//set dummy data for table
function generateTable() {
   var data = []

   for (var i=0; i<30; i++) {
     var row = []          
     row.push(commands[Math.round(Math.random()*(commands.length-1))])
     row.push(Math.round(Math.random()*5))
     row.push(Math.round(Math.random()*100))

     data.push(row)
   }

   table.setData({headers: ['Process', 'Cpu (%)', 'Memory'], data: data})
}

generateTable()
table.focus()
setInterval(generateTable, 3000)


//set log dummy data
setInterval(function() {
   var rnd = Math.round(Math.random()*2)
   if (rnd==0) log.log('starting process ' + commands[Math.round(Math.random()*(commands.length-1))])   
   else if (rnd==1) log.log('terminating server ' + servers[Math.round(Math.random()*(servers.length-1))])
   else if (rnd==2) log.log('avg. wait time ' + Math.random().toFixed(2))
   screen.render()
}, 500)


//set spark dummy data
var spark1 = [1,2,5,2,1,5,1,2,5,2,1,5,4,4,5,4,1,5,1,2,5,2,1,5,1,2,5,2,1,5,1,2,5,2,1,5]
var spark2 = [4,4,5,4,1,5,1,2,5,2,1,5,4,4,5,4,1,5,1,2,5,2,1,5,1,2,5,2,1,5,1,2,5,2,1,5]

refreshSpark()
setInterval(refreshSpark, 1000)

function refreshSpark() {
  spark1.shift()
  spark1.push(Math.random()*5+1)       
  spark2.shift()
  spark2.push(Math.random()*5+1)       
  sparkline.setData(['Server1', 'Server2'], [spark1, spark2])  
}



//set map dummy markers
var marker = true
setInterval(function() {
   if (marker) {
    map.addMarker({"lon" : "-79.0000", "lat" : "37.5000", color: randomColor(), char: 'X' })
    map.addMarker({"lon" : "-122.6819", "lat" : "45.5200" })
    map.addMarker({"lon" : "-6.2597", "lat" : "53.3478" })
    map.addMarker({"lon" : "103.8000", "lat" : "1.3000" })
   }
   else {
    map.clearMarkers()
   }
   marker =! marker
   screen.render()
}, 1000)

//set line charts dummy data

var transactionsData = {
   title: 'USA',
   style: {line:'red'},
   x: ['00:00', '00:05', '00:10', '00:15', '00:20', '00:30', '00:40', '00:50', '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00', '02:10', '02:20', '02:30', '02:40', '02:50', '03:00', '03:10', '03:20', '03:30', '03:40', '03:50', '04:00', '04:10', '04:20', '04:30'],
   y: [0, 20, 40, 45, 45, 50, 55, 70, 65, 58, 50, 55, 60, 65, 70, 80, 70, 50, 40, 50, 60, 70, 82, 88, 89, 89, 89, 80, 72, 70]
}

var transactionsData1 = {
   title: 'Europe',
   style: {line:'yellow'},
   x: ['00:00', '00:05', '00:10', '00:15', '00:20', '00:30', '00:40', '00:50', '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00', '02:10', '02:20', '02:30', '02:40', '02:50', '03:00', '03:10', '03:20', '03:30', '03:40', '03:50', '04:00', '04:10', '04:20', '04:30'],
   y: [0, 5, 5, 10, 10, 15, 20, 30, 25, 30, 30, 20, 20, 30, 30, 20, 15, 15, 19, 25, 30, 25, 25, 20, 25, 30, 35, 35, 30, 30]
}

var errorsData = {
   title: 'server 1',
   x: ['00:00', '00:05', '00:10', '00:15', '00:20', '00:25'],
   y: [30, 50, 70, 40, 50, 20]
}

var latencyData = {
   x: ['t1', 't2', 't3', 't4'],
   y: [5, 1, 7, 5]
}

setLineData([transactionsData, transactionsData1], transactionsLine)
setLineData([errorsData], errorsLine)
// setLineData([latencyData], latencyLine)

setInterval(function() {
   setLineData([transactionsData, transactionsData1], transactionsLine)
   screen.render()
}, 500)

setInterval(function() {   
    setLineData([errorsData], errorsLine)
}, 1500)

setInterval(function(){
  var colors = [randomColor(),randomColor(),randomColor(),randomColor(),randomColor()];
  var text = ['A','B','C','D','E','F','G','H','I','J','K','L'];

  var value = Math.round(Math.random() * 100);
  lcdLineOne.setDisplay(value + text[value%12]);
  lcdLineOne.setOptions({
    color: colors[value%5],
    elementPadding: 4
  });
  screen.render()
}, 1500);

var pct = 0.00;

function updateDonut(){
  if (pct > 0.99) pct = 0.00;
  var color = "green";
  if (pct >= 0.25) color = "cyan";
  if (pct >= 0.5) color = "yellow";
  if (pct >= 0.75) color = "red";  
  donut.setData([
    {percent: parseFloat((pct+0.00) % 1).toFixed(2), label: 'storage', 'color': color}
  ]);
  pct += 0.01;
}

setInterval(function() {   
   updateDonut();
   screen.render()
}, 500)

function setLineData(mockData, line) {
  for (var i=0; i<mockData.length; i++) {
    var last = mockData[i].y[mockData[i].y.length-1]
    mockData[i].y.shift()
    var num = Math.max(last + Math.round(Math.random()*10) - 5, 10)    
    mockData[i].y.push(num)  
  }
  
  line.setData(mockData)
}


screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.render()


================================================
FILE: examples/dashboard.js
================================================
var blessed = require('blessed')
  , contrib = require('../index')

var screen = blessed.screen()

//create layout and widgets

var grid = new contrib.grid({rows: 12, cols: 12, screen: screen})

/**
 * Donut Options
  self.options.radius = options.radius || 14; // how wide is it? over 5 is best
  self.options.arcWidth = options.arcWidth || 4; //width of the donut
  self.options.yPadding = options.yPadding || 2; //padding from the top
 */
var donut = grid.set(8, 8, 4, 2, contrib.donut, 
  {
  label: 'Percent Donut',
  radius: 16,
  arcWidth: 4,
  yPadding: 2,
  data: [{label: 'Storage', percent: 87}]
})

// var latencyLine = grid.set(8, 8, 4, 2, contrib.line, 
//   { style: 
//     { line: "yellow"
//     , text: "green"
//     , baseline: "black"}
//   , xLabelPadding: 3
//   , xPadding: 5
//   , label: 'Network Latency (sec)'})

var gauge = grid.set(8, 10, 2, 2, contrib.gauge, {label: 'Storage', percent: [80,20]})
var gauge_two = grid.set(2, 9, 2, 3, contrib.gauge, {label: 'Deployment Progress', percent: 80})

var sparkline = grid.set(10, 10, 2, 2, contrib.sparkline, 
  { label: 'Throughput (bits/sec)'
  , tags: true
  , style: { fg: 'blue', titleFg: 'white' }})

var bar = grid.set(4, 6, 4, 3, contrib.bar, 
  { label: 'Server Utilization (%)'
  , barWidth: 4
  , barSpacing: 6
  , xOffset: 2
  , maxHeight: 9})

var table =  grid.set(4, 9, 4, 3, contrib.table, 
  { keys: true
  , fg: 'green'
  , label: 'Active Processes'
  , columnSpacing: 1
  , columnWidth: [24, 10, 10]})

/*
 *
 * LCD Options
//these options need to be modified epending on the resulting positioning/size
  options.segmentWidth = options.segmentWidth || 0.06; // how wide are the segments in % so 50% = 0.5
  options.segmentInterval = options.segmentInterval || 0.11; // spacing between the segments in % so 50% = 0.5
  options.strokeWidth = options.strokeWidth || 0.11; // spacing between the segments in % so 50% = 0.5
//default display settings
  options.elements = options.elements || 3; // how many elements in the display. or how many characters can be displayed.
  options.display = options.display || 321; // what should be displayed before anything is set
  options.elementSpacing = options.spacing || 4; // spacing between each element
  options.elementPadding = options.padding || 2; // how far away from the edges to put the elements
//coloring
  options.color = options.color || "white";
*/
var lcdLineOne = grid.set(0,9,2,3, contrib.lcd,
  {
    label: "LCD Test",
    segmentWidth: 0.06,
    segmentInterval: 0.11,
    strokeWidth: 0.1,
    elements: 5,
    display: 3210,
    elementSpacing: 4,
    elementPadding: 2
  }
);

var errorsLine = grid.set(0, 6, 4, 3, contrib.line, 
  { style: 
    { line: "red"
    , text: "white"
    , baseline: "black"}
  , label: 'Errors Rate'
  , maxY: 60
  , showLegend: true })

var transactionsLine = grid.set(0, 0, 6, 6, contrib.line, 
          { showNthLabel: 5
          , maxY: 100
          , label: 'Total Transactions'
          , showLegend: true
          , legend: {width: 10}})

var map = grid.set(6, 0, 6, 6, contrib.map, {label: 'Servers Location'})

var log = grid.set(8, 6, 4, 2, contrib.log, 
  { fg: "green"
  , selectedFg: "green"
  , label: 'Server Log'})


//dummy data
var servers = ['US1', 'US2', 'EU1', 'AU1', 'AS1', 'JP1']
var commands = ['grep', 'node', 'java', 'timer', '~/ls -l', 'netns', 'watchdog', 'gulp', 'tar -xvf', 'awk', 'npm install']


//set dummy data on gauge
var gauge_percent = 0
setInterval(function() {
  gauge.setData([gauge_percent, 100-gauge_percent]);
  gauge_percent++;
  if (gauge_percent>=100) gauge_percent = 0  
}, 200)

var gauge_percent_two = 0
setInterval(function() {
  gauge_two.setData(gauge_percent_two);
  gauge_percent_two++;
  if (gauge_percent_two>=100) gauge_percent_two = 0  
}, 200);


//set dummy data on bar chart
function fillBar() {
  var arr = []
  for (var i=0; i<servers.length; i++) {
    arr.push(Math.round(Math.random()*10))
  }
  bar.setData({titles: servers, data: arr})
}
fillBar()
setInterval(fillBar, 2000)


//set dummy data for table
function generateTable() {
   var data = []

   for (var i=0; i<30; i++) {
     var row = []          
     row.push(commands[Math.round(Math.random()*(commands.length-1))])
     row.push(Math.round(Math.random()*5))
     row.push(Math.round(Math.random()*100))

     data.push(row)
   }

   table.setData({headers: ['Process', 'Cpu (%)', 'Memory'], data: data})
}

generateTable()
table.focus()
setInterval(generateTable, 3000)


//set log dummy data
setInterval(function() {
   var rnd = Math.round(Math.random()*2)
   if (rnd==0) log.log('starting process ' + commands[Math.round(Math.random()*(commands.length-1))])   
   else if (rnd==1) log.log('terminating server ' + servers[Math.round(Math.random()*(servers.length-1))])
   else if (rnd==2) log.log('avg. wait time ' + Math.random().toFixed(2))
   screen.render()
}, 500)


//set spark dummy data
var spark1 = [1,2,5,2,1,5,1,2,5,2,1,5,4,4,5,4,1,5,1,2,5,2,1,5,1,2,5,2,1,5,1,2,5,2,1,5]
var spark2 = [4,4,5,4,1,5,1,2,5,2,1,5,4,4,5,4,1,5,1,2,5,2,1,5,1,2,5,2,1,5,1,2,5,2,1,5]

refreshSpark()
setInterval(refreshSpark, 1000)

function refreshSpark() {
  spark1.shift()
  spark1.push(Math.random()*5+1)       
  spark2.shift()
  spark2.push(Math.random()*5+1)       
  sparkline.setData(['Server1', 'Server2'], [spark1, spark2])  
}



//set map dummy markers
var marker = true
setInterval(function() {
   if (marker) {
    map.addMarker({"lon" : "-79.0000", "lat" : "37.5000", color: 'yellow', char: 'X' })
    map.addMarker({"lon" : "-122.6819", "lat" : "45.5200" })
    map.addMarker({"lon" : "-6.2597", "lat" : "53.3478" })
    map.addMarker({"lon" : "103.8000", "lat" : "1.3000" })
   }
   else {
    map.clearMarkers()
   }
   marker =! marker
   screen.render()
}, 1000)

//set line charts dummy data

var transactionsData = {
   title: 'USA',
   style: {line: 'red'},
   x: ['00:00', '00:05', '00:10', '00:15', '00:20', '00:30', '00:40', '00:50', '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00', '02:10', '02:20', '02:30', '02:40', '02:50', '03:00', '03:10', '03:20', '03:30', '03:40', '03:50', '04:00', '04:10', '04:20', '04:30'],
   y: [0, 20, 40, 45, 45, 50, 55, 70, 65, 58, 50, 55, 60, 65, 70, 80, 70, 50, 40, 50, 60, 70, 82, 88, 89, 89, 89, 80, 72, 70]
}

var transactionsData1 = {
   title: 'Europe',
   style: {line: 'yellow'},
   x: ['00:00', '00:05', '00:10', '00:15', '00:20', '00:30', '00:40', '00:50', '01:00', '01:10', '01:20', '01:30', '01:40', '01:50', '02:00', '02:10', '02:20', '02:30', '02:40', '02:50', '03:00', '03:10', '03:20', '03:30', '03:40', '03:50', '04:00', '04:10', '04:20', '04:30'],
   y: [0, 5, 5, 10, 10, 15, 20, 30, 25, 30, 30, 20, 20, 30, 30, 20, 15, 15, 19, 25, 30, 25, 25, 20, 25, 30, 35, 35, 30, 30]
}

var errorsData = {
   title: 'server 1',
   x: ['00:00', '00:05', '00:10', '00:15', '00:20', '00:25'],
   y: [30, 50, 70, 40, 50, 20]
}

var latencyData = {
   x: ['t1', 't2', 't3', 't4'],
   y: [5, 1, 7, 5]
}

setLineData([transactionsData, transactionsData1], transactionsLine)
setLineData([errorsData], errorsLine)
// setLineData([latencyData], latencyLine)

setInterval(function() {
   setLineData([transactionsData, transactionsData1], transactionsLine)
   screen.render()
}, 500)

setInterval(function() {   
    setLineData([errorsData], errorsLine)
}, 1500)

setInterval(function(){
  var colors = ['green','magenta','cyan','red','blue'];
  var text = ['A','B','C','D','E','F','G','H','I','J','K','L'];

  var value = Math.round(Math.random() * 100);
  lcdLineOne.setDisplay(value + text[value%12]);
  lcdLineOne.setOptions({
    color: colors[value%5],
    elementPadding: 4
  });
  screen.render()
}, 1500);

var pct = 0.00;

function updateDonut(){
  if (pct > 0.99) pct = 0.00;
  var color = "green";
  if (pct >= 0.25) color = "cyan";
  if (pct >= 0.5) color = "yellow";
  if (pct >= 0.75) color = "red";  
  donut.setData([
    {percent: parseFloat((pct+0.00) % 1).toFixed(2), label: 'storage', 'color': color}
  ]);
  pct += 0.01;
}

setInterval(function() {   
   updateDonut();
   screen.render()
}, 500)

function setLineData(mockData, line) {
  for (var i=0; i<mockData.length; i++) {
    var last = mockData[i].y[mockData[i].y.length-1]
    mockData[i].y.shift()
    var num = Math.max(last + Math.round(Math.random()*10) - 5, 10)    
    mockData[i].y.push(num)  
  }
  
  line.setData(mockData)
}


screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

// fixes https://github.com/yaronn/blessed-contrib/issues/10
screen.on('resize', function() {
  donut.emit('attach');
  gauge.emit('attach');
  gauge_two.emit('attach');
  sparkline.emit('attach');
  bar.emit('attach');
  table.emit('attach');
  lcdLineOne.emit('attach');
  errorsLine.emit('attach');
  transactionsLine.emit('attach');
  map.emit('attach');
  log.emit('attach');
});

screen.render()


================================================
FILE: examples/donut.js
================================================
var blessed = require('blessed')
  , contrib = require('../index')
  , screen = blessed.screen();

/**
 * Donut Options
  self.options.stroke = options.stroke || "magenta"
  self.options.radius = options.radius || 14;
  self.options.arcWidth = options.arcWidth || 4;
  self.options.spacing = options.spacing || 2;
  self.options.yPadding = options.yPadding || 2;
 */

var donut = contrib.donut({
  	label: 'Test',
  	radius: 8,
  	arcWidth: 3,
  	yPadding: 2,
    data: [
      {percent: 80, label: 'web1', color: 'green'}
    ]
  });
    
screen.append(donut)

setInterval(updateDonuts, 5);

var pct = 0.00;

function updateDonuts(){
	if (pct > 0.99) pct = 0.00;
	donut.update([
		{percent: parseFloat((pct+0.00) % 1).toFixed(2), label: 'rcp','color':[100,200,170]},
		{percent: parseFloat((pct+0.25) % 1).toFixed(2), label: 'rcp','color':[128,128,128]},
		{percent: parseFloat((pct+0.50) % 1).toFixed(2), label: 'rcp','color':[255,0,0]},
		{percentAltNumber: 42, percent: parseFloat((pct+0.75) % 1).toFixed(2), label: 'web1', 'color': [255,128,0]}
	]);
	screen.render();
	pct += 0.01;
}

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
	return process.exit(0);
});


================================================
FILE: examples/explorer.js
================================================
var blessed = require('blessed')
  , contrib = require('../index')
  , fs = require('fs')
  , path = require('path')

var screen = blessed.screen()

//create layout and widgets
var grid = new contrib.grid({rows: 1, cols: 2, screen: screen})

var tree =  grid.set(0, 0, 1, 1, contrib.tree, 
  { style: { text: "red" }
  , template: { lines: true }
  , label: 'Filesystem Tree'})

var table =  grid.set(0, 1, 1, 1, contrib.table, 
  { keys: true
  , fg: 'green'
  , label: 'Informations'
  , columnWidth: [24, 10, 10]})

//file explorer
var explorer = { name: '/'
  , extended: true
  // Custom function used to recursively determine the node path
  , getPath: function(self){
      // If we don't have any parent, we are at tree root, so return the base case
      if(! self.parent)
        return '';
      // Get the parent node path and add this node name
      return self.parent.getPath(self.parent)+'/'+self.name;
    }
  // Child generation function
  , children: function(self){
      var result = {};
      var selfPath = self.getPath(self);
      try {
        // List files in this directory
        var children = fs.readdirSync(selfPath+'/');

        // childrenContent is a property filled with self.children() result
        // on tree generation (tree.setData() call)
        if (!self.childrenContent) {
          for(var child in children){
            child = children[child];
            var completePath = selfPath+'/'+child;
            if( fs.lstatSync(completePath).isDirectory() ){
              // If it's a directory we generate the child with the children generation function
              result[child] = { name: child, getPath: self.getPath, extended: false, children: self.children };
            }else{
              // Otherwise children is not set (you can also set it to "{}" or "null" if you want)
              result[child] = { name: child, getPath: self.getPath, extended: false };
            }
          }
        }else{
          result = self.childrenContent;
        }
      } catch (e){}
      return result;
    }
}

//set tree
tree.setData(explorer);

// Handling select event. Every custom property that was added to node is 
// available like the "node.getPath" defined above
tree.on('select',function(node){
  var path = node.getPath(node);
  var data = [];

  // The filesystem root return an empty string as a base case
  if ( path == '')
    path = '/';
  
  // Add data to right array
  data.push([path]);
  data.push(['']);
  try {
    // Add results
    data = data.concat(JSON.stringify(fs.lstatSync(path),null,2).split("\n").map(function(e){return [e]}));
    table.setData({headers: ['Info'], data: data});
  }catch(e){
    table.setData({headers: ['Info'], data: [[e.toString()]]});
  }
  
  screen.render();
});

//set default table
table.setData({headers: ['Info'], data: [[]]})

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.key(['tab'], function(ch, key) {
  if(screen.focused == tree.rows)
    table.focus();
  else
    tree.focus();
});

tree.focus()
screen.render()


================================================
FILE: examples/gauge-list.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
  , grid = new contrib.grid({rows: 2, cols: 2, hideBorder: true, screen: screen})
  , gaugeList = grid.set(0, 0, 1, 2, contrib.gaugeList,
      {
        gaugeSpacing: 0,
        gaugeHeight: 1,
        gauges:
          [ {showLabel: false, stack: [{percent: 30, stroke: 'green'}, {percent: 30, stroke: 'magenta'}, {percent: 40, stroke: 'cyan'}] }
          , {showLabel: false, stack: [{percent: 40, stroke: 'yellow'}, {percent: 20, stroke: 'magenta'}, {percent: 40, stroke: 'green'}] }
          , {showLabel: false, stack: [{percent: 50, stroke: 'red'}, {percent: 10, stroke: 'magenta'}, {percent: 40, stroke: 'cyan'}] } ]
      }
    )

screen.render()



screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});



================================================
FILE: examples/gauge-stack.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
  , grid = new contrib.grid({rows: 2, cols: 2, hideBorder: true, screen: screen})
  , gauge1 = grid.set(0, 0, 1, 1, contrib.gauge, {showLabel: false, stack: [{percent: 30, stroke: 'green'}, {percent: 30, stroke: 'magenta'}, {percent: 40, stroke: 'cyan'}] })

screen.render()


================================================
FILE: examples/gauge.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
  , gauge = contrib.gauge({label: 'Progress'})
    
screen.append(gauge)

gauge.setPercent(25)

screen.render()

================================================
FILE: examples/grid-no-border.js
================================================

var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
  , grid = new contrib.grid({rows: 12, cols: 12, hideBorder: true, screen: screen})
  , map = grid.set(0, 0, 4, 4, contrib.map, {})
  , box = grid.set(4, 4, 4, 4, blessed.box, {content: 'My Box'})

screen.render()


================================================
FILE: examples/grid.js
================================================

var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
  , grid = new contrib.grid({rows: 12, cols: 12, screen: screen})
  , map = grid.set(0, 0, 4, 4, contrib.map, {label: 'World Map'})
  , box = grid.set(4, 4, 4, 4, blessed.box, {content: 'My Box'})

screen.render()


================================================
FILE: examples/inline-data/bar.js
================================================
var blessed = require('blessed')
  , contrib = require('../../')
  , screen = blessed.screen()
  , bar = contrib.bar(
       { label: 'Server Utilization (%)'
       , barWidth: 4
       , barSpacing: 6
       , xOffset: 0
       , maxHeight: 9
       , height: "40%"
       , data: { titles: ['bar1', 'bar2']
               , data: [5, 10]}
               })

screen.append(bar)

screen.render()

================================================
FILE: examples/inline-data/donut.js
================================================
var blessed = require('blessed')
  , contrib = require('../../')
  , screen = blessed.screen()
  , donut = contrib.donut(
       {
        data: [ { color: 'red', percent: '50', label: 'a'}
              , { color: 'blue', percent: '20', label: 'b'}
              , { color: 'yellow', percent: '80', label: 'c'}
              ]
       })

screen.append(donut)

screen.render()

================================================
FILE: examples/inline-data/gauge.js
================================================
var blessed = require('blessed')
  , contrib = require('../../')
  , screen = blessed.screen()
  , gauge = contrib.gauge({label: 'Progress', percent: 25})
    
screen.append(gauge)
screen.render()

================================================
FILE: examples/inline-data/lcd.js
================================================
var blessed = require('blessed')
  , contrib = require('../../')
  , screen = blessed.screen()
  , grid = new contrib.grid({rows: 12, cols: 12, screen: screen})
  , map = grid.set(0, 0, 4, 4, contrib.map, {label: 'World Map'})
  , lcd = grid.set(4,4,4,4, contrib.lcd,
    {
      label: "LCD Test",
      segmentWidth: 0.06,
      segmentInterval: 0.11,
      strokeWidth: 0.1,
      elements: 5,
      display: 3210,
      elementSpacing: 4,
      elementPadding: 2
    })


screen.render()
  


================================================
FILE: examples/inline-data/map.js
================================================
var blessed = require('blessed')
  , contrib = require('../../')
  , screen = blessed.screen()
  , map = contrib.map({
      label: 'World Map',
      markers: 
         [ {"lon" : "-79.0000", "lat" : "37.5000", color: "red", char: "X" }
         , {"lon" : "79.0000", "lat" : "37.5000", color: "blue", char: "O" }
         ]
   })
    
screen.append(map)

screen.render()

================================================
FILE: examples/inline-data/markdown.js
================================================

var blessed = require('blessed')
  , contrib = require('../../')
  , screen = blessed.screen()
  , chalk = require('chalk')
  , markdown = contrib.markdown({markdown: '# Hello \n blessed-contrib renders markdown using `marked-terminal` '
                                , style: { firstHeading: 'chalk.green.italic' }})

screen.append(markdown)

screen.render()


================================================
FILE: examples/inline-data/multi-line-chart.js
================================================
var blessed = require('blessed')
, contrib = require('../../index')
, screen = blessed.screen()
, line = contrib.line(
   { width: 80
   , height: 30
   , left: 15
   , top: 12  
   , xPadding: 5
   , label: 'Title'
   , showLegend: true
   , legend: {width: 12}
   , data: [ { title: 'us-east',
             x: ['t1', 't2', 't3', 't4'],
             y: [5, 1, 7, 5],
             style: {
              line: 'red'
             }
           }
         , { title: 'us-west',
             x: ['t1', 't2', 't3', 't4'],
             y: [2, 4, 9, 8],
             style: {line: 'yellow'}
           }
          , {title: 'eu-north-with-some-long-string', 
             x: ['t1', 't2', 't3', 't4'],
             y: [22, 7, 12, 1],
             style: {line: 'blue'}
           }]

   })

screen.append(line)

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.render()

================================================
FILE: examples/inline-data/picture.js
================================================
var blessed = require('blessed')
  , contrib = require('../../')
  , screen = blessed.screen()

var pic = contrib.picture(
   { base64: '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'
   , cols: 95
   , onReady: ready
   })

function ready() { screen.render() }

screen.append(pic)





================================================
FILE: examples/inline-data/sparkline.js
================================================

var blessed = require('blessed')
  , contrib = require('../../')
  , screen = blessed.screen()

var spark = contrib.sparkline(
     { label: 'Sparkline'
     , tags: true
     , border: {type: "line", fg: "cyan"} 
     , width: '50%'
     , height: '50%'
     , style: { fg: 'blue' }
     , data: { titles: [ 'Sparkline1', 'Sparkline2'], 
               data: [ [10, 20, 30, 20, 50, 70, 60, 30, 35, 38]
                     , [40, 10, 40, 50, 20, 30, 20, 20, 19, 40] ]
             }
      })

screen.append(spark)

screen.render()



================================================
FILE: examples/inline-data/table.js
================================================
var blessed = require('blessed')
  , contrib = require('../../')
  , screen = blessed.screen()

var table = contrib.table(
   { keys: true
   , fg: 'white'
   , interactive: false
   , label: 'Active Processes'
   , width: '30%'
   , height: '30%'
   , border: {type: "line", fg: "cyan"}
   , columnSpacing: 10
   , columnWidth: [16, 12]
   , data: { headers: ['col1', 'col2']
           , data: [ [1, 2] 
                   , [3, 4]
                   , [5, 6] ]}
    })

screen.append(table)

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.render()

================================================
FILE: examples/lcd.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen();
  
/*
//these options need to be modified epending on the resulting positioning/size
  options.segmentWidth = options.segmentWidth || 0.06; // how wide are the segments in % so 50% = 0.5
  options.segmentInterval = options.segmentInterval || 0.11; // spacing between the segments in % so 50% = 0.5
  options.strokeWidth = options.strokeWidth || 0.11; // spacing between the segments in % so 50% = 0.5

//default display settings
  options.elements = options.elements || 3; // how many elements in the display. or how many characters can be displayed.
  options.display = options.display || 321; // what should be displayed before anything is set
  options.elementSpacing = options.spacing || 4; // spacing between each element
  options.elementPadding = options.padding || 2; // how far away from the edges to put the elements

//coloring
  options.color = options.color || "white";
*/


var lcd = contrib.lcd({
	label: 'Test',
	elements: 4
});

screen.append(lcd);

setInterval(function(){
	var colors = ['green','magenta','cyan','red','blue'];
	var text = ['A','B','C','D','E','F','G','H','I','J','K','L'];

	var value = Math.round(Math.random() * 1000);
	lcd.setDisplay(value + text[value%12]);
	lcd.setOptions({
		color: colors[value%5],
		elementPadding: 5
	});
	screen.render();
}, 1000);

screen.key(['g'], function(ch, key) {
	lcd.increaseWidth();
	screen.render();
});
screen.key(['h'], function(ch, key) {
	lcd.decreaseWidth();
	screen.render();
});
screen.key(['t'], function(ch, key) {
	lcd.increaseInterval();
	screen.render();
});
screen.key(['y'], function(ch, key) {
	lcd.decreaseInterval();
	screen.render();
});
screen.key(['b'], function(ch, key) {
	lcd.increaseStroke();
	screen.render();
});
screen.key(['n'], function(ch, key) {
	lcd.decreaseStroke();
	screen.render();
});

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
	return process.exit(0);
});

screen.render()

================================================
FILE: examples/line-abbreviate.js
================================================
var blessed = require('blessed')
, contrib = require('../index')
, screen = blessed.screen()
, line = contrib.line(
   { width: 80
   , height: 30
   , left: 15
   , top: 12
   , xPadding: 5
   , label: 'Title'
   , abbreviate: true
   , style: { baseline: 'white' }
   })

, data = [ { title: 'us-east',
             x: ['t1', 't2', 't3', 't4'],
             y: [5, 8800, 99999, 3179000000],
             style: {
              line: 'red'
             }
           }
        ]


screen.append(line) //must append before setting data
line.setData(data)

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.render()


================================================
FILE: examples/line-fraction.js
================================================
var blessed = require('blessed')
, contrib = require('../index')
, screen = blessed.screen()
, line = contrib.line(
   { width: 80
   , height: 30
   , left: 15
   , top: 12
   , xPadding: 5
   , label: 'Title'
   , numYLabels: 7
   //, wholeNumbersOnly: true
   })

, data = [ { title: 'us-east',
             x: ['t1', 't2', 't3', 't4'],
             y: [0, 0.0695652173913043, 0.11304347826087, 2],
             style: {
              line: 'red'
             }
           }
        ]


screen.append(line) //must append before setting data
line.setData(data)

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.render()


================================================
FILE: examples/line-random-colors.js
================================================
var blessed = require('blessed')
, contrib = require('../index')

function randomColor() {
  return [Math.random() * 255,Math.random()*255, Math.random()*255]
}

var screen = blessed.screen()
, line = contrib.line(
   { width: 80
   , height: 30
   , left: 15
   , top: 12
   , xPadding: 5
   , minY: 30
   , maxY: 90
   , label: 'Title'
   , style: { line: randomColor(), text: randomColor(), baseline: randomColor() }
   })

, data = [ { title: 'us-east',
             x: ['t1', 't2', 't3', 't4'],
             y: [50, 88, 72, 91],
             style: {
              line: 'red'
             }
           }
        ]

screen.append(line) //must append before setting data
line.setData(data)

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.render()


================================================
FILE: examples/line-start-above-zero.js
================================================
var blessed = require('blessed')
, contrib = require('../index')
, screen = blessed.screen()
, line = contrib.line(
   { width: 80
   , height: 30
   , left: 15
   , top: 12
   , xPadding: 5
   , minY: 30
   , label: 'Title'
   , style: { baseline: 'white' }
   })

, data = [ { title: 'us-east',
             x: ['t1', 't2', 't3', 't4'],
             y: [50, 88, 72, 91],
             style: {
              line: 'red'
             }
           }
        ]


screen.append(line) //must append before setting data
line.setData(data)

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.render()


================================================
FILE: examples/line-zoomed-in.js
================================================
var blessed = require('blessed')
, contrib = require('../index')
, screen = blessed.screen()
, line = contrib.line(
   { width: 80
   , height: 30
   , left: 15
   , top: 12
   , xPadding: 5
   , minY: 1000
   , maxY: 1050
   , label: 'Title'
   , style: { baseline: 'white' }
   })

, data = [ { title: 'us-east',
             x: ['t1', 't2', 't3', 't4'],
             y: [1010, 1040, 1020, 1030],
             style: {
              line: 'red'
             }
           }
        ]


screen.append(line) //must append before setting data
line.setData(data)

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.render()


================================================
FILE: examples/log.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
  , log = contrib.log(
      { fg: "green"
      , label: 'Server Log'      
      , height: "20%"
      , tags: true      
      , border: {type: "line", fg: "cyan"} })
    
screen.append(log)

var i = 0
setInterval(function() {log.log("new {red-fg}log{/red-fg} line " + i++)}, 500)

screen.render()


================================================
FILE: examples/map.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
  , map = contrib.map({label: 'World Map'})
    
screen.append(map)

map.addMarker({"lon" : "-79.0000", "lat" : "37.5000", color: "red", char: "X" })

screen.render()

================================================
FILE: examples/markdown.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
  , chalk = require('chalk')
  , markdown = contrib.markdown()
    
screen.append(markdown)
markdown.setOptions({ firstHeading: chalk.red.italic })
markdown.setMarkdown('# Hello \n This is **markdown** printed in the `terminal` 11')
screen.render()

================================================
FILE: examples/marked-terminal.js
================================================
const blessed = require("blessed")
const contrib = require("../")

const screen = blessed.screen()
const markdown = contrib.markdown()
screen.append(markdown)
markdown.setMarkdown("- [x] Checkbox")
screen.render()


================================================
FILE: examples/multi-line-chart.js
================================================
var blessed = require('blessed')
, contrib = require('../index')
, screen = blessed.screen()
, line = contrib.line(
   { width: 80
   , height: 30
   , left: 15
   , top: 12  
   , xPadding: 5
   , label: 'Title'
   , showLegend: true
   , legend: {width: 12}})
, data = [ { title: 'us-east',
             x: ['t1', 't2', 't3', 't4'],
             y: [5, 1, 7, 5],
             style: {
              line: 'red'
             }
           }
         , { title: 'us-west',
             x: ['t1', 't2', 't3', 't4'],
             y: [2, 4, 9, 8],
             style: {line: 'yellow'}
           }
          , {title: 'eu-north-with-some-long-string', 
             x: ['t1', 't2', 't3', 't4'],
             y: [22, 7, 12, 1],
             style: {line: 'blue'}
           }]

screen.append(line) //must append before setting data
line.setData(data)

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.render()

================================================
FILE: examples/picture.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
    
var pic = contrib.picture(
   { file: './media/flower.png'
   , cols: 95
   , onReady: ready})
function ready() { screen.render() }

screen.append(pic)



================================================
FILE: examples/sparkline.js
================================================

var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()

var spark = contrib.sparkline(
     { label: 'Sparkline'
     , tags: true
     , border: {type: "line", fg: "cyan"} 
     , width: '50%'
     , height: '50%'
     , style: { fg: 'blue' }})

screen.append(spark)

spark.setData(
   [ 'Sparkline1', 'Sparkline2'], 
   [ [10, 20, 30, 20, 50, 70, 60, 30, 35, 38]
   , [40, 10, 40, 50, 20, 30, 20, 20, 19, 40]])

screen.render()



================================================
FILE: examples/stacked-bar.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
  , bar = contrib.stackedBar(
       { label: 'Server Utilization (%)'
       , barWidth: 4
       , barSpacing: 6
       , xOffset: 0
       //, maxValue: 15
       , height: "40%"
       , width: "50%"
       , barBgColor: [ 'red', 'blue', 'green' ]})

screen.append(bar)

bar.setData(
       { barCategory: ['Q1', 'Q2', 'Q3', 'Q4']
       , stackedCategory: ['US', 'EU', 'AP']
       , data:
          [ [ 7, 7, 5]
          , [8, 2, 0]
          , [0, 0, 0]
          , [2, 3, 2] ]
       })

screen.render()


================================================
FILE: examples/table-color.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()
  , colors = require('colors/safe');

var table = contrib.table(
   { keys: true
   , fg: 'white'
   , selectedFg: 'white'
   , selectedBg: 'blue'
   , interactive: false
   , label: 'Active Processes'
   , width: '80%'
   , height: '30%'
   , border: {type: "line", fg: "cyan"}
   , columnSpacing: 10
   , columnWidth: [7, 12, 15]})

table.focus()
screen.append(table)

table.setData(
 { headers: ['col1', 'col2', 'col3']
 , data:
  [ [colors.blue('1111'), '22222', '55555']
  , ['33333', '44444', '66666'] ]})

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.render()


================================================
FILE: examples/table.js
================================================
var blessed = require('blessed')
  , contrib = require('../')
  , screen = blessed.screen()

var table = contrib.table(
   { keys: true
   , vi: true
   , fg: 'white'
   , selectedFg: 'white'
   , selectedBg: 'blue'
   , interactive: true
   , label: 'Active Processes'
   , width: '30%'
   , height: '30%'
   , border: {type: "line", fg: "cyan"}
   , columnSpacing: 10
   , columnWidth: [16, 12]})

table.focus()
screen.append(table)

table.setData(
 { headers: ['col1', 'col2']
 , data:
  [ [1, 2]
  , [3, 4]
  , [5, 6]
  , [7, 8] ]})

screen.key(['escape', 'q', 'C-c'], function(ch, key) {
  return process.exit(0);
});

screen.render()


================================================
FILE: index.d.ts
================================================
import * as Blessed from 'blessed'
export = BlessedContrib
declare namespace BlessedContrib {

    export type Optionals<T, K extends keyof T> = {
        [P in keyof K]?: T[K]
        }
    export type Picker<T, K extends keyof T> = {
        [P in K]: T[P];
        };


    export module Widgets {
        import IHasOptions = Blessed.Widgets.IHasOptions;
        import BoxOptions = Blessed.Widgets.BoxOptions;
        import ListOptions = Blessed.Widgets.ListOptions;
        import Types = Blessed.Widgets.Types;
        import ListElementStyle = Blessed.Widgets.ListElementStyle;
        import BoxElement = Blessed.Widgets.BoxElement;
        import ListElement = Blessed.Widgets.ListElement;

        export interface GridOptions {

            top?: Types.TTopLeft;
            left?: Types.TTopLeft;
            right?: Types.TPosition;
            bottom?: Types.TPosition;
            rows?: number
            cols?: number
            screen: Blessed.Widgets.Screen
            border?: Blessed.Widgets.Border
            hideBorder?: boolean
        }

        export type WidgetOptions =
            BoxOptions
            | BarOptions
            | StackedBarOptions
            | CanvasOptions
            | TreeOptions
            | TableOptions
            | PictureOptions
            | MarkdownOptions
            | MapOptions
            | SparklineOptions
            | LogOptions
            | LcdOptions
            | GaugeOptions
            | GaugeListOptions
            | DonutOptions


        export type WidgetElements = BoxElement
            | BarElement
            | LineElement
            | StackedBarElement
            | CanvasElement
            | TreeElement
            | TableElement
            | PictureElement
            | MarkdownElement
            | MapElement
            | SparklineElement
            | LogElement
            | LcdElement
            | GaugeElement
            | GaugeListElement
            | DonutElement


        export class GridElement extends BoxElement implements IHasOptions<GridOptions> {
            constructor(opts: GridOptions);

            set<T extends (options?: TreeOptions) => S, S extends TreeElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: TreeOptions): TreeElement
            set<T extends (options?: TableOptions) => S, S extends TableElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: TableOptions): TableElement
            set<T extends (options?: PictureOptions) => S, S extends PictureElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: PictureOptions): PictureElement
            set<T extends (options?: MarkdownOptions) => S, S extends MarkdownElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: MarkdownOptions): MarkdownElement
            set<T extends (options?: MapOptions) => S, S extends MapElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: MapOptions): MapElement
            set<T extends (options?: LogOptions) => S, S extends LogElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: LogOptions): LogElement
            set<T extends (options?: LcdOptions) => S, S extends LcdElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: LcdOptions): LcdElement
            set<T extends (options?: GaugeOptions) => S, S extends GaugeElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: GaugeOptions): GaugeElement
            set<T extends (options?: GaugeListOptions) => S, S extends GaugeListElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: GaugeListOptions): GaugeListElement
            set<T extends (options?: DonutOptions) => S, S extends DonutElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: DonutOptions): DonutElement

            set<T extends (options?: BarOptions) => S, S extends BarElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: BarOptions): BarElement
            set<T extends (options?: LineOptions) => S, S extends LineElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: LineOptions): LineElement
            set<T extends (options?: StackedBarOptions) => S, S extends StackedBarElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: StackedBarOptions): StackedBarElement
            set<T extends (options?: CanvasOptions) => S, S extends CanvasElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: CanvasOptions): CanvasElement


            // set<T extends (options?: WidgetOptions) => S, S extends WidgetElements>(row: number, col: number, rowSpan: number, colSpan: number, obj: T, opt: WidgetOptions): WidgetElements
            set<T, S>(...args:any[]): any

            // set<K extends keyof Factories>(row: number, col: number, rowSpan: number, colSpan: number,
            //     obj: T, opts?: P<T> ): P<T>
            // set<A =BarOptions, T=BarElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof bar
            // set<A =Line, T=LineElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof line
            // set<A =StackedBar, T=StackedBarElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof stackedBar
            // set<A =Canvas, T=CanvasElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof canvas
            // set<A =Tree, T=TreeElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof tree
            // set<A =Table, T=TableElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof table
            // set<A =Picture, T=PictureElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof picture
            // set<A =Markdown, T=MarkdownElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof markdown
            // set<A =Map, T=MapElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof map
            // set<A =Log, T=LogElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof log
            // set<A =Lcd, T=LcdElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof lcd
            // set<A =Gauge, T=GaugeElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof gauge
            // set<A =GaugeList, T=GaugeListElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof gaugeList
            // set<A =Donut, T=DonutElement>(row: number, col: number, rowSpan: number, colSpan: number, obj: A, opts?: O): T //typeof donut

            options: GridOptions;
        }


        export interface BarData {
            titles?: string[],
            data?: number[]
        }

        export interface BarOptions extends CanvasOptions<BarData> {
            barWidth?: number
            barSpacing?: number
            xOffset?: number
            maxHeight?: number
            showText?: boolean
            barBgColor?: string
            barFgColor?: string
        }


        export class BarElement extends CanvasElement<BarData> implements IHasOptions<BarOptions> {
            constructor(opts: BarOptions);

            setData(data: BarData): void;

            options: BarOptions;
        }


        export interface LineData {
            title?: string
            x?: string[]
            y?: number[]
            style?: {
                line?: string
                text?: string
                baseline?: string
            }
        }

        export interface LineOptions extends CanvasOptions<LineData[]> {
            showNthLabel?: boolean
            style?: {
                line?: string
                text?: string
                baseline?: string
            }
            xLabelPadding?: number
            xPadding?: number
            numYLabels?: number
            legend?: { width: number }
            wholeNumbersOnly?: boolean
            minY?: number
            maxY?: number
            label?: string
        }

        export class LineElement extends CanvasElement<LineData[]> implements IHasOptions<LineOptions> {
            constructor(opts: LineOptions);

            options: LineOptions;
        }

        export interface StackedBarData {
            barCategory?: string[]
            stackedCategory?: string[]
            data?: Array<number[]>
        }

        export interface StackedBarOptions extends CanvasOptions<StackedBarData[]> {

            barWidth?: number
            barSpacing?: number
            xOffset?: number
            maxValue?: number
            barBgColor?: string
            showLegend?: boolean
            legend?: any
            showText?: boolean
        }

        export class StackedBarElement extends CanvasElement<StackedBarData[]> implements IHasOptions<StackedBarOptions> {
            constructor(opts: StackedBarOptions)

            options: StackedBarOptions;

            addLegend(bars: any, x: number): void;
        }


        export interface CanvasOptions<D extends any=any>  extends BoxOptions {
            canvasSize?: {
                width?: number,
                height?: number
            }
            data?: D
        }

        export class CanvasElement<D extends any=any> extends BoxElement implements IHasOptions<CanvasOptions> {
            constructor(opts: CanvasOptions<D>)

            options: CanvasOptions<D>;

            calcSize(): void;

            setData(data: D): void;
            setData(titles: string[], data: D): void;

            canvasSize: { width: number, height: number }
        }

        export interface DonutData {
            percent?: string,
            label?: string,
            color?: string
        }

        export interface DonutOptions extends CanvasOptions<DonutData[]> {
            stroke?: string
            fill?: string
            label?: string
            radius?: number
            arcWidth?: number
            spacing?: number
            remainColor?: string
            yPadding?: number


        }

        export class DonutElement extends CanvasElement<DonutData[]> implements IHasOptions<DonutOptions> {
            constructor(opts: DonutOptions)

            options: DonutOptions;

        }


        export interface GaugeListOptions extends CanvasOptions {
        }

        export class GaugeListElement extends CanvasElement implements IHasOptions<GaugeListOptions> {
            constructor(opts: GaugeListOptions)

            options: GaugeListOptions;
        }


        export interface GaugeOptions extends CanvasOptions {
            percent: number[]
            stroke?: string
            fill?: string
            label?: string
            stack?: any
            showLabel?: boolean
        }

        export class GaugeElement extends CanvasElement implements IHasOptions<GaugeOptions> {
            constructor(opts: GaugeOptions)

            options: GaugeOptions;

            setPercent(number: number): void;

            setStack(stack: Array<{ percent: number, stroke: string }>): void;

            setData(percent: number[]): void;
            setData(percent: number): void;
        }


        export interface LcdOptions extends CanvasOptions {
            segmentWidth?: number// how wide are the segments in % so 50% = 0.5
            segmentInterval?: number// spacing between the segments in % so 50% = 0.550% = 0.5
            strokeWidth?: number// spacing between the segments in % so 50% = 0.5
            elements?: number// how many elements in the display. or how many characters can be displayed.
            display?: number// what should be displayed before first call to setDisplay
            elementSpacing?: number// spacing between each element
            elementPadding?: number// how far away from the edges to put the elements
            color?: 'white' // color for the segments
            label?: 'Storage Remaining'
        }

        export class LcdElement extends CanvasElement implements IHasOptions<LcdOptions> {
            constructor(opts: LcdOptions)

            options: LcdOptions;

            increaseWidth(): void;

            decreaseWidth(): void;

            increaseInterval(): void;

            decreaseInterval(): void;

            increaseStroke(): void;

            decreaseStroke(): void;

            setOptions(options: any): void;

            setDisplay(display: any): void;
        }

        export interface LogOptions extends ListOptions<ListElementStyle> {
            border: Blessed.Widgets.Border
            bufferLength?: number
            logLines?: string[]
            interactive?: boolean
        }

        export class LogElement extends ListElement implements IHasOptions<LogOptions> {
            constructor(opts: LogOptions);

            options: LogOptions;

            log(str: string): boolean;

            emit(str:any): boolean;
        }


        export interface MapOptions extends CanvasOptions {
        }

        export class MapElement extends CanvasElement implements IHasOptions<MapOptions> {
            constructor(opts: MapOptions)

            options: MapOptions;
        }


        export interface SparklineOptions extends CanvasOptions<string[]> {
        }

        export class SparklineElement extends CanvasElement<string[]> implements IHasOptions<SparklineOptions> {
            constructor(opts: CanvasOptions);

            options: SparklineOptions;

            setData(...str: any[]): void;
        }

        export interface MarkdownOptions extends CanvasOptions {
          /** 
           * Markdown text to render.
           */
          markdown?: string;

          markdownStyle?: any;
        }

        export class MarkdownElement extends CanvasElement implements IHasOptions<MarkdownOptions> {
            constructor(opts: MarkdownOptions)

            options: MarkdownOptions;

            setOptions(options: any): void;

            setMarkdown(markdown: string): void;
        }


        export interface PictureOptions extends CanvasOptions {
        }

        export class PictureElement extends CanvasElement implements IHasOptions<PictureOptions> {
            constructor(opts: PictureOptions)

            options: PictureOptions;
        }

        export interface TableData {
            headers?: string[]
            data?: Array<string[]>
        }

        export interface TableOptions extends CanvasOptions<TableData> {
            parent?: any
            bold?: string
            columnSpacing?: number
            columnWidth?: number[]
            rows?: ListOptions<ListElementStyle>
            selectedFg?: string
            selectedBg?: string
            label?: string
            fg?: string
            bg?: string
            width?: string
            height?: string
            border?: object
            interactive?: string
        }

        export class TableElement extends CanvasElement<TableData> implements IHasOptions<TableOptions> {
            constructor(opts: TableOptions);

            options: TableOptions;
        }


        export interface TreeNode {
            name?: string,
            children?: TreeChildren | ((node: TreeNode) => TreeChildren | Promise<TreeChildren>),
            childrenContent?: TreeChildren,
            extended?: boolean,
            parent?: TreeNode,
            [custom: string]: any
        }

        export type TreeChildren = Record<string, TreeNode>

        export interface TreeOptions extends BoxOptions {
            data?: any
            extended?: boolean
            keys?: string[]
            template?: {
                extend?: string
                retract?: string
                lines?: boolean
            }
        }

        export class TreeElement extends BoxElement implements IHasOptions<TreeOptions> {
            constructor(opts: TreeOptions)

            rows: Blessed.Widgets.ListElement
            nodeLines?: string[]
            lineNbr?: number
            data: any

            options: TreeOptions;

            setData(data: TreeNode): void
        }


    }

    export module widget {

        export class Grid extends Widgets.GridElement {}

        export class Bar extends Widgets.BarElement {}

        export class Line extends Widgets.LineElement {}

        export class StackedBar extends Widgets.StackedBarElement {}

        export class Canvas extends Widgets.CanvasElement {}

        export class Tree extends Widgets.TreeElement {}

        export class Table extends Widgets.TableElement {}

        export class Picture extends Widgets.PictureElement {}

        export class Markdown extends Widgets.MarkdownElement {}

        export class Map extends Widgets.MapElement {}

        export class Log extends Widgets.LogElement {}

        export class Lcd extends Widgets.LcdElement {}

        export class Gauge extends Widgets.GaugeElement {}

        export class GaugeList extends Widgets.GaugeListElement {}

        export class Donut extends Widgets.DonutElement {}

        export class Sparkline extends Widgets.SparklineElement {}

    }


    export class grid extends Widgets.GridElement {}

    export function line(options?: Widgets.LineOptions): Widgets.LineElement

    export function bar(options?: Widgets.BarOptions): Widgets.BarElement

    export function stackedBar(options?: Widgets.StackedBarOptions): Widgets.StackedBarElement

    export function canvas(options?: Widgets.CanvasOptions): Widgets.CanvasElement

    export function tree(options?: Widgets.TreeOptions): Widgets.TreeElement

    export function table(options?: Widgets.TableOptions): Widgets.TableElement

    export function picture(options?: Widgets.PictureOptions): Widgets.PictureElement

    export function markdown(options?: Widgets.MarkdownOptions): Widgets.MarkdownElement

    export function sparkline(options?: Widgets.SparklineOptions): Widgets.SparklineElement

    export function map(options?: Widgets.MapOptions): Widgets.MapElement

    export function log(options?: Widgets.LogOptions): Widgets.LogElement

    export function lcd(options?: Widgets.LcdOptions): Widgets.LcdElement

    export function gauge(options?: Widgets.GaugeOptions): Widgets.GaugeElement

    export function gaugeList(options?: Widgets.GaugeListOptions): Widgets.GaugeListElement

    export function donut(options?: Widgets.DonutOptions): Widgets.DonutElement

}



================================================
FILE: index.js
================================================

exports.grid = require('./lib/layout/grid')
exports.carousel = require('./lib/layout/carousel')

exports.map = require('./lib/widget/map')
exports.canvas = require('./lib/widget/canvas')

exports.gauge = require('./lib/widget/gauge.js')
exports.gaugeList = require('./lib/widget/gauge-list.js')

exports.lcd = require('./lib/widget/lcd.js')
exports.donut = require('./lib/widget/donut.js')
exports.log = require('./lib/widget/log.js')
exports.picture = require('./lib/widget/picture.js')
exports.sparkline = require('./lib/widget/sparkline.js')
exports.table = require('./lib/widget/table.js')
exports.tree = require('./lib/widget/tree.js')
exports.markdown = require('./lib/widget/markdown.js')

exports.bar = require('./lib/widget/charts/bar')
exports.stackedBar = require('./lib/widget/charts/stacked-bar')
exports.line = require('./lib/widget/charts/line')

exports.OutputBuffer = require('./lib/server-utils').OutputBuffer
exports.InputBuffer = require('./lib/server-utils').InputBuffer
exports.createScreen = require('./lib/server-utils').createScreen
exports.serverError = require('./lib/server-utils').serverError


================================================
FILE: lib/layout/carousel.js
================================================
'use strict';
function Carousel(pages, options) {
  this.currPage = 0;
  this.pages = pages;
  this.options = options;
  this.screen = this.options.screen;
}

Carousel.prototype.move = function() {
  var i = this.screen.children.length;
  while (i--) this.screen.children[i].detach();

  this.pages[this.currPage](this.screen, this.currPage);
  this.screen.render();
};

Carousel.prototype.next = function() {
  this.currPage++;
  if (this.currPage==this.pages.length){
    if (!this.options.rotate) {
      this.currPage--;
      return;
    } else {
      this.currPage=0;
    }
  }
  this.move();
};

Carousel.prototype.prev = function() {
  this.currPage--;
  if (this.currPage<0) {
    if (!this.options.rotate) {
      this.currPage++;
      return;
    } else {
      this.currPage=this.pages.length-1;
    }
  }
  this.move();
};

Carousel.prototype.home = function() {
  this.currPage = 0;
  this.move();
};

Carousel.prototype.end = function() {
  this.currPage = this.pages.length -1;
  this.move();
};

Carousel.prototype.start = function() {
  var self = this;

  this.move();

  if (this.options.interval) {
    setInterval(this.next.bind(this), this.options.interval);
  }

  if (this.options.controlKeys) {
    this.screen.key(['right', 'left', 'home', 'end'], function(ch, key) {
      if (key.name=='right') self.next();
      if (key.name=='left') self.prev();
      if (key.name=='home') self.home();
      if (key.name=='end') self.end();
    });
  }

};

module.exports = Carousel;


================================================
FILE: lib/layout/grid.js
================================================
'use strict';
var utils = require('../utils');

var widgetSpacing = 0;

function Grid(options) {
  if (!options.screen) throw 'Error: A screen property must be specified in the grid options.\r\n' +
                              'Note: Release 2.0.0 has breaking changes. Please refer to the README or to https://github.com/yaronn/blessed-contrib/issues/39';
  this.options = options;
  this.options.dashboardMargin = this.options.dashboardMargin || 0;
  this.cellWidth = ((100 - this.options.dashboardMargin*2) / this.options.cols);
  this.cellHeight = ((100  - this.options.dashboardMargin*2) / this.options.rows);
}

Grid.prototype.set = function(row, col, rowSpan, colSpan, obj, opts) {

  if (obj instanceof Grid) {
    throw 'Error: A Grid is not allowed to be nested inside another grid.\r\n' +
            'Note: Release 2.0.0 has breaking changes. Please refer to the README or to https://github.com/yaronn/blessed-contrib/issues/39';
  }

  var top = row * this.cellHeight + this.options.dashboardMargin;
  var left = col * this.cellWidth + this.options.dashboardMargin;

  //var options = JSON.parse(JSON.stringify(opts));
  var options = {};
  options = utils.MergeRecursive(options, opts);
  options.top = top + '%';
  options.left = left + '%';
  options.width = (this.cellWidth * colSpan - widgetSpacing) + '%';
  options.height = (this.cellHeight * rowSpan - widgetSpacing) + '%';
  if (!this.options.hideBorder)
    options.border = {type: 'line', fg: this.options.color || 'cyan'};

  var instance = obj(options);
  this.options.screen.append(instance);
  return instance;
};

module.exports = Grid;


================================================
FILE: lib/server-utils.js
================================================
'use strict';
var url = require('url')
  , contrib = require('../index')
  , blessed = require('blessed');

function OutputBuffer(options) {
  this.isTTY = true;
  this.columns = options.cols;
  this.rows = options.rows;
  this.write = function(s) {
    s = s.replace('\x1b8', ''); //not clear from where in blessed this code comes from. It forces the terminal to clear and loose existing content.
    options.res.write(s);
  };

  this.on = function() {};
}

function InputBuffer() {
  this.isTTY = true;
  this.isRaw = true;

  this.emit = function() {};

  this.setRawMode = function() {};
  this.resume = function() {};
  this.pause = function() {};

  this.on = function() {};
}

function serverError(req, res, err) {
  setTimeout(function() {
    if (!res.headersSent) res.writeHead(500, {'Content-Type': 'text/plain'});
    res.write('\r\n\r\n'+err+'\r\n\r\n');
    //restore cursor
    res.end('\u001b[?25h');
  }, 0);

  return true;
}


function createScreen(req, res) {
  var query = url.parse(req.url, true).query;

  var cols = query.cols || 250;
  var rows = query.rows || 50;

  if (cols<=35 || cols>=500 || rows<=5 || rows>=300) {
    serverError(req, res, 'cols must be bigger than 35 and rows must be bigger than 5');
    return null;
  }

  res.writeHead(200, {'Content-Type': 'text/plain'});

  var output = new contrib.OutputBuffer({res: res, cols: cols, rows: rows});
  var input = new contrib.InputBuffer(); //required to run under forever since it replaces stdin to non-tty
  var program = blessed.program({output: output, input: input});

  if (query.terminal) program.terminal = query.terminal;
  if (query.isOSX) program.isOSXTerm = query.isOSX;
  if (query.isiTerm2) program.isiTerm2 = query.isiTerm2;

  var screen = blessed.screen({program: program});
  return screen;
}


exports.createScreen = createScreen;
exports.OutputBuffer = OutputBuffer;
exports.InputBuffer = InputBuffer;
exports.serverError = serverError;


================================================
FILE: lib/utils.js
================================================
'use strict';
var x256 = require('x256');

/*
* Recursively merge properties of two objects
*/
function MergeRecursive(obj1, obj2) {
  if (obj1==null) {
    return obj2;
  }
  if (obj2==null) {
    return obj1;
  }

  for (var p in obj2) {
    try {
      // property in destination object set; update its value
      if ( obj2[p].constructor==Object ) {
        obj1[p] = MergeRecursive(obj1[p], obj2[p]);

      } else {
        obj1[p] = obj2[p];

      }

    } catch(e) {
      // property in destination object not set; create it and set its value
      obj1[p] = obj2[p];

    }
  }

  return obj1;
}


function getTypeName(thing){
  if(thing===null)return '[object Null]'; // special case
  return Object.prototype.toString.call(thing);
}

function abbreviateNumber(value) {
  var newValue = value;
  if (value >= 1000) {
    var suffixes = ['', 'k', 'm', 'b','t'];
    var suffixNum = Math.floor( (''+value).length/3 );
    var shortValue = '';
    for (var precision = 2; precision >= 1; precision--) {
      shortValue = parseFloat( (suffixNum != 0 ? (value / Math.pow(1000,suffixNum) ) : value).toPrecision(precision));
      var dotLessShortValue = (shortValue + '').replace(/[^a-zA-Z 0-9]+/g,'');
      if (dotLessShortValue.length <= 2) {
        break;
      }
    }
    newValue = shortValue+suffixes[suffixNum];
  }
  return newValue;
}

function getColorCode(color) {
  if (Array.isArray(color) && color.length == 3) {
    return x256(color[0],color[1],color[2]);
  } else {
    return color;
  }
}

exports.MergeRecursive = MergeRecursive;
exports.getTypeName = getTypeName;
exports.abbreviateNumber = abbreviateNumber;
exports.getColorCode = getColorCode;



================================================
FILE: lib/widget/canvas.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , Box = blessed.Box
  , InnerCanvas = require('drawille-canvas-blessed-contrib').Canvas;

function Canvas(options, canvasType) {

  var self = this;

  if (!(this instanceof Node)) {
    return new Canvas(options);
  }

  options = options || {};
  this.options = options;
  Box.call(this, options);

  this.on('attach', function() {
    self.calcSize();

    self._canvas = new InnerCanvas(this.canvasSize.width, this.canvasSize.height, canvasType);
    self.ctx = self._canvas.getContext();

    if (self.options.data) {
      self.setData(self.options.data);
    }
  });
}

Canvas.prototype = Object.create(Box.prototype);

Canvas.prototype.type = 'canvas';

Canvas.prototype.calcSize = function() {
  this.canvasSize = {width: this.width*2-12, height: this.height*4};
};

Canvas.prototype.clear = function() {
  this.ctx.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height);
};

Canvas.prototype.render = function() {

  this.clearPos(true);
  var inner = this.ctx._canvas.frame();
  this.setContent(inner);
  return this._render();
};

module.exports = Canvas;


================================================
FILE: lib/widget/charts/bar.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , Canvas = require('../canvas');

function Bar(options) {
  if (!(this instanceof Node)) {
    return new Bar(options);
  }

  var self = this;

  Canvas.call(this, options, require('ansi-term'));

  this.options.barWidth = this.options.barWidth || 6;
  this.options.barSpacing = this.options.barSpacing || 9;

  if ((this.options.barSpacing - this.options.barWidth) < 3) {
    this.options.barSpacing = this.options.barWidth + 3;
  }

  this.options.xOffset = this.options.xOffset==null? 5 : this.options.xOffset;
  if (this.options.showText === false)
    this.options.showText = false;
  else
    this.options.showText = true;

  this.on('attach', function() {
    if (self.options.data) {
      self.setData(self.options.data);
    }
  });
}

Bar.prototype = Object.create(Canvas.prototype);

Bar.prototype.calcSize = function() {
  this.canvasSize = {width: this.width-2, height: this.height};
};

Bar.prototype.setData = function(bar) {

  if (!this.ctx) {
    throw 'error: canvas context does not exist. setData() for bar charts must be called after the chart has been added to the screen via screen.append()';
  }

  this.clear();

  var c = this.ctx;
  var max = Math.max.apply(Math, bar.data);
  max = Math.max(max, this.options.maxHeight);
  var x = this.options.xOffset;
  var barY = this.canvasSize.height - 5;

  for (var i = 0; i < bar.data.length; i++) {
    var h = Math.round(barY * (bar.data[i] / max));

    if (bar.data[i] > 0) {
      c.strokeStyle = 'blue';
      if (this.options.barBgColor)
        c.strokeStyle = this.options.barBgColor;
      c.fillRect(x, barY - h + 1, this.options.barWidth, h);
    } else {
      c.strokeStyle = 'normal';
    }

    c.fillStyle = 'white';
    if (this.options.barFgColor)
      c.fillStyle = this.options.barFgColor;
    if (this.options.showText)
      c.fillText(bar.data[i].toString(), x + 1, this.canvasSize.height - 4);
    c.strokeStyle = 'normal';
    c.fillStyle = 'white';
    if (this.options.labelColor)
      c.fillStyle = this.options.labelColor;
    if (this.options.showText)
      c.fillText(bar.titles[i], x + 1, this.canvasSize.height - 3);

    x += this.options.barSpacing;
  }
};

Bar.prototype.getOptionsPrototype = function() {
  return  {  barWidth: 1
    ,  barSpacing: 1
    ,  xOffset: 1
    ,  maxHeight: 1
    ,  data: { titles: ['s']
      , data: [1]}
  };
};

Bar.prototype.type = 'bar';

module.exports = Bar;


================================================
FILE: lib/widget/charts/line.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , Canvas = require('../canvas')
  , utils = require('../../utils.js')
  , _ = require('lodash');

function Line(options) {
  if (!(this instanceof Node)) {
    return new Line(options);
  }

  options.showNthLabel = options.showNthLabel || 1;
  options.style = options.style || {};
  options.style.line = options.style.line || 'yellow';
  options.style.text = options.style.text || 'green';
  options.style.baseline = options.style.baseline || 'black';
  options.xLabelPadding = options.xLabelPadding || 5;
  options.xPadding = options.xPadding || 10;
  options.numYLabels = options.numYLabels || 5;
  options.legend = options.legend || {};
  options.wholeNumbersOnly = options.wholeNumbersOnly || false;
  options.minY = options.minY || 0;

  Canvas.call(this, options);
}

Line.prototype = Object.create(Canvas.prototype);

Line.prototype.calcSize = function() {
  this.canvasSize = {width: this.width*2-12, height: this.height*4-8};
};

Line.prototype.type = 'line';

Line.prototype.setData = function(data) {

  if (!this.ctx) {
    throw 'error: canvas context does not exist. setData() for line charts must be called after the chart has been added to the screen via screen.append()';
  }

  //compatability with older api
  if (!Array.isArray(data)) data = [data];

  var self = this;
  var xLabelPadding = this.options.xLabelPadding;
  var yLabelPadding = 3;
  var xPadding = this.options.xPadding;
  var yPadding = 11;
  var c = this.ctx;
  var labels = data[0].x;

  function addLegend() {
    if (!self.options.showLegend) return;
    if (self.legend) self.remove(self.legend);
    var legendWidth = self.options.legend.width || 15;
    self.legend = blessed.box({
      height: data.length+2,
      top: 1,
      width: legendWidth,
      left: self.width-legendWidth-3,
      content: '',
      fg: 'green',
      tags: true,
      border: {
        type: 'line',
        fg: 'black'
      },
      style: {
        fg: 'blue',
      },
      screen: self.screen
    });

    var legandText = '';
    var maxChars = legendWidth-2;
    for (let i=0; i<data.length; i++) {
      var style = data[i].style || {};
      var color = utils.getColorCode(style.line || self.options.style.line);
      legandText += '{'+color+'-fg}'+ data[i].title.substring(0, maxChars)+'{/'+color+'-fg}\r\n';
    }
    self.legend.setContent(legandText);
    self.append(self.legend);
  }

  //iteratee for lodash _.max
  function getMaxY() {
    if (self.options.maxY) {
      return self.options.maxY;
    }

    var max = -Infinity;

    for(let i = 0; i < data.length; i++) {
      if (data[i].y.length) {
        var current = _.max(data[i].y, parseFloat);
        if (current > max) {
          max = current;
        }
      }
    }

    return max + (max - self.options.minY) * 0.2;
  }

  function formatYLabel(value, max, min, numLabels, wholeNumbersOnly, abbreviate) {
    var fixed = (((max - min) / numLabels) < 1 && value!=0 && !wholeNumbersOnly) ? 2 : 0;
    var res = value.toFixed(fixed);
    return abbreviate?utils.abbreviateNumber(res):res;
  }

  function getMaxXLabelPadding(numLabels, wholeNumbersOnly, abbreviate, min) {
    var max = getMaxY();

    return formatYLabel(max, max, min, numLabels, wholeNumbersOnly, abbreviate).length * 2;
  }

  var maxPadding = getMaxXLabelPadding(this.options.numYLabels, this.options.wholeNumbersOnly, this.options.abbreviate, this.options.minY);
  if (xLabelPadding < maxPadding) {
    xLabelPadding = maxPadding;
  }

  if ((xPadding - xLabelPadding) < 0) {
    xPadding = xLabelPadding;
  }

  function getMaxX() {
    var maxLength = 0;

    for(var i = 0; i < labels.length; i++) {
      if(labels[i] === undefined) {
        // console.log("label[" + i + "] is undefined");
      } else if(labels[i].length > maxLength) {
        maxLength = labels[i].length;
      }
    }

    return maxLength;
  }

  function getXPixel(val) {
    return ((self.canvasSize.width - xPadding) / labels.length) * val + (xPadding * 1.0) + 2;
  }

  function getYPixel(val, minY) {
    var res = self.canvasSize.height - yPadding - (((self.canvasSize.height - yPadding) / (getMaxY()-minY)) * (val-minY));
    res-=2; //to separate the baseline and the data line to separate chars so canvas will show separate colors
    return res;
  }

  // Draw the line graph
  function drawLine(values, style, minY) {
    style = style || {};
    var color = self.options.style.line;
    c.strokeStyle = style.line || color;

    c.moveTo(0, 0);
    c.beginPath();
    c.lineTo(getXPixel(0), getYPixel(values[0], minY));

    for(var k = 1; k < values.length; k++) {
      c.lineTo(getXPixel(k), getYPixel(values[k], minY));
    }

    c.stroke();
  }

  addLegend();

  c.fillStyle = this.options.style.text;

  c.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height);


  var yLabelIncrement = (getMaxY()-this.options.minY)/this.options.numYLabels;
  if (this.options.wholeNumbersOnly) yLabelIncrement = Math.floor(yLabelIncrement);
  //if (getMaxY()>=10) {
  //  yLabelIncrement = yLabelIncrement + (10 - yLabelIncrement % 10)
  //}

  //yLabelIncrement = Math.max(yLabelIncrement, 1) // should not be zero

  if (yLabelIncrement==0) yLabelIncrement = 1;

  // Draw the Y value texts
  var maxY = getMaxY();
  for(var i = this.options.minY; i < maxY; i += yLabelIncrement) {
    c.fillText(formatYLabel(i, maxY, this.options.minY, this.options.numYLabels, this.options.wholeNumbersOnly, this.options.abbreviate), xPadding - xLabelPadding, getYPixel(i, this.options.minY));
  }

  for (var h=0; h<data.length; h++) {
    drawLine(data[h].y, data[h].style, this.options.minY);
  }


  c.strokeStyle = this.options.style.baseline;

  // Draw the axises
  c.beginPath();

  c.lineTo(xPadding, 0);
  c.lineTo(xPadding, this.canvasSize.height - yPadding);
  c.lineTo(this.canvasSize.width, this.canvasSize.height - yPadding);

  c.stroke();

  // Draw the X value texts
  var charsAvailable = (this.canvasSize.width - xPadding) / 2;
  var maxLabelsPossible = charsAvailable / (getMaxX() + 2);
  var pointsPerMaxLabel = Math.ceil(data[0].y.length / maxLabelsPossible);
  var showNthLabel = this.options.showNthLabel;
  if (showNthLabel < pointsPerMaxLabel) {
    showNthLabel = pointsPerMaxLabel;
  }

  for(let i = 0; i < labels.length; i += showNthLabel) {
    if((getXPixel(i) + (labels[i].length * 2)) <= this.canvasSize.width) {
      c.fillText(labels[i], getXPixel(i), this.canvasSize.height - yPadding + yLabelPadding);
    }
  }

};

Line.prototype.getOptionsPrototype = function() {
  return { width: 80
    , height: 30
    , left: 15
    , top: 12
    , xPadding: 5
    , label: 'Title'
    , showLegend: true
    , legend: {width: 12}
    , data: [ { title: 'us-east',
      x: ['t1', 't2', 't3', 't4'],
      y: [5, 1, 7, 5],
      style: {
        line: 'red'
      }
    }
    , { title: 'us-west',
      x: ['t1', 't2', 't3', 't4'],
      y: [2, 4, 9, 8],
      style: {line: 'yellow'}
    }
    , {title: 'eu-north-with-some-long-string',
      x: ['t1', 't2', 't3', 't4'],
      y: [22, 7, 12, 1],
      style: {line: 'blue'}
    }]

  };
};

module.exports = Line;


================================================
FILE: lib/widget/charts/stacked-bar.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , Canvas = require('../canvas')
  , utils = require('../../utils.js');

function StackedBar(options) {
  if (!(this instanceof Node)) {
    return new StackedBar(options);
  }

  var self = this;
  Canvas.call(this, options, require('ansi-term'));

  this.options.barWidth = this.options.barWidth || 6;
  this.options.barSpacing = this.options.barSpacing || 9;

  if ((this.options.barSpacing - this.options.barWidth) < 3) {
    this.options.barSpacing = this.options.barWidth + 3;
  }

  this.options.xOffset = this.options.xOffset==null? 5 : this.options.xOffset;
  if (this.options.showText === false)
    this.options.showText = false;
  else
    this.options.showText = true;

  this.options.legend = this.options.legend || {};
  if (this.options.showLegend === false)
    this.options.showLegend = false;
  else
    this.options.showLegend = true;

  this.on('attach', function() {
    if (self.options.data) {
      self.setData(self.options.data);
    }
  });
}

StackedBar.prototype = Object.create(Canvas.prototype);

StackedBar.prototype.calcSize = function() {
  this.canvasSize = {width: this.width-2, height: this.height};
};

StackedBar.prototype.getSummedBars = function(bars) {
  var res = [];
  bars.forEach(function(stackedValues) {
    var sum = stackedValues.reduce(function(a,b) {
      return a + b;
    } , 0);
    res.push(sum);
  });
  return res;
};

StackedBar.prototype.setData = function(bars) {

  if (!this.ctx) {
    throw 'error: canvas context does not exist. setData() for bar charts must be called after the chart has been added to the screen via screen.append()';
  }

  this.clear();

  var summedBars = this.getSummedBars(bars.data);
  var maxBarValue = Math.max.apply(Math, summedBars);
  if (this.options.maxValue)
    maxBarValue = Math.max(maxBarValue, this.options.maxValue);
  var x = this.options.xOffset;
  for (var i = 0; i < bars.data.length; i++) {
    this.renderBar(x, bars.data[i], summedBars[i], maxBarValue, bars.barCategory[i]);
    x += this.options.barSpacing;
  }

  this.addLegend(bars, x);
};

StackedBar.prototype.renderBar = function(x, bar, curBarSummedValue, maxBarValue, category) {
/*
  var c = this.ctx
  c.strokeStyle = 'red';
  c.fillRect(0,7,4,0)
  c.strokeStyle = 'blue';
  c.fillRect(0,4,4,1)
  c.strokeStyle = 'green';
  c.fillRect(5,7,4,2)
  return
*/
  //first line is for label
  const BUFFER_FROM_TOP = 2;
  const BUFFER_FROM_BOTTOM = (this.options.border ? 2 : 0) + (this.options.showText ? 1 : 0);

  var c = this.ctx;
  c.strokeStyle = 'normal';
  c.fillStyle = 'white';
  if (this.options.labelColor)
    c.fillStyle = this.options.labelColor;
  if (this.options.showText) {
    c.fillText(category, x + 1, this.canvasSize.height - BUFFER_FROM_BOTTOM);
  }

  if (curBarSummedValue < 0) return;
  var maxBarHeight = this.canvasSize.height - BUFFER_FROM_TOP - BUFFER_FROM_BOTTOM;
  var currentBarHeight = Math.round(maxBarHeight * (curBarSummedValue / maxBarValue));
  //start painting from bottom of bar, section by section
  var y = maxBarHeight + BUFFER_FROM_TOP;
  var availableBarHeight = currentBarHeight;
  for (var i=0; i < bar.length; i++) {
    var currStackHeight = this.renderBarSection(
      x,
      y,
      bar[i],
      curBarSummedValue,
      currentBarHeight,
      availableBarHeight,
      this.options.barBgColor[i]);
    y -= currStackHeight;
    availableBarHeight -= currStackHeight;
  }
};

StackedBar.prototype.renderBarSection = function(
  x,
  y,
  data,
  curBarSummedValue,
  currentBarHeight,
  availableBarHeight,
  bg) {
  var c = this.ctx;

  var currStackHeight = currentBarHeight <= 0?
    0 :
    Math.min(
      availableBarHeight, //round() can make total stacks excceed curr bar height so we limit it
      Math.round(currentBarHeight * (data / curBarSummedValue))
    );
  c.strokeStyle = bg;

  if (currStackHeight>0) {
    var calcY = y - currStackHeight;
    /*fillRect starts from the point bottom of start point so we compensate*/
    var calcHeight = Math.max(0, currStackHeight-1);
    c.fillRect(
      x,
      calcY,
      this.options.barWidth,
      calcHeight
    );

    c.fillStyle = 'white';
    if (this.options.barFgColor)
      c.fillStyle = this.options.barFgColor;
    if (this.options.showText) {
      var str = utils.abbreviateNumber(data.toString());
      c.fillText(
        str,
        Math.floor(x + this.options.barWidth/2 + str.length/2),
        calcY + Math.round(calcHeight/2));
    }
  }

  return currStackHeight;
};

StackedBar.prototype.getOptionsPrototype = function() {
  return  {  barWidth: 1
    ,  barSpacing: 1
    ,  xOffset: 1
    ,  maxValue: 1
    ,  barBgColor: 's'
    ,  data: { barCategory: ['s']
      , stackedCategory: ['s']
      , data: [ [ 1] ]
    }
  };
};



StackedBar.prototype.addLegend = function(bars, x) {
  var self = this;
  if (!self.options.showLegend) return;
  if (self.legend) self.remove(self.legend);
  var legendWidth = self.options.legend.width || 15;
  self.legend = blessed.box({
    height: bars.stackedCategory.length+2,
    top: 1,
    width: legendWidth,
    left: x,
    content: '',
    fg: 'green',
    tags: true,
    border: {
      type: 'line',
      fg: 'black'
    },
    style: {
      fg: 'blue',
    },
    screen: self.screen
  });

  var legandText = '';
  var maxChars = legendWidth-2;
  for (var i=0; i<bars.stackedCategory.length; i++) {
    var color = utils.getColorCode(self.options.barBgColor[i]);
    legandText += '{'+color+'-fg}'+ bars.stackedCategory[i].substring(0, maxChars)+'{/'+color+'-fg}\r\n';
  }
  self.legend.setContent(legandText);
  self.append(self.legend);
};

StackedBar.prototype.type = 'bar';

module.exports = StackedBar;


================================================
FILE: lib/widget/donut.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , Canvas = require('./canvas');

function Donut(options) {
  if (!(this instanceof Node)) {
    return new Donut(options);
  }

  options = options || {};
  this.options = options;
  this.options.stroke = options.stroke || 'magenta';
  this.options.fill = options.fill || 'white';
  this.options.radius = options.radius || 14;
  this.options.arcWidth = options.arcWidth || 4;
  this.options.spacing = options.spacing || 2;
  this.options.yPadding = options.yPadding || 2;
  this.options.remainColor = options.remainColor || 'black';
  this.options.data = options.data || [];

  Canvas.call(this, options);

  var self = this;
  this.on('attach', function() {
    this.setData(self.options.data);
  });
}

Donut.prototype = Object.create(Canvas.prototype);

Donut.prototype.calcSize = function() {
  this.canvasSize = {width: Math.round(this.width*2-5), height: this.height*4-12};
  if (this.canvasSize.width % 2 == 1)
    this.canvasSize.width--;
  if (this.canvasSize.height % 4 != 1)
    this.canvasSize.height += (this.canvasSize.height % 4);
};

Donut.prototype.type = 'donut';

var cos = Math.cos;
var sin = Math.sin;
var pi = 3.141592635;
Donut.prototype.setData = function(data){
  this.update(data);
};
Donut.prototype.update = function(data) {

  if (!this.ctx) {
    throw 'error: canvas context does not exist. setData() for line charts must be called after the chart has been added to the screen via screen.append()';
  }

  var c = this.ctx;
  c.save();
  c.translate(0,-this.options.yPadding);

  c.strokeStyle = this.options.stroke;
  c.fillStyle = this.options.fill;

  c.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height);

  var cheight = this.canvasSize.height;
  var cwidth = this.canvasSize.width;

  function makeRound(percent, radius, width, cx, cy, color){
    var s = 0;
    var points = 370;
    c.strokeStyle = color || 'green';
    while(s<radius){
      if (s < (radius - width)) {
        s++;
        continue;
      }
      var slice = 2 * pi / points;
      c.beginPath();
      var p = parseFloat(percent*360);
      for(var i = 0;i<=points;i++){
        if (i>p) continue;
        var si = i-90;
        var a = slice * si;
        c.lineTo(Math.round(cx+s*cos(a)), Math.round(cy+s*sin(a)));
      }
      c.stroke();
      c.closePath();
      s++;
    }
  }

  var donuts = data.length;
  var radius = this.options.radius;
  var width = this.options.arcWidth;
  var remainColor = this.options.remainColor;

  var middle = cheight / 2;
  var spacing = (cwidth - (donuts * radius * 2)) / (donuts + 1);

  function drawDonut(label, percent, radius, width, cxx, middle, color, percentAltNumber){
    makeRound(100, radius, width, cxx, middle, remainColor );
    makeRound(percent, radius, width, cxx, middle, color);
    var ptext = percentAltNumber ? percentAltNumber.toFixed(0) : parseFloat(percent*100).toFixed(0) + '%';
    c.fillText(ptext, cxx - Math.round(parseFloat((c.measureText(ptext).width)/2)) + 3, middle);
    c.fillText(label, cxx - Math.round(parseFloat((c.measureText(label).width)/2)) + 3, (middle + radius) + 5);
  }

  function makeDonut(stat, which){
    var left = radius + (spacing * which) + (radius * 2 * (which - 1));
    var percent = stat.percent;
    if (percent > 1.001){
      percent = parseFloat(percent / 100).toFixed(2);
    }
    var label = stat.label;
    var percentAltNumber = stat.percentAltNumber;
    var color = stat.color || 'green';
    var cxx = left;
    drawDonut(label, percent, radius, width, cxx, middle, color, percentAltNumber);
  }
  function makeDonuts(stats){
    for(var l = 0; l<=stats.length-1;l++){
      makeDonut(stats[l], l+1);
    }
  }

  if (data.length){
    makeDonuts(data);
  }

  this.currentData = data;

  c.strokeStyle = 'magenta';

  c.restore();
  return;
};

Donut.prototype.getOptionsPrototype = function() {
  return {
    spacing: 1,
    yPadding: 1,
    radius: 1,
    arcWidth: 1,
    data: [ { color: 'red', percent: '50', label: 'a'}
      , { color: 'blue', percent: '20', label: 'b'}
      , { color: 'yellow', percent: '80', label: 'c'}
    ]
  };
};

module.exports = Donut;


================================================
FILE: lib/widget/gauge-list.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , Canvas = require('./canvas');

function GaugeList(options) {
  if (!(this instanceof Node)) {
    return new GaugeList(options);
  }

  var self = this;

  options = options || {};
  self.options = options;
  self.options.stroke = options.stroke || 'magenta';
  self.options.fill = options.fill || 'white';
  self.options.data = options.data || [];
  self.options.showLabel = options.showLabel !== false;
  self.options.gaugeSpacing = options.gaugeSpacing || 0;
  self.options.gaugeHeight = options.gaugeHeight || 1;

  Canvas.call(this, options, require('ansi-term'));

  this.on('attach', function() {
    var gauges = this.gauges = self.options.gauges;
    this.setGauges(gauges);
  });

}

GaugeList.prototype = Object.create(Canvas.prototype);

GaugeList.prototype.calcSize = function() {
  this.canvasSize = {width: this.width-2, height: this.height};
};

GaugeList.prototype.type = 'gauge';

GaugeList.prototype.setData = function() {
};

GaugeList.prototype.setGauges = function(gauges) {

  if (!this.ctx) {
    throw 'error: canvas context does not exist. setData() for gauges must be called after the gauge has been added to the screen via screen.append()';
  }

  var c = this.ctx;
  c.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height);

  for (var i=0; i<gauges.length; i++) {
    this.setSingleGauge(gauges[i], i);
  }

};

GaugeList.prototype.setSingleGauge = function(gauge, offset) {

  var colors = ['green','magenta','cyan','red','blue'];
  var stack = gauge.stack;

  var c = this.ctx;
  var leftStart = 3;
  var textLeft = 5;

  c.strokeStyle='normal';
  c.fillStyle='white';
  c.fillText(offset.toString(), 0, offset*(this.options.gaugeHeight+this.options.gaugeSpacing));

  for (var i = 0; i < stack.length; i++) {
    var currentStack = stack[i];

    var percent;
    if (typeof(currentStack) == typeof({})){
      percent = currentStack.percent;
    } else {
      percent = currentStack;
    }

    c.strokeStyle = currentStack.stroke || colors[(i%colors.length)]; // use specified or choose from the array of colors
    c.fillStyle = this.options.fill;//'white'

    textLeft = 5;

    var width = percent/100*(this.canvasSize.width-5);

    c.fillRect(leftStart, offset*(this.options.gaugeHeight+this.options.gaugeSpacing), width, this.options.gaugeHeight-1);

    textLeft = (width / 2) - 1;
    // if (textLeft)
    var textX = leftStart+textLeft;

    if ((leftStart+width)<textX) {
      c.strokeStyle = 'normal';
    }
    if (gauge.showLabel) c.fillText(percent+'%', textX, 3);

    leftStart += width;
  }
};

GaugeList.prototype.getOptionsPrototype = function() {
  return {percent: 10};
};

module.exports = GaugeList;


================================================
FILE: lib/widget/gauge.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , Canvas = require('./canvas');

function Gauge(options) {
  if (!(this instanceof Node)) {
    return new Gauge(options);
  }

  var self = this;

  options = options || {};
  self.options = options;
  self.options.stroke = options.stroke || 'magenta';
  self.options.fill = options.fill || 'white';
  self.options.data = options.data || [];
  self.options.showLabel = options.showLabel !== false;

  Canvas.call(this, options, require('ansi-term'));

  this.on('attach', function() {
    if (self.options.stack) {
      var stack = this.stack = self.options.stack;
      this.setStack(stack);
    } else {
      var percent = this.percent = self.options.percent || 0;
      this.setData(percent);
    }
  });
}

Gauge.prototype = Object.create(Canvas.prototype);

Gauge.prototype.calcSize = function() {
  this.canvasSize = {width: this.width-2, height: this.height};
};

Gauge.prototype.type = 'gauge';

Gauge.prototype.setData = function(data){
  if (typeof(data) == typeof([]) && data.length > 0){
    this.setStack(data);
  } else if(typeof(data) == typeof(1)) {
    this.setPercent(data);
  }
};

Gauge.prototype.setPercent = function(percent) {

  if (!this.ctx) {
    throw 'error: canvas context does not exist. setData() for gauges must be called after the gauge has been added to the screen via screen.append()';
  }

  var c = this.ctx;

  c.strokeStyle = this.options.stroke;//'magenta'
  c.fillStyle = this.options.fill;//'white'

  c.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height);
  if (percent < 1.001){
    percent = percent * 100;
  }
  var width = percent/100*(this.canvasSize.width-3);
  c.fillRect(1, 2, width, 2);

  var textX = 7;
  if (width<textX) {
    c.strokeStyle = 'normal';
  }

  if (this.options.showLabel) c.fillText(Math.round(percent)+'%', textX, 3);
};

Gauge.prototype.setStack = function(stack) {
  var colors = ['green','magenta','cyan','red','blue'];

  if (!this.ctx) {
    throw 'error: canvas context does not exist. setData() for gauges must be called after the gauge has been added to the screen via screen.append()';
  }

  var c = this.ctx;
  var leftStart = 1;
  var textLeft = 5;
  c.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height);

  for (var i = 0; i < stack.length; i++) {
    var currentStack = stack[i];

    let percent;
    if (typeof(currentStack) == typeof({}))
      percent = currentStack.percent;
    else
      percent = currentStack;

    c.strokeStyle = currentStack.stroke || colors[(i%colors.length)]; // use specified or choose from the array of colors
    c.fillStyle = this.options.fill;//'white'

    textLeft = 5;
    if (percent < 1.001){
      percent = percent * 100;
    }
    var width = percent/100*(this.canvasSize.width-3);

    c.fillRect(leftStart, 2, width, 2);

    textLeft = (width / 2) - 1;
    // if (textLeft)
    var textX = leftStart+textLeft;

    if ((leftStart+width)<textX) {
      c.strokeStyle = 'normal';
    }
    if (this.options.showLabel) c.fillText(percent+'%', textX, 3);

    leftStart += width;
  }
};

Gauge.prototype.getOptionsPrototype = function() {
  return {percent: 10};
};


module.exports = Gauge;


================================================
FILE: lib/widget/lcd.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , Canvas = require('./canvas');

function LCD(options) {
  if (!(this instanceof Node)) {
    return new LCD(options);
  }
  var self = this;

  options = options || {};
  self.options = options;

  //these options need to be modified epending on the resulting positioning/size
  self.options.segmentWidth = options.segmentWidth || 0.06; // how wide are the segments in % so 50% = 0.5
  self.options.segmentInterval = options.segmentInterval || 0.11; // spacing between the segments in % so 50% = 0.5
  self.options.strokeWidth = options.strokeWidth || 0.11; // spacing between the segments in % so 50% = 0.5

  //default display settings
  self.options.elements = options.elements || 3; // how many elements in the display. or how many characters can be displayed.
  self.options.display = options.display || 321; // what should be displayed before anything is set
  self.options.elementSpacing = options.spacing || 4; // spacing between each element
  self.options.elementPadding = options.padding || 2; // how far away from the edges to put the elements

  //coloring
  self.options.color = options.color || 'white';

  Canvas.call(this, options);

  this.segment16 = null;

  this.on('attach', function() {
    var display = self.options.display || 1234;
    if (!this.segment16)
      this.segment16 = new SixteenSegment(this.options.elements, this.ctx, this.canvasSize.width, this.canvasSize.height, 0, 0, this.options);

    this.setDisplay(display);
  });
}

LCD.prototype = Object.create(Canvas.prototype);

LCD.prototype.calcSize = function() {
  this.canvasSize = {width: this.width*2-8, height: (this.height*4)-12};
};

LCD.prototype.type = 'lcd';
LCD.prototype.increaseWidth = function(){
  if (this.segment16){
    this.segment16.SegmentWidth+=0.01;
  }
};
LCD.prototype.decreaseWidth = function(){
  if (this.segment16){
    this.segment16.SegmentWidth-=0.01;
  }
};
LCD.prototype.increaseInterval = function(){
  if (this.segment16){
    this.segment16.SegmentInterval+=0.01;
  }
};
LCD.prototype.decreaseInterval = function(){
  if (this.segment16){
    this.segment16.SegmentInterval-=0.01;
  }
};
LCD.prototype.increaseStroke = function(){
  if (this.segment16){
    this.segment16.StrokeWidth+=0.05;
  }
};
LCD.prototype.decreaseStroke = function(){
  if (this.segment16){
    this.segment16.StrokeWidth-=0.05;
  }
};
LCD.prototype.setOptions = function(options){
  if (this.segment16){
    this.segment16.setOptions(options);
  }
};

LCD.prototype.setData = function(data){
  this.setDisplay(data.toString());
};

LCD.prototype.getOptionsPrototype = function() {
  return {
    label: 'LCD Test',
    segmentWidth: 0.06,
    segmentInterval: 0.11,
    strokeWidth: 0.1,
    elements: 5,
    display: 3210,
    elementSpacing: 4,
    elementPadding: 2
  };
};

LCD.prototype.setDisplay = function(display) {

  if (!this.ctx) {
    throw 'error: canvas context does not exist. setData() for line charts must be called after the chart has been added to the screen via screen.append()';
  }

  this.ctx.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height);

  this.segment16.DisplayText(display);
};

function ElementArray(count) {
  this.SetCount = SetCount;
  this.SetText = SetText;
  this.SetElementValue = SetElementValue;
  this.NullMask = 0x10;
  this.Elements = [];
  this.SetCount(count || 0);

  function SetCount(count) {
    var c = parseInt(count, 10);
    if (isNaN(c)) {
      throw 'Invalid element count: ' + count;
    }
    this.Elements = [c];
    for (var i = 0; i < c; i++) {
      this.Elements[i] = 0;
    }
  }

  function SetText(value, charMaps) {
    // Get the string of the value passed in
    if (value === null) {
      value = '';
    }
    value = value.toString();

    // Clear the elements
    for (var i = 0; i < this.Elements.length; i++) {
      this.SetElementValue(i, 0);
    }
    if (value.length === 0) {
      return;
    }
    // Set the bitmask to dispay the proper character for each element
    for (var e = 0; e < this.Elements.length && e < value.length; e++){
      var c = value[e];
      var mask = charMaps[c];
      // Use blank of there is no bitmask for this character
      if (mask === null || mask === undefined) {
        mask = this.NullMask;
      }
      this.SetElementValue(e, mask);
    }
  }
  function SetElementValue(i, value) {
    if (i >= 0 && i < this.Elements.length){
      this.Elements[i] = parseInt(value, 10);
    }
  }
}

//thx to https://github.com/Enderer/sixteensegment!!!
//although it needed HEAVY rework since it was already somewhat busted ;-(
function SixteenSegment(count, canvas, width, height, x, y, options){
  this.ElementArray = new ElementArray(count);

  this.SegmentWidth = options.segmentWidth;//(this.ElementWidth * 0.0015) * 5 //0.1;           // Width of segments (% of Element Width)
  this.SegmentInterval = options.segmentInterval;//(this.ElementWidth * 0.0015) * 10 // 0.20;        // Spacing between segments (% of Element Width)
  this.BevelWidth = 0.01;             // Size of corner bevel (% of Element Width)
  this.SideBevelEnabled = true;      // Should the sides be beveled
  this.StrokeLight = options.color;       // Color of an on segment outline

  this.StrokeWidth = options.strokeWidth;               // Width of segment outline
  this.Padding = options.elementPadding;                   // Padding around the display
  this.Spacing = options.elementSpacing;                   // Spacing between elements

  this.ElementWidth = (width - (this.Spacing*count))/count;
  this.ElementHeight = height - (this.Padding*2);

  // console.error("w %s h %s", this.ElementWidth, this.ElementHeight);

  this.FillLight = 'red';           // Color of an on segment
  this.FillDark = 'cyan';             // Color of an off segment
  this.StrokeDark = 'black';          // Color of an off segment outline

  this.X = 0;
  this.Y = 0;

  this.ElementCount = count;

  this.CalcElementDimensions = CalcElementDimensions;
  this.FlipVertical = FlipVertical;
  this.FlipHorizontal = FlipHorizontal;
  this.CalcPoints = CalcPoints;
  this.DisplayText = DisplayText;
  this.Draw = Draw;
  this.setOptions = setOptions;

  this.Width = width || canvas.width;
  this.Height = height || canvas.height;

  this.Canvas = canvas;
  this.CalcPoints();
  this.ElementArray.SetCount(count);

  function setOptions(options){
    if (options.elements)
      this.ElementArray.SetCount(options.elements);

    this.SegmentWidth = options.segmentWidth || this.SegmentWidth;
    this.SegmentInterval = options.segmentInterval || this.SegmentInterval;
    this.BevelWidth = 0.01;
    this.SideBevelEnabled = true;
    this.StrokeLight = options.color || this.StrokeLight;

    this.StrokeWidth = options.strokeWidth || this.StrokeWidth;
    this.Padding = options.elementPadding || this.Padding;
    this.Spacing = options.elementSpacing || this.Spacing;

    this.ElementWidth = (width - (this.Spacing*count))/count;
    this.ElementHeight = height - (this.Padding*2);
  }

  function DisplayText(value) {
    // Recalculate points in case any settings changed
    // console.error("si: %s, sw: %s", this.SegmentInterval, this.SegmentWidth);
    // console.error("st: %s", this.StrokeWidth);
    // Set the display patterns and draw the canvas
    this.ElementArray.SetText(value, CharacterMasks);
    this.CalcPoints();
    this.Draw(this.Canvas, this.ElementArray.Elements);
  }

  function CalcElementDimensions() {
    var n = this.ElementCount;
    var h = this.ElementHeight;
    h -= this.Padding * 2;

    var w = this.Width;
    w -= this.Spacing * (n - 1);
    w -= this.Padding * 2;
    w /= n;
    var output = { Width: w, Height: h };
    // console.error(output);
    return output;
  }

  function FlipVertical(points, height) {
    var flipped = [];
    for(var i=0;i<points.length;i++) {
      flipped[i] = {};
      flipped[i].x = points[i].x;
      flipped[i].y = height - points[i].y;
    }
    return flipped;
  }

  function FlipHorizontal(points, width) {
    var flipped = [];
    for(var i=0;i<points.length;i++) {
      flipped[i] = {};
      flipped[i].x = width - points[i].x;
      flipped[i].y = points[i].y;
    }
    return flipped;
  }

  function Draw(context, elements) {
    // Get the context and clear the area
    context.clearRect(this.X, this.Y, this.Width, this.Height);
    context.save();

    // Calculate the width and spacing of each element
    var elementWidth = this.CalcElementDimensions().Width;
    // console.error("width: %s", elementWidth);
    // Offset to adjust for starting point and padding
    context.translate(this.X, this.Y);
    context.translate(this.Padding, this.Padding);

    // Draw each segment of each element
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      for (var s = 0; s < this.Points.length; s++) {
        // Pick the on or off color based on the bitmask
        var color = (element & 1 << s) ? this.FillLight : this.FillDark;
        var stroke = (element & 1 << s) ? this.StrokeLight : this.StrokeDark;
        if (stroke == this.StrokeDark) continue;
        // console.error("c: %s, s: %s", color, stroke);
        context.lineWidth = this.StrokeWidth;
        context.strokeStyle = stroke;
        context.fillStyle = color;
        context.moveTo(0,0);
        context.beginPath();
        context.moveTo(this.Points[s][0].x, this.Points[s][0].y);
        // Create the segment path
        var maxX = 0;
        for(var p = 1; p < this.Points[s].length; p++) {
          if (this.Points[s][p].x > maxX)
            maxX = this.Points[s][p].x;
          context.lineTo(Math.round(this.Points[s][p].x), Math.round(this.Points[s][p].y));
        }
        context.closePath();
        context.fill();
        context.stroke();
        if (this.StrokeWidth > 0) {
          context.stroke();
        }
      }
      context.translate(elementWidth+this.Spacing, 0);
    }
    context.restore();
  }

  function CalcPoints() {
    var w = this.ElementWidth,
      h = this.ElementHeight,
      sw = this.SegmentWidth * w,
      si = this.SegmentInterval * w,
      bw = this.BevelWidth * sw,
      ib = (this.SideBevelEnabled) ? 1 : 0,
      sf = sw * 0.8,
      slope = h / w,
      sqrt2 = Math.SQRT2,
      sqrt3 = Math.sqrt(3);

    // Base position of points w/out bevel and interval
    var w0 = w / 2 - sw / 2,        h0 = 0,
      w1 = w / 2,                 h1 = sw / 2,
      w2 = w / 2 + sw / 2,        h2 = sw,
      w3 = w - sw,                h3 = h / 2 - sw / 2,
      w4 = w - sw / 2,            h4 = h / 2,
      w5 = w,                     h5 = h / 2 + sw / 2;

    // Order of segments stored in Points[][]
    var A1 = 0, A2 = 1, B = 2,  C = 3,  D1 = 4, D2 = 5, E = 6,  F = 7,
      G1 = 8, G2 = 9, H = 10, I = 11, J = 12, K = 13, L = 14, M = 15;

    // Create the points array for all segments
    var points = [];
    points[A1] = [
      { x: bw * 2 + si / sqrt2,           y: h0        },
      { x: w1 - si / 2 - sw / 2 * ib,     y: h0        },
      { x: w1 - si / 2,                   y: h1        },
      { x: w0 - si / 2,                   y: h2        },
      { x: sw + si / sqrt2,               y: h2        },
      { x: bw + si / sqrt2,               y: h0 + bw   }
    ];
    points[G2] = [
      { x: w2 + si / sqrt2,               y: h3        },
      { x: w3 - si / 2 * sqrt3,           y: h3        },
      { x: w4 - si / 2 * sqrt3,           y: h4        },
      { x: w3 - si / 2 * sqrt3,           y: h5        },
      { x: w2 + si / sqrt2,               y: h5        },
      { x: w1 + si / sqrt2,               y: h4        }
    ];
    points[B] = [
      { x: w5,           y: h0 + bw * 2 + si / sqrt2   },
      { x: w5,           y: h4 - si / 2 - sw / 2 * ib  },
      { x: w4,           y: h4 - si / 2                },
      { x: w3,           y: h3 - si / 2                },
      { x: w3,           y: h2 + si / sqrt2            },
      { x: w5 - bw,      y: h0 + bw + si / sqrt2       }
    ];
    points[I] = [
      { x: w2,           y: h2 + si / 2 * sqrt3        },
      { x: w2,           y: h3 - si / sqrt2            },
      { x: w1,           y: h4 - si / sqrt2            },
      { x: w0,           y: h3 - si / sqrt2            },
      { x: w0,           y: h2 + si / 2 * sqrt3        },
      { x: w1,           y: h1 + si / 2 * sqrt3        }
    ];
    points[H] = [
      { x: (sw + sf) / slope + si,        y: h2 + si              },
      { x: w0 - si,                       y: w0 * slope - sf - si },
      { x: w0 - si,                       y: h3 - si              },
      { x: (h3 - sf) / slope - si,        y: h3 - si              },
      { x: sw + si,                       y: h2 * slope + sf + si },
      { x: sw + si,                       y: h2 + si              }
    ];
    points[A2] = this.FlipHorizontal(points[A1], w);    // A2
    points[C]  = this.FlipVertical(points[2], h);       // C
    points[D1] = this.FlipVertical(points[0], h);       // D1
    points[D2] = this.FlipHorizontal(points[4], w);     // D2
    points[E]  = this.FlipHorizontal(points[3], w);     // E
    points[F]  = this.FlipHorizontal(points[2], w);     // F
    points[G1] = this.FlipHorizontal(points[9], w);     // G1
    points[J]  = this.FlipHorizontal(points[10], w);    // J
    points[K]  = this.FlipVertical(points[12], h);      // K
    points[L]  = this.FlipVertical(points[11], h);      // L
    points[M]  = this.FlipVertical(points[10], h);      // M
    this.Points = points;
  }
}
var CharacterMasks = (function() {
  // Segment Bitmasks for individual segments.
  // Binary Or them together to create bitmasks
  // a1|a2|b|c|d1|d2|e|f|g1|g2|h|i|j|k|l|m
  var a1 = 1 << 0,    a2 = 1 << 1,    b = 1 << 2,    c = 1 << 3,
    d1 = 1 << 4,    d2 = 1 << 5,    e = 1 << 6,    f = 1 << 7,
    g1 = 1 << 8,    g2 = 1 << 9,    h = 1 << 10,   i = 1 << 11,
    j  = 1 << 12,   k  = 1 << 13,   l = 1 << 14,   m = 1 << 15;
  // Character map associates characters with a bit pattern
  return {
    ' ' : 0,
    ''  : 0,
    '0' : a1|a2|b|c|d1|d2|e|f|j|m,
    '1' : b|c|j,
    '2' : a1|a2|b|d1|d2|e|g1|g2,
    '3' : a1|a2|b|c|d1|d2|g2,
    '4' : b|c|f|g1|g2,
    '5' : a1|a2|c|d1|d2|f|g1|g2,
    '6' : a1|a2|c|d1|d2|e|f|g1|g2,
    '7' : a1|a2|b|c,
    '8' : a1|a2|b|c|d1|d2|e|f|g1|g2,
    '9' : a1|a2|b|c|f|g1|g2,
    'A' : e|f|a1|a2|b|c|g1|g2,
    'B' : a1|a2|b|c|d1|d2|g2|i|l,
    'C' : a1|a2|f|e|d1|d2,
    'D' : a1|a2|b|c|d1|d2|i|l,
    'E' : a1|a2|f|e|d1|d2|g1|g2,
    'F' : a1|a2|e|f|g1 ,
    'G' : a1|a2|c|d1|d2|e|f|g2,
    'H' : b|c|e|f|g1|g2,
    'I' : a1|a2|d1|d2|i|l,
    'J' : b|c|d1|d2|e,
    'K' : e|f|g1|j|k,
    'L' : d1|d2|e|f,
    'M' : b|c|e|f|h|j,
    'N' : b|c|e|f|h|k,
    'O' : a1|a2|b|c|d1|d2|e|f,
    'P' : a1|a2|b|e|f|g1|g2,
    'Q' : a1|a2|b|c|d1|d2|e|f|k,
    'R' : a1|a2|b|e|f|g1|g2|k,
    'S' : a1|a2|c|d1|d2|f|g1|g2,
    'T' : a1|a2|i|l,
    'U' : b|c|d1|d2|e|f,
    'V' : e|f|j|m,
    'W' : b|c|e|f|k|m,
    'X' : h|j|k|m,
    'Y' : b|f|g1|g2|l,
    'Z' : a1|a2|d1|d2|j|m,
    '-' : g1|g2,
    '?' : a1|a2|b|g2|l,
    '+' : g1|g2|i|l,
    '*' : g1|g2|h|i|j|k|l|m
  };
}());

module.exports = LCD;


================================================
FILE: lib/widget/log.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , List = blessed.List;

function Log(options) {
  if (!(this instanceof Node)) {
    return new Log(options);
  }

  options = options || {};
  options.bufferLength = options.bufferLength || 30;
  this.options = options;
  List.call(this, options);

  this.logLines = [];
  this.interactive = false;
}

Log.prototype = Object.create(List.prototype);

Log.prototype.log = function(str) {
  this.logLines.push(str);
  if (this.logLines.length>this.options.bufferLength) {
    this.logLines.shift();
  }
  this.setItems(this.logLines);
  this.scrollTo(this.logLines.length);
};

Log.prototype.type = 'log';

module.exports = Log;


================================================
FILE: lib/widget/map.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , Canvas = require('./canvas')
  , InnerMap = require('map-canvas');

function Map(options) {
  var self = this;

  if (!(this instanceof Node)) {
    return new Map(options);
  }

  Canvas.call(this, options);

  this.on('attach', function() {

    options.style = options.style || {};

    var opts = { excludeAntartica: (options.excludeAntarctica === undefined) ? true : options.excludeAntarctica
      , disableBackground: (options.disableBackground === undefined) ? true : options.disableBackground
      , disableMapBackground: (options.disableMapBackground === undefined) ? true : options.disableMapBackground
      , disableGraticule: (options.disableGraticule === undefined) ? true : options.disableGraticule
      , disableFill: (options.disableFill === undefined) ? true : options.disableFill
      , width: self.ctx._canvas.width
      , height: self.ctx._canvas.height
      , shapeColor: options.style.shapeColor || 'green'};

    opts.startLon = options.startLon || undefined;
    opts.endLon = options.endLon || undefined;
    opts.startLat = options.startLat || undefined;
    opts.endLat = options.endLat || undefined;
    opts.region = options.region || undefined;
    opts.labelSpace = options.labelSpace || 5;

    this.ctx.strokeStyle= options.style.stroke || 'green';
    this.ctx.fillStyle=options.style.fill || 'green';

    self.innerMap = new InnerMap(opts, this._canvas);
    self.innerMap.draw();

    if (self.options.markers) {

      for (var m in self.options.markers) {
        self.addMarker(self.options.markers[m]);
      }
    }
  });

}

Map.prototype = Object.create(Canvas.prototype);

Map.prototype.calcSize = function() {
  this.canvasSize = {width: this.width*2-12, height: this.height*4};
};

Map.prototype.type = 'map';

Map.prototype.addMarker = function(options) {
  if (!this.innerMap) {
    throw 'error: canvas context does not exist. addMarker() for maps must be called after the map has been added to the screen via screen.append()';
  }

  this.innerMap.addMarker(options);
};

Map.prototype.getOptionsPrototype = function() {

  return { startLon: 10
    , endLon: 10
    , startLat: 10
    , endLat: 10
    , region: 'us'
    , markers:
             [  {'lon' : '-79.0000', 'lat' : '37.5000', color: 'red', char: 'X' }
               ,{'lon' : '79.0000', 'lat' : '37.5000', color: 'blue', char: 'O' }
             ]
  };
};

Map.prototype.clearMarkers = function() {
  this.innerMap.draw();
};

module.exports = Map;


================================================
FILE: lib/widget/markdown.js
================================================
'use strict';
var blessed = require('blessed')
  , Box = blessed.Box
  , marked = require('marked')
  , TerminalRenderer = require('marked-terminal')
  , chalk = require('chalk');


function Markdown(options) {
  if (!(this instanceof Box)) {
    return new Markdown(options);
  }

  options = options || {};

  const markdownOptions = {
    style: options.markdownStyle
  };

  this.evalStyles(markdownOptions);

  this.setOptions(markdownOptions.style);

  this.options = options;
  Box.call(this, options);

  if (options.markdown) this.setMarkdown(options.markdown);
}

Markdown.prototype = Object.create(Box.prototype);

Markdown.prototype.setMarkdown = function(str) {
  this.setContent(marked.parse(str));
};

Markdown.prototype.setOptions = function(style) {
  marked.setOptions({
    renderer: new TerminalRenderer(style)
  });
};

Markdown.prototype.evalStyles = function(options) {
  if (!options.style) return;
  for (var st in options.style) {
    if (typeof(options.style[st])!='string') continue;

    var tokens = options.style[st].split('.');
    options.style[st] = chalk;
    for (var j=1; j<tokens.length; j++) {
      options.style[st] = options.style[st][tokens[j]];
    }
  }
};

Markdown.prototype.getOptionsPrototype = function() {
  return {
    markdown: 'string',
    markdownStyle: 'object'
  };
};

Markdown.prototype.type = 'markdown';

module.exports = Markdown;


================================================
FILE: lib/widget/picture.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , Box = blessed.Box
  , pictureTube = require('picture-tuber')
  , fs = require('fs')
  , streams = require('memory-streams')
  , MemoryStream = require('memorystream');

function Picture(options) {
  if (!(this instanceof Node)) {
    return new Picture(options);
  }

  options = options || {};
  options.cols = options.cols || 50;
  this.options = options;

  if (options.file || options.base64) {
    this.setImage(options);
  }

  Box.call(this, options);
}

Picture.prototype = Object.create(Box.prototype);

Picture.prototype.setImage = function(options) {

  var tube = pictureTube( { cols: options.cols } );

  if (options.file) fs.createReadStream(options.file).pipe(tube);
  else if (options.base64) {
    var memStream = new MemoryStream();
    memStream.pipe(tube);
    var buf = new Buffer(options.base64, 'base64');
    memStream.write(buf);
    memStream.end();
  }

  this.writer = new streams.WritableStream();
  tube.pipe(this.writer);

  tube.on('end', function() {
    if (options.onReady) {
      options.onReady();
    }
  });

};

Picture.prototype.render = function() {
  this.setContent(this.writer.toString());
  return this._render();
};

Picture.prototype.getOptionsPrototype = function() {

  return { base64:'AAAA'
    , cols: 1 };

};

Picture.prototype.type = 'picture';

module.exports = Picture;


================================================
FILE: lib/widget/sparkline.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , Box = blessed.Box
  , sparkline = require('sparkline');

function Sparkline(options) {

  var self = this;

  if (!(this instanceof Node)) {
    return new Sparkline(options);
  }

  options = options || {};
  options.bufferLength = options.bufferLength || 30;
  options.style = options.style || {};
  options.style.titleFg = options.style.titleFg || 'white';
  this.options = options;
  Box.call(this, options);


  this.on('attach', function() {
    if (self.options.data) {
      self.setData(self.options.data.titles, self.options.data.data);
    }
  });
}

Sparkline.prototype = Object.create(Box.prototype);

Sparkline.prototype.setData = function(titles, datasets) {
  var res = '\r\n';
  for (var i=0; i<titles.length; i++) {
    res += '{bold}{'+this.options.style.titleFg+'-fg}' + titles[i]+':{/'+this.options.style.titleFg+'-fg}{/bold}\r\n';
    res += sparkline(datasets[i].slice(0, this.width-2)) + '\r\n\r\n';
  }

  this.setContent(res);
};

Sparkline.prototype.getOptionsPrototype = function() {
  return { label: 'Sparkline'
    , tags: true
    , border: {type: 'line', fg: 'cyan'}
    , width: '50%'
    , height: '50%'
    , style: { fg: 'blue' }
    , data: { titles: [ 'Sparkline1', 'Sparkline2'],
      data: [ [10, 20, 30, 20, 50, 70, 60, 30, 35, 38]
        , [40, 10, 40, 50, 20, 30, 20, 20, 19, 40] ]
    }
  };
};

Sparkline.prototype.type = 'sparkline';

module.exports = Sparkline;


================================================
FILE: lib/widget/table.js
================================================
'use strict';
var blessed = require('blessed')
  , Node = blessed.Node
  , Box = blessed.Box
  , stripAnsi = require('strip-ansi');

function Table(options) {

  var self = this;

  if (!(this instanceof Node)) {
    return new Table(options);
  }

  if (Array.isArray(options.columnSpacing)) {
    throw 'Error: columnSpacing cannot be an array.\r\n' +
           'Note: From release 2.0.0 use property columnWidth instead of columnSpacing.\r\n' +
           'Please refere to the README or to https://github.com/yaronn/blessed-contrib/issues/39';
  }

  if (!options.columnWidth) {
    throw 'Error: A table must get columnWidth as a property. Please refer to the README.';
  }

  options = options || {};
  options.columnSpacing = options.columnSpacing==null? 10 : options.columnSpacing;
  options.bold = true;
  options.selectedFg = options.selectedFg || 'white';
  options.selectedBg = options.selectedBg || 'blue';
  options.fg = options.fg || 'green';
  options.bg = options.bg || '';
  options.interactive = (typeof options.interactive === 'undefined') ? true : options.interactive;
  this.options = options;
  Box.call(this, options);

  this.rows = blessed.list({
    //height: 0,
    top: 2,
    width: 0,
    left: 1,
    style: { selected: {
      fg: options.selectedFg
      , bg: options.selectedBg
    }
    , item: {
      fg: options.fg
      , bg: options.bg
    }},
    keys: options.keys,
    vi: options.vi,
    mouse: options.mouse,
    tags: true,
    interactive: options.interactive,
    screen: this.screen
  });

  this.append(this.rows);

  this.on('attach', function() {
    if (self.options.data) {
      self.setData(self.options.data);
    }
  });

}

Table.prototype = Object.create(Box.prototype);

Table.prototype.focus = function(){
  this.rows.focus();
};

Table.prototype.render = function() {
  if(this.screen.focused == this.rows)
    this.rows.focus();

  this.rows.width = this.width-3;
  this.rows.height = this.height-4;
  Box.prototype.render.call(this);
};


Table.prototype.setData = function(table) {
  var self = this;

  var dataToString = function(d) {
    var str = '';
    d.forEach(function(r, i) {
      var colsize = self.options.columnWidth[i]
        , strip = stripAnsi(r.toString())
        , ansiLen = r.toString().length - strip.length
        , spaceLength = colsize - strip.length + self.options.columnSpacing;
      r = r.toString().substring(0, colsize + ansiLen); //compensate for ansi len
      if (spaceLength < 0) {
        spaceLength = 0;
      }
      var spaces = new Array(spaceLength).join(' ');
      str += r + spaces;
    });
    return str;
  };

  var formatted = [];

  table.data.forEach(function(d) {
    var str = dataToString(d);
    formatted.push(str);
  });
  this.setContent(dataToString(table.headers));
  this.rows.setItems(formatted);
};

Table.prototype.getOptionsPrototype = function() {
  return  { keys: true
    , fg: 'white'
    , interactive: false
    , label: 'Active Processes'
    , width: '30%'
    , height: '30%'
    , border: {type: 'line', fg: 'cyan'}
    , columnSpacing: 10
    , columnWidth: [16, 12]
    , data: { headers: ['col1', 'col2']
      , data: [ ['a', 'b']
        , ['5', 'u']
        , ['x', '16.1'] ]}
  };
};

Table.prototype.type = 'table';

module.exports = Table;


================================================
FILE: lib/widget/tree.js
================================================
'use strict';
var blessed = require('blessed'),
  Node = blessed.Node,
  Box = blessed.Box;

function Tree(options) {
  if (!(this instanceof Node)) {
    return new Tree(options);
  }

  var self = this;
  options = options || {};
  options.bold = true;
  this.options = options;
  this.data = {};
  this.nodeLines = [];
  this.lineNbr = 0;
  Box.call(this, options);

  options.extended = options.extended || false;
  options.keys = options.keys || ['+', 'space', 'enter'];

  options.template = options.template || {};
  options.template.extend = options.template.extend || ' [+]';
  options.template.retract = options.template.retract || ' [-]';
  options.template.lines = options.template.lines || false;

  // Do not set height, since this create a bug where the first line is not always displayed
  this.rows = blessed.list({
    top: 1,
    width: 0,
    left: 1,
    style: options.style,
    padding: options.padding,
    keys: true,
    tags: options.tags,
    input: options.input,
    vi: options.vi,
    ignoreKeys: options.ignoreKeys,
    scrollable: options.scrollable,
    mouse: options.mouse,
    selectedBg: options.selectedBg || 'blue',
    selectedFg: options.selectedFg || 'black',
  });

  this.append(this.rows);

  this.rows.key(options.keys, function() {
    var selectedNode = self.nodeLines[this.getItemIndex(this.selected)];
    if (selectedNode.children) {
      selectedNode.extended = !selectedNode.extended;
      self.setData(self.data);
      self.screen.render();
    }

    self.emit('select', selectedNode, this.getItemIndex(this.selected));
  });

}

Tree.prototype = Object.create(Box.prototype);

Tree.prototype.walk = function(node, treeDepth) {

  var lines = [];

  if (!node.parent) {
    // root level
    this.lineNbr = 0;
    this.nodeLines.length = 0;
    node.parent = null;
  }

  if (treeDepth === '' && node.name) {
    this.lineNbr = 0;
    this.nodeLines[this.lineNbr++] = node;
    lines.push(node.name);
    treeDepth = ' ';
  }

  node.depth = treeDepth.length - 1;

  if (node.children && node.extended) {

    var i = 0;

    if (typeof node.children === 'function')
      node.childrenContent = node.children(node);

    if (!node.childrenContent)
      node.childrenContent = node.children;

    for (var child in node.childrenContent) {

      if (!node.childrenContent[child].name)
        node.childrenContent[child].name = child;

      child = node.childrenContent[child];
      child.parent = node;
      child.position = i++;

      if (typeof child.extended === 'undefined')
        child.extended = this.options.extended;

      if (typeof child.children === 'function')
        child.childrenContent = child.children(child);
      else
        child.childrenContent = child.children;

      var isLastChild = child.position === Object.keys(child.parent.childrenContent).length - 1;
      var treePrefix;
      var suffix = '';
      if (isLastChild)
        treePrefix = '└';
      else
        treePrefix = '├';

      if (!child.childrenContent || Object.keys(child.childrenContent).length === 0) {
        treePrefix += '─';
      } else if (child.extended) {
        treePrefix += '┬';
        suffix = this.options.template.retract;
      } else {
        treePrefix += '─';
        suffix = this.options.template.extend;
      }

      if (!this.options.template.lines) treePrefix = '|-';
      if (this.options.template.spaces) treePrefix = ' ';

      lines.push(treeDepth + treePrefix + child.name + suffix);

      this.nodeLines[this.lineNbr++] = child;

      var parentTree;
      if (isLastChild || !this.options.template.lines)
        parentTree = treeDepth + ' ';
      else
        parentTree = treeDepth + '│';

      lines = lines.concat(this.walk(child, parentTree));
    }
  }
  return lines;
};

Tree.prototype.focus = function() {
  this.rows.focus();
};

Tree.prototype.render = function() {
  if (this.screen.focused === this.rows) this.rows.focus();

  this.rows.width = this.width - 3;
  this.rows.height = this.height - 3;
  Box.prototype.render.call(this);
};

Tree.prototype.setData = function(nodes) {
  this.data = nodes;
  this.rows.setItems(this.walk(nodes, ''));
};

Tree.prototype.type = 'tree';

module.exports = Tree;


================================================
FILE: package.json
================================================
{
  "name": "blessed-contrib",
  "version": "4.11.0",
  "description": "",
  "main": "index.js",
  "types": "index.d.ts",
  "scripts": {
    "test": "npm run lint",
    "lint": "eslint lib",
    "lint:fix": "eslint lib --fix"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/yaronn/blessed-contrib.git"
  },
  "author": "Yaron Naveh (yaronn01@gmail.com)",
  "license": "MIT",
  "devDependencies": {
    "@types/blessed": "^0.1.6",
    "blessed": "0.1.54",
    "colors": "^1.1.2",
    "eslint": "^5.11.0",
    "eslint-config-standard": "^12.0.0",
    "eslint-plugin-import": "^2.14.0",
    "eslint-plugin-node": "^8.0.0",
    "eslint-plugin-promise": "^4.0.1",
    "eslint-plugin-standard": "^4.0.0"
  },
  "dependencies": {
    "ansi-term": ">=0.0.2",
    "chalk": "^1.1.0",
    "drawille-canvas-blessed-contrib": ">=0.1.3",
    "lodash": "~>=4.17.21",
    "map-canvas": ">=0.1.5",
    "marked": "^4.0.12",
    "marked-terminal": "^5.1.1",
    "memory-streams": "^0.1.0",
    "memorystream": "^0.3.1",
    "picture-tuber": "^1.0.1",
    "sparkline": "^0.1.1",
    "strip-ansi": "^3.0.0",
    "term-canvas": "0.0.5",
    "x256": ">=0.0.1"
  }
}
Download .txt
gitextract_i23csocn/

├── .eslintrc.json
├── .gitignore
├── .npmignore
├── LICENSE.md
├── README.md
├── examples/
│   ├── bar.js
│   ├── carousel.js
│   ├── dashboard-random-colors.js
│   ├── dashboard.js
│   ├── donut.js
│   ├── explorer.js
│   ├── gauge-list.js
│   ├── gauge-stack.js
│   ├── gauge.js
│   ├── grid-no-border.js
│   ├── grid.js
│   ├── inline-data/
│   │   ├── bar.js
│   │   ├── donut.js
│   │   ├── gauge.js
│   │   ├── lcd.js
│   │   ├── map.js
│   │   ├── markdown.js
│   │   ├── multi-line-chart.js
│   │   ├── picture.js
│   │   ├── sparkline.js
│   │   └── table.js
│   ├── lcd.js
│   ├── line-abbreviate.js
│   ├── line-fraction.js
│   ├── line-random-colors.js
│   ├── line-start-above-zero.js
│   ├── line-zoomed-in.js
│   ├── log.js
│   ├── map.js
│   ├── markdown.js
│   ├── marked-terminal.js
│   ├── multi-line-chart.js
│   ├── picture.js
│   ├── sparkline.js
│   ├── stacked-bar.js
│   ├── table-color.js
│   └── table.js
├── index.d.ts
├── index.js
├── lib/
│   ├── layout/
│   │   ├── carousel.js
│   │   └── grid.js
│   ├── server-utils.js
│   ├── utils.js
│   └── widget/
│       ├── canvas.js
│       ├── charts/
│       │   ├── bar.js
│       │   ├── line.js
│       │   └── stacked-bar.js
│       ├── donut.js
│       ├── gauge-list.js
│       ├── gauge.js
│       ├── lcd.js
│       ├── log.js
│       ├── map.js
│       ├── markdown.js
│       ├── picture.js
│       ├── sparkline.js
│       ├── table.js
│       └── tree.js
└── package.json
Download .txt
SYMBOL INDEX (116 symbols across 27 files)

FILE: examples/carousel.js
  function page1 (line 5) | function page1(screen) {
  function page2 (line 30) | function page2(screen) {

FILE: examples/dashboard-random-colors.js
  function randomColor (line 9) | function randomColor() {
  function fillBar (line 135) | function fillBar() {
  function generateTable (line 147) | function generateTable() {
  function refreshSpark (line 184) | function refreshSpark() {
  function updateDonut (line 265) | function updateDonut(){
  function setLineData (line 282) | function setLineData(mockData, line) {

FILE: examples/dashboard.js
  function fillBar (line 130) | function fillBar() {
  function generateTable (line 142) | function generateTable() {
  function refreshSpark (line 179) | function refreshSpark() {
  function updateDonut (line 260) | function updateDonut(){
  function setLineData (line 277) | function setLineData(mockData, line) {

FILE: examples/donut.js
  function updateDonuts (line 30) | function updateDonuts(){

FILE: examples/inline-data/picture.js
  function ready (line 11) | function ready() { screen.render() }

FILE: examples/line-random-colors.js
  function randomColor (line 4) | function randomColor() {

FILE: examples/picture.js
  function ready (line 9) | function ready() { screen.render() }

FILE: index.d.ts
  type Optionals (line 5) | type Optionals<T, K extends keyof T> = {
  type Picker (line 8) | type Picker<T, K extends keyof T> = {
  type GridOptions (line 22) | interface GridOptions {
  type WidgetOptions (line 35) | type WidgetOptions =
  type WidgetElements (line 53) | type WidgetElements = BoxElement
  class GridElement (line 71) | class GridElement extends BoxElement implements IHasOptions<GridOptions> {
  type BarData (line 115) | interface BarData {
  type BarOptions (line 120) | interface BarOptions extends CanvasOptions<BarData> {
  class BarElement (line 131) | class BarElement extends CanvasElement<BarData> implements IHasOptions<B...
  type LineData (line 140) | interface LineData {
  type LineOptions (line 151) | interface LineOptions extends CanvasOptions<LineData[]> {
  class LineElement (line 168) | class LineElement extends CanvasElement<LineData[]> implements IHasOptio...
  type StackedBarData (line 174) | interface StackedBarData {
  type StackedBarOptions (line 180) | interface StackedBarOptions extends CanvasOptions<StackedBarData[]> {
  class StackedBarElement (line 192) | class StackedBarElement extends CanvasElement<StackedBarData[]> implemen...
  type CanvasOptions (line 201) | interface CanvasOptions<D extends any=any>  extends BoxOptions {
  class CanvasElement (line 209) | class CanvasElement<D extends any=any> extends BoxElement implements IHa...
  type DonutData (line 222) | interface DonutData {
  type DonutOptions (line 228) | interface DonutOptions extends CanvasOptions<DonutData[]> {
  class DonutElement (line 241) | class DonutElement extends CanvasElement<DonutData[]> implements IHasOpt...
  type GaugeListOptions (line 249) | interface GaugeListOptions extends CanvasOptions {
  class GaugeListElement (line 252) | class GaugeListElement extends CanvasElement implements IHasOptions<Gaug...
  type GaugeOptions (line 259) | interface GaugeOptions extends CanvasOptions {
  class GaugeElement (line 268) | class GaugeElement extends CanvasElement implements IHasOptions<GaugeOpt...
  type LcdOptions (line 282) | interface LcdOptions extends CanvasOptions {
  class LcdElement (line 294) | class LcdElement extends CanvasElement implements IHasOptions<LcdOptions> {
  type LogOptions (line 316) | interface LogOptions extends ListOptions<ListElementStyle> {
  class LogElement (line 323) | class LogElement extends ListElement implements IHasOptions<LogOptions> {
  type MapOptions (line 334) | interface MapOptions extends CanvasOptions {
  class MapElement (line 337) | class MapElement extends CanvasElement implements IHasOptions<MapOptions> {
  type SparklineOptions (line 344) | interface SparklineOptions extends CanvasOptions<string[]> {
  class SparklineElement (line 347) | class SparklineElement extends CanvasElement<string[]> implements IHasOp...
  type MarkdownOptions (line 355) | interface MarkdownOptions extends CanvasOptions {
  class MarkdownElement (line 364) | class MarkdownElement extends CanvasElement implements IHasOptions<Markd...
  type PictureOptions (line 375) | interface PictureOptions extends CanvasOptions {
  class PictureElement (line 378) | class PictureElement extends CanvasElement implements IHasOptions<Pictur...
  type TableData (line 384) | interface TableData {
  type TableOptions (line 389) | interface TableOptions extends CanvasOptions<TableData> {
  class TableElement (line 406) | class TableElement extends CanvasElement<TableData> implements IHasOptio...
  type TreeNode (line 413) | interface TreeNode {
  type TreeChildren (line 422) | type TreeChildren = Record<string, TreeNode>
  type TreeOptions (line 424) | interface TreeOptions extends BoxOptions {
  class TreeElement (line 435) | class TreeElement extends BoxElement implements IHasOptions<TreeOptions> {
  class Grid (line 453) | class Grid extends Widgets.GridElement {}
  class Bar (line 455) | class Bar extends Widgets.BarElement {}
  class Line (line 457) | class Line extends Widgets.LineElement {}
  class StackedBar (line 459) | class StackedBar extends Widgets.StackedBarElement {}
  class Canvas (line 461) | class Canvas extends Widgets.CanvasElement {}
  class Tree (line 463) | class Tree extends Widgets.TreeElement {}
  class Table (line 465) | class Table extends Widgets.TableElement {}
  class Picture (line 467) | class Picture extends Widgets.PictureElement {}
  class Markdown (line 469) | class Markdown extends Widgets.MarkdownElement {}
  class Map (line 471) | class Map extends Widgets.MapElement {}
  class Log (line 473) | class Log extends Widgets.LogElement {}
  class Lcd (line 475) | class Lcd extends Widgets.LcdElement {}
  class Gauge (line 477) | class Gauge extends Widgets.GaugeElement {}
  class GaugeList (line 479) | class GaugeList extends Widgets.GaugeListElement {}
  class Donut (line 481) | class Donut extends Widgets.DonutElement {}
  class Sparkline (line 483) | class Sparkline extends Widgets.SparklineElement {}
  class grid (line 488) | class grid extends Widgets.GridElement {}

FILE: lib/layout/carousel.js
  function Carousel (line 2) | function Carousel(pages, options) {

FILE: lib/layout/grid.js
  function Grid (line 6) | function Grid(options) {

FILE: lib/server-utils.js
  function OutputBuffer (line 6) | function OutputBuffer(options) {
  function InputBuffer (line 18) | function InputBuffer() {
  function serverError (line 31) | function serverError(req, res, err) {
  function createScreen (line 43) | function createScreen(req, res) {

FILE: lib/utils.js
  function MergeRecursive (line 7) | function MergeRecursive(obj1, obj2) {
  function getTypeName (line 37) | function getTypeName(thing){
  function abbreviateNumber (line 42) | function abbreviateNumber(value) {
  function getColorCode (line 60) | function getColorCode(color) {

FILE: lib/widget/canvas.js
  function Canvas (line 7) | function Canvas(options, canvasType) {

FILE: lib/widget/charts/bar.js
  function Bar (line 6) | function Bar(options) {

FILE: lib/widget/charts/line.js
  function Line (line 8) | function Line(options) {
  function addLegend (line 53) | function addLegend() {
  function getMaxY (line 87) | function getMaxY() {
  function formatYLabel (line 106) | function formatYLabel(value, max, min, numLabels, wholeNumbersOnly, abbr...
  function getMaxXLabelPadding (line 112) | function getMaxXLabelPadding(numLabels, wholeNumbersOnly, abbreviate, mi...
  function getMaxX (line 127) | function getMaxX() {
  function getXPixel (line 141) | function getXPixel(val) {
  function getYPixel (line 145) | function getYPixel(val, minY) {
  function drawLine (line 152) | function drawLine(values, style, minY) {

FILE: lib/widget/charts/stacked-bar.js
  function StackedBar (line 7) | function StackedBar(options) {

FILE: lib/widget/donut.js
  function Donut (line 6) | function Donut(options) {
  function makeRound (line 66) | function makeRound(percent, radius, width, cx, cy, color){
  function drawDonut (line 98) | function drawDonut(label, percent, radius, width, cxx, middle, color, pe...
  function makeDonut (line 106) | function makeDonut(stat, which){
  function makeDonuts (line 118) | function makeDonuts(stats){

FILE: lib/widget/gauge-list.js
  function GaugeList (line 6) | function GaugeList(options) {

FILE: lib/widget/gauge.js
  function Gauge (line 6) | function Gauge(options) {

FILE: lib/widget/lcd.js
  function LCD (line 6) | function LCD(options) {
  function ElementArray (line 113) | function ElementArray(count) {
  function SixteenSegment (line 166) | function SixteenSegment(count, canvas, width, height, x, y, options){

FILE: lib/widget/log.js
  function Log (line 6) | function Log(options) {

FILE: lib/widget/map.js
  function Map (line 7) | function Map(options) {

FILE: lib/widget/markdown.js
  function Markdown (line 9) | function Markdown(options) {

FILE: lib/widget/picture.js
  function Picture (line 10) | function Picture(options) {

FILE: lib/widget/sparkline.js
  function Sparkline (line 7) | function Sparkline(options) {

FILE: lib/widget/table.js
  function Table (line 7) | function Table(options) {

FILE: lib/widget/tree.js
  function Tree (line 6) | function Tree(options) {
Condensed preview — 64 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (197K chars).
[
  {
    "path": ".eslintrc.json",
    "chars": 480,
    "preview": "{\n  \"env\": {\n    \"es6\": true,\n    \"node\": true\n  },\n  \"extends\": \"eslint:recommended\",\n  \"parserOptions\": {\n    \"ecmaVer"
  },
  {
    "path": ".gitignore",
    "chars": 75,
    "preview": ".dccache\nnode_modules\np.js\np1.js\np2.js\nnpm-debug.log\nlog.txt\nweather.query\n"
  },
  {
    "path": ".npmignore",
    "chars": 57,
    "preview": "node_modules\np.js\np1.js\np2.js\nnpm-debug.log\ndocs\nexamples"
  },
  {
    "path": "LICENSE.md",
    "chars": 1104,
    "preview": "## MIT License\n\nCopyright (c) 2015 Yaron Naveh and blessed-contrib contributors\n\nPermission is hereby granted, free of c"
  },
  {
    "path": "README.md",
    "chars": 16569,
    "preview": "## blessed-contrib\n\nBuild dashboards (or any other application) using ascii/ansi art and javascript.\n\nFriendly to termin"
  },
  {
    "path": "examples/bar.js",
    "chars": 376,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n  , bar = contrib.bar(\n     "
  },
  {
    "path": "examples/carousel.js",
    "chars": 1671,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n\nfunction page1(screen) {  \n"
  },
  {
    "path": "examples/dashboard-random-colors.js",
    "chars": 8696,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../index')\n\nvar screen = blessed.screen()\n\n//create layout and w"
  },
  {
    "path": "examples/dashboard.js",
    "chars": 8888,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../index')\n\nvar screen = blessed.screen()\n\n//create layout and w"
  },
  {
    "path": "examples/donut.js",
    "chars": 1174,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../index')\n  , screen = blessed.screen();\n\n/**\n * Donut Options\n"
  },
  {
    "path": "examples/explorer.js",
    "chars": 3080,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../index')\n  , fs = require('fs')\n  , path = require('path')\n\nva"
  },
  {
    "path": "examples/gauge-list.js",
    "chars": 839,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n  , grid = new contrib.grid("
  },
  {
    "path": "examples/gauge-stack.js",
    "chars": 367,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n  , grid = new contrib.grid("
  },
  {
    "path": "examples/gauge.js",
    "chars": 203,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n  , gauge = contrib.gauge({l"
  },
  {
    "path": "examples/grid-no-border.js",
    "chars": 307,
    "preview": "\nvar blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n  , grid = new contrib.grid"
  },
  {
    "path": "examples/grid.js",
    "chars": 307,
    "preview": "\nvar blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n  , grid = new contrib.grid"
  },
  {
    "path": "examples/inline-data/bar.js",
    "chars": 396,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../../')\n  , screen = blessed.screen()\n  , bar = contrib.bar(\n  "
  },
  {
    "path": "examples/inline-data/donut.js",
    "chars": 376,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../../')\n  , screen = blessed.screen()\n  , donut = contrib.donut"
  },
  {
    "path": "examples/inline-data/gauge.js",
    "chars": 196,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../../')\n  , screen = blessed.screen()\n  , gauge = contrib.gauge"
  },
  {
    "path": "examples/inline-data/lcd.js",
    "chars": 495,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../../')\n  , screen = blessed.screen()\n  , grid = new contrib.gr"
  },
  {
    "path": "examples/inline-data/map.js",
    "chars": 372,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../../')\n  , screen = blessed.screen()\n  , map = contrib.map({\n "
  },
  {
    "path": "examples/inline-data/markdown.js",
    "chars": 363,
    "preview": "\nvar blessed = require('blessed')\n  , contrib = require('../../')\n  , screen = blessed.screen()\n  , chalk = require('cha"
  },
  {
    "path": "examples/inline-data/multi-line-chart.js",
    "chars": 905,
    "preview": "var blessed = require('blessed')\n, contrib = require('../../index')\n, screen = blessed.screen()\n, line = contrib.line(\n "
  },
  {
    "path": "examples/inline-data/picture.js",
    "chars": 44808,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../../')\n  , screen = blessed.screen()\n\nvar pic = contrib.pictur"
  },
  {
    "path": "examples/inline-data/sparkline.js",
    "chars": 534,
    "preview": "\nvar blessed = require('blessed')\n  , contrib = require('../../')\n  , screen = blessed.screen()\n\nvar spark = contrib.spa"
  },
  {
    "path": "examples/inline-data/table.js",
    "chars": 596,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../../')\n  , screen = blessed.screen()\n\nvar table = contrib.tabl"
  },
  {
    "path": "examples/lcd.js",
    "chars": 1990,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen();\n  \n/*\n//these options need "
  },
  {
    "path": "examples/line-abbreviate.js",
    "chars": 657,
    "preview": "var blessed = require('blessed')\n, contrib = require('../index')\n, screen = blessed.screen()\n, line = contrib.line(\n   {"
  },
  {
    "path": "examples/line-fraction.js",
    "chars": 666,
    "preview": "var blessed = require('blessed')\n, contrib = require('../index')\n, screen = blessed.screen()\n, line = contrib.line(\n   {"
  },
  {
    "path": "examples/line-random-colors.js",
    "chars": 797,
    "preview": "var blessed = require('blessed')\n, contrib = require('../index')\n\nfunction randomColor() {\n  return [Math.random() * 255"
  },
  {
    "path": "examples/line-start-above-zero.js",
    "chars": 637,
    "preview": "var blessed = require('blessed')\n, contrib = require('../index')\n, screen = blessed.screen()\n, line = contrib.line(\n   {"
  },
  {
    "path": "examples/line-zoomed-in.js",
    "chars": 663,
    "preview": "var blessed = require('blessed')\n, contrib = require('../index')\n, screen = blessed.screen()\n, line = contrib.line(\n   {"
  },
  {
    "path": "examples/log.js",
    "chars": 393,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n  , log = contrib.log(\n     "
  },
  {
    "path": "examples/map.js",
    "chars": 258,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n  , map = contrib.map({label"
  },
  {
    "path": "examples/markdown.js",
    "chars": 340,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n  , chalk = require('chalk')"
  },
  {
    "path": "examples/marked-terminal.js",
    "chars": 214,
    "preview": "const blessed = require(\"blessed\")\nconst contrib = require(\"../\")\n\nconst screen = blessed.screen()\nconst markdown = cont"
  },
  {
    "path": "examples/multi-line-chart.js",
    "chars": 948,
    "preview": "var blessed = require('blessed')\n, contrib = require('../index')\n, screen = blessed.screen()\n, line = contrib.line(\n   {"
  },
  {
    "path": "examples/picture.js",
    "chars": 250,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n    \nvar pic = contrib.pictu"
  },
  {
    "path": "examples/sparkline.js",
    "chars": 469,
    "preview": "\nvar blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n\nvar spark = contrib.sparkl"
  },
  {
    "path": "examples/stacked-bar.js",
    "chars": 605,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n  , bar = contrib.stackedBar"
  },
  {
    "path": "examples/table-color.js",
    "chars": 707,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n  , colors = require('colors"
  },
  {
    "path": "examples/table.js",
    "chars": 640,
    "preview": "var blessed = require('blessed')\n  , contrib = require('../')\n  , screen = blessed.screen()\n\nvar table = contrib.table(\n"
  },
  {
    "path": "index.d.ts",
    "chars": 18930,
    "preview": "import * as Blessed from 'blessed'\nexport = BlessedContrib\ndeclare namespace BlessedContrib {\n\n    export type Optionals"
  },
  {
    "path": "index.js",
    "chars": 1123,
    "preview": "\nexports.grid = require('./lib/layout/grid')\nexports.carousel = require('./lib/layout/carousel')\n\nexports.map = require("
  },
  {
    "path": "lib/layout/carousel.js",
    "chars": 1504,
    "preview": "'use strict';\nfunction Carousel(pages, options) {\n  this.currPage = 0;\n  this.pages = pages;\n  this.options = options;\n "
  },
  {
    "path": "lib/layout/grid.js",
    "chars": 1617,
    "preview": "'use strict';\nvar utils = require('../utils');\n\nvar widgetSpacing = 0;\n\nfunction Grid(options) {\n  if (!options.screen) "
  },
  {
    "path": "lib/server-utils.js",
    "chars": 1947,
    "preview": "'use strict';\nvar url = require('url')\n  , contrib = require('../index')\n  , blessed = require('blessed');\n\nfunction Out"
  },
  {
    "path": "lib/utils.js",
    "chars": 1678,
    "preview": "'use strict';\nvar x256 = require('x256');\n\n/*\n* Recursively merge properties of two objects\n*/\nfunction MergeRecursive(o"
  },
  {
    "path": "lib/widget/canvas.js",
    "chars": 1149,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , Box = blessed.Box\n  , InnerCanvas = require('"
  },
  {
    "path": "lib/widget/charts/bar.js",
    "chars": 2483,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , Canvas = require('../canvas');\n\nfunction Bar("
  },
  {
    "path": "lib/widget/charts/line.js",
    "chars": 7186,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , Canvas = require('../canvas')\n  , utils = req"
  },
  {
    "path": "lib/widget/charts/stacked-bar.js",
    "chars": 5750,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , Canvas = require('../canvas')\n  , utils = req"
  },
  {
    "path": "lib/widget/donut.js",
    "chars": 4183,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , Canvas = require('./canvas');\n\nfunction Donut"
  },
  {
    "path": "lib/widget/gauge-list.js",
    "chars": 2745,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , Canvas = require('./canvas');\n\nfunction Gauge"
  },
  {
    "path": "lib/widget/gauge.js",
    "chars": 3220,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , Canvas = require('./canvas');\n\nfunction Gauge"
  },
  {
    "path": "lib/widget/lcd.js",
    "chars": 15216,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , Canvas = require('./canvas');\n\nfunction LCD(o"
  },
  {
    "path": "lib/widget/log.js",
    "chars": 700,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , List = blessed.List;\n\nfunction Log(options) {"
  },
  {
    "path": "lib/widget/map.js",
    "chars": 2546,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , Canvas = require('./canvas')\n  , InnerMap = r"
  },
  {
    "path": "lib/widget/markdown.js",
    "chars": 1395,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Box = blessed.Box\n  , marked = require('marked')\n  , TerminalRenderer"
  },
  {
    "path": "lib/widget/picture.js",
    "chars": 1404,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , Box = blessed.Box\n  , pictureTube = require('"
  },
  {
    "path": "lib/widget/sparkline.js",
    "chars": 1487,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , Box = blessed.Box\n  , sparkline = require('sp"
  },
  {
    "path": "lib/widget/table.js",
    "chars": 3296,
    "preview": "'use strict';\nvar blessed = require('blessed')\n  , Node = blessed.Node\n  , Box = blessed.Box\n  , stripAnsi = require('st"
  },
  {
    "path": "lib/widget/tree.js",
    "chars": 4230,
    "preview": "'use strict';\nvar blessed = require('blessed'),\n  Node = blessed.Node,\n  Box = blessed.Box;\n\nfunction Tree(options) {\n  "
  },
  {
    "path": "package.json",
    "chars": 1168,
    "preview": "{\n  \"name\": \"blessed-contrib\",\n  \"version\": \"4.11.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"types\": \"index.d.ts\""
  }
]

About this extraction

This page contains the full source code of the yaronn/blessed-contrib GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 64 files (184.0 KB), approximately 72.2k tokens, and a symbol index with 116 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!