Increase road label contrast

Increase road label contrast

Fixes stamen/toner#45

@text_font_transport_bold: 'Arial Unicode MS Bold';
@text_font_physical_bold: 'Arial Unicode MS Bold';
@text_font_administrative: 'Arial Unicode MS Regular';
@text_font_administrative_bold: 'Arial Unicode MS Bold';
@text_font_water: 'Arial Unicode MS Italic';
@text_font_water_bold: 'Arial Unicode MS Bold Italic';
@text_font_city: 'Arial Unicode MS Regular';
@text_font_city_bold: 'Arial Unicode MS Bold';
@text_font_poi_bold: 'Arial Unicode MS Bold Italic';

@label_color_transport: #000;
@label_color_transport_halo: #fff;
@label_color_physical: #000;
@label_color_physical_halo: #fff;
@label_color_administrative: #000;
@label_color_administrative_halo: #fff;
@label_color_city: #000;
@label_color_city_halo: #fff;
@label_color_poi: #000;
@label_color_poi_halo: #fff;

@text_font_size_xxsm: 10;
@text_font_size_xsm: 12;
@text_font_size_sm: 13;
@text_font_size_medium: 14;
@text_font_size_medium_plus: 16;
@text_font_size_large: 18;
@text_font_halo_radius_sm: 1;
@text_font_halo_radius_large: 2;

#minor_road_labels {
  text-name: "[name]";
  text-face-name: @text_font_transport_bold;
  text-placement: line;
  text-max-char-angle-delta: 30;
  text-fill: @label_color_transport;
  text-halo-radius: @text_font_halo_radius_sm;
  text-halo-fill: @label_color_transport_halo;
  text-avoid-edges: true;

  [zoom=16] {
    text-dy: 10;
    text-spacing: 124;
    text-size: @text_font_size_xxsm;
    text-halo-radius: @text_font_halo_radius_large;
  }
  [zoom=17] {
    text-dy: 13;
    text-spacing: 180;
    text-size: @text_font_size_xsm;
    text-halo-radius: @text_font_halo_radius_large;
  }
  [zoom>=18] {
    text-size: @text_font_size_xsm;
    text-spacing: 400;
    text-halo-radius: @text_font_halo_radius_large;
  }
}

#major_road_labels {
  text-name: "[name]";
  text-face-name: @text_font_transport_bold;
  text-placement: line;
  text-max-char-angle-delta: 30;
  text-fill: @label_color_transport;
  text-halo-radius: @text_font_halo_radius_sm;
  text-halo-fill: @label_color_transport_halo;
  text-spacing: 100;
  text-avoid-edges: true;

  [zoom>=16][highway='primary'] {
	text-halo-radius: @text_font_halo_radius_large;
  }
  [is_tunnel=1][zoom>=15] {
	text-fill: #777;
  }
  [zoom=12] {
    text-dy: 7;
    text-size: @text_font_size_xsm;
    text-min-distance: 4;
  }
  [zoom=13] {
    text-dy: 8;
    text-min-distance: 5;
    [highway='trunk'] {
		text-size: @text_font_size_sm;
    }
    [highway='primary'] {
		text-size: 13;
    }
  }

  [zoom=14] {
    text-min-distance: 5;
    [highway='trunk'],[highway='primary'] {
		text-dy: 9;
      	text-size: @text_font_size_medium;
    }
    [highway='secondary'] {
		text-dy: 7;
      	text-size: @text_font_size_xsm;
        text-halo-radius: 1.5;
    }
  }

  [zoom=15] {
    text-min-distance: 10;
    [highway='trunk'],[highway='primary'] {
		text-dy: @text_font_size_xsm;
      	text-size: 15;
    }
    [highway='secondary'],[highway='tertiary'] {
		text-dy: 11;
      	text-size: @text_font_size_sm;
    }
  }

  [zoom=16] {
    text-min-distance: 12;
    text-dy: 13;
    [highway='trunk'],[highway='primary'] {
      	text-size: @text_font_size_medium;
    }
    [highway='secondary'],[highway='tertiary'] {
      	text-spacing: 124;
      	text-size: @text_font_size_sm;
      	text-halo-radius: @text_font_halo_radius_large;
    }
  }

  [zoom=17] {
    text-min-distance: 12;
    [highway='trunk'] {
		text-dy: 16;
      	text-size: @text_font_size_medium_plus;
    }
    [highway='primary'] {
		text-dy: 14;
      	text-size: @text_font_size_medium;
    }
    [highway='secondary'] {
		text-dy: 14;
      	text-spacing: 180;
      	text-size: @text_font_size_medium;
      	text-halo-radius: @text_font_halo_radius_large;
    }
    [highway='tertiary'] {
		text-dy: 13;
      	text-spacing: 180;
      	text-size: @text_font_size_xsm;
      	text-halo-radius: @text_font_halo_radius_large;
    }
  }

  [zoom>=18] {
    text-min-distance: 12;
    [highway='trunk'] {
		text-size: @text_font_size_medium_plus;
    }
    [highway='primary'] {
		text-size: @text_font_size_medium;
    }
    [highway='secondary'] {
		text-size: @text_font_size_medium;
		text-spacing: 300;
		text-halo-radius: @text_font_halo_radius_large;
    }
    [highway='tertiary'] {
        text-size: @text_font_size_xsm;
        text-spacing: 400;
      	text-halo-radius: @text_font_halo_radius_large;
    }
  }
}

#poi_station_labels {
  [zoom>=16][railway='station'] {
    shield-name: "[label]";
    shield-face-name: @text_font_transport_bold;
    shield-fill: white;
    shield-size: 12;
    shield-file: url('images/subway_shield_small.svg');
  }
}

#water-bodies-labels-low,
#water-bodies-labels-med,
#water-bodies-labels-high {
  [zoom=9][area>100000000],
  [zoom=10][area>100000000],
  [zoom=11][area>25000000],
  [zoom=12][area>5000000],
  [zoom=13][area>2000000],
  [zoom=14][area>200000],
  [zoom=15][area>50000],
  [zoom=16][area>10000],
  [zoom>=17] {
 	text-name: "[name]";
	text-face-name: @text_font_water;
    text-placement: point;
    text-max-char-angle-delta: 30;
    text-wrap-width: 40;
    text-halo-radius: @text_font_halo_radius_large;
    text-fill: @label_color_physical_halo;
    text-halo-fill: @label_color_physical;
    text-size: @text_font_size_xsm;

    [zoom>9][zoom<12] {
      text-spacing: 200;
      text-wrap-width: 50;
    }
    [zoom=12] {
      text-size: @text_font_size_xsm;
      text-spacing: 200;
      text-wrap-width: 70;
    }
    [zoom=13] {
      text-size: @text_font_size_xsm;
      text-spacing: 100;
      text-wrap-width: 70;
    }
    [zoom=14] {
      text-size: @text_font_size_xsm;
      text-spacing: 100;
      text-wrap-width: 70;
    }
    [zoom>=15] {
      text-size: @text_font_size_sm;
      text-spacing: 100;
      text-wrap-width: 40;
    }
  }
}

#green-areas-labels-low,
#green-areas-labels-med,
#green-areas-labels-high {
  [zoom=9][area>100000000],
  [zoom=10][area>100000000],
  [zoom=11][area>25000000],
  [zoom=12][area>5000000],
  [zoom=13][area>2000000],
  [zoom=14][area>200000],
  [zoom=15][area>50000],
  [zoom=16][area>10000],
  [zoom>=17] {
 	text-name: "[name]";
	text-face-name: @text_font_water;
    text-placement: point;
    text-max-char-angle-delta: 30;
    text-wrap-width: 40;
    text-halo-radius: @text_font_halo_radius_large;

    text-fill: @label_color_physical;
    text-halo-fill: @label_color_physical_halo;

    text-line-spacing: -1;
    text-min-distance: 10;
    text-size: @text_font_size_xsm;

    [zoom>9][zoom<12] {
      text-spacing: 200;
      text-wrap-width: 50;
    }

    [zoom=12] {
      text-size: @text_font_size_xsm;
      text-spacing: 200;
      text-wrap-width: 70;
    }
    [zoom=13] {
      text-size: @text_font_size_xsm;
      text-spacing: 100;
      text-wrap-width: 70;
    }
    [zoom=14] {
      text-size: @text_font_size_xsm;
      text-spacing: 100;
      text-wrap-width: 70;
    }
    [zoom>=15] {
      text-size: @text_font_size_sm;
      text-spacing: 100;
      text-wrap-width: 40;
    }
  }
}

#continents[zoom>=1][zoom<3]
{
  	text-name: "[name]";
    text-face-name: @text_font_physical_bold;
    text-wrap-width: 32;
    text-size: @text_font_size_medium;
    text-fill: @label_color_physical;
    text-halo-radius: 3;
    text-halo-fill: @label_color_physical_halo;
}

#admin1-labels-50m-z4 {
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
    text-name: "[label_z4]";
    text-size:  @text_font_size_xsm;
}

#admin1-labels-50m-z5 {
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
    text-name: "[label_z5]";
    text-size:  @text_font_size_medium_plus;
}

#admin1-labels-50m-z6 {
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
    text-name: "[label_z6]";
    text-size:  @text_font_size_large;
}

#admin1-labels-50m-z7 {
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
    text-name: "[label_z7]";
    text-size:  @text_font_size_large;
}

#admin0-labels-z3[longfrom>3] {
  	text-name: "[shortname]";
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-size: @text_font_size_sm;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
  	text-min-distance: 1;
}

#admin0-labels-z3[longfrom<=3] {
  	text-name: "[name]";
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-size: @text_font_size_sm;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
}

#admin0-labels-z4 {
  	text-name: "[name]";
    text-face-name: @text_font_administrative_bold;
    text-wrap-width: 80;
    text-size: @text_font_size_medium;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
}

#admin0-labels-z5 {
  	text-name: "[name]";
    text-face-name: @text_font_administrative_bold;
    text-wrap-width: 80;
    text-size: @text_font_size_medium_plus;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
}

#admin0-labels-z6 {
  	text-name: "[name]";
    text-face-name: @text_font_administrative_bold;
    text-wrap-width: 80;
    text-size: @text_font_size_large;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
}

// HACK! All the problematic water bodies with accents
// e.g. "Bahia de Campeche" with an accented i,
// have an empty "changed" string. So abuse this for now.

