/*
Copyright 2012-2026 VeloViewer. All Rights Reserved
###V100###
*/
var KQOMText = typeof(gender) !== 'undefined' && gender == 'F' ? 'QOM' : 'KOM';
var columns = [
    { id: 0, title: 'When', desc: 'When', lngDesc: '', width: 'auto', class: '', field: 's', type: 'date', display: 'date', filterActive: 1, hideZeros: 0, defOrder: 'desc' },
    { id: 1, title: 'Type', desc: 'Activity type', lngDesc: '', width: 'auto', class: '', field: 't', type: 'list', display: 'list', filterActive: 1, hideZeros: 0, defOrder: 'asc' },
    { id: 2, title: 'Name', desc: 'Activity name', lngDesc: '', width: '200px', class: 'clipText', field: 'an', type: 'text', display: 'text', hideZeros: 0, defOrder: 'asc' },
    { id: 3, title: 'City', desc: 'City', lngDesc: '', width: 'auto', class: '', field: 'c', type: 'text', display: 'text', maxLen: 15, hideZeros: 0, defOrder: 'asc' },
    { id: 4, title: 'State', desc: 'State', lngDesc: '', width: 'auto', class: '', field: 'st', type: 'text', display: 'text', maxLen: 15, hideZeros: 0, defOrder: 'asc' },
    { id: 5, title: 'Dist<br/>' + lrgLenUnit, desc: 'Distance ' + lrgLenUnit, lngDesc: '', width: 'auto', class: '', field: 'd', type: 'num', display: 'lLen', filterActive: 1, hideZeros: 0, defOrder: 'desc' },
    { id: 6, title: 'Elv<br/>' + smlLenUnit, desc: 'Elevation gain ' + smlLenUnit, lngDesc: '', width: 'auto', class: '', field: 'eg', type: 'num', display: 'sLen', hideZeros: 0, defOrder: 'desc' },
    { id: 7, title: 'Elapsed<br/>Time', desc: 'Elapsed time', lngDesc: '', width: 'auto', class: '', field: 'et', type: 'num', display: 'lTime', hideZeros: 0, defOrder: 'desc' },
    { id: 8, title: 'Moving<br/>Time', desc: 'Moving time', lngDesc: '', width: 'auto', class: '', field: 'mt', type: 'num', display: 'lTime', hideZeros: 0, defOrder: 'desc' },
    { id: 9, title: 'Speed<br/>' + speedUnit, desc: 'Avg speed ' + speedUnit, lngDesc: '', width: 'auto', class: '', field: 'as', type: 'num', display: 'speed', hideZeros: 1, defOrder: 'desc' },
    { id: 10, title: 'Max<br/>Speed<br/>' + speedUnit, desc: 'Max speed ' + speedUnit, lngDesc: '', width: 'auto', class: '', field: 'ms', type: 'num', display: 'speed', hideZeros: 1, defOrder: 'desc' },
    { id: 11, title: 'Pace<br/>' + lrgPaceUnit, desc: 'Avg pace ' + lrgPaceUnit, lngDesc: 'Average pace for the activity using moving time (i.e. not including stops)', width: 'auto', class: '', field: 'apLrg', type: 'lrgPace', display: 'sTime', hideZeros: 0, defOrder: 'asc' },
    { id: 12, title: 'Max<br/>Pace<br/>' + lrgPaceUnit, desc: 'Max pace ' + lrgPaceUnit, lngDesc: '', width: 'auto', class: '', field: 'mpLrg', type: 'lrgPace', display: 'sTime', hideZeros: 0, defOrder: 'asc' },
    { id: 13, title: 'Pace<br/>' + smlPaceUnit, desc: 'Avg pace ' + smlPaceUnit, lngDesc: 'Average pace for the activity using moving time (i.e. not including stops)', width: 'auto', class: '', field: 'apSml', type: 'smlPace', display: 'sTime', hideZeros: 0, defOrder: 'asc' },
    { id: 14, title: 'Max<br/>Pace<br/>' + smlPaceUnit, desc: 'Max pace ' + smlPaceUnit, lngDesc: '', width: 'auto', class: '', field: 'mpSml', type: 'smlPace', display: 'sTime', hideZeros: 0, defOrder: 'asc' },
    { id: 15, title: 'Pwr<br/>W', desc: 'Avg power W', lngDesc: '', width: 'auto', class: '', field: 'aw', type: 'num', display: 'int', hideZeros: 1, defOrder: 'desc' },
    { id: 73, title: 'Weighted<br/>Avg Pwr<br/>W', desc: 'Weighted avg pwr W', lngDesc: 'Weighted average power', width: 'auto', class: '', field: 'waw', type: 'num', display: 'int', hideZeros: 1, defOrder: 'desc' },
    { id: 99, title: 'Max Pwr<br/>W', desc: 'Maximum pwr', lngDesc: 'Maximum power', width: 'auto', class: '', field: 'mw', type: 'num', display: 'int', hideZeros: 1, defOrder: 'desc' },
    { id: 44, title: 'Power<br/>Meter', desc: 'Power meter', lngDesc: '', width: 'auto', class: '', field: 'hp', type: 'list', display: 'list', hideZeros: 0, defOrder: 'asc' },
    { id: 16, title: 'Cad', desc: 'Cadence average', lngDesc: 'Cadence average', width: 'auto', class: '', field: 'ac', type: 'num', display: 'int', hideZeros: 1, defOrder: 'desc' },
    { id: 17, title: 'Heart', desc: 'Avg heart rate bpm', lngDesc: '', width: 'auto', class: '', field: 'ah', type: 'num', display: 'int', hideZeros: 1, defOrder: 'desc' },
    { id: 18, title: 'Max<br/>Heart', desc: 'Max heart rate bpm', lngDesc: '', width: 'auto', class: '', field: 'mh', type: 'num', display: 'int', hideZeros: 1, defOrder: 'desc' },
    { id: 19, title: 'Elev/Dist<br/>' + smlLenUnit + '/' + lrgLenUnit, desc: 'Elev/dist', lngDesc: '', width: 'auto', class: '', field: 'ed', type: 'num', display: 'sbylLen', hideZeros: 1, defOrder: 'desc' },
    { id: 20, title: 'Elev/Time<br/>' + smlLenUnit + '/h', desc: 'Elev/time', lngDesc: '', width: 'auto', class: '', field: 'elt', type: 'num', display: 'sLenbyTime', hideZeros: 1, defOrder: 'desc' },
    { id: 21, title: 'W/HR', desc: 'Power per heartrate', lngDesc: 'Weighted average power (or just average power if weighted not available) divided by heartrate.', width: 'auto', class: '', field: 'ph', type: 'num', display: '2dp', hideZeros: 1, defOrder: 'desc' },
    { id: 22, title: 'Cal', desc: 'Calories', lngDesc: '', width: 'auto', class: '', field: 'ca', type: 'num', display: 'int', hideZeros: 1, defOrder: 'desc' },
    { id: 23, title: 'Energy<br/>kJ', desc: 'Energy (kJ)', lngDesc: '', width: 'auto', class: '', field: 'k', type: 'num', display: 'int', hideZeros: 1, defOrder: 'desc' },
    { id: 24, title: 'Segs', desc: 'No. of segments', lngDesc: '', width: 'auto', class: '', field: 'segs', type: 'num', display: 'int', hideZeros: 0, defOrder: 'desc' },
    { id: 25, title: 'PRs', desc: 'No. of PRs', lngDesc: '', width: 'auto', class: '', field: 'prs', type: 'num', display: 'int', hideZeros: 0, defOrder: 'desc' },
    { id: 28, title: 'Man', desc: 'Manual', lngDesc: '', width: 'auto', class: '', field: 'm', type: 'list', display: 'list', hideZeros: 0, defOrder: 'asc' },
    { id: 29, title: 'Pri', desc: 'Private', lngDesc: '', width: 'auto', class: '', field: 'p', type: 'list', display: 'list', hideZeros: 0, defOrder: 'asc' },
    { id: 30, title: 'Dist<br/>away<br/>' + lrgLenUnit, desc: 'Distance away', lngDesc: '', width: 'auto', class: '', field: 'startLngLat', type: 'geo', lat: 'lat', lng: 'lng', display: 'lLen', hideZeros: 0, defOrder: 'asc' },
    { id: 35, title: 'Segment PRs (K/QOM positions)', desc: 'Segment PRs', lngDesc: '', width: '450px', class: 'clipText segPRs', field: 'sp', type: 'segPRs', display: 'segPRs', hideZeros: 0, s_s: 1, defOrder: 'desc' },
    { id: 36, title: 'All segments (personal positions)', desc: 'All Segments', lngDesc: '', width: '450px', class: 'clipText segPRs', field: 'sp2', type: 'segPRs', display: 'segPRs', hideZeros: 0, s_s: 1, defOrder: 'desc' },
    { id: 39, title: 'Flagged', desc: 'Flagged', lngDesc: '', width: 'auto', class: '', field: 'f', type: 'list', display: 'list', hideZeros: 0, defOrder: 'asc' },
    { id: 40, title: 'Group<br/>Size', desc: 'Group size', lngDesc: 'How many athletes (including you) in the group for the activity', width: 'auto', class: 'ar', field: 'atc', type: 'num', display: 'int', hideZeros: 0, defOrder: 'asc' },
    { id: 41, title: 'Kudos', desc: 'Kudos count', lngDesc: 'Kudos count', width: 'auto', class: 'ar', field: 'kc', type: 'num', display: 'int', hideZeros: 0, defOrder: 'asc' },
    { id: 42, title: 'Comments', desc: 'Comment count', lngDesc: 'Comment count', width: 'auto', class: 'ar', field: 'cc', type: 'num', display: 'int', hideZeros: 0, defOrder: 'asc' },
    { id: 43, title: 'Gear', desc: 'Gear', lngDesc: 'Gear (bike or shoes)', width: 'auto', class: 'ar', field: 'g', type: 'list', display: 'list', hideZeros: 0, defOrder: 'asc' },
    { id: 47, title: 'Com', desc: 'Commute', lngDesc: '', width: 'auto', class: '', field: 'co', type: 'list', display: 'list', hideZeros: 0, defOrder: 'asc' },
    { id: 48, title: 'Trn', desc: 'Trainer', lngDesc: '', width: 'auto', class: '', field: 'trn', type: 'list', display: 'list', hideZeros: 0, defOrder: 'asc' },
    { id: 50, title: '400m', desc: 'Best 400m', lngDesc: '', width: 'auto', class: '', field: 'b4', type: 'num', display: 'sTime', hideZeros: 1, defOrder: 'asc' },
    { id: 51, title: '1 km', desc: 'Best 1 km', lngDesc: '', width: 'auto', class: '', field: 'b1k', type: 'num', display: 'sTime', hideZeros: 1, defOrder: 'asc' },
    { id: 52, title: '5 km', desc: 'Best 5 km', lngDesc: '', width: 'auto', class: '', field: 'b5k', type: 'num', display: 'sTime', hideZeros: 1, defOrder: 'asc' },
    { id: 53, title: '10 km', desc: 'Best 10 km', lngDesc: '', width: 'auto', class: '', field: 'b10k', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'asc' },
    { id: 54, title: '15 km', desc: 'Best 15 km', lngDesc: '', width: 'auto', class: '', field: 'b15k', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'asc' },
    { id: 55, title: '20 km', desc: 'Best 20 km', lngDesc: '', width: 'auto', class: '', field: 'b20k', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'asc' },
    { id: 56, title: '30 km', desc: 'Best 30 km', lngDesc: '', width: 'auto', class: '', field: 'b30k', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'asc' },
    { id: 57, title: '50 km', desc: 'Best 50 km', lngDesc: '', width: 'auto', class: '', field: 'b50k', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'asc' },
    { id: 58, title: '1/2 Mile', desc: 'Best 1/2 mile', lngDesc: '', width: 'auto', class: '', field: 'bh', type: 'num', display: 'sTime', hideZeros: 1, defOrder: 'asc' },
    { id: 59, title: '1 mile', desc: 'Best 1 mile', lngDesc: '', width: 'auto', class: '', field: 'b1m', type: 'num', display: 'sTime', hideZeros: 1, defOrder: 'asc' },
    { id: 60, title: '2 mile', desc: 'Best 2 mile', lngDesc: '', width: 'auto', class: '', field: 'b2m', type: 'num', display: 'sTime', hideZeros: 1, defOrder: 'asc' },
    { id: 61, title: '10 mile', desc: 'Best 10 miles', lngDesc: '', width: 'auto', class: '', field: 'b10m', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'asc' },
    { id: 62, title: 'Half<br/>Marathon', desc: 'Best half marathon', lngDesc: '', width: 'auto', class: '', field: 'bhm', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'asc' },
    { id: 63, title: 'Marathon', desc: 'Best marathon', lngDesc: '', width: 'auto', class: '', field: 'bmar', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'asc' },
    { id: 64, title: 'Temp<br/>°' + tempUnit, desc: 'Temperature', lngDesc: 'Average temperature.', width: 'auto', class: '', field: 'tm', type: 'num', display: 'int', hideZeros: 0, defOrder: 'asc' },
    { id: 65, title: 'Ride/Run Type', desc: 'Ride/Run type', lngDesc: '', width: 'auto', class: '', field: 'wt', type: 'list', display: 'list', filterActive: 0, hideZeros: 0, defOrder: 'asc' },
    { id: 70, title: 'Description', desc: 'Description', lngDesc: '', width: '350px', class: 'clipText', field: 'd1', type: 'text', display: 'text', hideZeros: 0, defOrder: 'asc' },
    { id: 71, title: 'PR Score<br/>Distribution', desc: 'PR Score Distribution', lngDesc: 'The distribution of your relative PR positions on the segments of this activity. Distribution weighted towards the right is a comparatively good effort, towards the left not so good! Hover over each column for more info.', width: 'auto', class: 'prsDist', field: 'prsDist', type: 'prsDist', display: 'prsDist', hideZeros: 0, s_s: 1, defOrder: 'asc' },
    { id: 72, title: KQOMText+' Score<br/>Distribution', desc: KQOMText+' Score Distribution', lngDesc: 'The distribution of your '+KQOMText+' positions on the segments you PRed of this activity. Distribution weighted towards the right is a comparatively good effort, towards the left not so good! Hover over each column for more info.', width: 'auto', class: 'prsDist', field: 'ksDist', type: 'prsDist', display: 'prsDist', hideZeros: 0, s_s: 1, defOrder: 'asc' },
    { id: 74, title: 'H/R<br/>Zone 1', desc: 'Heart rate zone 1', lngDesc: 'Time in heart rate zone 1.', width: 'auto', class: '', field: 'hz1', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 75, title: 'H/R<br/>Zone 2', desc: 'Heart rate zone 2', lngDesc: 'Time in heart rate zone 2.', width: 'auto', class: '', field: 'hz2', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 76, title: 'H/R<br/>Zone 3', desc: 'Heart rate zone 3', lngDesc: 'Time in heart rate zone 3.', width: 'auto', class: '', field: 'hz3', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 77, title: 'H/R<br/>Zone 4', desc: 'Heart rate zone 4', lngDesc: 'Time in heart rate zone 4.', width: 'auto', class: '', field: 'hz4', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 78, title: 'H/R<br/>Zone 5', desc: 'Heart rate zone 5', lngDesc: 'Time in heart rate zone 5.', width: 'auto', class: '', field: 'hz5', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 79, title: 'Power<br/>0W', desc: 'Power 0W (time)', lngDesc: 'Time at zero watts.', width: 'auto', class: '', field: 'pz1', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 80, title: 'Power<br/>0-50W', desc: 'Power 0-50W (time)', lngDesc: 'Time at 0 to 50 watts.', width: 'auto', class: '', field: 'pz2', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 81, title: 'Power<br/>50-100W', desc: 'Power 50-100W', lngDesc: 'Time at 50 to 100 watts.', width: 'auto', class: '', field: 'pz3', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 82, title: 'Power<br/>100-150W', desc: 'Power 100-150W', lngDesc: 'Time at 100 to 150 watts.', width: 'auto', class: '', field: 'pz4', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 83, title: 'Power<br/>150-200W', desc: 'Power 150-200W', lngDesc: 'Time at 150 to 200 watts.', width: 'auto', class: '', field: 'pz5', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 84, title: 'Power<br/>200-250W', desc: 'Power 200-250W', lngDesc: 'Time at 200 to 250 watts.', width: 'auto', class: '', field: 'pz6', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 85, title: 'Power<br/>250-300W', desc: 'Power 250-300W', lngDesc: 'Time at 250 to 300 watts.', width: 'auto', class: '', field: 'pz7', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 86, title: 'Power<br/>300-350W', desc: 'Power 300-350W', lngDesc: 'Time at 300 to 350 watts.', width: 'auto', class: '', field: 'pz8', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 87, title: 'Power<br/>350-400W', desc: 'Power 350-400W', lngDesc: 'Time at 350 to 400 watts.', width: 'auto', class: '', field: 'pz9', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 88, title: 'Power<br/>400-450W', desc: 'Power 400-450W', lngDesc: 'Time at 400 to 450 watts.', width: 'auto', class: '', field: 'pz10', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 89, title: 'Power<br/>450W+', desc: 'Power 450W+', lngDesc: 'Time above 450 watts.', width: 'auto', class: '', field: 'pz11', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 90, title: 'Relative<br/>Effort', desc: 'Relative Effort', lngDesc: 'Relative Effort', width: 'auto', class: 'ar', field: 'sc', type: 'num', display: 'int', hideZeros: 1, defOrder: 'desc' },
    { id: 91, title: 'Points<br/>in red', desc: 'Points in red', lngDesc: 'Points in the Red is the portion of your Relative Effort that you earned in your Zone 4 and Zone 5 heart rate zones. Points in the Red shows you the intensity of your workout – if your Relative Effort and Points in the Red are the same, you were hammering the entire time!', width: 'auto', class: 'ar', field: 'r', type: 'num', display: 'int', hideZeros: 1, defOrder: 'desc' },
    { id: 92, title: '% in red', desc: 'Percent in red', lngDesc: 'Percentage of Relative Effort in red', width: 'auto', class: 'ar', field: 'prd', type: 'num', display: '1dp', hideZeros: 1, defOrder: 'desc' },
    { id: 93, title: 'Pace<br/>Zone 1', desc: 'Pace zone 1', lngDesc: 'Time in pace zone 1.', width: 'auto', class: '', field: 'pcz1', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 94, title: 'Pace<br/>Zone 2', desc: 'Pace zone 2', lngDesc: 'Time in pace zone 2.', width: 'auto', class: '', field: 'pcz2', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 95, title: 'Pace<br/>Zone 3', desc: 'Pace zone 3', lngDesc: 'Time in pace zone 3.', width: 'auto', class: '', field: 'pcz3', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 96, title: 'Pace<br/>Zone 4', desc: 'Pace zone 4', lngDesc: 'Time in pace zone 4.', width: 'auto', class: '', field: 'pcz4', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 97, title: 'Pace<br/>Zone 5', desc: 'Pace zone 5', lngDesc: 'Time in pace zone 5.', width: 'auto', class: '', field: 'pcz5', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 114, title: 'Pace<br/>Zone 6', desc: 'Pace zone 6', lngDesc: 'Time in pace zone 6.', width: 'auto', class: '', field: 'pcz6', type: 'num', display: 'lTime', hideZeros: 1, defOrder: 'desc' },
    { id: 98, title: 'Day of Week', desc: 'Day of Week', lngDesc: 'Day of Week', width: 'auto', class: '', field: 'dow', type: 'list', display: 'list', hideZeros: 0, defOrder: 'asc' },
    { id: 107, title: 'Start<br/>Time', desc: 'Start time', lngDesc: '', width: 'auto', class: '', field: 'time', type: 'num', display: 'lTime', hideZeros: 0, defOrder: 'asc' },
    { id: 100, title: 'Activity<br/>Score', desc: 'Activity score', lngDesc: 'Score from all segment efforts on the activity compared to all of your previous attempts on those segments.', width: 'auto', class: '', field: 'prScoreFull', type: 'num', display: '2dp', hideZeros: 0, s_s: 1, defOrder: 'desc' },
    { id: 101, title: 'Activity<br/>Score 25%', desc: 'Activity score 25%', lngDesc: 'Score from the top 25% of the segment efforts on the activity compared to all of your previous attempts on those segments.', width: 'auto', class: '', field: 'prScore25', type: 'num', display: '2dp', hideZeros: 0, s_s: 1, defOrder: 'desc' },
    { id: 102, title: 'Training<br/>Load', desc: 'Training load', lngDesc: 'Training load', width: 'auto', class: 'ar', field: 'tl', type: 'num', display: 'int', hideZeros: 1, defOrder: 'desc' },
    { id: 103, title: 'Intensity %', desc: 'Intensity %', lngDesc: 'Intensity', width: 'auto', class: 'ar', field: 'in', type: 'num', display: '1dp', hideZeros: 1, defOrder: 'desc' },
    { id: 104, title: 'Activity Id', desc: 'Activity Id', lngDesc: 'Activity id', width: 'auto', class: 'ar', field: 'ai', type: 'num', display: 'text', hideZeros: 0, defOrder: 'asc' },
    { id: 105, title: 'Speed/HR', desc: 'Speed per heartbeat', lngDesc: 'Average speed by average heart rate', width: 'auto', class: '', field: 'sh', type: 'num', display: '3dp', hideZeros: 1, defOrder: 'desc' },
    { id: 106, title: 'Explorer<br/>Tiles<br/>calculated', desc: 'Explorer Tiles calculated', lngDesc: 'Definitive set of Explorer tiles have been calculated', width: 'auto', class: '', field: 'expSet', type: 'list', display: 'list', hideZeros: 0, defOrder: 'asc' },
    { id: 108, title: 'Device/App', desc: 'Device/App', lngDesc: 'Device/App used to record the data', width: 'auto', class: '', field: 'dv', type: 'list', display: 'list', hideZeros: 0, defOrder: 'asc' },
    { id: 109, title: 'Count', desc: 'Count', lngDesc: 'Used in column chart for activity count values', width: 'auto', class: '', field: 'count', type: 'num', display: 'int', hideZeros: 0, defOrder: 'asc' },
    { id: 110, title: 'Includes segment (id)', desc: 'Includes segment (id)', lngDesc: 'Includes segment', width: 'auto', class: '', field: 'actSegId', type: 'text', display: 'text', hideZeros: 0, defOrder: 'asc' },
    { id: 111, title: 'Elv High<br/>' + smlLenUnit, desc: 'Elevation high ' + smlLenUnit, lngDesc: '', width: 'auto', class: '', field: 'eh', type: 'num', display: 'sLen', hideZeros: 0, defOrder: 'desc' },
    { id: 112, title: 'Elv Low<br/>' + smlLenUnit, desc: 'Elevation low ' + smlLenUnit, lngDesc: '', width: 'auto', class: '', field: 'el', type: 'num', display: 'sLen', hideZeros: 0, defOrder: 'desc' },
    { id: 113, title: 'Perceived<br/>Effort', desc: 'Perceived Effort', lngDesc: 'Perceived Effort 1 - 10 (easy - brutal)', width: 'auto', class: '', field: 'pe', type: 'num', display: 'list', hideZeros: 0, defOrder: 'desc' },
    { id: 115, title: 'Dist start<br/>to end ' + lrgLenUnit, desc: 'Distance start to end', lngDesc: 'The distance between the start and end locations', width: 'auto', class: '', field: 'dsf', type: 'num', display: 'lLen', filterActive: 1, hideZeros: 0, defOrder: 'desc' },
    { id: 116, title: 'Efficiency %', desc: 'Efficiency', lngDesc: 'Efficiency is the moving time divided by the elapsed time as a percentage. 100% means you didn\'t stop, the lower the value the more/longer the stops.', width: 'auto', class: '', field: 'ae', type: 'num', display: '1dp', hideZeros: 1, defOrder: 'desc' },
    { id: 117, title: 'Visibility', desc: 'Visibility', lngDesc: 'Who can view this activity on Strava', width: 'auto', class: '', field: 'v', type: 'list', display: 'list', filterActive: 1, hideZeros: 0, defOrder: 'asc' },
    { id: 118, title: 'Photos', desc: 'Photo count', lngDesc: 'Count of photos on the activity', width: 'auto', class: '', field: 'photosCount', type: 'num', display: 'int', hideZeros: 0, defOrder: 'desc' },
    { id: 119, title: 'Elapsed<br/>Time<br/>Pace<br/>' + lrgPaceUnit, desc: 'Elapsed time pace ' + lrgPaceUnit, lngDesc: 'Average pace for the activity using elapsed time (i.e. including stops)', width: 'auto', class: '', field: 'apEtLrg', type: 'lrgPace', display: 'sTime', hideZeros: 0, defOrder: 'asc' },
    { id: 120, title: 'Sport<br/>Type', desc: 'Sport type', lngDesc: '', width: 'auto', class: '', field: 'spt', type: 'list', display: 'list', filterActive: 1, hideZeros: 0, defOrder: 'asc' },
    { id: 121, title: 'Last<br/>Changed', desc: 'Last changed', lngDesc: 'Date the activity was last changed in Strava', width: 'auto', class: '', field: 'dateLastChanged', type: 'date', display: 'date', filterActive: 1, hideZeros: 0, defOrder: 'desc' },
    { id: 122, title: 'Last<br/>Synced', desc: 'Last synced', lngDesc: 'Date the activity was last synced with VeloViewer (initial upload, updated or checking for new segments)', width: 'auto', class: '', field: 'dateLastChecked', type: 'date', display: 'date', filterActive: 1, hideZeros: 0, defOrder: 'desc' },
    { id: 123, title: 'Month', desc: 'Month', lngDesc: 'Month', width: 'auto', class: '', field: 'month', type: 'list', display: 'list', hideZeros: 0, defOrder: 'asc' },
    { id: 124, title: 'Has Map', desc: 'Has Map', lngDesc: '', width: 'auto', class: '', field: 'hasMap', type: 'list', display: 'list', hideZeros: 0, defOrder: 'asc' },
    { id: 125, title: 'Total<br/>Explorer<br/>Tiles', desc: 'Total number of Explorer Tiles visited by this activity', lngDesc: '', width: 'auto', class: '', field: 'tilesLength', type: 'num', display: 'int', hideZeros: 0, defOrder: 'desc' },
    { id: 126, title: 'New<br/>Explorer<br/>Tiles', desc: 'Total number of New Explorer Tiles visited by this activity (all time, all non-Virtual activities ordered by date)', lngDesc: '', width: 'auto', class: '', field: 'tilesNewLength', type: 'num', display: 'int', hideZeros: 0, defOrder: 'desc' }
    ];
