├── sample-trusts
├── harmj0y-testlab-contoso.csv
├── harmj0y-trusts.csv
└── harmj0y-trusts_complex.csv
├── README.md
├── index.html
├── css
├── trusts.css
└── vis.min.css
└── js
├── trusts.js
└── papaparse.min.js
/sample-trusts/harmj0y-testlab-contoso.csv:
--------------------------------------------------------------------------------
1 | "SourceName","TargetName","TrustType","TrustAttributes","TrustDirection","WhenCreated","WhenChanged"
2 | "sub.dev.testlab.local","dev.testlab.local","WINDOWS_ACTIVE_DIRECTORY","WITHIN_FOREST","Bidirectional","10/20/2017 10:07:32 AM","10/20/2017 10:07:32 AM"
3 | "dev.testlab.local","testlab.local","WINDOWS_ACTIVE_DIRECTORY","WITHIN_FOREST","Bidirectional","10/20/2017 10:07:32 AM","10/20/2017 10:07:32 AM"
4 | "dev.testlab.local","sub.dev.testlab.local","WINDOWS_ACTIVE_DIRECTORY","WITHIN_FOREST","Bidirectional","10/20/2017 10:07:32 AM","10/20/2017 10:07:32 AM"
5 | "testlab.local","dev.testlab.local","WINDOWS_ACTIVE_DIRECTORY","WITHIN_FOREST","Bidirectional","10/20/2017 10:07:32 AM","10/20/2017 10:07:32 AM"
6 | "testlab.local","contoso.local","WINDOWS_ACTIVE_DIRECTORY","FOREST_TRANSITIVE","Bidirectional","10/20/2017 10:07:32 AM","10/20/2017 10:07:32 AM"
7 | "contoso.local","prod.contoso.local","WINDOWS_ACTIVE_DIRECTORY","WITHIN_FOREST","Bidirectional","10/20/2017 10:07:32 AM","10/20/2017 10:07:32 AM"
8 | "prod.contoso.local","contoso.local","WINDOWS_ACTIVE_DIRECTORY","WITHIN_FOREST","Bidirectional","10/20/2017 10:07:32 AM","10/20/2017 10:07:32 AM"
9 | "sub.dev.testlab.local","external.local","WINDOWS_ACTIVE_DIRECTORY","TREAT_AS_EXTERNAL","Outbound","10/20/2017 10:07:32 AM","10/20/2017 10:07:32 AM"
--------------------------------------------------------------------------------
/sample-trusts/harmj0y-trusts.csv:
--------------------------------------------------------------------------------
1 | SourceDomain,TargetDomain,TrustType,TrustDirection
2 | finance.mothership.com,mothership.com,ParentChild,Bidirectional
3 | mothership.com,corp.mothership.com,ParentChild,Bidirectional
4 | mothership.com,finance.mothership.com,ParentChild,Bidirectional
5 | mothership.com,engineering.mothership.com,ParentChild,Bidirectional
6 | corp.mothership.com,mothership.com,ParentChild,Bidirectional
7 | corp.mothership.com,subsidiary.com,External,Inbound
8 | finance.mothership.com,mothership.com,ParentChild,Bidirectional
9 | engineering.mothership.com,mothership.com,ParentChild,Bidirectional
10 | subsidiary.com,product.subsidiary.com,ParentChild,Bidirectional
11 | subsidiary.com,finance.subsidiary.com,ParentChild,Bidirectional
12 | subsidiary.com,engineering.subsidiary.com,ParentChild,Bidirectional
13 | subsidiary.com,crownjewels.subsidiary.com,ParentChild,Bidirectional
14 | subsidiary.com,corp.mothership.com,External,Outbound
15 | product.subsidiary.com,subsidiary.com,ParentChild,Bidirectional
16 | product.subsidiary.com,engineering.subsidiary.com,CrossLink,Bidirectional
17 | finance.subsidiary.com,subsidiary.com,ParentChild,Bidirectional
18 | engineering.subsidiary.com,subsidiary.com,ParentChild,Bidirectional
19 | engineering.subsidiary.com,product.subsidiary.com,CrossLink,Bidirectional
20 | crownjewels.subsidiary.com,subsidiary.com,ParentChild,Bidirectional
--------------------------------------------------------------------------------
/sample-trusts/harmj0y-trusts_complex.csv:
--------------------------------------------------------------------------------
1 | SourceDomain,TargetDomain,TrustType,TrustDirection
2 | finance.mothership.com,mothership.com,ParentChild,Bidirectional
3 | mothership.com,corp.mothership.com,ParentChild,Bidirectional
4 | mothership.com,finance.mothership.com,ParentChild,Bidirectional
5 | mothership.com,contracts.mothership.com,ParentChild,Bidirectional
6 | corp.mothership.com,mothership.com,ParentChild,Bidirectional
7 | contracts.mothership.com,mothership.com,ParentChild,Bidirectional
8 | contracts.mothership.com,product.othercompany.com,External,Inbound
9 | product.othercompany.com,contracts.mothership.com,External,Outbound
10 | product.othercompany.com,othercompany.com,ParentChild,Bidirectional
11 | othercompany.com,product.othercompany.com,ParentChild,Bidirectional
12 | othercompany.com,finance.othercompany.com,ParentChild,Bidirectional
13 | othercompany.com,engineering.othercompany.com,ParentChild,Bidirectional
14 | othercompany.com,secretnet.othercompany.com,ParentChild,Bidirectional
15 | secretnet.othercompany.com,othercompany.com,ParentChild,Bidirectional
16 | secretnet.othercompany.com,engineering.othercompany.com,CrossLink,Bidirectional
17 | secretnet.othercompany.com,secretnet.company1.com,External,Inbound
18 | secretnet.othercompany.com,secretnet.company2.com,External,Inbound
19 | secretnet.othercompany.com,crownjewels.com,External,Bidirectional
20 | crownjewels.com,secretnet.othercompany.com,External,Bidirectional
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PrettyTrusts
2 | **Try it out at: http://peewpw.github.io/PrettyTrusts**
3 |
4 | Visualizes the output of [PowerView's](https://github.com/PowerShellMafia/PowerSploit/blob/dev/Recon/PowerView.ps1) `Get-DomainTrustMapping | Export-CSV -NoTypeInformation trusts.csv`. Hand it the csv file and get a pretty diagram to play with!
5 |
6 | *Should* work with older and new PowerView outputs.
7 |
8 | Everything is processed client-side, and no resources are loaded from outside of this repository. You can just clone/download the repository and open index.html in a browser to get started! Or go to http://peewpw.github.io/PrettyTrusts.
9 |
10 | You can choose to have arrows display direction of access (default) or direction of trust (how Microsoft talks about trusts).
11 |
12 | Colors and display are based off of Harmj0y's [TrustVisualizer](https://github.com/HarmJ0y/TrustVisualizer).
13 | The provided trust mapping examples are taken from various Harmj0y blogposts:
14 | [Domain Trusts: Why You Should Care](http://www.harmj0y.net/blog/redteaming/domain-trusts-why-you-should-care/)
15 | [A Guide to Attacking Domain Trusts](http://www.harmj0y.net/blog/redteaming/a-guide-to-attacking-domain-trusts/)
16 |
17 | Credit to other projects that came before:
18 | [TrustVisualizer](https://github.com/HarmJ0y/TrustVisualizer)
19 | [DomainTrustExplorer](https://github.com/sixdub/DomainTrustExplorer/)
20 | [domain-trust-grapher](https://github.com/tomsteele/domain-trust-grapher)
21 |
22 | Includes:
23 | [vis.js](https://visjs.org/)
24 | [Papa Parse](https://www.papaparse.com/)
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Pretty Trusts
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | Drop trust csv files here or click to select.
17 | All processing is client-side, nothing is uploaded.
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/css/trusts.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | font-family: Roboto, "Open Sans", sans-serif;
4 | color: #646C7F;
5 | font-size: 18px;
6 | font-weight: 300;
7 | text-rendering: optimizeLegibility;
8 | margin: 0px;
9 | }
10 |
11 | #dropzone {
12 | margin-left: auto;
13 | margin-right: auto;
14 | width: 700px;
15 | height: 250px;
16 | position: absolute;
17 | left: 50%;
18 | top: 50%;
19 | margin: -125px 0 0 -350px;
20 | }
21 |
22 | .dropzone {
23 | border: 2px dashed #0087F7;
24 | border-radius: 5px;
25 | background: white;
26 | min-height: 150px;
27 | padding: 54px 54px;
28 | }
29 |
30 | .dropzone .dz-message {
31 | font-weight: 400;
32 | text-align: center;
33 | margin: 2em 0;
34 | }
35 |
36 | .dropzone.dz-clickable {
37 | cursor: pointer;
38 | }
39 |
40 | .note {
41 | font-size: 14px;
42 | }
43 |
44 | #mynetwork {
45 | width: 100%;
46 | height: calc(100% - 47px);
47 | position: absolute;
48 | left: 0;
49 | }
50 |
51 | /* Navbar container */
52 | .navbar {
53 | overflow: hidden;
54 | background-color: #333;
55 | height: 47px;
56 | }
57 |
58 | /* Links inside the navbar */
59 | .navbar .linkbtn {
60 | font-size: 16px;
61 | padding: 14px 16px;
62 | text-decoration: none;
63 | }
64 |
65 | /* The dropdown container */
66 | .dropdown {
67 | float: left;
68 | overflow: hidden;
69 | }
70 |
71 | /* Dropdown button */
72 | .dropdown .dropbtn {
73 | font-size: 16px;
74 | border: none;
75 | outline: none;
76 | color: white;
77 | padding: 14px 16px;
78 | background-color: inherit;
79 | font-family: inherit;
80 | /* Important for vertical align on mobile phones */
81 | margin: 0;
82 | /* Important for vertical align on mobile phones */
83 | }
84 |
85 | /* Link button */
86 | .linkbtn {
87 | font-size: 16px;
88 | border: none;
89 | outline: none;
90 | padding: 14px 16px;
91 | background-color: inherit;
92 | font-family: inherit;
93 | /* Important for vertical align on mobile phones */
94 | margin: 0;
95 | /* Important for vertical align on mobile phones */
96 | cursor: pointer;
97 | }
98 |
99 | .linkleft {
100 | float: left;
101 | border-right: 1px solid #bbb;
102 | color: white;
103 | text-align: center;
104 | }
105 |
106 | .linkright {
107 | float: right;
108 | border-left: 1px solid #bbb;
109 | color: white;
110 | text-align: center;
111 | }
112 |
113 | /* Add a red background color to navbar links on hover */
114 | .dropdown:hover .dropbtn,
115 | .navbar .linkbtn:hover {
116 | background-color: blue;
117 | }
118 |
119 | /* Dropdown content (hidden by default) */
120 | .dropdown-content {
121 | display: none;
122 | position: absolute;
123 | background-color: #f9f9f9;
124 | min-width: 160px;
125 | box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
126 | z-index: 1;
127 | }
128 |
129 | /* Links inside the dropdown */
130 | .dropdown-content button {
131 | float: none;
132 | color: black;
133 | padding: 12px 16px;
134 | text-decoration: none;
135 | display: block;
136 | text-align: left;
137 | width: 100%;
138 | }
139 |
140 | /* Add a grey background color to dropdown links on hover */
141 | .dropdown-content .linkbtn:hover {
142 | background-color: #ddd;
143 | }
144 |
145 | /* Show the dropdown menu on hover */
146 | .dropdown:hover .dropdown-content {
147 | display: block;
148 | }
149 |
--------------------------------------------------------------------------------
/js/trusts.js:
--------------------------------------------------------------------------------
1 | var nodes = null;
2 | var edges = null;
3 | var network = null;
4 | var dataURL;
5 | var direction = 'access';
6 | var csvData;
7 |
8 | function ready () {
9 | let dropArea = document.getElementById('dropzone');
10 | ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
11 | dropArea.addEventListener(eventName, preventDefaults, false);
12 | });
13 |
14 | dropArea.addEventListener('drop', handleDrop, false);
15 | dropArea.addEventListener('click', selectFile, false);
16 | }
17 |
18 | function preventDefaults (e) {
19 | e.preventDefault();
20 | e.stopPropagation();
21 | }
22 |
23 | function handleFiles (files) {
24 | files = [...files];
25 | previewFile(files[0]);
26 | }
27 |
28 | function handleDrop (e) {
29 | let dt = e.dataTransfer;
30 | let files = dt.files;
31 |
32 | handleFiles(files);
33 | }
34 |
35 | function selectFile (e) {
36 | document.getElementById('fileElem').click();
37 | }
38 |
39 | function multiDimensionalUnique (arr) {
40 | var uniques = [];
41 | var itemsFound = {};
42 | for (var i = 0, l = arr.length; i < l; i++) {
43 | var stringified = JSON.stringify(arr[i]);
44 | if (itemsFound[stringified]) { continue; }
45 | uniques.push(arr[i]);
46 | itemsFound[stringified] = true;
47 | }
48 | return uniques;
49 | }
50 |
51 | function previewFile (file) {
52 | let reader = new FileReader();
53 | reader.readAsText(file, 'UTF-8');
54 | reader.onloadend = function () {
55 | var cdata = Papa.parse(reader.result).data;
56 | csvData = multiDimensionalUnique(cdata);
57 | parseCsvData(csvData);
58 | draw();
59 | };
60 | }
61 |
62 | function parseCsvData (cdata) {
63 | var sourceI = Math.max(cdata[0].indexOf('SourceDomain'), cdata[0].indexOf('SourceName'));
64 | var targetI = Math.max(cdata[0].indexOf('TargetDomain'), cdata[0].indexOf('TargetName'));
65 | var typeI = cdata[0].indexOf('TrustType');
66 | var attrI = cdata[0].indexOf('TrustAttributes');
67 | var directionI = cdata[0].indexOf('TrustDirection');
68 | if (sourceI < 0 || targetI < 0 || directionI < 0) {
69 | alert('could not find required columns in csv');
70 | }
71 |
72 | var nodesA = [];
73 | var edgesA = [];
74 | var domains = [];
75 |
76 | for (let i = 1; i < cdata.length; i++) {
77 | if (cdata[0].length !== cdata[i].length) { continue; }
78 | let source = cdata[i][sourceI];
79 | let target = cdata[i][targetI];
80 | let type = cdata[i][typeI];
81 | let direction = cdata[i][directionI];
82 | let attr = (attrI > -1) ? cdata[i][attrI] : null;
83 |
84 | if (!domains.includes(source)) {
85 | domains.push(source);
86 | nodesA.push({ id: source, label: source, shape: 'box', color: '#FFCC00' });
87 | }
88 | if (!domains.includes(target)) {
89 | domains.push(target);
90 | nodesA.push({ id: target, label: target, shape: 'box', color: '#FFCC00' });
91 | }
92 |
93 | if (!edgesA.find(e => (e.from === source && e.to === target) ||
94 | (e.from === target && e.to === source))) {
95 | let arrows = '';
96 | if (direction === 'Inbound') {
97 | arrows = 'to';
98 | } else if (direction === 'Outbound') {
99 | arrows = 'from';
100 | } else if (direction === 'Bidirectional') { arrows = 'to, from'; }
101 |
102 | let color = { color: 'violet', highlight: 'violet' };
103 | let title = 'Unknown Type';
104 | if (type === 'ParentChild') {
105 | title = 'ParentChild';
106 | color = { color: 'green', highlight: 'green' };
107 | } else if (type === 'CrossLink') {
108 | title = 'CrossLink';
109 | color = { color: 'teal', highlight: 'teal' };
110 | } else if (attr && attr.indexOf('WITHIN_FOREST') > -1) {
111 | title = 'Intra-Forest';
112 | color = { color: 'green', highlight: 'green' };
113 | } else if (type === 'External' || attr === '' || attr === 'TREAT_AS_EXTERNAL' || attr === 'FILTER_SIDS') {
114 | title = 'External';
115 | color = { color: 'red', highlight: 'red' };
116 | } else if (attr === 'FOREST_TRANSITIVE') {
117 | title = 'Inter-Forest';
118 | color = { color: 'blue', highlight: 'blue' };
119 | }
120 |
121 | edgesA.push({ from: source, to: target, title: title, arrows: arrows, length: 150, color: color, width: 2 });
122 | }
123 | }
124 |
125 | console.log(nodesA);
126 | console.log(edgesA);
127 |
128 | nodes = new vis.DataSet(nodesA);
129 | edges = new vis.DataSet(edgesA);
130 | }
131 |
132 | function destroy () {
133 | if (network !== null) {
134 | network.destroy();
135 | network = null;
136 | }
137 | }
138 |
139 | function draw () {
140 | destroy();
141 |
142 | var data = {
143 | nodes: nodes,
144 | edges: edges
145 | };
146 |
147 | document.getElementById('dropzone').style.display = 'none';
148 | document.getElementById('main').style.display = 'initial';
149 |
150 | var container = document.getElementById('mynetwork');
151 | console.log(data);
152 | console.log(container);
153 | network = new vis.Network(container, data, {});
154 |
155 | network.on('afterDrawing', function (ctx) {
156 | dataURL = ctx.canvas.toDataURL('image/png');
157 | });
158 | }
159 |
160 | function savePng (filename) {
161 | // var png = dataURL.split(',')[1];
162 | var blob = fetch(dataURL)
163 | .then(res => res.blob())
164 | .then(blob => {
165 | if (window.navigator.msSaveOrOpenBlob) {
166 | window.navigator.msSaveBlob(blob, filename);
167 | } else {
168 | var elem = window.document.createElement('a');
169 | elem.href = window.URL.createObjectURL(blob);
170 | elem.download = filename;
171 | document.body.appendChild(elem);
172 | elem.click();
173 | document.body.removeChild(elem);
174 | }
175 | });
176 | }
177 |
178 | function updateDir (dir) {
179 | if (dir === direction) return;
180 |
181 | if (dir === 'access' && direction === 'trust') {
182 | flipArrows();
183 | direction = 'access';
184 | document.getElementById('dir-of-trust').innerHTML = '☐ Direction of Trust';
185 | document.getElementById('dir-of-access').innerHTML = '☑ Direction of Access';
186 | }
187 | if (dir === 'trust' && direction === 'access') {
188 | flipArrows();
189 | direction = 'trust';
190 | document.getElementById('dir-of-trust').innerHTML = '☑ Direction of Trust';
191 | document.getElementById('dir-of-access').innerHTML = '☐ Direction of Access';
192 | }
193 | }
194 |
195 | function flipArrows () {
196 | edges.getIds().forEach(id => {
197 | let edge = edges.get(id);
198 | if (edge.arrows === 'to') {
199 | edge.arrows = 'from';
200 | } else if (edge.arrows === 'from') {
201 | edge.arrows = 'to';
202 | }
203 | edges.update(edge);
204 | });
205 | }
206 |
--------------------------------------------------------------------------------
/js/papaparse.min.js:
--------------------------------------------------------------------------------
1 | /* @license
2 | Papa Parse
3 | v5.0.0
4 | https://github.com/mholt/PapaParse
5 | License: MIT
6 | */
7 | !function(e,t){"function"==typeof define&&define.amd?define([],t):"object"==typeof module&&"undefined"!=typeof exports?module.exports=t():e.Papa=t()}(this,function s(){"use strict";var f="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==f?f:{};var n=!f.document&&!!f.postMessage,o=n&&/blob:/i.test((f.location||{}).protocol),a={},h=0,k={parse:function(e,t){var r=(t=t||{}).dynamicTyping||!1;q(r)&&(t.dynamicTypingFunction=r,r={});if(t.dynamicTyping=r,t.transform=!!q(t.transform)&&t.transform,t.worker&&k.WORKERS_SUPPORTED){var i=function(){if(!k.WORKERS_SUPPORTED)return!1;var e=(r=f.URL||f.webkitURL||null,i=s.toString(),k.BLOB_URL||(k.BLOB_URL=r.createObjectURL(new Blob(["(",i,")();"],{type:"text/javascript"})))),t=new f.Worker(e);var r,i;return t.onmessage=_,t.id=h++,a[t.id]=t}();return i.userStep=t.step,i.userChunk=t.chunk,i.userComplete=t.complete,i.userError=t.error,t.step=q(t.step),t.chunk=q(t.chunk),t.complete=q(t.complete),t.error=q(t.error),delete t.worker,void i.postMessage({input:e,config:t,workerId:i.id})}var n=null;k.NODE_STREAM_INPUT,"string"==typeof e?n=t.download?new l(t):new p(t):!0===e.readable&&q(e.read)&&q(e.on)?n=new m(t):(f.File&&e instanceof File||e instanceof Object)&&(n=new c(t));return n.stream(e)},unparse:function(e,t){var i=!1,_=!0,g=",",v="\r\n",n='"',s=n+n,r=!1,a=null;!function(){if("object"!=typeof t)return;"string"!=typeof t.delimiter||k.BAD_DELIMITERS.filter(function(e){return-1!==t.delimiter.indexOf(e)}).length||(g=t.delimiter);("boolean"==typeof t.quotes||Array.isArray(t.quotes))&&(i=t.quotes);"boolean"!=typeof t.skipEmptyLines&&"string"!=typeof t.skipEmptyLines||(r=t.skipEmptyLines);"string"==typeof t.newline&&(v=t.newline);"string"==typeof t.quoteChar&&(n=t.quoteChar);"boolean"==typeof t.header&&(_=t.header);if(Array.isArray(t.columns)){if(0===t.columns.length)throw new Error("Option columns is empty");a=t.columns}void 0!==t.escapeChar&&(s=t.escapeChar+n)}();var o=new RegExp(U(n),"g");"string"==typeof e&&(e=JSON.parse(e));if(Array.isArray(e)){if(!e.length||Array.isArray(e[0]))return u(null,e,r);if("object"==typeof e[0])return u(a||h(e[0]),e,r)}else if("object"==typeof e)return"string"==typeof e.data&&(e.data=JSON.parse(e.data)),Array.isArray(e.data)&&(e.fields||(e.fields=e.meta&&e.meta.fields),e.fields||(e.fields=Array.isArray(e.data[0])?e.fields:h(e.data[0])),Array.isArray(e.data[0])||"object"==typeof e.data[0]||(e.data=[e.data])),u(e.fields||[],e.data||[],r);throw new Error("Unable to serialize unrecognized input");function h(e){if("object"!=typeof e)return[];var t=[];for(var r in e)t.push(r);return t}function u(e,t,r){var i="";"string"==typeof e&&(e=JSON.parse(e)),"string"==typeof t&&(t=JSON.parse(t));var n=Array.isArray(e)&&0=this._config.preview;if(o)f.postMessage({results:n,workerId:k.WORKER_ID,finished:a});else if(q(this._config.chunk)&&!t){if(this._config.chunk(n,this._handle),this._handle.paused()||this._handle.aborted())return void(this._halted=!0);n=void 0,this._completeResults=void 0}return this._config.step||this._config.chunk||(this._completeResults.data=this._completeResults.data.concat(n.data),this._completeResults.errors=this._completeResults.errors.concat(n.errors),this._completeResults.meta=n.meta),this._completed||!a||!q(this._config.complete)||n&&n.meta.aborted||(this._config.complete(this._completeResults,this._input),this._completed=!0),a||n&&n.meta.paused||this._nextChunk(),n}this._halted=!0},this._sendError=function(e){q(this._config.error)?this._config.error(e):o&&this._config.error&&f.postMessage({workerId:k.WORKER_ID,error:e,finished:!1})}}function l(e){var i;(e=e||{}).chunkSize||(e.chunkSize=k.RemoteChunkSize),u.call(this,e),this._nextChunk=n?function(){this._readChunk(),this._chunkLoaded()}:function(){this._readChunk()},this.stream=function(e){this._input=e,this._nextChunk()},this._readChunk=function(){if(this._finished)this._chunkLoaded();else{if(i=new XMLHttpRequest,this._config.withCredentials&&(i.withCredentials=this._config.withCredentials),n||(i.onload=E(this._chunkLoaded,this),i.onerror=E(this._chunkError,this)),i.open("GET",this._input,!n),this._config.downloadRequestHeaders){var e=this._config.downloadRequestHeaders;for(var t in e)i.setRequestHeader(t,e[t])}if(this._config.chunkSize){var r=this._start+this._config.chunkSize-1;i.setRequestHeader("Range","bytes="+this._start+"-"+r)}try{i.send()}catch(e){this._chunkError(e.message)}n&&0===i.status?this._chunkError():this._start+=this._config.chunkSize}},this._chunkLoaded=function(){4===i.readyState&&(i.status<200||400<=i.status?this._chunkError():(this._finished=!this._config.chunkSize||this._start>function(e){var t=e.getResponseHeader("Content-Range");if(null===t)return-1;return parseInt(t.substr(t.lastIndexOf("/")+1))}(i),this.parseChunk(i.responseText)))},this._chunkError=function(e){var t=i.statusText||e;this._sendError(new Error(t))}}function c(e){var i,n;(e=e||{}).chunkSize||(e.chunkSize=k.LocalChunkSize),u.call(this,e);var s="undefined"!=typeof FileReader;this.stream=function(e){this._input=e,n=e.slice||e.webkitSlice||e.mozSlice,s?((i=new FileReader).onload=E(this._chunkLoaded,this),i.onerror=E(this._chunkError,this)):i=new FileReaderSync,this._nextChunk()},this._nextChunk=function(){this._finished||this._config.preview&&!(this._rowCount=this._input.size,this.parseChunk(e.target.result)},this._chunkError=function(){this._sendError(i.error)}}function p(e){var r;u.call(this,e=e||{}),this.stream=function(e){return r=e,this._nextChunk()},this._nextChunk=function(){if(!this._finished){var e=this._config.chunkSize,t=e?r.substr(0,e):r;return r=e?r.substr(e):"",this._finished=!r,this.parseChunk(t)}}}function m(e){u.call(this,e=e||{});var t=[],r=!0,i=!1;this.pause=function(){u.prototype.pause.apply(this,arguments),this._input.pause()},this.resume=function(){u.prototype.resume.apply(this,arguments),this._input.resume()},this.stream=function(e){this._input=e,this._input.on("data",this._streamData),this._input.on("end",this._streamEnd),this._input.on("error",this._streamError)},this._checkIsFinished=function(){i&&1===t.length&&(this._finished=!0)},this._nextChunk=function(){this._checkIsFinished(),t.length?this.parseChunk(t.shift()):r=!0},this._streamData=E(function(e){try{t.push("string"==typeof e?e:e.toString(this._config.encoding)),r&&(r=!1,this._checkIsFinished(),this.parseChunk(t.shift()))}catch(e){this._streamError(e)}},this),this._streamError=E(function(e){this._streamCleanUp(),this._sendError(e)},this),this._streamEnd=E(function(){this._streamCleanUp(),i=!0,this._streamData("")},this),this._streamCleanUp=E(function(){this._input.removeListener("data",this._streamData),this._input.removeListener("end",this._streamEnd),this._input.removeListener("error",this._streamError)},this)}function r(_){var a,o,h,i=/^\s*-?(\d*\.?\d+|\d+\.?\d*)(e[-+]?\d+)?\s*$/i,n=/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/,t=this,r=0,u=0,f=!1,e=!1,d=[],l={data:[],errors:[],meta:{}};if(q(_.step)){var s=_.step;_.step=function(e){if(l=e,p())c();else{if(c(),0===l.data.length)return;r+=e.data.length,_.preview&&r>_.preview?o.abort():s(l,t)}}}function g(e){return"greedy"===_.skipEmptyLines?""===e.join("").trim():1===e.length&&0===e[0].length}function c(){if(l&&h&&(v("Delimiter","UndetectableDelimiter","Unable to auto-detect delimiting character; defaulted to '"+k.DefaultDelimiter+"'"),h=!1),_.skipEmptyLines)for(var e=0;e=d.length?"__parsed_extra":d[r]),_.transform&&(s=_.transform(s,n)),s=m(n,s),"__parsed_extra"===n?(i[n]=i[n]||[],i[n].push(s)):i[n]=s}return _.header&&(r>d.length?v("FieldMismatch","TooManyFields","Too many fields: expected "+d.length+" fields but parsed "+r,u+t):r=i.length/2?"\r\n":"\r"}(e,i)),h=!1,_.delimiter)q(_.delimiter)&&(_.delimiter=_.delimiter(e),l.meta.delimiter=_.delimiter);else{var n=function(e,t,r,i,n){var s,a,o;n=n||[",","\t","|",";",k.RECORD_SEP,k.UNIT_SEP];for(var h=0;h=L)return R(!0)}else for(g=M,M++;;){if(-1===(g=a.indexOf(O,g+1)))return t||u.push({type:"Quotes",code:"MissingQuotes",message:"Quoted field unterminated",row:h.length,index:M}),w();if(g===i-1)return w(a.substring(M,g).replace(_,O));if(O!==z||a[g+1]!==z){if(O===z||0===g||a[g-1]!==z){var y=E(-1===m?p:Math.min(p,m));if(a[g+1+y]===D){f.push(a.substring(M,g).replace(_,O)),a[M=g+1+y+e]!==O&&(g=a.indexOf(O,M)),p=a.indexOf(D,M),m=a.indexOf(I,M);break}var k=E(m);if(a.substr(g+1+k,n)===I){if(f.push(a.substring(M,g).replace(_,O)),C(g+1+k+n),p=a.indexOf(D,M),g=a.indexOf(O,M),o&&(S(),j))return R();if(L&&h.length>=L)return R(!0);break}u.push({type:"Quotes",code:"InvalidQuotes",message:"Trailing quote on quoted field is malformed",row:h.length,index:M}),g++}}else g++}return w();function b(e){h.push(e),d=M}function E(e){var t=0;if(-1!==e){var r=a.substring(g+1,e);r&&""===r.trim()&&(t=r.length)}return t}function w(e){return t||(void 0===e&&(e=a.substr(M)),f.push(e),M=i,b(f),o&&S()),R()}function C(e){M=e,b(f),f=[],m=a.indexOf(I,M)}function R(e,t){return{data:t||!1?h[0]:h,errors:u,meta:{delimiter:D,linebreak:I,aborted:j,truncated:!!e,cursor:d+(r||0)}}}function S(){A(R(void 0,!0)),h=[],u=[]}function x(e,t,r){var i={nextDelim:void 0,quoteSearch:void 0},n=a.indexOf(O,t+1);if(t.vis-content{position:relative}.vis-panel .vis-shadow{position:absolute;width:100%;height:1px;box-shadow:0 0 10px rgba(0,0,0,.8)}.vis-panel .vis-shadow.vis-top{top:-1px;left:0}.vis-panel .vis-shadow.vis-bottom{bottom:-1px;left:0}.vis-graph-group0{fill:#4f81bd;fill-opacity:0;stroke-width:2px;stroke:#4f81bd}.vis-graph-group1{fill:#f79646;fill-opacity:0;stroke-width:2px;stroke:#f79646}.vis-graph-group2{fill:#8c51cf;fill-opacity:0;stroke-width:2px;stroke:#8c51cf}.vis-graph-group3{fill:#75c841;fill-opacity:0;stroke-width:2px;stroke:#75c841}.vis-graph-group4{fill:#ff0100;fill-opacity:0;stroke-width:2px;stroke:#ff0100}.vis-graph-group5{fill:#37d8e6;fill-opacity:0;stroke-width:2px;stroke:#37d8e6}.vis-graph-group6{fill:#042662;fill-opacity:0;stroke-width:2px;stroke:#042662}.vis-graph-group7{fill:#00ff26;fill-opacity:0;stroke-width:2px;stroke:#00ff26}.vis-graph-group8{fill:#f0f;fill-opacity:0;stroke-width:2px;stroke:#f0f}.vis-graph-group9{fill:#8f3938;fill-opacity:0;stroke-width:2px;stroke:#8f3938}.vis-timeline .vis-fill{fill-opacity:.1;stroke:none}.vis-timeline .vis-bar{fill-opacity:.5;stroke-width:1px}.vis-timeline .vis-point{stroke-width:2px;fill-opacity:1}.vis-timeline .vis-legend-background{stroke-width:1px;fill-opacity:.9;fill:#fff;stroke:#c2c2c2}.vis-timeline .vis-outline{stroke-width:1px;fill-opacity:1;fill:#fff;stroke:#e5e5e5}.vis-timeline .vis-icon-fill{fill-opacity:.3;stroke:none}.vis-time-axis{position:relative;overflow:hidden}.vis-time-axis.vis-foreground{top:0;left:0;width:100%}.vis-time-axis.vis-background{position:absolute;top:0;left:0;width:100%;height:100%}.vis-time-axis .vis-text{position:absolute;color:#4d4d4d;padding:3px;overflow:hidden;box-sizing:border-box;white-space:nowrap}.vis-time-axis .vis-text.vis-measure{position:absolute;padding-left:0;padding-right:0;margin-left:0;margin-right:0;visibility:hidden}.vis-time-axis .vis-grid.vis-vertical{position:absolute;border-left:1px solid}.vis-time-axis .vis-grid.vis-vertical-rtl{position:absolute;border-right:1px solid}.vis-time-axis .vis-grid.vis-minor{border-color:#e5e5e5}.vis-time-axis .vis-grid.vis-major{border-color:#bfbfbf}.vis-timeline{position:relative;border:1px solid #bfbfbf;overflow:hidden;padding:0;margin:0;box-sizing:border-box}
--------------------------------------------------------------------------------