#ne_110m_geography_marine_polys[zoom=2][scalerank=0][changed!=''],
#ne_110m_geography_marine_polys[zoom=3][changed!=''],
#ne_50m_geography_marine_polys[zoom=4][scalerank<4][changed!=''] {
    text-name: "[name]";
	text-face-name: @text_font_water_bold;
    text-wrap-width: 80;
    text-size: @text_font_size_medium;
    text-fill: @label_color_physical_halo;
    text-halo-radius: @text_font_halo_radius_sm;
    text-halo-fill: @label_color_physical;
}

#ne_50m_geography_marine_polys[zoom=5][changed!=''],
#ne_10m_geography_marine_polys[zoom>=6][zoom<=8][changed!='']
{
  	text-name: "[name]";
    text-face-name: @text_font_water;
    text-wrap-width: 80;
    text-size: @text_font_size_medium;
    text-fill: @label_color_physical_halo;
    text-halo-radius: @text_font_halo_radius_sm;
    text-halo-fill: @label_color_physical;
}

#city_labels_z4,
#city_labels_z5,
#city_labels_z6 {
  	text-name: "[name]";
    text-face-name: @text_font_city;
    text-fill: @label_color_city;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_city_halo;
  	text-min-distance: 5;

  	#city_labels_z4 {
      text-size: @text_font_size_xxsm;
      [font_size=14] {
          text-size: @text_font_size_medium;
      }
    }

   	#city_labels_z5 {
      text-size: @text_font_size_xsm;
      [font_size=16] {
          text-size: @text_font_size_medium_plus;
      }
    }

    #city_labels_z6 {
      text-size: @text_font_size_xsm;
      [font_size=18] {
          text-size: @text_font_size_large;
      }
   }

    [justified='left'] {
    	text-horizontal-alignment: middle;
    	text-dx: -5;
    }
    [justified='right'] {
    	text-horizontal-alignment: middle;
    	text-dx: 5;
    }
}

#city_labels_z7,
#city_labels_z8, {
	text-name: "[name]";
    text-face-name: @text_font_city_bold;
    text-fill: @label_color_city;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_city_halo;
	text-size: @text_font_size_sm;
    [font_size=20] { text-size: @text_font_size_large; }

  	#city_labels_z7 {
   	  text-size: @text_font_size_xsm;
      [font_size=18] {
          text-size: @text_font_size_large;
      }
    }

  	[justified='left'] {
    	text-horizontal-alignment: middle;
    	text-dx: -5;
    }
    [justified='right'] {
    	text-horizontal-alignment: middle;
    	text-dx: 5;
    }
}

#city_labels_z9,
#city_labels_z10,
#city_labels_z11,
#city_labels_z12, {
  	text-name: "[name]";
    text-face-name: @text_font_city_bold;
    text-fill: @label_color_city;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_city_halo;
	text-size: @text_font_size_sm;
    [font_size=20] { text-size: @text_font_size_large; }
}

#city_points_z4,
#city_points_z5,
#city_points_z6,
#city_points_z7,
#city_points_z8 {
  	marker-ignore-placement: true;
  	marker-width: 7;
  	marker-fill: black;
  	marker-line-color: white;
  	marker-line-width: 2;
}

#airports[zoom>=10][zoom<=13] {
    marker-width: 18;
	marker-file: url('images/airplane.svg');
}

#airports[zoom>=13][scalerank<=12]
{
  	text-name: "[name]";
    text-face-name: @text_font_poi_bold;
    text-fill: @label_color_poi;
    text-size: @text_font_size_medium;
    text-halo-fill: @label_color_poi_halo;
    text-halo-radius: @text_font_halo_radius_large;
    text-wrap-width: 128;
    text-dy: 14;
    text-allow-overlap: true;

  	[zoom>=14] {
    	text-dy: 0;
    }
}

@text_font_transport_bold: 'Arial Unicode MS Bold';
@text_font_physical_bold: 'Arial Unicode MS Bold';
@text_font_administrative: 'Arial Unicode MS Regular';
@text_font_administrative_bold: 'Arial Unicode MS Bold';
@text_font_water: 'Arial Unicode MS Italic';
@text_font_water_bold: 'Arial Unicode MS Bold Italic';
@text_font_city: 'Arial Unicode MS Regular';
@text_font_city_bold: 'Arial Unicode MS Bold';
@text_font_poi_bold: 'Arial Unicode MS Bold Italic';

@label_color_transport: #000;
@text_font_halo_radius_sm: 1;
@label_color_transport_halo: #fff;
@label_color_physical: #000;
@label_color_physical_halo: #fff;
@label_color_administrative: #000;
@label_color_administrative_halo: #fff;
@label_color_city: #000;
@label_color_city_halo: #fff;
@label_color_poi: #000;
@label_color_poi_halo: #fff;

@text_font_size_xxsm: 10;
@text_font_size_xsm: 12;
@text_font_size_sm: 13;
@text_font_size_medium: 14;
@text_font_size_medium_plus: 16;
@text_font_size_large: 18;
@text_font_halo_radius_large: 2;

#minor_road_labels {
  text-name: "[name]";
  text-face-name: @text_font_transport_bold;
  text-placement: line;
  text-max-char-angle-delta: 30;
  text-fill: @label_color_transport;
  text-halo-radius: @text_font_halo_radius_sm;
  text-halo-fill: @label_color_transport_halo;
  text-avoid-edges: true;

  [zoom=16] {
    text-dy: 10;
    text-spacing: 124;
    text-size: @text_font_size_xxsm;
    text-halo-radius: @text_font_halo_radius_large;
  }
  [zoom=17] {
    text-dy: 13;
    text-spacing: 180;
    text-size: @text_font_size_xsm;
    text-halo-radius: @text_font_halo_radius_large;
  }
  [zoom>=18] {
    text-size: @text_font_size_xsm;
    text-spacing: 400;
    text-halo-radius: @text_font_halo_radius_large;
  }
}

#major_road_labels {
  text-name: "[name]";
  text-face-name: @text_font_transport_bold;
  text-placement: line;
  text-max-char-angle-delta: 30;
  text-fill: @label_color_transport;
  text-halo-radius: @text_font_halo_radius_sm;
  text-halo-fill: @label_color_transport_halo;
  text-spacing: 100;
  text-avoid-edges: true;

  [zoom>=16][highway='primary'] {
	text-halo-radius: @text_font_halo_radius_large;
  }
  [is_tunnel=1][zoom>=15] {
	text-fill: #777;
  }
  [zoom=12] {
    text-dy: 7;
    text-size: @text_font_size_xsm;
    text-min-distance: 4;
  }
  [zoom=13] {
    text-dy: 8;
    text-min-distance: 5;
    [highway='trunk'] {
		text-size: @text_font_size_sm;
    }
    [highway='primary'] {
		text-size: 13;
    }
  }

  [zoom=14] {
    text-min-distance: 5;
    [highway='trunk'],[highway='primary'] {
		text-dy: 9;
      	text-size: @text_font_size_medium;
    }
    [highway='secondary'] {
		text-dy: 7;
      	text-size: @text_font_size_xsm;
    }
  }

  [zoom=15] {
    text-min-distance: 10;
    [highway='trunk'],[highway='primary'] {
		text-dy: @text_font_size_xsm;
      	text-size: 15;
    }
    [highway='secondary'],[highway='tertiary'] {
		text-dy: 11;
      	text-size: @text_font_size_sm;
    }
  }

  [zoom=16] {
    text-min-distance: 12;
    text-dy: 13;
    [highway='trunk'],[highway='primary'] {
      	text-size: @text_font_size_medium;
    }
    [highway='secondary'],[highway='tertiary'] {
      	text-spacing: 124;
      	text-size: @text_font_size_sm;
      	text-halo-radius: @text_font_halo_radius_large;
    }
  }

  [zoom=17] {
    text-min-distance: 12;
    [highway='trunk'] {
		text-dy: 16;
      	text-size: @text_font_size_medium_plus;
    }
    [highway='primary'] {
		text-dy: 14;
      	text-size: @text_font_size_medium;
    }
    [highway='secondary'] {
		text-dy: 14;
      	text-spacing: 180;
      	text-size: @text_font_size_medium;
      	text-halo-radius: @text_font_halo_radius_large;
    }
    [highway='tertiary'] {
		text-dy: 13;
      	text-spacing: 180;
      	text-size: @text_font_size_xsm;
      	text-halo-radius: @text_font_halo_radius_large;
    }
  }

  [zoom>=18] {
    text-min-distance: 12;
    [highway='trunk'] {
		text-size: @text_font_size_medium_plus;
    }
    [highway='primary'] {
		text-size: @text_font_size_medium;
    }
    [highway='secondary'] {
		text-size: @text_font_size_medium;
		text-spacing: 300;
		text-halo-radius: @text_font_halo_radius_large;
    }
    [highway='tertiary'] {
        text-size: @text_font_size_xsm;
        text-spacing: 400;
      	text-halo-radius: @text_font_halo_radius_large;
    }
  }
}

#poi_station_labels {
  [zoom>=16][railway='station'] {
    shield-name: "[label]";
    shield-face-name: @text_font_transport_bold;
    shield-fill: white;
    shield-size: 12;
    shield-file: url('images/subway_shield_small.svg');
  }
}

#water-bodies-labels-low,
#water-bodies-labels-med,
#water-bodies-labels-high {
  [zoom=9][area>100000000],
  [zoom=10][area>100000000],
  [zoom=11][area>25000000],
  [zoom=12][area>5000000],
  [zoom=13][area>2000000],
  [zoom=14][area>200000],
  [zoom=15][area>50000],
  [zoom=16][area>10000],
  [zoom>=17] {
 	text-name: "[name]";
	text-face-name: @text_font_water;
    text-placement: point;
    text-max-char-angle-delta: 30;
    text-wrap-width: 40;
    text-halo-radius: @text_font_halo_radius_large;
    text-fill: @label_color_physical_halo;
    text-halo-fill: @label_color_physical;
    text-size: @text_font_size_xsm;

    [zoom>9][zoom<12] {
      text-spacing: 200;
      text-wrap-width: 50;
    }
    [zoom=12] {
      text-size: @text_font_size_xsm;
      text-spacing: 200;
      text-wrap-width: 70;
    }
    [zoom=13] {
      text-size: @text_font_size_xsm;
      text-spacing: 100;
      text-wrap-width: 70;
    }
    [zoom=14] {
      text-size: @text_font_size_xsm;
      text-spacing: 100;
      text-wrap-width: 70;
    }
    [zoom>=15] {
      text-size: @text_font_size_sm;
      text-spacing: 100;
      text-wrap-width: 40;
    }
  }
}