var chartDefX = 0;
var chartDefY = 5;
var chartDefZ = 6;
var chartDefC = 9;
var chartTypeVal = 0;

// runs : 0,1,2,3,5,6,8,11,12,17,18,24,25,30
// rides: 0,1,2,3,5,6,8,9,10,15,17,18,24,25,30

var segAsyncCount = 0,
    actAsyncCount = 0;

var cpref = 'a';
var confCookie = 'acnf';
var mapsRequired = true;
var segsRequired = true;

function getConfigs() {
    var allCols = (s_s ? "72,71,100," : '') + "0,1,120,43,2,5,6,125,126,7,8,107,98,9,10,11,119,12,13,14,15,73,99,44,16,17,18,111,112,116,19,20,21,105,64,22,23,24,25,40,41,42,118,47,48,28,29,117,30,115," + (s_s ? "101,102,103,90,91,92,35,36," : '') + "65,50,51,52,53,54,55,56,57,58,59,60,61,62,63,113,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,93,94,95,96,97,114,39,70,106,108,104,121,122,123,124";
    c = [{
            "id": "3",
            "athleteId": "-1",
            "type": "0",
            "name": "All",
            "colOrder": allCols,
            "dataOrder": "0:1",
            "editable": false,
            "temp": false,
            "filters": "0:-1000000|1000000,1:All,5:-1000000|1000000,6:-1000000|1000000"
        },
        {
            "id": "1",
            "athleteId": "-1",
            "type": "0",
            "name": "Rides",
            "colOrder": (s_s ? "72,71,100," : '') + "0,1,120,43,2,5,6,125,126,8,107,98,9,10,15,73,99,44,16,17,18,24,25,40,30,115," + (s_s ? "101,102,103,90,91,92,35,36," : '') + "74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,39,70",
            "dataOrder": "0:1",
            "editable": false,
            "temp": false,
            "filters": "1:Ride|VirtualRide,5:-1000000|1000000"
        },
        {
            "id": "2",
            "athleteId": "-1",
            "type": "0",
            "name": "Runs",
            "colOrder": (s_s ? "72,71,100," : '') + "0,1,120,43,2,5,6,125,126,8,107,98,11,119,12,16,17,18,105,24,25,30,115,65,50,51,52,53,54,55,56,57,58,59,60,61,62,63,101,35,36,90,91,92,74,75,76,77,78,93,94,95,96,97,114,70",
            "dataOrder": "0:1",
            "editable": false,
            "temp": false,
            "filters": "1:Run|VirtualRun,11:-1000000|1000000"
        }
    ];

    curConfig = getCookie('acnf');
    if (typeof(curConfig) == 'undefined') {
        curConfig = 3;
    }
    var ci = jsonIndexOf(c, 'id', curConfig.toString());

    if (ci == -1) {
        curConfig = 3;
        ci = 0;
    }

    if (window.location.search != '' &&
        ((getParameterByName('f') != '' && c[ci].filters != getParameterByName('f')) ||
            (getParameterByName('o') != '' && c[ci].dataOrder != getParameterByName('o')))) {
        var filters = getParameterByName('f');
        var order = getParameterByName('o');
        customConfig = c.length;
        c.push({
            "id": "4",
            "athleteId": "-1",
            "type": "0",
            "name": "Custom",
            "colOrder": allCols,
            "dataOrder": (order == '' ? "0:1" : order),
            "editable": false,
            "temp": false,
            "filters": filters
        });
        curConfig = 4;
    }

    if (window.location.search != '' && (getParameterByName('c') != '')) {
        var co = getParameterByName('c').split(',').map(function(d) {
            return +d
        });
        if (co.length > 2) {
            chartTypeVal = co[0];
            chartDefX = co[1];
            chartDefY = co[2];
            chartDefZ = (co.length > 3 ? co[3] : 0);
            chartDefC = (co.length > 4 ? co[4] : 0);
        }
    }
}
getConfigs();

