1(function(factory){if(typeof define=='function'&&define.amd) 2define(['picker','jquery'],factory) 3else if(typeof exports=='object') 4module.exports=factory(require('./picker.js'),require('jquery')) 5else factory(Picker,jQuery)}(function(Picker,$){var DAYS_IN_WEEK=7,WEEKS_IN_CALENDAR=6,_=Picker._ 6function DatePicker(picker,settings){var calendar=this,element=picker.$node[0],elementValue=element.value,elementDataValue=picker.$node.data('value'),valueString=elementDataValue||elementValue,formatString=elementDataValue?settings.formatSubmit:settings.format,isRTL=function(){return element.currentStyle?element.currentStyle.direction=='rtl':getComputedStyle(picker.$root[0]).direction=='rtl'} 7calendar.settings=settings 8calendar.$node=picker.$node 9calendar.queue={min:'measure create',max:'measure create',now:'now create',select:'parse create validate',highlight:'parse navigate create validate',view:'parse create validate viewset',disable:'deactivate',enable:'activate'} 10calendar.item={} 11calendar.item.clear=null 12calendar.item.disable=(settings.disable||[]).slice(0) 13calendar.item.enable=-(function(collectionDisabled){return collectionDisabled[0]===!0?collectionDisabled.shift():-1})(calendar.item.disable) 14calendar.set('min',settings.min).set('max',settings.max).set('now') 15if(valueString){calendar.set('select',valueString,{format:formatString,defaultValue:!0})} 16else{calendar.set('select',null).set('highlight',calendar.item.now)} 17calendar.key={40:7,38:-7,39:function(){return isRTL()?-1:1},37:function(){return isRTL()?1:-1},go:function(timeChange){var highlightedObject=calendar.item.highlight,targetDate=new Date(highlightedObject.year,highlightedObject.month,highlightedObject.date+timeChange) 18calendar.set('highlight',targetDate,{interval:timeChange}) 19this.render()}} 20picker.on('render',function(){picker.$root.find('.'+settings.klass.selectMonth).on('change',function(){var value=this.value 21if(value){picker.set('highlight',[picker.get('view').year,value,picker.get('highlight').date]) 22picker.$root.find('.'+settings.klass.selectMonth).trigger('focus')}}) 23picker.$root.find('.'+settings.klass.selectYear).on('change',function(){var value=this.value 24if(value){picker.set('highlight',[value,picker.get('view').month,picker.get('highlight').date]) 25picker.$root.find('.'+settings.klass.selectYear).trigger('focus')}})},1).on('open',function(){var includeToday='' 26if(calendar.disabled(calendar.get('now'))){includeToday=':not(.'+settings.klass.buttonToday+')'} 27picker.$root.find('button'+includeToday+', select').attr('disabled',!1)},1).on('close',function(){picker.$root.find('button, select').attr('disabled',!0)},1)} 28DatePicker.prototype.set=function(type,value,options){var calendar=this,calendarItem=calendar.item 29if(value===null){if(type=='clear')type='select' 30calendarItem[type]=value 31return calendar} 32calendarItem[(type=='enable'?'disable':type=='flip'?'enable':type)]=calendar.queue[type].split(' ').map(function(method){value=calendar[method](type,value,options) 33return value}).pop() 34if(type=='select'){calendar.set('highlight',calendarItem.select,options)} 35else if(type=='highlight'){calendar.set('view',calendarItem.highlight,options)} 36else if(type.match(/^(flip|min|max|disable|enable)$/)){if(calendarItem.select&&calendar.disabled(calendarItem.select)){calendar.set('select',calendarItem.select,options)} 37if(calendarItem.highlight&&calendar.disabled(calendarItem.highlight)){calendar.set('highlight',calendarItem.highlight,options)}} 38return calendar} 39DatePicker.prototype.get=function(type){return this.item[type]} 40DatePicker.prototype.create=function(type,value,options){var isInfiniteValue,calendar=this 41value=value===undefined?type:value 42if(value==-Infinity||value==Infinity){isInfiniteValue=value} 43else if($.isPlainObject(value)&&_.isInteger(value.pick)){value=value.obj} 44else if($.isArray(value)){value=new Date(value[0],value[1],value[2]) 45value=_.isDate(value)?value:calendar.create().obj} 46else if(_.isInteger(value)||_.isDate(value)){value=calendar.normalize(new Date(value),options)} 47else{value=calendar.now(type,value,options)} 48return{year:isInfiniteValue||value.getFullYear(),month:isInfiniteValue||value.getMonth(),date:isInfiniteValue||value.getDate(),day:isInfiniteValue||value.getDay(),obj:isInfiniteValue||value,pick:isInfiniteValue||value.getTime()}} 49DatePicker.prototype.createRange=function(from,to){var calendar=this,createDate=function(date){if(date===!0||$.isArray(date)||_.isDate(date)){return calendar.create(date)} 50return date} 51if(!_.isInteger(from)){from=createDate(from)} 52if(!_.isInteger(to)){to=createDate(to)} 53if(_.isInteger(from)&&$.isPlainObject(to)){from=[to.year,to.month,to.date+from]} 54else if(_.isInteger(to)&&$.isPlainObject(from)){to=[from.year,from.month,from.date+to]} 55return{from:createDate(from),to:createDate(to)}} 56DatePicker.prototype.withinRange=function(range,dateUnit){range=this.createRange(range.from,range.to) 57return dateUnit.pick>=range.from.pick&&dateUnit.pick<=range.to.pick} 58DatePicker.prototype.overlapRanges=function(one,two){var calendar=this 59one=calendar.createRange(one.from,one.to) 60two=calendar.createRange(two.from,two.to) 61return calendar.withinRange(one,two.from)||calendar.withinRange(one,two.to)||calendar.withinRange(two,one.from)||calendar.withinRange(two,one.to)} 62DatePicker.prototype.now=function(type,value,options){value=new Date() 63if(options&&options.rel){value.setDate(value.getDate()+options.rel)} 64return this.normalize(value,options)} 65DatePicker.prototype.navigate=function(type,value,options){var targetDateObject,targetYear,targetMonth,targetDate,isTargetArray=$.isArray(value),isTargetObject=$.isPlainObject(value),viewsetObject=this.item.view 66if(isTargetArray||isTargetObject){if(isTargetObject){targetYear=value.year 67targetMonth=value.month 68targetDate=value.date} 69else{targetYear=+value[0] 70targetMonth=+value[1] 71targetDate=+value[2]} 72if(options&&options.nav&&viewsetObject&&viewsetObject.month!==targetMonth){targetYear=viewsetObject.year 73targetMonth=viewsetObject.month}
74targetDateObject=new Date(targetYear,targetMonth+(options&&options.nav?options.nav:0),1) 75targetYear=targetDateObject.getFullYear() 76targetMonth=targetDateObject.getMonth() 77while(new Date(targetYear,targetMonth,targetDate).getMonth()!==targetMonth){targetDate-=1} 78value=[targetYear,targetMonth,targetDate]} 79return value} 80DatePicker.prototype.normalize=function(value){value.setHours(0,0,0,0) 81return value} 82DatePicker.prototype.measure=function(type,value){var calendar=this 83if(!value){value=type=='min'?-Infinity:Infinity} 84else if(typeof value=='string'){value=calendar.parse(type,value)} 85else if(_.isInteger(value)){value=calendar.now(type,value,{rel:value})} 86return value} 87DatePicker.prototype.viewset=function(type,dateObject){return this.create([dateObject.year,dateObject.month,1])} 88DatePicker.prototype.validate=function(type,dateObject,options){var calendar=this,originalDateObject=dateObject,interval=options&&options.interval?options.interval:1,isFlippedBase=calendar.item.enable===-1,hasEnabledBeforeTarget,hasEnabledAfterTarget,minLimitObject=calendar.item.min,maxLimitObject=calendar.item.max,reachedMin,reachedMax,hasEnabledWeekdays=isFlippedBase&&calendar.item.disable.filter(function(value){if($.isArray(value)){var dateTime=calendar.create(value).pick 89if(dateTime<dateObject.pick)hasEnabledBeforeTarget=!0 90else if(dateTime>dateObject.pick)hasEnabledAfterTarget=!0} 91return _.isInteger(value)}).length 92if(!options||(!options.nav&&!options.defaultValue))if((!isFlippedBase&&calendar.disabled(dateObject))||(isFlippedBase&&calendar.disabled(dateObject)&&(hasEnabledWeekdays||hasEnabledBeforeTarget||hasEnabledAfterTarget))||(!isFlippedBase&&(dateObject.pick<=minLimitObject.pick||dateObject.pick>=maxLimitObject.pick))){if(isFlippedBase&&!hasEnabledWeekdays&&((!hasEnabledAfterTarget&&interval>0)||(!hasEnabledBeforeTarget&&interval<0))){interval*=-1} 93while(calendar.disabled(dateObject)){if(Math.abs(interval)>1&&(dateObject.month<originalDateObject.month||dateObject.month>originalDateObject.month)){dateObject=originalDateObject 94interval=interval>0?1:-1} 95if(dateObject.pick<=minLimitObject.pick){reachedMin=!0 96interval=1 97dateObject=calendar.create([minLimitObject.year,minLimitObject.month,minLimitObject.date+(dateObject.pick===minLimitObject.pick?0:-1)])} 98else if(dateObject.pick>=maxLimitObject.pick){reachedMax=!0 99interval=-1 100dateObject=calendar.create([maxLimitObject.year,maxLimitObject.month,maxLimitObject.date+(dateObject.pick===maxLimitObject.pick?0:1)])} 101if(reachedMin&&reachedMax){break} 102dateObject=calendar.create([dateObject.year,dateObject.month,dateObject.date+interval])}} 103return dateObject} 104DatePicker.prototype.disabled=function(dateToVerify){var 105calendar=this,isDisabledMatch=calendar.item.disable.filter(function(dateToDisable){if(_.isInteger(dateToDisable)){return dateToVerify.day===(calendar.settings.firstDay?dateToDisable:dateToDisable-1)%7} 106if($.isArray(dateToDisable)||_.isDate(dateToDisable)){return dateToVerify.pick===calendar.create(dateToDisable).pick} 107if($.isPlainObject(dateToDisable)){return calendar.withinRange(dateToDisable,dateToVerify)}}) 108isDisabledMatch=isDisabledMatch.length&&!isDisabledMatch.filter(function(dateToDisable){return $.isArray(dateToDisable)&&dateToDisable[3]=='inverted'||$.isPlainObject(dateToDisable)&&dateToDisable.inverted}).length 109return calendar.item.enable===-1?!isDisabledMatch:isDisabledMatch||dateToVerify.pick<calendar.item.min.pick||dateToVerify.pick>calendar.item.max.pick} 110DatePicker.prototype.parse=function(type,value,options){var calendar=this,parsingObject={} 111if(!value||typeof value!='string'){return value} 112if(!(options&&options.format)){options=options||{} 113options.format=calendar.settings.format} 114calendar.formats.toArray(options.format).map(function(label){var 115formattingLabel=calendar.formats[label],formatLength=formattingLabel?_.trigger(formattingLabel,calendar,[value,parsingObject]):label.replace(/^!/,'').length 116if(formattingLabel){parsingObject[label]=value.substr(0,formatLength)} 117value=value.substr(formatLength)}) 118return[parsingObject.yyyy||parsingObject.yy,+(parsingObject.mm||parsingObject.m)-1,parsingObject.dd||parsingObject.d]} 119DatePicker.prototype.formats=(function(){function getWordLengthFromCollection(string,collection,dateObject){var word=string.match(/[^\x00-\x7F]+|\w+/)[0] 120if(!dateObject.mm&&!dateObject.m){dateObject.m=collection.indexOf(word)+1} 121return word.length} 122function getFirstWordLength(string){return string.match(/\w+/)[0].length} 123return{d:function(string,dateObject){return string?_.digits(string):dateObject.date},dd:function(string,dateObject){return string?2:_.lead(dateObject.date)},ddd:function(string,dateObject){return string?getFirstWordLength(string):this.settings.weekdaysShort[dateObject.day]},dddd:function(string,dateObject){return string?getFirstWordLength(string):this.settings.weekdaysFull[dateObject.day]},m:function(string,dateObject){return string?_.digits(string):dateObject.month+1},mm:function(string,dateObject){return string?2:_.lead(dateObject.month+1)},mmm:function(string,dateObject){var collection=this.settings.monthsShort 124return string?getWordLengthFromCollection(string,collection,dateObject):collection[dateObject.month]},mmmm:function(string,dateObject){var collection=this.settings.monthsFull 125return string?getWordLengthFromCollection(string,collection,dateObject):collection[dateObject.month]},yy:function(string,dateObject){return string?2:(''+dateObject.year).slice(2)},yyyy:function(string,dateObject){return string?4:dateObject.year},toArray:function(formatString){return formatString.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g)},toString:function(formatString,itemObject){var calendar=this 126return calendar.formats.toArray(formatString).map(function(label){return _.trigger(calendar.formats[label],calendar,[0,itemObject])||label.replace(/^!/,'')}).join('')}}})() 127DatePicker.prototype.isDateExact=function(one,two){var calendar=this 128if((_.isInteger(one)&&_.isInteger(two))||(typeof one=='boolean'&&typeof two=='boolean')){return one===two} 129if((_.isDate(one)||$.isArray(one))&&(_.isDate(two)||$.isArray(two))){return calendar.create(one).pick===calendar.create(two).pick} 130if($.isPlainObject(one)&&$.isPlainObject(two)){return calendar.isDateExact(one.from,two.from)&&calendar.isDateExact(one.to,two.to)} 131return!1} 132DatePicker.prototype.isDateOverlap=function(one,two){var calendar=this,firstDay=calendar.settings.firstDay?1:0 133if(_.isInteger(one)&&(_.isDate(two)||$.isArray(two))){one=one%7+firstDay 134return one===calendar.create(two).day+1} 135if(_.isInteger(two)&&(_.isDate(one)||$.isArray(one))){two=two%7+firstDay 136return two===calendar.create(one).day+1} 137if($.isPlainObject(one)&&$.isPlainObject(two)){return calendar.overlapRanges(one,two)} 138return!1} 139DatePicker.prototype.flipEnable=function(val){var itemObject=this.item 140itemObject.enable=val||(itemObject.enable==-1?1:-1)} 141DatePicker.prototype.deactivate=function(type,datesToDisable){var calendar=this,disabledItems=calendar.item.disable.slice(0) 142if(datesToDisable=='flip'){calendar.flipEnable()} 143else if(datesToDisable===!1){calendar.flipEnable(1) 144disabledItems=[]} 145else if(datesToDisable===!0){calendar.flipEnable(-1) 146disabledItems=[]} 147else{datesToDisable.map(function(unitToDisable){var matchFound 148for(var index=0;
148index<disabledItems.length;index+=1){if(calendar.isDateExact(unitToDisable,disabledItems[index])){matchFound=!0 149break}} 150if(!matchFound){if(_.isInteger(unitToDisable)||_.isDate(unitToDisable)||$.isArray(unitToDisable)||($.isPlainObject(unitToDisable)&&unitToDisable.from&&unitToDisable.to)){disabledItems.push(unitToDisable)}}})} 151return disabledItems} 152DatePicker.prototype.activate=function(type,datesToEnable){var calendar=this,disabledItems=calendar.item.disable,disabledItemsCount=disabledItems.length 153if(datesToEnable=='flip'){calendar.flipEnable()} 154else if(datesToEnable===!0){calendar.flipEnable(1) 155disabledItems=[]} 156else if(datesToEnable===!1){calendar.flipEnable(-1) 157disabledItems=[]} 158else{datesToEnable.map(function(unitToEnable){var matchFound,disabledUnit,index,isExactRange 159for(index=0;index<disabledItemsCount;index+=1){disabledUnit=disabledItems[index] 160if(calendar.isDateExact(disabledUnit,unitToEnable)){matchFound=disabledItems[index]=null 161isExactRange=!0 162break} 163else if(calendar.isDateOverlap(disabledUnit,unitToEnable)){if($.isPlainObject(unitToEnable)){unitToEnable.inverted=!0 164matchFound=unitToEnable} 165else if($.isArray(unitToEnable)){matchFound=unitToEnable 166if(!matchFound[3])matchFound.push('inverted')} 167else if(_.isDate(unitToEnable)){matchFound=[unitToEnable.getFullYear(),unitToEnable.getMonth(),unitToEnable.getDate(),'inverted']} 168break}} 169if(matchFound)for(index=0;index<disabledItemsCount;index+=1){if(calendar.isDateExact(disabledItems[index],unitToEnable)){disabledItems[index]=null 170break}} 171if(isExactRange)for(index=0;index<disabledItemsCount;index+=1){if(calendar.isDateOverlap(disabledItems[index],unitToEnable)){disabledItems[index]=null 172break}} 173if(matchFound){disabledItems.push(matchFound)}})} 174return disabledItems.filter(function(val){return val!=null})} 175DatePicker.prototype.nodes=function(isOpen){var 176calendar=this,settings=calendar.settings,calendarItem=calendar.item,nowObject=calendarItem.now,selectedObject=calendarItem.select,highlightedObject=calendarItem.highlight,viewsetObject=calendarItem.view,disabledCollection=calendarItem.disable,minLimitObject=calendarItem.min,maxLimitObject=calendarItem.max,tableHead=(function(collection,fullCollection){if(settings.firstDay){collection.push(collection.shift()) 177fullCollection.push(fullCollection.shift())} 178return _.node('thead',_.node('tr',_.group({min:0,max:DAYS_IN_WEEK-1,i:1,node:'th',item:function(counter){return[collection[counter],settings.klass.weekdays,'scope=col title="'+fullCollection[counter]+'"']}})))})((settings.showWeekdaysFull?settings.weekdaysFull:settings.weekdaysShort).slice(0),settings.weekdaysFull.slice(0)),createMonthNav=function(next){return _.node('div',' ',settings.klass['nav'+(next?'Next':'Prev')]+((next&&viewsetObject.year>=maxLimitObject.year&&viewsetObject.month>=maxLimitObject.month)||(!next&&viewsetObject.year<=minLimitObject.year&&viewsetObject.month<=minLimitObject.month)?' '+settings.klass.navDisabled:''),'data-nav='+(next||-1)+' '+_.ariaAttr({role:'button',controls:calendar.$node[0].id+'_table'})+' '+'title="'+(next?settings.labelMonthNext:settings.labelMonthPrev)+'"')},createMonthLabel=function(){var monthsCollection=settings.showMonthsShort?settings.monthsShort:settings.monthsFull 179if(settings.selectMonths){return _.node('select',_.group({min:0,max:11,i:1,node:'option',item:function(loopedMonth){return[monthsCollection[loopedMonth],0,'value='+loopedMonth+(viewsetObject.month==loopedMonth?' selected':'')+(((viewsetObject.year==minLimitObject.year&&loopedMonth<minLimitObject.month)||(viewsetObject.year==maxLimitObject.year&&loopedMonth>maxLimitObject.month))?' disabled':'')]}}),settings.klass.selectMonth,(isOpen?'':'disabled')+' '+_.ariaAttr({controls:calendar.$node[0].id+'_table'})+' '+'title="'+settings.labelMonthSelect+'"')} 180return _.node('div',monthsCollection[viewsetObject.month],settings.klass.month)},createYearLabel=function(){var focusedYear=viewsetObject.year,numberYears=settings.selectYears===!0?5:~~(settings.selectYears/2) 181if(numberYears){var 182minYear=minLimitObject.year,maxYear=maxLimitObject.year,lowestYear=focusedYear-numberYears,highe
182stYear=focusedYear+numberYears 183if(minYear>lowestYear){highestYear+=minYear-lowestYear 184lowestYear=minYear} 185if(maxYear<highestYear){var availableYears=lowestYear-minYear,neededYears=highestYear-maxYear 186lowestYear-=availableYears>neededYears?neededYears:availableYears 187highestYear=maxYear} 188return _.node('select',_.group({min:lowestYear,max:highestYear,i:1,node:'option',item:function(loopedYear){return[loopedYear,0,'value='+loopedYear+(focusedYear==loopedYear?' selected':'')]}}),settings.klass.selectYear,(isOpen?'':'disabled')+' '+_.ariaAttr({controls:calendar.$node[0].id+'_table'})+' '+'title="'+settings.labelYearSelect+'"')} 189return _.node('div',focusedYear,settings.klass.year)} 190return _.node('div',(settings.selectYears?createYearLabel()+createMonthLabel():createMonthLabel()+createYearLabel())+createMonthNav()+createMonthNav(1),settings.klass.header)+_.node('table',tableHead+_.node('tbody',_.group({min:0,max:WEEKS_IN_CALENDAR-1,i:1,node:'tr',item:function(rowCounter){var shiftDateBy=settings.firstDay&&calendar.create([viewsetObject.year,viewsetObject.month,1]).day===0?-7:0 191return[_.group({min:DAYS_IN_WEEK*rowCounter-viewsetObject.day+shiftDateBy+1,max:function(){return this.min+DAYS_IN_WEEK-1},i:1,node:'td',item:function(targetDate){targetDate=calendar.create([viewsetObject.year,viewsetObject.month,targetDate+(settings.firstDay?1:0)]) 192var isSelected=selectedObject&&selectedObject.pick==targetDate.pick,isHighlighted=highlightedObject&&highlightedObject.pick==targetDate.pick,isDisabled=disabledCollection&&calendar.disabled(targetDate)||targetDate.pick<minLimitObject.pick||targetDate.pick>maxLimitObject.pick,formattedDate=_.trigger(calendar.formats.toString,calendar,[settings.format,targetDate]) 193return[_.node('div',targetDate.date,(function(klasses){klasses.push(viewsetObject.month==targetDate.month?settings.klass.infocus:settings.klass.outfocus) 194if(nowObject.pick==targetDate.pick){klasses.push(settings.klass.now)} 195if(isSelected){klasses.push(settings.klass.selected)} 196if(isHighlighted){klasses.push(settings.klass.highlighted)} 197if(isDisabled){klasses.push(settings.klass.disabled)} 198return klasses.join(' ')})([settings.klass.day]),'data-pick='+targetDate.pick+' '+_.ariaAttr({role:'gridcell',label:formattedDate,selected:isSelected&&calendar.$node.val()===formattedDate?!0:null,activedescendant:isHighlighted?!0:null,disabled:isDisabled?!0:null})),'',_.ariaAttr({role:'presentation'})]}})]}})),settings.klass.table,'id="'+calendar.$node[0].id+'_table'+'" '+_.ariaAttr({role:'grid',controls:calendar.$node[0].id,readonly:!0}))+_.node('div',_.node('button',settings.today,settings.klass.buttonToday,'type=button data-pick='+nowObject.pick+(isOpen&&!calendar.disabled(nowObject)?'':' disabled')+' '+_.ariaAttr({controls:calendar.$node[0].id}))+_.node('button',settings.clear,settings.klass.buttonClear,'type=button data-clear=1'+(isOpen?'':' disabled')+' '+_.ariaAttr({controls:calendar.$node[0].id}))+_.node('button',settings.close,settings.klass.buttonClose,'type=button data-close=true '+(isOpen?'':' disabled')+' '+_.ariaAttr({controls:calendar.$node[0].id})),settings.klass.footer)} 199DatePicker.defaults=(function(prefix){return{labelMonthNext:'Next month',labelMonthPrev:'Previous month',labelMonthSelect:'Select a month',labelYearSelect:'Select a year',monthsFull:['January','February','March','April','May','June','July','August','September','October','November','December'],monthsShort:['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],weekdaysFull:['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],weekdaysShort:['Sun','Mon','Tue','Wed','Thu','Fri','Sat'],today:'Today',clear:'Clear',close:'Close',closeOnSelect:!0,closeOnClear:!0,format:'d mmmm, yyyy',klass:{table:prefix+'table',header:prefix+'header',navPrev:prefix+'nav--prev',navNext:prefix+'nav--next',navDisabled:prefix+'nav--disabled',month:prefix+'month',year:prefix+'year',selectMonth:prefix+'select--month',selectYear:prefix+'select--year',weekdays:prefix+'weekday',day:prefix+'day',disabled:prefix+'day--disabled',selected:prefix+'day--selected',highlighted:prefix+'day--highlighted',now:prefix+'day--today',infocus:prefix+'day--infocus',outfocus:prefix+'day--outfocus',footer
199:prefix+'footer',buttonClear:prefix+'button--clear',buttonToday:prefix+'button--today',buttonClose:prefix+'button--close'}}})(Picker.klasses().picker+'__') 200Picker.extend('pickadate',DatePicker)}))
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.