#green-areas-labels-low,
#green-areas-labels-med,
#green-areas-labels-high {
  [zoom=9][area>100000000],
  [zoom=10][area>100000000],
  [zoom=11][area>25000000],
  [zoom=12][area>5000000],
  [zoom=13][area>2000000],
  [zoom=14][area>200000],
  [zoom=15][area>50000],
  [zoom=16][area>10000],
  [zoom>=17] {
 	text-name: "[name]";
	text-face-name: @text_font_water;
    text-placement: point;
    text-max-char-angle-delta: 30;
    text-wrap-width: 40;
    text-halo-radius: @text_font_halo_radius_large;

    text-fill: @label_color_physical;
    text-halo-fill: @label_color_physical_halo;

    text-line-spacing: -1;
    text-min-distance: 10;
    text-size: @text_font_size_xsm;

    [zoom>9][zoom<12] {
      text-spacing: 200;
      text-wrap-width: 50;
    }

    [zoom=12] {
      text-size: @text_font_size_xsm;
      text-spacing: 200;
      text-wrap-width: 70;
    }
    [zoom=13] {
      text-size: @text_font_size_xsm;
      text-spacing: 100;
      text-wrap-width: 70;
    }
    [zoom=14] {
      text-size: @text_font_size_xsm;
      text-spacing: 100;
      text-wrap-width: 70;
    }
    [zoom>=15] {
      text-size: @text_font_size_sm;
      text-spacing: 100;
      text-wrap-width: 40;
    }
  }
}

#continents[zoom>=1][zoom<3]
{
  	text-name: "[name]";
    text-face-name: @text_font_physical_bold;
    text-wrap-width: 32;
    text-size: @text_font_size_medium;
    text-fill: @label_color_physical;
    text-halo-radius: 3;
    text-halo-fill: @label_color_physical_halo;
}

#admin1-labels-50m-z4 {
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
    text-name: "[label_z4]";
    text-size:  @text_font_size_xsm;
}

#admin1-labels-50m-z5 {
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
    text-name: "[label_z5]";
    text-size:  @text_font_size_medium_plus;
}

#admin1-labels-50m-z6 {
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
    text-name: "[label_z6]";
    text-size:  @text_font_size_large;
}

#admin1-labels-50m-z7 {
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
    text-name: "[label_z7]";
    text-size:  @text_font_size_large;
}

#admin0-labels-z3[longfrom>3] {
  	text-name: "[shortname]";
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-size: @text_font_size_sm;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
  	text-min-distance: 1;
}

#admin0-labels-z3[longfrom<=3] {
  	text-name: "[name]";
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-size: @text_font_size_sm;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
}

#admin0-labels-z4 {
  	text-name: "[name]";
    text-face-name: @text_font_administrative_bold;
    text-wrap-width: 80;
    text-size: @text_font_size_medium;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
}

#admin0-labels-z5 {
  	text-name: "[name]";
    text-face-name: @text_font_administrative_bold;
    text-wrap-width: 80;
    text-size: @text_font_size_medium_plus;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
}

#admin0-labels-z6 {
  	text-name: "[name]";
    text-face-name: @text_font_administrative_bold;
    text-wrap-width: 80;
    text-size: @text_font_size_large;
    text-fill: @label_color_administrative;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_administrative_halo;
}

// HACK! All the problematic water bodies with accents
// e.g. "Bahia de Campeche" with an accented i,
// have an empty "changed" string. So abuse this for now.

#ne_110m_geography_marine_polys[zoom=2][scalerank=0][changed!=''],
#ne_110m_geography_marine_polys[zoom=3][changed!=''],
#ne_50m_geography_marine_polys[zoom=4][scalerank<4][changed!=''] {
    text-name: "[name]";
	text-face-name: @text_font_water_bold;
    text-wrap-width: 80;
    text-size: @text_font_size_medium;
    text-fill: @label_color_physical_halo;
    text-halo-radius: @text_font_halo_radius_sm;
    text-halo-fill: @label_color_physical;
}

#ne_50m_geography_marine_polys[zoom=5][changed!=''],
#ne_10m_geography_marine_polys[zoom>=6][zoom<=8][changed!='']
{
  	text-name: "[name]";
    text-face-name: @text_font_water;
    text-wrap-width: 80;
    text-size: @text_font_size_medium;
    text-fill: @label_color_physical_halo;
    text-halo-radius: @text_font_halo_radius_sm;
    text-halo-fill: @label_color_physical;
}

#city_labels_z4,
#city_labels_z5,
#city_labels_z6 {
  	text-name: "[name]";
    text-face-name: @text_font_city;
    text-fill: @label_color_city;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_city_halo;
  	text-min-distance: 5;

  	#city_labels_z4 {
      text-size: @text_font_size_xxsm;
      [font_size=14] {
          text-size: @text_font_size_medium;
      }
    }

   	#city_labels_z5 {
      text-size: @text_font_size_xsm;
      [font_size=16] {
          text-size: @text_font_size_medium_plus;
      }
    }

    #city_labels_z6 {
      text-size: @text_font_size_xsm;
      [font_size=18] {
          text-size: @text_font_size_large;
      }
   }

    [justified='left'] {
    	text-horizontal-alignment: middle;
    	text-dx: -5;
    }
    [justified='right'] {
    	text-horizontal-alignment: middle;
    	text-dx: 5;
    }
}

#city_labels_z7,
#city_labels_z8, {
	text-name: "[name]";
    text-face-name: @text_font_city_bold;
    text-fill: @label_color_city;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_city_halo;
	text-size: @text_font_size_sm;
    [font_size=20] { text-size: @text_font_size_large; }

  	#city_labels_z7 {
   	  text-size: @text_font_size_xsm;
      [font_size=18] {
          text-size: @text_font_size_large;
      }
    }

  	[justified='left'] {
    	text-horizontal-alignment: middle;
    	text-dx: -5;
    }
    [justified='right'] {
    	text-horizontal-alignment: middle;
    	text-dx: 5;
    }
}

#city_labels_z9,
#city_labels_z10,
#city_labels_z11,
#city_labels_z12, {
  	text-name: "[name]";
    text-face-name: @text_font_city_bold;
    text-fill: @label_color_city;
    text-halo-radius: @text_font_halo_radius_large;
    text-halo-fill: @label_color_city_halo;
	text-size: @text_font_size_sm;
    [font_size=20] { text-size: @text_font_size_large; }
}

#city_points_z4,
#city_points_z5,
#city_points_z6,
#city_points_z7,
#city_points_z8 {
  	marker-ignore-placement: true;
  	marker-width: 7;
  	marker-fill: black;
  	marker-line-color: white;
  	marker-line-width: 2;
}

#airports[zoom>=10][zoom<=13] {
    marker-width: 18;
	marker-file: url('images/airplane.svg');
}

#airports[zoom>=13][scalerank<=12]
{
  	text-name: "[name]";
    text-face-name: @text_font_poi_bold;
    text-fill: @label_color_poi;
    text-size: @text_font_size_medium;
    text-halo-fill: @label_color_poi_halo;
    text-halo-radius: @text_font_halo_radius_large;
    text-wrap-width: 128;
    text-dy: 14;
    text-allow-overlap: true;

  	[zoom>=14] {
    	text-dy: 0;
    }
}


Proper defaults for output file name and folder

function Run() {
    //$module(Run.mss)

    // do some preliminary checks
    if (Sibelius.ProgramVersion < 7000)
    {
        Sibelius.MessageBox(_VersionNotSupported);
        return False;
    }

    if (Sibelius.ScoreCount = 0)
    {
        Sibelius.MessageBox(_ScoreError);
        return False;
    }

    // get the active score object
    activeScore = Sibelius.ActiveScore;

    if (Sibelius.FileExists(activeScore.FileName)) {
        scoreFile = Sibelius.GetFile(activeScore.FileName);
        activeFileName = scoreFile.NameNoPath & '.mei';
        activePath = scoreFile.Path;
    } else {
        activeFileName = 'untitled.mei';
        activePath = Sibelius.GetDocumentsFolder();
    }

    if (not InitGlobals(null))
    {
        return false;
    }

    // Ask to the file to be saved somewhere
    filename = Sibelius.SelectFileToSave('Save as...', activeFileName, activePath, 'mei', 'TEXT', 'Music Encoding Initiative');

    if (filename = null)
    {
        Sibelius.MessageBox(_ExportFileIsNull);
        return False;
    }

    DoExport(filename);

}  //$end

function DoExport (filename) {
    //$module(Run.mss)

    if (not Self._property:_Initialized)
    {
        Trace('InitGlobals() must be called before running DoExport()');
        return null;
    }

    // first, ensure we're running with a clean slate.
    // (initialization of libmei has moved to InitGlobals())
    libmei.destroy();

    // set the active score here so we can refer to it throughout the plugin
    Self._property:ActiveScore = Sibelius.ActiveScore;
    if (Self._property:ActiveScore = null)
    {
        Sibelius.MessageBox('Could not find an active score. Cannot export to ' & filename);
        return false;
    }

    // Set up the warnings tracker
    Self._property:warnings = CreateSparseArray();

    // Deal with the Progress GUI
    progCount = Sibelius.ActiveScore.SystemStaff.BarCount;
    fn = utils.ExtractFileName(filename);
    progressTitle = utils.Format(_InitialProgressTitle, fn);
    Sibelius.CreateProgressDialog(progressTitle, 0, progCount - 1);

    // finally, process the score.
    ProcessScore();

    doc = libmei.getDocument();
    // save the file
    export_status = libmei.meiDocumentToFile(doc, filename);

    // start cleaning up.
    Sibelius.DestroyProgressDialog();

    // display the warnings that were registered during the export process
    for each warning in Self._property:warnings
    {
        trace('Warning: ' & warning);
    }

    if (export_status = False)
    {
        Sibelius.MessageBox(_ExportFailure);
    }

    // clean up after ourself
    libmei.destroy();
}  //$end

function Run() {
    //$module(Run.mss)

    // do some preliminary checks
    if (Sibelius.ProgramVersion < 7000)
    {
        Sibelius.MessageBox(_VersionNotSupported);
        return False;
    }

    if (Sibelius.ScoreCount = 0)
    {
        Sibelius.MessageBox(_ScoreError);
        return False;
    }

    // get the active score object
    activeScore = Sibelius.ActiveScore;

    // it does not seem possible to get the current folder for the file
    // so we will default to the user's documents folder.
    // NB: it seems that if we don't specify a folder name, the filename
    // is not properly set.
    activeFileNameFull = activeScore.FileName;
    activeFileName = utils.ExtractFileName(activeFileNameFull);
    activePath = Sibelius.GetDocumentsFolder();

    if (not InitGlobals(null))
    {
        return false;
    }

    // Ask to the file to be saved somewhere
    filename = Sibelius.SelectFileToSave('Save as...', activeFileName, activePath, 'mei', 'TEXT', 'Music Encoding Initiative');

    if (filename = null)
    {
        Sibelius.MessageBox(_ExportFileIsNull);
        return False;
    }

    DoExport(filename);

}  //$end