function localInit() {
    if (segCacheReady && actCacheReady && segAsyncCount + actAsyncCount == 0) {
        if (typeof(cacheSeg) !== 'undefined' && typeof(cacheAct) !== 'undefined') {
            if ( /*cacheSeg.length > 0 &&*/ cacheAct.length > 0) {
                delete cacheSeg;
                a = cacheAct;
                delete cacheAct;
                var pi = 0;

                for (var i = 0; i < a.length; i++) {
                  a[i].spt = typeof(a[i].spt) !== 'undefined' || a[i].spt == '' ? a[i].spt : 'n/a';
                  a[i].dateLastChecked = new Date(a[i].dc * 1000);
                  a[i].dateLastChanged = parseDateTime(a[i].lc);
                    a[i].time = (a[i].ls ? a[i].ls : a[i].s).substr(-8).toSeconds();
                    a[i].date = parseDateTime(a[i].s, a[i].tz);
                    a[i].apEt = (a[i].d == 0 || a[i].et == 0 ? 0 : (1 / (a[i].d / a[i].et)).round(4));
                    a[i].dow = d3.time.format('%A')(a[i].date);
                    a[i].dowOrd1 = d3.time.format('%w')(a[i].date) - 1;
                    if (a[i].dowOrd1 == -1) a[i].dowOrd1 = 6;
                    a[i].month = d3.time.format('%B')(a[i].date);
                    a[i].monthOrd1 = d3.time.format('%m')(a[i].date).padStart(2, '0');
                    a[i].expSet = typeof(texplorer[a[i].i]) !== 'undefined' ? 1 : 0;
                    a[i].count = 1;
                    a[i].ll1 = decompressN(a[i].map, 5, 2);
                    a[i].ll1 = a[i].ll1.slice(0, a[i].ll1.length / 2).map(function(e, j) {
                        return [a[i].ll1[j * 2], a[i].ll1[j * 2 + 1]]
                    });
                    a[i].dsf = a[i].ll1.length == 0 ? 0 : distLatLon(a[i].ll1[0][0], a[i].ll1[0][1], a[i].ll1.last()[0], a[i].ll1.last()[1]);
                    a[i].ae = a[i].mt == 0 ? 0 : 100 * a[i].mt / a[i].et;
                    a[i].v = a[i].v == 'e' ? 'Everyone' : (a[i].v == 'f' ? 'Followers' : (a[i].v == 'o' ? 'Only you' : 'n/a'));
                    a[i].hasMap = a[i].map == null || a[i].map == '' ? 0 : 1;

                    a[i].photosCount = a[i].photos ? a[i].photos.length : 0;
                    if (a[i].photosCount > 0) {
                        a[i].photos = a[i].photos.filter(function (d) { return d.u != null && d.u.indexOf('placeholder') == -1 });
                      a[i].photosCount = a[i].photos.length;
                    }
                    for (j=0; j<a[i].photosCount; j++) {
                      var o = a[i].photos[j];
                      o.i = pi;
                      o.act = a[i];
                      if (o.l) {
                        o.lat = o.l[0];
                        o.lng = o.l[1];
                      }
                      o.caption = '<a title="View ' + a[i].an.htmlEscape() + ' on Strava" target="_blank" href="http://www.strava.com/activities/' + a[i].ai + '" style="display:inline"><img src="https://' + assetPrefix + '/img/strava_icon.svg" style="height:16px"></a> <a title="View ' + a[i].an.htmlEscape() + ' on VeloViewer" target="_blank" href="/athletes/' + contextAthleteId + '/activities/' + a[i].ai + '" style="display:inline">' + a[i].an + '</a>' + (o.c != '' ? '<br/>' + o.c : '');
                      o.title = a[i].an.htmlEscape() + (o.c != '' ? ' - ' + o.c : '');

                      var s = o.u.match(/([0-9]*)x([0-9]*)\.jpg$/);
                        if (s && typeof (o.v) === 'undefined') {
                        o.x = +s[1];
                        o.y = +s[2];
                        o.u64 = o.u.replace(/[0-9]*x[0-9]*\.jpg$/, Math.floor(o.x / 2 / 2 / 2 / 2 / 2) + 'x' + Math.floor(o.y / 2 / 2 / 2 / 2 / 2) + '.jpg');
                        o.u128 = o.u.replace(/[0-9]*x[0-9]*\.jpg$/, Math.floor(o.x / 2 / 2 / 2 / 2) + 'x' + Math.floor(o.y / 2 / 2 / 2 / 2) + '.jpg');
                        o.u256 = o.u.replace(/[0-9]*x[0-9]*\.jpg$/, Math.floor(o.x / 2 / 2 / 2) + 'x' + Math.floor(o.y / 2 / 2 / 2) + '.jpg');
                        o.u512 = o.u.replace(/[0-9]*x[0-9]*\.jpg$/, Math.floor(o.x / 2 / 2) + 'x' + Math.floor(o.y / 2 / 2) + '.jpg');
                        o.u1024 = o.u.replace(/[0-9]*x[0-9]*\.jpg$/, Math.floor(o.x / 2) + 'x' + Math.floor(o.y / 2) + '.jpg');
                        o.u2048 = o.u;

                        o.thumbnail = isRetinaDisplay() ? o.u128 : o.u64;
                        o.url = isRetinaDisplay() ? o.u1024 : o.u512;
                      } else {
                        // check for video thumbnail
                        s = o.u.match(/width=([0-9]*)\&height=([0-9]*)/);
                        if (s) {
                          o.x = +s[1];
                          o.y = +s[2];
                          o.u64 = o.u.replace(/width=[0-9]*\&height=[0-9]*/, 'width=' + Math.floor(o.x / 2 / 2 / 2 / 2 / 2) + '&height=' + Math.floor(o.y / 2 / 2 / 2 / 2 / 2));
                          o.u128 = o.u.replace(/width=[0-9]*\&height=[0-9]*/, 'width=' + Math.floor(o.x / 2 / 2 / 2 / 2) + '&height=' + Math.floor(o.y / 2 / 2 / 2 / 2));
                          o.u256 = o.u.replace(/width=[0-9]*\&height=[0-9]*/, 'width=' + Math.floor(o.x / 2 / 2 / 2) + '&height=' + Math.floor(o.y / 2 / 2 / 2));
                          o.u512 = o.u.replace(/width=[0-9]*\&height=[0-9]*/, 'width=' + Math.floor(o.x / 2 / 2) + '&height=' + Math.floor(o.y / 2 / 2));
                          o.u1024 = o.u.replace(/width=[0-9]*\&height=[0-9]*/, 'width=' + Math.floor(o.x / 2) + '&height=' + Math.floor(o.y / 2));

                          o.thumbnail = isRetinaDisplay() ? o.u128 : o.u64;
                          o.url = isRetinaDisplay() ? o.u1024 : o.u512;
                          o.videoUrl = o.u2048 = o.v;
                        } else {
                            // cloudfront video with fixed thumbnail image
                            s = o.u.match(/_([0-9]*)x([0-9]*)\./);
                            o.x = +s[1];
                            o.y = +s[2];
                            o.u64 = o.u128 = o.u256 = o.u512 = o.u1024 = o.thumbnail = o.url = o.u;
                            o.videoUrl = o.u2048 = o.v;
                        }
                      }
                      pi++;
                    }
                }

                a.sort(function (a, b) { return a.date - b.date });                
                var newTiles = {};
                a.filter(function (d) {
                    return (typeof (d.map) !== 'undefined' && d.map != null) || typeof (texplorer[d.i]) !== 'undefined'
                }).forEach(function (d) {
                    getActMapTiles(d, explorerZoom, 100);
                    if (['VirtualRide', 'VirtualRun'].indexOf(d.t) == -1) {
                        d.tilesNew = d.tiles.filter(function(e){ return typeof(newTiles[e.x+'-'+e.y]) === 'undefined' });
                        d.tilesNewLength = d.tilesNew.length;
                        d.tilesNew.forEach(function(e){ newTiles[e.x+'-'+e.y] = 1 });
                    } else {
                        d.tilesNew = [];
                    }
                });
                tilesCalculated = true;

                setConfig();
                init();
            } else {
                localStorage.clear();
                alert('Your data doesn\'t appear to be complete! Make sure you\'ve completed at least one, full sync on the update page. If you think all your data is already synced then try refreshing the page. Also make sure that your activities in Strava contain at least one segment.');
            }
        } else {
            localStorage.clear();
            alert('Oh dear, something\'s not gone right. Try refreshing the page (Ctrl+F5 to clear your cache might help) and see if it helps. If you keep seeing this message then let me know.');
        }
    }
}

