1/** 2 * Creates a sun diagram to display a number of items in a fun way 3 */ 4var solarDisplay = { 5 6 /** 7 * 8 */ 9 defaults: { 10 width: 600, 11 height: 600, 12 innerRadius: 100, 13 barMaxSize : 200, 14 items: [ 15 { title: 'define', frequency: 1 }, 16 { title: 'some', frequency: 0.7 }, 17 { title: 'items', frequency: 0.5 }, 18 { title: 'first', frequency: 0.3 } 19 ] 20 }, 21 22 vars: { 23 built: false, 24 focusedBar: false, 25 barPosition: {}, 26 barTransitioning: false 27 }, 28 29 containerOffset: { 30 x: 0, 31 y: 0 32 }, 33 34 /** 35 * @static 36 */ 37 transformCentralText: function(d){ 38 var b; 39 try { b = this.getBBox(); } catch ( ex ) { b = { width: 0, height: 0 }; }; 40 return 'translate(' + (-b.width/2) + ',' + (b.height/4) + ')'; 41 }, 42 43 /** 44 * 45 */ 46 transformBarElementsFunction: function(){ 47 var opt = this.options; 48 return function(d, index) { 49 return 'translate(' 50 //+ (opt.dims.width / 2 + opt.innerRadius * Math.cos(opt.theta * index)) + ',' 51 //+ (opt.dims.height / 2.2 - opt.innerRadius * Math.sin(opt.theta * index)) + 52 + (opt.innerRadius * Math.cos(opt.theta * index)) + ',' 53 + (- opt.innerRadius * Math.sin(opt.theta * index)) + 54 ') ' + 55 'rotate(' + (98 - index * opt.thetaD) + ')'; 56 }; 57 }, 58 59 /** 60 * 61 */ 62 transformLabelElementsFunction: function(){ 63 var opt = this.options; 64 return function(d, index) { 65 return 'rotate(90) translate(' + ((opt.innerRadius * 2) + 10) + ', ' + ((-opt.barWidth * 0.15) - 2) + ')'; 66 }; 67 }, 68 69 /** 70 * 71 */ 72 transformLabelTextFunction: function(){ 73 var opt = this.options; 74 return function(d, index) { 75 var b; 76 try { b = this.getBBox(); } catch ( ex ) { b = { width: 0, height: 0 }; }; 77 return index < opt.dataSize/4 || index > (opt.dataSize - opt.dataSize/4) 78 ? 'scale(-1,-1) translate(' + (-b.width) + ',' + (b.height-8) + ')' 79 : '' 80 ; 81 }; 82 }, 83 84 /** 85 * Create an instance of solarDisplay 86 */ 87 translate: function(x, y) { 88 return "translate(" + x + "," + y + ") "; 89 }, 90 91 scale: function(s){ 92 return s < 1 ? "scale(" + s + ") " : " "; 93 }, 94 95 /** 96 * Create an instance of solarDisplay 97 */ 98 create: function(options) { 99 return this.prep.call(Object.create(this), options||{}); 100 }, 101 102 /** 103 * prep an instance of solarDisplay with unique references 104 */ 105 prep: function(options){ 106 107 var sol = this, 108 opt = this.options = {} 109 ; 110 111 opt.title = options.title || ""; 112 opt.x = options.x || 0; 113 opt.y = options.y || 0; 114 opt.dims = { 115 width: options.width || this.defaults.width, 116 height: options.height || this.defaults.height 117 }; 118 opt.container = options.container 119 ? d3.select(options.container) 120 : d3.select('body') 121 ; 122 this.state = 'unstarted'; 123 this.ui = {}; 124 this.ui.solarContainer = opt.container; 125 this.svg = this.ui.solarContainer.append('svg').attr(opt.dims).classed('solar-display', true) 126 .style({ 127 width: '100%', 128 height: '100%' 129 }) 130 ; 131 this.data = options.items || this.defaults.items; 132 133 opt.dataSize = this.data.length; 134 opt.innerRadius = options.innerRadius || this.defaults.innerRadius; 135 opt.barWidth = Math.max(Math.min(2 * Math.PI * opt.innerRadius / opt.dataSize, 80), 3); 136 opt.theta = 2 * Math.PI / opt.dataSize; 137 opt.thetaD = 360 / opt.dataSize; 138 opt.barMaxSize = options.barMaxSize || this.defaults.barMaxSize; 139 opt.outerRadius = opt.innerRadius + opt.barMaxSize; 140 141 //this.svg.attr('preserveAspectRatio', 'xMidYMid'); 142 //this.svg.attr('viewBox', ([0, 0, opt.dims.width, opt.dims.height]).join(' ')) 143 144 this.ui.container = this.svg.append('g'); 145 146 if ( options.hidden ) { 147 this.hide(); 148 } 149 else { 150 this.show(); 151 } 152 153 // click off 154 d3.select('body').on('click', function(e){ 155 sol.clickOff(); 156 }); 157 158 return this; 159 160 }, 161 162 show: function(){ 163 this.ui.solarContainer.style('display', 'block'); 164 this.vars.hidden = false; 165 (!this.vars.built) && this.buildAttempt(); 166 }, 167 168 hide: function(){ 169 this.ui.solarContainer.style('display', 'none'); 170 this.vars.hidden = true; 171 }, 172 173 toggle: function(){ 174 if ( this.vars.hidden ) { 175 this.show(); 176 } 177 else { 178 this.hide(); 179 } 180 return this; 181 }, 182 183 /** 184 * Make sure we can getBBox before building. 185 * Otherwise dimensions will be alll screwy. 186 */ 187 buildAttempt: function(){ 188 var sol = this, build = function(){ 189 sol.ui.container[0][0].getBBox(); 190 sol.build(); 191 sol.animateIn(function(){ 192 //sol.animateExplode(); 193 }); 194 }; 195 try { build(); } catch ( ex ) { 196 var iid = setInterval(function(){ 197 try { build(); clearInterval(iid); } catch ( ex ) { }; 198 }, 500); 199 } 200 }, 201 202 build: function(){ 203 204 var sol = this, 205 opt = this.options 206 ; 207 208 this.vars.built = true; 209 210 /// TODO: this could be improved to handle wide but short displays 211 d3.select(window).on('resize', function(){ sol.resize(); }); 212 213 /// clear existing bars 214 this.ui.container.selectAll(".bar").remove(); 215 216 this.ui.txtcontainer = this.ui.container.append('g').style('opacity', 0); 217 this.ui.txtline1 = this.ui.txtcontainer.append('text') 218 .attr('fill', 'white') 219 .style('text-anchor', 'middle') 220 .html('Press a light bar to view, darker bars yet to have content:') 221 ; 222 this.ui.txtarrow1 = this.ui.txtcontainer.append('text').html('\u2935').attr({ 223 x: 190, 224 y: 12, 225 fill: 'white', 226 'font-size': '1.5em' 227 }); 228 229 this.resize(); 230 231 /// create the central group 232 this.ui.centralDisc = this.ui.container.append("g") 233 //.attr("transform", this.translate(opt.dims.width / 2, opt.dims.height / 2.2)) 234 .attr("transform", this.translate(0, 0)) 235 .on("mouseover", function(){ 236 sol.animateExplode(); 237 }) 238 //.on("mouseout", function(){ 239 // sol.animateImplode(); 240 //}) 241 ; 242 243 /// create new bars 244 this.ui.bars = this.ui.container.selectAll(".bar") 245 .data(this.data) 246 .enter() 247 .append("g") 248 .attr("class", "bar") 249 .attr("transform", this.transformBarElementsFunction()) 250 .attr('x', 0) 251 .attr('y', opt.innerRadius * 2) 252 .on("click", function( d ){ 253 d3.event.stopPropagation(); 254 sol.focusBar( this, d ); 255 }) 256 ; 257 258 /// create the rectangles within in the bar groups 259 this.ui.rects = this.ui.bars.append("rect") 260 .attr("class", function( d ){ 261 return d && d.description 262 ? 'bar-itself with-description' 263 : 'bar-itself' 264 ; 265 }) 266 .attr("width", opt.barWidth-2) 267 .attr('x', 0) 268 .attr('y', opt.innerRadius*2) 269 //.attr('fill', 'white') 270 .attr("height", 0) 271 .style("opacity", 0) 272 ; 273 274 /// create the labels 275 this.ui.labels = this.ui.bars 276 .append('g') 277 .style("opacity", 0) 278 .attr("transform", this.transformLabelElementsFunction()) 279 ; 280 281 /// create the label text 282 this.ui.labelText = this.ui.labels 283 .append('text') 284 .text(function(d, index){return d.title;}) 285 .style('fill-opacity', 0.5) 286 .attr({ 287 "class": "text", 288 "width": "100%", 289 "height": "100%", 290 "fill": "black", 291 "pointer-events": "none", 292 "font-size": Math.max(Math.min(opt.barWidth * 0.8, 18), 12), 293 "transform": this.transformLabelTextFunction() 294 }) 295 ; 296 297 /// create the central circle 298 this.ui.centralDisc.append("circle") 299 .attr({ 300 "cx": 0, 301 "cy": 0, 302 "r": opt.innerRadius * 2 303 }) 304 .attr("fill", "rgba(0,0,0,0)") 305 ; 306 307 /// create the central text 308 this.ui.centralText = this.ui.centralDisc.append("text")
309 .text(opt.title) 310 .attr({ 311 "x": 0, 312 "y": 0, 313 "fill": "white", 314 "font-size": '1.6em', 315 "line-height": '1.6em' 316 }) 317 .attr({ 318 "transform": solarDisplay.transformCentralText 319 }) 320 .classed("main-title", true) 321 .style({ 322 'opacity': 0, 323 'cursor': 'default' 324 }) 325 ; 326 327 var con = this.ui.solarContainer.node(); 328 this.ui.slideBars = this.ui.container.selectAll('.sbars') 329 .data([0,0.2,0.5,0.3,0.7,0.1,0.9,1]) 330 .enter() 331 .append('rect') 332 .attr('rx', 6) 333 .attr('ry', 6) 334 .attr('height', opt.dims.height * 2) 335 .attr('width', Math.round(opt.dims.width / 8)) 336 .attr('y', con.offsetHeight) 337 .attr('x', function(d, i){ 338 return -opt.dims.width/2 + i * (opt.dims.width / 8); 339 }) 340 .attr('fill', 'black') 341 .on("click", function( d ){ 342 d3.event.stopPropagation(); 343 }) 344 ; 345 346 this.resize(); 347 348 }, 349 350 clickOff: function(){ 351 if ( this.vars.focusedBar ) { 352 this.focusClose(); 353 } 354 }, 355 356 animateSlideBarsIn: function(callback){ 357 var sol = this; 358 var opt = this.options; 359 var con = this.ui.solarContainer.node(); 360 this.ui.slideBars 361 .transition() 362 .delay(function(d){ 363 return d * 500; 364 }) 365 .attr('rx', 0) 366 .attr('ry', 0) 367 .attr('y', -con.offsetHeight / 2) 368 .duration(500) 369 .call(this.afterAllEnded, function(){ 370 callback && callback.apply && callback.apply(sol); 371 }) 372 ; 373 }, 374 375 animateSlideBarsOut: function(delay){ 376 var opt = this.options; 377 var con = this.ui.solarContainer.node(); 378 this.ui.slideBars 379 .transition() 380 .delay(function(d){ 381 return (delay||0) + d * 500; 382 }) 383 .attr('rx', 6) 384 .attr('ry', 6) 385 .attr('y', con.offsetHeight) 386 .duration(500) 387 ; 388 }, 389 390 /** 391 * 392 */ 393 focusBar: function ( clicked, d ){ 394 var sol = this; 395 if ( this.vars.focusedBar ) { 396 this.focusClose(); 397 } 398 else { 399 if ( d.description ) { 400 this.animateSlideBarsIn(function(){ 401 sol.focusContent(d); 402 }); 403 /// configure variables 404 this.vars.focusedBar = clicked; 405 this.ui.focusedBar = d3.select(clicked); 406 this.vars.previousBarTransform = this.ui.focusedBar.attr('transform'); 407 /* 408 /// trigger transitions 409 this.focusCentralDiscTransitionOut(); 410 this.vars.barTransitioning = true; 411 this.focusBarTransitionIn(function(){ 412 this.vars.barTransitioning = false; 413 this.resize(); 414 }); 415 /// display the content for this bar 416 this.focusContent(d); 417 */ 418 } 419 /// trigger any configured functions on click 420 this.options.click && this.options.click(d); 421 } 422 }, 423 424 /** 425 * 426 */ 427 focusContent: function ( d ){ 428 var sol = this, 429 con = this.ui.solarContainer.node(), 430 w, h, 431 fs = 'inherit', 432 lh = 'inherit', 433 ics = 28/32 434 ; 435 if ( con.offsetWidth < this.options.dims.width ) { 436 w = con.offsetWidth / 2; 437 h = this.options.dims.height / 2 - 100; 438 fs = '1.6em'; 439 lh = '1.3em'; 440 ics = 28/20; 441 } 442 else { 443 w = this.options.dims.width / 2 - 100, 444 h = this.options.dims.height / 2 - 100; 445 } 446 this.ui.htmlWrapper = this.ui.container.append('foreignObject') 447 .attr({ 448 x: -w, 449 y: -h * 1.5, 450 width: w * 2, 451 height: h * 3 452 }) 453 .style('opacity', 0) 454 .on("click", function( d ){ 455 d3.event.stopPropagation(); 456 }) 457 ; 458 this.ui.htmlContent = this.ui.htmlWrapper 459 .append('xhtml:div') 460 .attr('xmlns', 'http://www.w3.org/1999/xhtml') 461 .style({ 462 'color': 'white', 463 'text-align': 'left', 464 'display': 'block', 465 'font-size': fs, 466 'line-height': lh 467 }) 468 .html('<h3>' + d.title + '</h3>' + d.description) 469 ; 470 this.ui.closeContent = sol.ui.container.append('g') 471 .attr('transform', this.translate(w, - con.offsetHeight / 2 + 10)) 472 .style('cursor', 'pointer') 473 .on('click', function(){ sol.focusClose(); }) 474 .on('mouseover', function(){ sol.ui.closeIcon.transition().attr('fill', 'orange').duration(300); }) 475 .on('mouseout', function(){ sol.ui.closeIcon.transition().attr('fill', 'white').duration(300); }); 476 ; 477 this.ui.closeIcon = this.ui.closeContent.append('path') 478 .attr('d', 'M0,7L7,0L16,10L26,0L32,7L23,16L32,25L26,31L16,22L7,31L0,24L9,16Z') 479 .attr('fill', 'white') 480 .attr('transform', 'scale(' + ics + ')') 481 ; 482 this.ui.fadeRect = this.ui.container.append('rect') 483 .attr({ 484 x: -w * 1.25, 485 y: -h * 1.5, 486 width: w * 2.5, 487 height: h * 4, 488 fill: '#000', 489 opacity: 1 490 }) 491 .on("click", function( d ){ 492 d3.event.stopPropagation(); 493 }) 494 ; 495 this.resize(); 496 // this works in firefox (but not in chrome!) 497 this.ui.htmlWrapper 498 .transition() 499 .style('opacity', 1) 500 .duration(500) 501 ; 502 // this works in chrome (but not in firefox!) 503 this.ui.fadeRect && this.ui.fadeRect.transition() 504 .attr('opacity', 0) 505 .duration(500) 506 }, 507 508 focusClose: function(){ 509 var sol = this; 510 this.animateSlideBarsOut(300); 511 this.ui.closeContent.transition() 512 .attr('opacity', 1) 513 .duration(500) 514 .remove() 515 ; 516 this.ui.fadeRect && this.ui.fadeRect.transition() 517 .attr('opacity', 1) 518 .duration(500) 519 .call(this.afterAllEnded, function(){ 520 sol.ui.htmlWrapper.remove(); 521 }) 522 .remove() 523 ; 524 /* 525 this.focusCentralDiscTransitionIn(); 526 this.focusBarTransitionOut(); 527 this.ui.htmlContent.transition() 528 .delay(0) 529 .style('opacity', 0) 530 .duration(500) 531 ; 532 */ 533 this.vars.focusedBar = null; 534 }, 535 536 /** 537 * 538 */ 539 focusBarTransitionIn: function( callback ){ 540 var sol = this, opt = this.options; 541 this.ui.txtcontainer 542 .transition() 543 .delay(2000) 544 .style('opacity', 0) 545 .duration(300) 546 ; 547 this.ui.bars.transition() 548 .delay(0) 549 .style('opacity', function(){ 550 return this === sol.vars.focusedBar ? 1 : 0; 551 }) 552 .attr('transform', function(d, index){ 553 var item = d3.select(this), rect = item.select('rect'), x, y, w, h, r, p = 15; 554 if ( this === sol.vars.focusedBar ) { 555 if ( index < opt.dataSize/4 || index > (opt.dataSize - opt.dataSize/4) ) { 556 y = parseInt(rect.attr('y'), 10); 557 h = parseInt(rect.attr('height'), 10); 558 x = y + h + p - sol.containerOffset.x + 35; 559 y = p;// - sol.containerOffset.y/2; 560 r = 90; 561 } 562 else { 563 y = parseInt(rect.attr('y'), 10); 564 w = parseInt(rect.attr('width'), 10); 565 x = - (y - p + sol.containerOffset.x) + 35; 566 y = w + p;// - sol.containerOffset.y/2; 567 r = -90; 568 } 569 sol.vars.barPosition = { 570 x: x + ( sol.containerOffset ? sol.containerOffset.x : 0), 571 y: y, 572 r: r 573 }; 574 return 'translate(' + x + ',' + y + ') rotate(' + r + ')'; 575 } 576 else { 577 return item.attr('transform'); 578 } 579 })
580 .ease('cubic-in-out') 581 .duration(1000) 582 .call(this.afterAllEnded, function(){ 583 callback && callback.apply && callback.apply(sol); 584 }) 585 ; 586 }, 587 588 /** 589 * 590 */ 591 focusBarTransitionOut: function( callback ){ 592 var sol = this; 593 this.ui.bars.transition() 594 .delay(0) 595 .style('opacity', 1) 596 .attr('transform', function(){ 597 return (this === sol.vars.focusedBar) 598 ? sol.vars.previousBarTransform 599 : d3.select(this).attr('transform') 600 ; 601 }) 602 .ease('cubic-in-out') 603 .duration(1000) 604 .call(this.afterAllEnded, function(){ 605 callback && callback.apply && callback.apply(sol); 606 }) 607 ; 608 }, 609 610 /** 611 * 612 */ 613 focusCentralDiscTransitionIn: function(){ 614 this.ui.centralDisc.transition() 615 .delay(0) 616 .style('opacity', 1) 617 .ease('cubic-in-out') 618 .duration(500) 619 ; 620 }, 621 622 /** 623 * 624 */ 625 focusCentralDiscTransitionOut: function(){ 626 this.ui.centralDisc.transition() 627 .delay(0) 628 .style('opacity', 0) 629 .ease('cubic-in-out') 630 .duration(500) 631 ; 632 }, 633 634 /** 635 * 636 */ 637 afterAllEnded: function( transition, callback ){ 638 var n = 0; 639 transition.each(function(){++n;}); 640 transition.each("end", function(){ if(!--n) callback.apply(this, arguments); }); 641 }, 642 643 /** 644 * 645 */ 646 animateExplode: function(){ 647 if ( !this.vars.built ) { 648 return; 649 } 650 this.ui.solarContainer.classed('blur-back', true); 651 if ( this.state != 'exploding' && this.state != 'started' && this.state != 'looping' && this.state != 'unstarted' ) { 652 var sol = this, opt = this.options; 653 this.state = 'exploding'; 654 this.ui.txtcontainer 655 .transition() 656 .delay(2000) 657 .style('opacity', 1) 658 .duration(300) 659 ; 660 this.ui.rects 661 .transition() 662 .delay(function(d, i){return i * 30;}) 663 .attr('height', function(d, i){ return d.frequency * opt.barMaxSize; }) 664 .ease('elastic') 665 .duration(1500) 666 .call(this.afterAllEnded, function(){ 667 sol && (sol.state = 'exploded'); 668 }) 669 ; 670 this.ui.labels 671 .transition() 672 .delay(function(d,i,k){return i * 30;}) 673 .style('opacity', 1) 674 .duration(500) 675 ; 676 } 677 }, 678 679 /** 680 * 681 */ 682 animateImplode: function(){ 683 if ( !this.vars.built ) { 684 return; 685 } 686 if ( this.state != 'imploding' ) { 687 var sol = this, opt = this.options; 688 this.state = 'imploding'; 689 sol.animateLoop(100, function(){ 690 this.state = 'ready'; 691 }); 692 this.ui.labels 693 .transition() 694 .style('opacity', 0) 695 .duration(500) 696 ; 697 } 698 }, 699 700 /** 701 * Trigger the waiting loop 702 */ 703 animateLoop: function(time, callback){ 704 if ( !time ) { time = 500; } 705 var opt = this.options; 706 var sol = this; 707 var loop = function(){ 708 if ( sol.state != 'looping' ) return; 709 d3.select(this) 710 .transition() 711 .attr('height', 5) 712 .ease('quad') 713 .duration(500) 714 .each("end", function(){ 715 if ( sol.state != 'looping' ) return; 716 d3.select(this) 717 .transition() 718 .attr('height', 10) 719 .ease('quad') 720 .duration(500) 721 .each("end", function(){ 722 loop.call(this); 723 }); 724 }); 725 }; 726 this.state = 'looping'; 727 this.ui.rects 728 .transition() 729 .delay(function(d,i,k){ return i * ((time + 500) / opt.dataSize); }) 730 .attr('height', 10) 731 .style('opacity', 1) 732 .ease('quad') 733 .duration(time) 734 .call(this.afterAllEnded, function(){ 735 callback && callback.apply(sol); 736 }) 737 //.each("end", loop); 738 ; 739 }, 740 741 /** 742 * Initial animation 743 */ 744 animateIn: function(callback){ 745 if ( !this.vars.built ) { 746 return; 747 } 748 var sol = this; 749 this.resize(); 750 this.state = 'started'; 751 this.ui.rects.attr('index', function(d,i,k){ return k; }); 752 this.ui.centralText 753 .transition() 754 .style('opacity', 1) 755 .duration(2000) 756 .each("end", function(){ 757 sol.state = 'ready'; 758 callback && callback.apply(sol); 759 }) 760 ; 761 this.animateLoop(500); 762 }, 763 764 getContentMargin: function(){ 765 if ( this.containerOffset && this.containerOffset.width > 800 ) { 766 return { 767 x: 100, 768 y: 50 769 }; 770 } 771 else if ( this.containerOffset && this.containerOffset.width > 600 ) { 772 return { 773 x: 50, 774 y: 50 775 }; 776 } 777 else { 778 return { 779 x: 30, 780 y: 50 781 }; 782 } 783 }, 784 785 resize: function(){ 786 if ( !this.vars.built ) { return; } 787 var opt = this.options, con = this.ui.solarContainer.node(); 788 var co = this.containerOffset; 789 var tb = this.ui.txtcontainer.node().getBBox(); 790 var cb = this.ui.container.node().getBBox(); 791 var cs = 1; 792 793 co.width = con.offsetWidth; 794 co.height = con.offsetHeight; 795 co.x = co.width / 2; 796 co.y = co.height / 2; 797 798 if ( co.width < cb.width ) { 799 cs = co.width / cb.width * 1.4; 800 } 801 802 this.ui.container.attr('transform', this.translate(co.x, co.y) + this.scale(cs)); 803 this.ui.txtcontainer.attr('transform', this.translate(0, -co.y + tb.height/2 + 10)); 804 805 /* 806 if ( this.ui.htmlWrapper ) { 807 var w = opt.dims.width / 2 - 100; 808 var h = opt.dims.height / 2 - 100; 809 this.ui.htmlWrapper.attr({ 810 this.ui.htmlWrapper = this.ui.container.append('foreignObject') 811 .attr({ 812 x: -w, 813 y: -h * 1.5, 814 width: w * 2, 815 height: h * 3 816 }) 817 } 818 */ 819 820 /* 821 if ( this.vars.focusedBar ) { 822 var bp = this.vars.barPosition, 823 cm = this.getContentMargin() 824 ; 825 if ( !this.vars.barTransitioning ) { 826 this.ui.focusedBar.attr('transform', 'translate(' + (bp.x - tx) + ',' + bp.y + ') rotate(' + bp.r + ')'); 827 } 828 this.ui.closeContent.attr('transform', 'translate(' + (this.containerOffset.width - 86 - tx) + ',20)'); 829 this.ui.htmlWrapper 830 .attr({ 831 x: cm.x - tx, 832 y: cm.y + 20, 833 width: this.containerOffset.width - cm.x * 2, 834 height: this.containerOffset.height - cm.y * 2 835 }) 836 ; 837 } 838 */ 839 } 840 841};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.