function DoExport (filename) {
    //$module(Run.mss)

    if (not Self._property:_Initialized)
    {
        Trace('InitGlobals() must be called before running DoExport()');
        return null;
    }

    // first, ensure we're running with a clean slate.
    // (initialization of libmei has moved to InitGlobals())
    libmei.destroy();

    // set the active score here so we can refer to it throughout the plugin
    Self._property:ActiveScore = Sibelius.ActiveScore;
    if (Self._property:ActiveScore = null)
    {
        Sibelius.MessageBox('Could not find an active score. Cannot export to ' & filename);
        return false;
    }

    // Set up the warnings tracker
    Self._property:warnings = CreateSparseArray();

    // Deal with the Progress GUI
    progCount = Sibelius.ActiveScore.SystemStaff.BarCount;
    fn = utils.ExtractFileName(filename);
    progressTitle = utils.Format(_InitialProgressTitle, fn);
    Sibelius.CreateProgressDialog(progressTitle, 0, progCount - 1);

    // finally, process the score.
    ProcessScore();

    doc = libmei.getDocument();
    // save the file
    export_status = libmei.meiDocumentToFile(doc, filename);

    // start cleaning up.
    Sibelius.DestroyProgressDialog();

    // display the warnings that were registered during the export process
    for each warning in Self._property:warnings
    {
        trace('Warning: ' & warning);
    }

    if (export_status = False)
    {
        Sibelius.MessageBox(_ExportFailure);
    }

    // clean up after ourself
    libmei.destroy();
}  //$end


Update ConvertDate to use built-in time format

function ConvertClef (clefid) {
    //$module(ExportConverters.mss)
    clefparts = MSplitString(clefid, '.');
    shape = ' ';
    line = ' ';
    dis = ' ';
    dir = ' ';

    switch(clefparts[2])
    {
        case ('down')
        {
            dir = 'below';
        }
        case ('up')
        {
            dir = 'above';
        }
    }

    switch(clefparts[3])
    {
        case ('8')
        {
            dis = '8';
        }
        case ('15')
        {
            dis = '15';
        }
    }
    switch (clefparts[1]) {
        case ('bass')
        {
            shape = 'F';
            line = '4';
        }
        case ('treble')
        {
            if (clefparts[4] = 'old')
            {
                shape = 'GG';
            }
            else
            {
                shape = 'G';
            }
            line = '2';
        }
        case ('tenor')
        {
            shape = 'C';
            line = '4';
        }
        case ('alto')
        {
            shape = 'C';
            line = '3';
        }
        case ('soprano')
        {
            shape = 'C';
            if (clefparts[2] = 'mezzo')
            {
                line = '2';
            }
            else
            {
                line = '1';
            }
        }
        case ('baritone')
        {
            if (clefparts[2] = 'c')
            {
                shape = 'C';
                line = '5';
            }
            else
            {
                shape = 'F';
                line = '3';
            }
        }
        case ('violin')
        {
            shape = 'G';
            line = '1';
        }
        case ('sub-bass')
        {
            shape = 'F';
            line = '5';
        }
        case ('tab')
        {
            shape = 'TAB';
        }
        case (('percussion') or ('percussion_2'))
        {
            shape = 'perc';
        }
    }
    ret = CreateSparseArray(shape, line, dis, dir);
    return ret;
}  //$end

function ConvertOctava (octava_id) {
    //$module(ExportConverters.mss)
    octparts = MSplitString(octava_id, '.');
    switch(octparts[3])
    {
        case ('minus15')
        {
            dis = '15';
            place = 'below';
        }
        case ('minus8')
        {
            dis = '8';
            place = 'below';
        }
        case ('plus15')
        {
            dis = '15';
            place = 'above';
        }
        case ('plus8')
        {
            dis = '8';
            place = 'above';
        }
        default
        {
            dis = ' ';
            place = ' ';
        }
    }
    return CreateSparseArray(dis, place);
}  //$end

function ConvertSlur (slur_value) {
    //$module(ExportConverters.mss)
    slurparts = MSplitString(slur_value, '.');
    direction = ' ';
    style = ' ';
    switch(slurparts[3])
    {
        case ('up')
        {
            direction = 'above';
        }
        case ('down')
        {
            direction = 'below';
        }
        default
        {
            direction = ' ';
        }
    }
    switch(slurparts[4])
    {
        case ('dashed')
        {
            style = 'dashed';
        }
        case ('dotted')
        {
            style = 'dotted';
        }
        default
        {
            style = ' ';
        }
    }
    return CreateSparseArray(direction, style);
}  //$end

function ConvertDiatonicPitch (diatonic_pitch) {
    //$module(ExportConverters)
    octv = (diatonic_pitch / 7) - 1;
    pnames = CreateSparseArray('c', 'd', 'e', 'f', 'g', 'a', 'b');
    idx = (diatonic_pitch % 7);
    pname = pnames[idx];

    return CreateSparseArray(pname, octv);
}  //$end

function ConvertOffsets (offset) {
    //$module(ExportConverters.mss)

    /*
     This function will convert the 1/32 unit
     Sibelius offsets into a millimeter measurement as required by the
     data.MEASUREMENT datatype used by MEI.

    Most offsets are given in Sibelius Units, which
    are defined as 1/32 of a space. A space is 1/4 of the staff height
    set at 128. For real world calculations, then, a unit is:
    ((staffheight / 4) / 32).

    The `StaffHeight` property always returns the staff height in millimeters.

    So a staff height of 7mm (default) gives us (7/4 = 1.75) / 32 = 0.05mm per Sibelius
    Unit.
    */
    scr = Sibelius.ActiveScore;
    staffheight = scr.StaffHeight;
    factor = (((staffheight & '.0') / 4.0) / 32.0);
    oset = factor * offset;
    retval = oset & 'mm';
    return retval;
}  //$end

function ConvertDuration (dur) {
    //$module(ExportConverters.mss)
    // there doesn't really seem to be a smarter way to do this...
    // 1024 = 1 whole note

    ret = CreateSparseArray();

    pow = PrevPow2(dur);
    counter = pow;
    dots = 0;
    powcount = pow;
    durset = false;

    durrem = 1024 % dur;
    if (durrem != 0)
    {
        while (counter < dur)
        {
            powcount = (powcount / 2);
            counter = counter + powcount;
            dots = dots + 1;

            if (dots > 5)
            {
                // prevent a runaway loop.
                counter = 1000000000;
            }
        }
    }

    switch (powcount)
    {
        case (pow >= 4096)
        {
            ret[0] = 'long';
            durset = true;
        }
        case (pow >= 2048)
        {
            ret[0] = 'breve';
            durset = true;
        }
        default
        {
            if (durset = false)
            {
                ret[0] = 1024 / pow;
            }
        }
    }

    if (dots = 0)
    {
        ret[1] = ' ';
    }
    else
    {
        ret[1] = dots;
    }

    return ret;
}  //$end

function ConvertKeySignature (numsharps) {
    //$module(ExportConverters.mss)
    switch (numsharps)
    {
        case (0)
        {
            // key of c
            return '0';
        }
        case (-8)
        {
            // atonal in Sibelius
            return '0';
        }
        case (numsharps > 0)
        {
            // sharps
            return numsharps & 's';
        }
        case (numsharps < 0)
        {
            //flats
            return utils.AbsoluteValue(numsharps) & 'f';
        }
    }
}  //$end

function PitchesInKeySignature (keysig) {
    //$module(ExportConverters.mss)

    // keysig is 7 >= 0 >= -7, for the number of sharps (negative is flats)
    ac = CreateSparseArray('F', 'C', 'G', 'D', 'A', 'E', 'B');
    if (keysig = 0)
    {
        return CreateSparseArray();
    }

    if (keysig > 0)
    {
        return ac.Slice(0, keysig);
    }
    else
    {
        v = ac.Slice(keysig);
        v.Reverse();
        return v;
    }
}  //$end

function ConvertAccidental (noteobj) {
    //$module(ExportConverters.mss)
    // If accidentals are audible, but not visible, you get @accid.ges
    // If accidentals are both audible and visible, you get @accid
    // is_visible is not to be confused with hidden accidentals! is_visible
    // just determines whether an accidental is shown or not based on
    // the rules of CMN.

    // Returns a tuple [0 => accid (string), 1 => is_visible (bool)]
    // If the accidental is a natural and is visible, returns ('n', true); otherwise,
    // it returns ('', false);

    // first, determine if the accidental is visible.
    is_visible = HasVisibleAccidental(noteobj);
    ac = ' ';

    pname = Substring(noteobj.Name, 0, 1);  // captures first letter
    accid = Substring(noteobj.Name, 1);     // captures all other characters

    switch(accid)
    {
        case('bb')
        {
            ac = 'ff';
        }
        case('b-')
        {
            ac = 'fd';
        }
        case('b')
        {
            ac = 'f';
        }
        case('-')
        {
            ac = 'fu';
        }
        case('')
        {
            if (is_visible = True)
            {
                ac = 'n';
            }
        }
        case('+')
        {
            ac = 'sd';
        }
        case('#')
        {
            ac = 's';
        }
        case('#+')
        {
            ac = 'su';
        }
        case('x')
        {
            ac = 'x';
        }
        case('##')
        {
            ac = 'ss';
        }
    }

    ret = CreateSparseArray(ac, is_visible);
    return ret;
}  //$end