var s_sNotice = (!s_s ? '<p style="' + (isFree ? 'margin-top:8px;' : '') + '"><b>Important note:</b> Columns related to segment placings are <a href="' + s_sBlogLink + '" target="_blank">only available to Strava Subscribers</a>. VeloViewer users can get a <a href="https://promo.strava.com/veloviewer/" target="_blank">60 day free Strava Premium trial here</a>.</p>' : '');
if (isFree) {
    d3.select('#tourInfo')
        .style('display', null)
        .classed('alert alert-info', true)
        .html('<h4>VeloViewer Tour Notes</h4>' + s_sNotice + '<p style="' + (s_s ? 'margin-top:8px;' : '') + 'font-weight:bold">Restricted to 25 activities for free users. <a href="/update">Upgrade to PRO</a> to see your entire Strava history.</p><p>Your Activities page provides a fully filterable and sortable list of everything you\'ve uploaded to Strava. Filter your data by as many columns, simultaneously, as you wish to find out exactly what you want to know.  Hover your mouse over any column header to get aggregated stats for the currently filtered activities.</p><p>Turn on the "Map" view to see where you\'ve been or more importantly, where you haven\'t!  Turn on the "Filter" option below the map to filter the list by the map\'s current region. Clicking on an activity in the list will zoom the map to that activity.</p><p>Turn on the "Chart" view and try out endless configurations of graphs to further analyse your data.</p><p>Before moving onto another tab it is worth clicking on the name of one of your activities to view the very in-depth <b>Activity Details</b> page and then come back here and move onto your <b>"Segments"</b> to see that all-important list of up-to-date segment placings!</p><p><b>Go to your Update page at any time to <a href="/update">Upgrade to PRO</a> to view your entire Strava history and segments in VeloViewer (and to hide these notes).</b></p>');
} else {
    if (!s_s) {
        d3.select('#tourInfo')
            .style('display', null)
            .classed('alert alert-info', true)
            .html(s_sNotice);
        d3.select('#tourInfo p').style('margin-bottom', '0px');
    }
}
