├── 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 | 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} --------------------------------------------------------------------------------