function HasVisibleAccidental (noteobj) {
    //$module(ExportConverters.mss)
    // determines whether a note is *likely* to have a visible accidental.
    // Caution: This is probably not 100% accurate.

    // Returns a boolean if the note is visible.

    // If it has a cautionary accidental, it's most likely to be visible.
    if (noteobj.AccidentalStyle = CautionaryAcc)
    {
        return True;
    }

    if (noteobj.AccidentalStyle = HiddenAcc)
    {
        return False;
    }

    keysig = noteobj.ParentNoteRest.ParentBar.GetKeySignatureAt(noteobj.ParentNoteRest.Position);
    sf = sibmei2.PitchesInKeySignature(keysig.Sharps);
    pname = Substring(noteobj.Name, 0, 1);  // captures first letter
    accid = Substring(noteobj.Name, 1);  // captures all other characters

    // if the note is not in the key signature, then it should have an accidental
    note_is_in_keysig = utils.IsInArray(sf, pname);
    has_prev_pitch_with_accidental = False;

    parent_nr = noteobj.ParentNoteRest;
    parent_bar = parent_nr.ParentBar;

    for each NoteRest nr in parent_bar
    {
        if (nr.Position < parent_nr.Position)
        {
            for each n in nr
            {
                pname2 = Substring(n.Name, 0, 1);  // captures first letter
                accid2 = Substring(n.Name, 1);  // captures all other characters

                if (n.Name = noteobj.Name and note_is_in_keysig = False and n.Accidental != 0)
                {
                    has_prev_pitch_with_accidental = True;
                }

                if (n.Name = noteobj.Name and n.AccidentalStyle = CautionaryAcc)
                {
                    has_prev_pitch_with_accidental = True;
                }

                if (n.Name = noteobj.Name and note_is_in_keysig = True)
                {
                    has_prev_pitch_with_accidental = False;
                }

                // this is a special case for dealing with naturals. If the pitch names
                // match, and the note is not in the key signature, and the previous pitch
                // was not empty, then we probably have a natural on the query note.
                if (pname = pname2 and note_is_in_keysig = False and accid2 != '')
                {
                    has_prev_pitch_with_accidental = True;
                }

            }
        }
        else
        {
            for each n in nr
            {
                if (n.Name = noteobj.Name and n.Accidental != 0 and note_is_in_keysig = True)
                {
                    has_prev_pitch_with_accidental = False;
                }
            }
        }
    }

    // deal with the 'weird' accidental values that don't have a value in noteobj.Accidental
    switch (accid)
    {
        case ('bb')
        {
            ret = (has_prev_pitch_with_accidental != True);
            return ret;
        }
        case ('b-')
        {
            ret = (has_prev_pitch_with_accidental != True);
            return ret;
        }
        case ('-')
        {
            ret = (has_prev_pitch_with_accidental != True);
            return ret;
        }
        case ('+')
        {
            ret = (has_prev_pitch_with_accidental != True);
            return ret;
        }
        case ('#+')
        {
            ret = (has_prev_pitch_with_accidental != True);
            return ret;
        }
    }

    if (noteobj.Accidental = 0 and note_is_in_keysig = True and has_prev_pitch_with_accidental = False)
    {
        // it's a natural?
        return True;
    }

    if (note_is_in_keysig = True and has_prev_pitch_with_accidental = False)
    {
        return False;
    }

    if (has_prev_pitch_with_accidental = False and noteobj.Accidental != 0)
    {
        return True;
    }

    if (has_prev_pitch_with_accidental = True and accid = '')
    {
        // this is the corresponding return value for special cased naturals.
        return True;
    }

    // Finally, by default, assume this has no accidental.
    return False;
}  //$end

function ConvertNamedTimeSignature (timesig) {
    //$module(ExportConverters.mss)
    switch(timesig)
    {
        case(CommonTimeString)
        {
            return 'common';
        }
        case(AllaBreveTimeString)
        {
            return 'cut';
        }
        default
        {
            return ' ';
        }
    }
}  //$end

function ConvertBracket (bracket) {
    //$module(ExportConverters.mss)
    switch(bracket)
    {
        case(BracketFull)
        {
            return 'bracket';
        }
        case(BracketBrace)
        {
            return 'brace';
        }
        case(BracketSub)
        {
            return 'line';
        }
        default
        {
            return 'none';
        }
    }
}  //$end

function ConvertSibeliusStructure (score) {
    //$module(ExportConverters.mss)
    // Takes in the Staff/Bar Sibelius Structure and returns a Bar/Staff
    // mapping for our MEI writers.
    bar_to_staff = CreateDictionary();

    // Invert the Sibelius structure
    for each Staff s in score
    {
        for each Bar b in s
        {
            if (bar_to_staff.PropertyExists(b.BarNumber))
            {
                bar_to_staff[b.BarNumber].Push(s.StaffNum);
            }
            else
            {
                bar_to_staff[b.BarNumber] = CreateSparseArray();
                bar_to_staff[b.BarNumber].Push(s.StaffNum);
            }
        }
    }
    return bar_to_staff;
}  //$end

function ConvertColor (nrest) {
    //$module(ExportConverters.mss)
    r = nrest.ColorRed;
    g = nrest.ColorGreen;
    b = nrest.ColorBlue;
    a_dec = nrest.ColorAlpha & '.0';
    a = a_dec / 255.0;

    return 'rgba(' & r & ',' & g & ',' & b & ',' & a & ')';
}  //$end

function ConvertNoteStyle (style) {
    //$module(ExportConverters.mss)
    noteStyle = ' ';

    if (style = NormalNoteStyle)
    {
        return ' ';
    }

    switch (style)
    {
        case (CrossNoteStyle)
        {
            noteStyle = 'cross';
        }
        case (DiamondNoteStyle)
        {
            noteStyle = 'diamond';
        }
        case (CrossOrDiamondNoteStyle)
        {
            // Sibelius uses this for percussion
            // and does not differentiate in the
            // head style, so we have to choose one
            // or the other.
            noteStyle = 'cross';
        }
        case (BlackAndWhiteDiamondNoteStyle)
        {
            noteStyle = 'filldiamond';
        }
        case (SlashedNoteStyle)
        {
            noteStyle = 'addslash';
        }
        case (BackSlashedNoteStyle)
        {
            noteStyle = 'addbackslash';
        }
        case (ArrowDownNoteStyle)
        {
            // this is not completely correct, since
            // we use the same value for up and down
            // iso triangles. But it's all we have for now.
            noteStyle = 'isotriangle';
        }
        case (ArrowUpNoteStyle)
        {
            noteStyle = 'isotriangle';
        }
        case (InvertedTriangleNoteStyle)
        {
            noteStyle = 'isotriangle';
        }
        case (ShapedNote1NoteStyle)
        {
            noteStyle = 'isotriangle';
        }
        case (ShapedNote2NoteStyle)
        {
            noteStyle = 'semicircle';
        }
        case (ShapedNote3NoteStyle)
        {
            noteStyle = 'diamond';
        }
        case (ShapedNote4StemUpNoteStyle)
        {
            noteStyle = 'rtriangle';
        }
        case (ShapedNote4StemDownNoteStyle)
        {
            noteStyle = 'rtriangle';
        }
        case (ShapedNote5NoteStyle)
        {
            // this looks normal...
            noteStyle = ' ';
        }
        case (ShapedNote6NoteStyle)
        {
            // there is no square in MEI...
            noteStyle = ' ';
        }
        case (ShapedNote7NoteStyle)
        {
            noteStyle = 'piewedge';
        }
    }

    return noteStyle;
}  //$end

function ConvertSlurStyle (style) {
    //$module(ExportConverters.mss)
    slurparts = MSplitString(style, '.');
    direction = ' ';
    style = ' ';

    switch(slurparts[3])
    {
        case ('up')
        {
            direction = 'above';
        }
        case ('down')
        {
            direction = 'below';
        }
        default
        {
            direction = ' ';
        }
    }
    switch(slurparts[4])
    {
        case ('dashed')
        {
            style = 'dashed';
        }
        case ('dotted')
        {
            style = 'dotted';
        }
        default
        {
            style = ' ';
        }
    }
    return CreateSparseArray(direction, style);
}  //$end

function ConvertPositionToTimestamp (position, bar) {
    //$module(ExportConverters.mss)
    /*
        To convert Sibelius ticks to musical timestamps
        we use the formula:

        tstamp = (notePosition / (barLength / beatsInBar))
    */

    // make sure we're working with floating point numbers
    // and yes, this makes me feel very, very dirty in case
    // you were wondering, but this is the only way ManuScript
    // can cast to floating point...
    barlength = bar.Length;
    timesignature = Sibelius.ActiveScore.SystemStaff.CurrentTimeSignature(bar.BarNumber);

    if (position = 0)
    {
        return 1;
    }

    barlen = barlength & '.0';
    pos = position & '.0';
    beats = timesignature.Numerator & '.0';
    unit = (barlen / beats);
    ret = (pos / unit) + 1;

    return ret;
}  //$end

function ConvertTupletStyle (tupletStyle) {
    //$module(ExportConverters.mss)
    switch (tupletStyle)
    {
        case(TupletNoNumber)
        {
            libmei.addAttribute(activeTuplet, 'dur.visible', 'false');
        }
        case(TupletLeft)
        {
            libmei.addAttribute(activeTuplet, 'num.format', 'count');
        }
        case(TupletLeftRight)
        {
            libmei.addAttribute(activeTuplet, 'num.format', 'ratio');
        }
    }

}  //$end

function ConvertBarline (linetype) {
    //$module(ExportConverters.mss)
    switch(linetype)
    {
        case (SpecialBarlineStartRepeat)
        {
            // start repeat
            return 'rptstart';
        }
        case (SpecialBarlineEndRepeat)
        {
            // end repeat
            return 'rptend';
        }
        case (SpecialBarlineDashed)
        {
            // dashed
            return 'dashed';
        }
        case (SpecialBarlineDouble)
        {
            // double
            return 'dbl';
        }
        case (SpecialBarlineFinal)
        {
            // final
            return 'end';
        }
        case (SpecialBarlineInvisible)
        {
            // invisible
            return 'invis';
        }
        case (SpecialBarlineBetweenStaves)
        {
            // between staves
            // no MEI equiv.
            return ' ';
        }
        case (SpecialBarlineNormal)
        {
            // normal
            // this should usually be needed.
            return 'single';
        }
        case (SpecialBarlineTick)
        {
            // tick
            // unknown
            return ' ';
        }
        case (SpecialBarlineShort)
        {
            // short
            // unknown
            return ' ';
        }
        default
        {
            return ' ';
        }
    }
}  //$end

function ConvertText (textobj) {
    //$module(ExportConverters.mss)
    styleid = textobj.StyleId;
    switch (styleid)
    {
        case ('text.staff.expression')
        {
            dynam = libmei.Dynam();
            libmei.SetText(dynam, lstrip(textobj.Text));
            libmei.AddAttribute(dynam, 'staff', textobj.ParentBar.ParentStaff.StaffNum);
            libmei.AddAttribute(dynam, 'tstamp', ConvertPositionToTimestamp(textobj));

            if (textobj.Dx != 0)
            {
                libmei.AddAttribute(dynam, 'ho', ConvertOffset(textobj.Dx));
            }

            if (textobj.Dy != 0)
            {
                libmei.AddAttribute(dynam, 'vo', ConvertOffset(textobj.Dy));
            }
            return dynam;
        }
        case ('text.system.page_aligned.title')
        {
            return ConvertTextElement(textobj);
        }
        case ('text.system.page_aligned.composer')
        {
            return ConvertTextElement(textobj);
        }
        default
        {
            return null;
        }
    }
}  //$end

function ConvertTextElement (textobj) {
    //$module(ExportConverters.mss)
    obj = libmei.AnchoredText();
    libmei.SetText(obj, lstrip(textobj.Text));

    if (textobj.Dx != 0)
    {
        libmei.AddAttribute(obj, 'ho', ConvertOffsets(textobj.Dx));
    }

    if (textobj.Dy != 0)
    {
        libmei.AddAttribute(obj, 'vo', ConvertOffset(textobj.Dy));
    }

    return obj;
}  //$end

function ConvertEndingValues (styleid) {
    //$module(ExportConverters)
    ending_style = MSplitString(styleid, '.');
    num = ' ';
    label = ' ';
    type = ' ';

    switch(ending_style[3])
    {
        case ('1st')
        {
            num = 1;
            label = '1.';
            type = 'closed';
        }
        case ('1st_n_2nd')
        {
            num = 1;
            label = '1. 2.';
            type = 'closed';
        }
        case ('2nd')
        {
            num = 2;
            label = '2.';
            if (ending_style[-1] = 'closed')
            {
                type = 'closed';
            }
            else
            {
                type = 'open';
            }
        }
        case ('3rd')
        {
            num = 3;
            label = '3.';
            type = 'closed';
        }
        case ('open')
        {
            type = 'open';
        }
        case ('closed')
        {
            type = 'closed';
        }
    }

    return CreateSparseArray(num, label, type);

}  //$end

function ConvertDate (datetime) {
    //$module(ExportConverters.mss)
    d = datetime.DayOfMonth;
    m = datetime.Month;
    y = datetime.Year;

    time = datetime.TimeWithSeconds;

    isodate = utils.Format('%s-%s-%sT%sZ', y, m, d, time);

    return isodate;
}  //$end

function ConvertClef (clefid) {
    //$module(ExportConverters.mss)
    clefparts = MSplitString(clefid, '.');
    shape = ' ';
    line = ' ';
    dis = ' ';
    dir = ' ';

    switch(clefparts[2])
    {
        case ('down')
        {
            dir = 'below';
        }
        case ('up')
        {
            dir = 'above';
        }
    }

    switch(clefparts[3])
    {
        case ('8')
        {
            dis = '8';
        }
        case ('15')
        {
            dis = '15';
        }
    }
    switch (clefparts[1]) {
        case ('bass')
        {
            shape = 'F';
            line = '4';
        }
        case ('treble')
        {
            if (clefparts[4] = 'old')
            {
                shape = 'GG';
            }
            else
            {
                shape = 'G';
            }
            line = '2';
        }
        case ('tenor')
        {
            shape = 'C';
            line = '4';
        }
        case ('alto')
        {
            shape = 'C';
            line = '3';
        }
        case ('soprano')
        {
            shape = 'C';
            if (clefparts[2] = 'mezzo')
            {
                line = '2';
            }
            else
            {
                line = '1';
            }
        }
        case ('baritone')
        {
            if (clefparts[2] = 'c')
            {
                shape = 'C';
                line = '5';
            }
            else
            {
                shape = 'F';
                line = '3';
            }
        }
        case ('violin')
        {
            shape = 'G';
            line = '1';
        }
        case ('sub-bass')
        {
            shape = 'F';
            line = '5';
        }
        case ('tab')
        {
            shape = 'TAB';
        }
        case (('percussion') or ('percussion_2'))
        {
            shape = 'perc';
        }
    }
    ret = CreateSparseArray(shape, line, dis, dir);
    return ret;
}  //$end

function ConvertOctava (octava_id) {
    //$module(ExportConverters.mss)
    octparts = MSplitString(octava_id, '.');
    switch(octparts[3])
    {
        case ('minus15')
        {
            dis = '15';
            place = 'below';
        }
        case ('minus8')
        {
            dis = '8';
            place = 'below';
        }
        case ('plus15')
        {
            dis = '15';
            place = 'above';
        }
        case ('plus8')
        {
            dis = '8';
            place = 'above';
        }
        default
        {
            dis = ' ';
            place = ' ';
        }
    }
    return CreateSparseArray(dis, place);
}  //$end

function ConvertSlur (slur_value) {
    //$module(ExportConverters.mss)
    slurparts = MSplitString(slur_value, '.');
    direction = ' ';
    style = ' ';
    switch(slurparts[3])
    {
        case ('up')
        {
            direction = 'above';
        }
        case ('down')
        {
            direction = 'below';
        }
        default
        {
            direction = ' ';
        }
    }
    switch(slurparts[4])
    {
        case ('dashed')
        {
            style = 'dashed';
        }
        case ('dotted')
        {
            style = 'dotted';
        }
        default
        {
            style = ' ';
        }
    }
    return CreateSparseArray(direction, style);
}  //$end

function ConvertDiatonicPitch (diatonic_pitch) {
    //$module(ExportConverters)
    octv = (diatonic_pitch / 7) - 1;
    pnames = CreateSparseArray('c', 'd', 'e', 'f', 'g', 'a', 'b');
    idx = (diatonic_pitch % 7);
    pname = pnames[idx];

    return CreateSparseArray(pname, octv);
}  //$end

function ConvertOffsets (offset) {
    //$module(ExportConverters.mss)

    /*
     This function will convert the 1/32 unit
     Sibelius offsets into a millimeter measurement as required by the
     data.MEASUREMENT datatype used by MEI.

    Most offsets are given in Sibelius Units, which
    are defined as 1/32 of a space. A space is 1/4 of the staff height
    set at 128. For real world calculations, then, a unit is:
    ((staffheight / 4) / 32).

    The `StaffHeight` property always returns the staff height in millimeters.

    So a staff height of 7mm (default) gives us (7/4 = 1.75) / 32 = 0.05mm per Sibelius
    Unit.
    */
    scr = Sibelius.ActiveScore;
    staffheight = scr.StaffHeight;
    factor = (((staffheight & '.0') / 4.0) / 32.0);
    oset = factor * offset;
    retval = oset & 'mm';
    return retval;
}  //$end

function ConvertDuration (dur) {
    //$module(ExportConverters.mss)
    // there doesn't really seem to be a smarter way to do this...
    // 1024 = 1 whole note

    ret = CreateSparseArray();

    pow = PrevPow2(dur);
    counter = pow;
    dots = 0;
    powcount = pow;
    durset = false;

    durrem = 1024 % dur;
    if (durrem != 0)
    {
        while (counter < dur)
        {
            powcount = (powcount / 2);
            counter = counter + powcount;
            dots = dots + 1;

            if (dots > 5)
            {
                // prevent a runaway loop.
                counter = 1000000000;
            }
        }
    }

    switch (powcount)
    {
        case (pow >= 4096)
        {
            ret[0] = 'long';
            durset = true;
        }
        case (pow >= 2048)
        {
            ret[0] = 'breve';
            durset = true;
        }
        default
        {
            if (durset = false)
            {
                ret[0] = 1024 / pow;
            }
        }
    }

    if (dots = 0)
    {
        ret[1] = ' ';
    }
    else
    {
        ret[1] = dots;
    }

    return ret;
}  //$end

function ConvertKeySignature (numsharps) {
    //$module(ExportConverters.mss)
    switch (numsharps)
    {
        case (0)
        {
            // key of c
            return '0';
        }
        case (-8)
        {
            // atonal in Sibelius
            return '0';
        }
        case (numsharps > 0)
        {
            // sharps
            return numsharps & 's';
        }
        case (numsharps < 0)
        {
            //flats
            return utils.AbsoluteValue(numsharps) & 'f';
        }
    }
}  //$end

function PitchesInKeySignature (keysig) {
    //$module(ExportConverters.mss)

    // keysig is 7 >= 0 >= -7, for the number of sharps (negative is flats)
    ac = CreateSparseArray('F', 'C', 'G', 'D', 'A', 'E', 'B');
    if (keysig = 0)
    {
        return CreateSparseArray();
    }

    if (keysig > 0)
    {
        return ac.Slice(0, keysig);
    }
    else
    {
        v = ac.Slice(keysig);
        v.Reverse();
        return v;
    }
}  //$end

function ConvertAccidental (noteobj) {
    //$module(ExportConverters.mss)
    // If accidentals are audible, but not visible, you get @accid.ges
    // If accidentals are both audible and visible, you get @accid
    // is_visible is not to be confused with hidden accidentals! is_visible
    // just determines whether an accidental is shown or not based on
    // the rules of CMN.

    // Returns a tuple [0 => accid (string), 1 => is_visible (bool)]
    // If the accidental is a natural and is visible, returns ('n', true); otherwise,
    // it returns ('', false);

    // first, determine if the accidental is visible.
    is_visible = HasVisibleAccidental(noteobj);
    ac = ' ';

    pname = Substring(noteobj.Name, 0, 1);  // captures first letter
    accid = Substring(noteobj.Name, 1);     // captures all other characters

    switch(accid)
    {
        case('bb')
        {
            ac = 'ff';
        }
        case('b-')
        {
            ac = 'fd';
        }
        case('b')
        {
            ac = 'f';
        }
        case('-')
        {
            ac = 'fu';
        }
        case('')
        {
            if (is_visible = True)
            {
                ac = 'n';
            }
        }
        case('+')
        {
            ac = 'sd';
        }
        case('#')
        {
            ac = 's';
        }
        case('#+')
        {
            ac = 'su';
        }
        case('x')
        {
            ac = 'x';
        }
        case('##')
        {
            ac = 'ss';
        }
    }

    ret = CreateSparseArray(ac, is_visible);
    return ret;
}  //$end

function HasVisibleAccidental (noteobj) {
    //$module(ExportConverters.mss)
    // determines whether a note is *likely* to have a visible accidental.
    // Caution: This is probably not 100% accurate.

    // Returns a boolean if the note is visible.

    // If it has a cautionary accidental, it's most likely to be visible.
    if (noteobj.AccidentalStyle = CautionaryAcc)
    {
        return True;
    }

    if (noteobj.AccidentalStyle = HiddenAcc)
    {
        return False;
    }

    keysig = noteobj.ParentNoteRest.ParentBar.GetKeySignatureAt(noteobj.ParentNoteRest.Position);
    sf = sibmei2.PitchesInKeySignature(keysig.Sharps);
    pname = Substring(noteobj.Name, 0, 1);  // captures first letter
    accid = Substring(noteobj.Name, 1);  // captures all other characters

    // if the note is not in the key signature, then it should have an accidental
    note_is_in_keysig = utils.IsInArray(sf, pname);
    has_prev_pitch_with_accidental = False;

    parent_nr = noteobj.ParentNoteRest;
    parent_bar = parent_nr.ParentBar;

    for each NoteRest nr in parent_bar
    {
        if (nr.Position < parent_nr.Position)
        {
            for each n in nr
            {
                pname2 = Substring(n.Name, 0, 1);  // captures first letter
                accid2 = Substring(n.Name, 1);  // captures all other characters

                if (n.Name = noteobj.Name and note_is_in_keysig = False and n.Accidental != 0)
                {
                    has_prev_pitch_with_accidental = True;
                }

                if (n.Name = noteobj.Name and n.AccidentalStyle = CautionaryAcc)
                {
                    has_prev_pitch_with_accidental = True;
                }

                if (n.Name = noteobj.Name and note_is_in_keysig = True)
                {
                    has_prev_pitch_with_accidental = False;
                }

                // this is a special case for dealing with naturals. If the pitch names
                // match, and the note is not in the key signature, and the previous pitch
                // was not empty, then we probably have a natural on the query note.
                if (pname = pname2 and note_is_in_keysig = False and accid2 != '')
                {
                    has_prev_pitch_with_accidental = True;
                }

            }
        }
        else
        {
            for each n in nr
            {
                if (n.Name = noteobj.Name and n.Accidental != 0 and note_is_in_keysig = True)
                {
                    has_prev_pitch_with_accidental = False;
                }
            }
        }
    }

    // deal with the 'weird' accidental values that don't have a value in noteobj.Accidental
    switch (accid)
    {
        case ('bb')
        {
            ret = (has_prev_pitch_with_accidental != True);
            return ret;
        }
        case ('b-')
        {
            ret = (has_prev_pitch_with_accidental != True);
            return ret;
        }
        case ('-')
        {
            ret = (has_prev_pitch_with_accidental != True);
            return ret;
        }
        case ('+')
        {
            ret = (has_prev_pitch_with_accidental != True);
            return ret;
        }
        case ('#+')
        {
            ret = (has_prev_pitch_with_accidental != True);
            return ret;
        }
    }

    if (noteobj.Accidental = 0 and note_is_in_keysig = True and has_prev_pitch_with_accidental = False)
    {
        // it's a natural?
        return True;
    }

    if (note_is_in_keysig = True and has_prev_pitch_with_accidental = False)
    {
        return False;
    }

    if (has_prev_pitch_with_accidental = False and noteobj.Accidental != 0)
    {
        return True;
    }

    if (has_prev_pitch_with_accidental = True and accid = '')
    {
        // this is the corresponding return value for special cased naturals.
        return True;
    }

    // Finally, by default, assume this has no accidental.
    return False;
}  //$end

function ConvertNamedTimeSignature (timesig) {
    //$module(ExportConverters.mss)
    switch(timesig)
    {
        case(CommonTimeString)
        {
            return 'common';
        }
        case(AllaBreveTimeString)
        {
            return 'cut';
        }
        default
        {
            return ' ';
        }
    }
}  //$end

function ConvertBracket (bracket) {
    //$module(ExportConverters.mss)
    switch(bracket)
    {
        case(BracketFull)
        {
            return 'bracket';
        }
        case(BracketBrace)
        {
            return 'brace';
        }
        case(BracketSub)
        {
            return 'line';
        }
        default
        {
            return 'none';
        }
    }
}  //$end

function ConvertSibeliusStructure (score) {
    //$module(ExportConverters.mss)
    // Takes in the Staff/Bar Sibelius Structure and returns a Bar/Staff
    // mapping for our MEI writers.
    bar_to_staff = CreateDictionary();

    // Invert the Sibelius structure
    for each Staff s in score
    {
        for each Bar b in s
        {
            if (bar_to_staff.PropertyExists(b.BarNumber))
            {
                bar_to_staff[b.BarNumber].Push(s.StaffNum);
            }
            else
            {
                bar_to_staff[b.BarNumber] = CreateSparseArray();
                bar_to_staff[b.BarNumber].Push(s.StaffNum);
            }
        }
    }
    return bar_to_staff;
}  //$end

function ConvertColor (nrest) {
    //$module(ExportConverters.mss)
    r = nrest.ColorRed;
    g = nrest.ColorGreen;
    b = nrest.ColorBlue;
    a_dec = nrest.ColorAlpha & '.0';
    a = a_dec / 255.0;

    return 'rgba(' & r & ',' & g & ',' & b & ',' & a & ')';
}  //$end

function ConvertNoteStyle (style) {
    //$module(ExportConverters.mss)
    noteStyle = ' ';

    if (style = NormalNoteStyle)
    {
        return ' ';
    }

    switch (style)
    {
        case (CrossNoteStyle)
        {
            noteStyle = 'cross';
        }
        case (DiamondNoteStyle)
        {
            noteStyle = 'diamond';
        }
        case (CrossOrDiamondNoteStyle)
        {
            // Sibelius uses this for percussion
            // and does not differentiate in the
            // head style, so we have to choose one
            // or the other.
            noteStyle = 'cross';
        }
        case (BlackAndWhiteDiamondNoteStyle)
        {
            noteStyle = 'filldiamond';
        }
        case (SlashedNoteStyle)
        {
            noteStyle = 'addslash';
        }
        case (BackSlashedNoteStyle)
        {
            noteStyle = 'addbackslash';
        }
        case (ArrowDownNoteStyle)
        {
            // this is not completely correct, since
            // we use the same value for up and down
            // iso triangles. But it's all we have for now.
            noteStyle = 'isotriangle';
        }
        case (ArrowUpNoteStyle)
        {
            noteStyle = 'isotriangle';
        }
        case (InvertedTriangleNoteStyle)
        {
            noteStyle = 'isotriangle';
        }
        case (ShapedNote1NoteStyle)
        {
            noteStyle = 'isotriangle';
        }
        case (ShapedNote2NoteStyle)
        {
            noteStyle = 'semicircle';
        }
        case (ShapedNote3NoteStyle)
        {
            noteStyle = 'diamond';
        }
        case (ShapedNote4StemUpNoteStyle)
        {
            noteStyle = 'rtriangle';
        }
        case (ShapedNote4StemDownNoteStyle)
        {
            noteStyle = 'rtriangle';
        }
        case (ShapedNote5NoteStyle)
        {
            // this looks normal...
            noteStyle = ' ';
        }
        case (ShapedNote6NoteStyle)
        {
            // there is no square in MEI...
            noteStyle = ' ';
        }
        case (ShapedNote7NoteStyle)
        {
            noteStyle = 'piewedge';
        }
    }

    return noteStyle;
}  //$end

function ConvertSlurStyle (style) {
    //$module(ExportConverters.mss)
    slurparts = MSplitString(style, '.');
    direction = ' ';
    style = ' ';

    switch(slurparts[3])
    {
        case ('up')
        {
            direction = 'above';
        }
        case ('down')
        {
            direction = 'below';
        }
        default
        {
            direction = ' ';
        }
    }
    switch(slurparts[4])
    {
        case ('dashed')
        {
            style = 'dashed';
        }
        case ('dotted')
        {
            style = 'dotted';
        }
        default
        {
            style = ' ';
        }
    }
    return CreateSparseArray(direction, style);
}  //$end

function ConvertPositionToTimestamp (position, bar) {
    //$module(ExportConverters.mss)
    /*
        To convert Sibelius ticks to musical timestamps
        we use the formula:

        tstamp = (notePosition / (barLength / beatsInBar))
    */

    // make sure we're working with floating point numbers
    // and yes, this makes me feel very, very dirty in case
    // you were wondering, but this is the only way ManuScript
    // can cast to floating point...
    barlength = bar.Length;
    timesignature = Sibelius.ActiveScore.SystemStaff.CurrentTimeSignature(bar.BarNumber);

    if (position = 0)
    {
        return 1;
    }

    barlen = barlength & '.0';
    pos = position & '.0';
    beats = timesignature.Numerator & '.0';
    unit = (barlen / beats);
    ret = (pos / unit) + 1;

    return ret;
}  //$end

function ConvertTupletStyle (tupletStyle) {
    //$module(ExportConverters.mss)
    switch (tupletStyle)
    {
        case(TupletNoNumber)
        {
            libmei.addAttribute(activeTuplet, 'dur.visible', 'false');
        }
        case(TupletLeft)
        {
            libmei.addAttribute(activeTuplet, 'num.format', 'count');
        }
        case(TupletLeftRight)
        {
            libmei.addAttribute(activeTuplet, 'num.format', 'ratio');
        }
    }

}  //$end

function ConvertBarline (linetype) {
    //$module(ExportConverters.mss)
    switch(linetype)
    {
        case (SpecialBarlineStartRepeat)
        {
            // start repeat
            return 'rptstart';
        }
        case (SpecialBarlineEndRepeat)
        {
            // end repeat
            return 'rptend';
        }
        case (SpecialBarlineDashed)
        {
            // dashed
            return 'dashed';
        }
        case (SpecialBarlineDouble)
        {
            // double
            return 'dbl';
        }
        case (SpecialBarlineFinal)
        {
            // final
            return 'end';
        }
        case (SpecialBarlineInvisible)
        {
            // invisible
            return 'invis';
        }
        case (SpecialBarlineBetweenStaves)
        {
            // between staves
            // no MEI equiv.
            return ' ';
        }
        case (SpecialBarlineNormal)
        {
            // normal
            // this should usually be needed.
            return 'single';
        }
        case (SpecialBarlineTick)
        {
            // tick
            // unknown
            return ' ';
        }
        case (SpecialBarlineShort)
        {
            // short
            // unknown
            return ' ';
        }
        default
        {
            return ' ';
        }
    }
}  //$end

function ConvertText (textobj) {
    //$module(ExportConverters.mss)
    styleid = textobj.StyleId;
    switch (styleid)
    {
        case ('text.staff.expression')
        {
            dynam = libmei.Dynam();
            libmei.SetText(dynam, lstrip(textobj.Text));
            libmei.AddAttribute(dynam, 'staff', textobj.ParentBar.ParentStaff.StaffNum);
            libmei.AddAttribute(dynam, 'tstamp', ConvertPositionToTimestamp(textobj));

            if (textobj.Dx != 0)
            {
                libmei.AddAttribute(dynam, 'ho', ConvertOffset(textobj.Dx));
            }

            if (textobj.Dy != 0)
            {
                libmei.AddAttribute(dynam, 'vo', ConvertOffset(textobj.Dy));
            }
            return dynam;
        }
        case ('text.system.page_aligned.title')
        {
            return ConvertTextElement(textobj);
        }
        case ('text.system.page_aligned.composer')
        {
            return ConvertTextElement(textobj);
        }
        default
        {
            return null;
        }
    }
}  //$end

function ConvertTextElement (textobj) {
    //$module(ExportConverters.mss)
    obj = libmei.AnchoredText();
    libmei.SetText(obj, lstrip(textobj.Text));

    if (textobj.Dx != 0)
    {
        libmei.AddAttribute(obj, 'ho', ConvertOffsets(textobj.Dx));
    }

    if (textobj.Dy != 0)
    {
        libmei.AddAttribute(obj, 'vo', ConvertOffset(textobj.Dy));
    }

    return obj;
}  //$end

function ConvertEndingValues (styleid) {
    //$module(ExportConverters)
    ending_style = MSplitString(styleid, '.');
    num = ' ';
    label = ' ';
    type = ' ';

    switch(ending_style[3])
    {
        case ('1st')
        {
            num = 1;
            label = '1.';
            type = 'closed';
        }
        case ('1st_n_2nd')
        {
            num = 1;
            label = '1. 2.';
            type = 'closed';
        }
        case ('2nd')
        {
            num = 2;
            label = '2.';
            if (ending_style[-1] = 'closed')
            {
                type = 'closed';
            }
            else
            {
                type = 'open';
            }
        }
        case ('3rd')
        {
            num = 3;
            label = '3.';
            type = 'closed';
        }
        case ('open')
        {
            type = 'open';
        }
        case ('closed')
        {
            type = 'closed';
        }
    }

    return CreateSparseArray(num, label, type);

}  //$end

function ConvertDate (datetime) {
    //$module(ExportConverters.mss)
    d = datetime.DayOfMonth;
    m = datetime.Month;
    y = datetime.Year;

    hh  = datetime.Hours;
    mm = datetime.Minutes;
    ss = datetime.Seconds;

    isodate = utils.Format("%s-%s-%sT%s:%s:%sZ", y, m, d, hh, mm, ss);

    return isodate;
}  //$end


suburb place name tweaks

suburb place name tweaks

/* locality and place name labels
   admin boundaries
   national parks and protected areas */

// country border
#locality-labels[admin_level='2'][zoom > 1][zoom < 6] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Bold";
  text-fill: white;
  text-placement: point;
  text-halo-fill: black;
  text-halo-radius: 2.0;
  text-allow-overlap: true;
  text-transform: uppercase;
  text-wrap-width: 50px;
  text-line-spacing: 6px;

  text-opacity: 0.8;
  [zoom = 2] { text-size: 18; }
  [zoom = 3] { text-size: 20; }
  [zoom = 4] { text-size: 22; }
  [zoom = 5] { text-size: 25; }
}

// state and territor borders
#locality-labels[admin_level='4'][zoom > 3][zoom < 7] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Bold";
  text-fill: white;
  text-placement: point;
  text-halo-fill: black;
  text-halo-radius: 2.0;
  text-allow-overlap: true;
  text-transform: uppercase;
  text-wrap-width: 50px;
  text-line-spacing: 6px;

  text-opacity: 0.8;
  [zoom = 4] { text-size: 14; }
  [zoom = 5] { text-size: 16; }
  [zoom = 6] { text-size: 18; }
}

// council/LGA borders
#locality-labels[admin_level='6'] {
}

// city
#locality-labels[place='city'][zoom > 5][zoom < 19] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Bold";
  text-fill: white;
  text-placement: point;
  text-halo-fill: black;
  text-halo-radius: 2.0;
  text-allow-overlap: true;
  text-transform: uppercase;
  text-wrap-width: 50px;
  text-line-spacing: 6px;

  text-opacity: 1.0;

  [zoom > 17] { text-size: 45px; text-opacity: 0.7 }
  [zoom = 17] { text-size: 40px; text-opacity: 0.7 }
  [zoom = 16] { text-size: 35px; }
  [zoom = 15] { text-size: 30px; }
  [zoom = 14] { text-size: 24px; }
  [zoom = 13] { text-size: 20px; }
  [zoom < 13][zoom > 7] { text-size: 16px; }
  [zoom = 7 ] {
    text-size: 12px;

    text-placement-type: simple;
    text-placements: "N,S,10,8";
  }
  [zoom < 7 ] {
    text-size: 10px;

    text-placement-type: simple;
    text-placements: "N,S,8";
  }
}

// suburb borders
/*
don't add label for #locality-labels[place='suburb']
in Australia this will lead to lots of duplicates
*/
[zoom > 11][zoom < 19] {
  #locality-labels[admin_level='9'],#locality-labels[admin_level='10'] {
    text-name: "[name]";
    text-face-name: "Liberation Sans Bold";
    text-fill: white;
    text-placement: point;
    text-halo-fill: black;
    text-allow-overlap: true;
    text-transform: uppercase;
    text-wrap-width: 50px;
    text-line-spacing: 6px;

    text-opacity: 0.9;

    [zoom>16] { text-size: 35; text-halo-radius: 2.0; text-opacity: 0.7 }
    [zoom=16] { text-size: 30; text-halo-radius: 2.0; }
    [zoom=15] { text-size: 17; text-halo-radius: 2.0; }
    [zoom=14] { text-size: 13; text-halo-radius: 2.0; }
    [zoom=13] {
      text-size: 11;
      text-halo-radius: 1.5;
      text-line-spacing: 4px;
      text-transform: none;

      text-placement-type: simple;
      text-placements: "N,S,12";
    }
    [zoom=12] {
      text-size: 9;
      text-halo-radius: 1.0;
      text-line-spacing: 3px;
      text-transform: none;

      text-placement-type: simple;
      text-placements: "N,S,12";
    }
  }
}

/* national parks... */
#locality-labels[boundary='national_park'][zoom > 11][way_area > 1000000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Bold";
  text-fill: green;
  text-placement: point;
  text-halo-fill: white;
  text-wrap-width: 50px;

  text-opacity: 0.8;

  [zoom>14] { text-size: 20; text-halo-radius: 2.0; }
  [zoom=14] { text-size: 16; text-halo-radius: 1.75; }
  [zoom=13] { text-size: 14; text-halo-radius: 1.5; }
  [zoom=12] { text-size: 12; text-halo-radius: 1.0; }
}

#locality-labels[boundary='national_park'][zoom > 13][way_area < 1000000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Bold";
  text-fill: green;
  text-placement: point;
  text-halo-fill: white;
  text-wrap-width: 50px;

  text-opacity: 0.8;

  [zoom>14] { text-size: 20; text-halo-radius: 2.0; }
  [zoom=14] { text-size: 16; text-halo-radius: 1.75; }
}

/* locality and place name labels
   admin boundaries
   national parks and protected areas */

// country border
#locality-labels[admin_level='2'][zoom > 1][zoom < 6] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Bold";
  text-fill: white;
  text-placement: point;
  text-halo-fill: black;
  text-halo-radius: 2.0;
  text-allow-overlap: true;
  text-transform: uppercase;
  text-wrap-width: 50px;
  text-line-spacing: 6px;

  text-opacity: 0.8;
  [zoom = 2] { text-size: 18; }
  [zoom = 3] { text-size: 20; }
  [zoom = 4] { text-size: 22; }
  [zoom = 5] { text-size: 25; }
}

// state and territor borders
#locality-labels[admin_level='4'][zoom > 3][zoom < 7] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Bold";
  text-fill: white;
  text-placement: point;
  text-halo-fill: black;
  text-halo-radius: 2.0;
  text-allow-overlap: true;
  text-transform: uppercase;
  text-wrap-width: 50px;
  text-line-spacing: 6px;

  text-opacity: 0.8;
  [zoom = 4] { text-size: 14; }
  [zoom = 5] { text-size: 16; }
  [zoom = 6] { text-size: 18; }
}

// council/LGA borders
#locality-labels[admin_level='6'] {
}

// city
#locality-labels[place='city'][zoom > 5] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Bold";
  text-fill: white;
  text-placement: point;
  text-halo-fill: black;
  text-halo-radius: 2.0;
  text-allow-overlap: true;
  text-transform: uppercase;
  text-wrap-width: 50px;
  text-line-spacing: 6px;

  text-opacity: 0.8;

  [zoom > 14] { text-size: 30px; }
  [zoom = 14] { text-size: 18px; }
  [zoom = 13] { text-size: 17px; }
  [zoom < 13][zoom > 7] { text-size: 16px; }
  [zoom = 7 ] {
    text-size: 12px;

    text-placement-type: simple;
    text-placements: "N,S,10,8";
  }
  [zoom < 7 ] {
    text-size: 10px;

    text-placement-type: simple;
    text-placements: "N,S,8";
  }
}

// suburb borders
/*
don't add label for #locality-labels[place='suburb']
in Australia this will lead to lots of duplicates
*/
[zoom > 12] {
  #locality-labels[admin_level='9'],#locality-labels[admin_level='10'] {
    text-name: "[name]";
    text-face-name: "Liberation Sans Bold";
    text-fill: black;
    text-placement: point;
    text-halo-fill: white;
    text-allow-overlap: true;
    text-transform: uppercase;
    text-wrap-width: 50px;
    text-line-spacing: 6px;

    text-opacity: 0.8;

    [zoom>14] { text-size: 20; text-halo-radius: 2.0; }
    [zoom=14] { text-size: 12; text-halo-radius: 1.0; }
    [zoom=13] { text-size: 10; text-halo-radius: 1.0; text-transform: none; }
  }
}

/* national parks... */
#locality-labels[boundary='national_park'][zoom > 11][way_area > 1000000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Bold";
  text-fill: green;
  text-placement: point;
  text-halo-fill: white;
  text-wrap-width: 50px;

  text-opacity: 0.8;

  [zoom>14] { text-size: 20; text-halo-radius: 2.0; }
  [zoom=14] { text-size: 16; text-halo-radius: 1.75; }
  [zoom=13] { text-size: 14; text-halo-radius: 1.5; }
  [zoom=12] { text-size: 12; text-halo-radius: 1.0; }
}

#locality-labels[boundary='national_park'][zoom > 13][way_area < 1000000] {
  text-name: "[name]";
  text-face-name: "Liberation Sans Bold";
  text-fill: green;
  text-placement: point;
  text-halo-fill: white;
  text-wrap-width: 50px;

  text-opacity: 0.8;

  [zoom>14] { text-size: 20; text-halo-radius: 2.0; }
  [zoom=14] { text-size: 16; text-halo-radius: 1.75; }
}