Lighten land outline

Lighten land outline

Map {
  background-color: darken(#b8dee6,70);
}

#countries,
#landpolygons {
  line-color: #cdd;
  line-width: 1;
  line-join: round;
  polygon-fill: black;
  polygon-opacity: 1;
}

#rasterextents {
  line-color:#594;
  line-width:2;
  polygon-opacity:0.1;
  polygon-fill:#ae8;
}

#latlonextents {
  line-color:salmon;
  line-width:0.5;
  polygon-opacity:0.1;
  polygon-fill:salmon;
}

@linewidth: 0;

@stop0: 0;
@stop1: 0.0001;
@stop2: 10;
@stop3: 100;
@stop4: 500;
@stop5: 1000;
@stop6: 3000;
@stop7: 10000;
@stop8: 50000;
@stop9: 100000;

#glcount00 {
  comp-op: lighten;
  raster-opacity: 1;
  raster-scaling: near;
  raster-colorizer-default-mode:linear;
  raster-colorizer-default-color: transparent;
  raster-colorizer-epsilon:0.41;
  // For some reason there are negative values? this will help us spot them.
  // dark gray for zero population... ocean mainly. But also northern canada and greenland
  // black for very low population, siberia, australia, etc

  raster-colorizer-stops:
    stop(@stop0,transparent)
    stop(@stop4,darken(#cd570c,20))
    stop(@stop7,#cd570c)
    stop(@stop9,white)
}

.raster {
  raster-opacity:1;
  comp-op: overlay;
  raster-scaling: near;
  raster-colorizer-default-mode:linear;
  raster-colorizer-default-color: transparent;
  raster-colorizer-epsilon:0.41;
  raster-colorizer-stops:
    stop(0,transparent)
    stop(10,red)
    stop(500,blue)
    stop(1000,white)
}

Map {
  background-color: darken(#b8dee6,70);
}

#countries,
#landpolygons {
  line-color: #899;
  line-width: 1;
  line-join: round;
  polygon-fill: black;
  polygon-opacity: 1;
}

#rasterextents {
  line-color:#594;
  line-width:2;
  polygon-opacity:0.1;
  polygon-fill:#ae8;
}

#latlonextents {
  line-color:salmon;
  line-width:0.5;
  polygon-opacity:0.1;
  polygon-fill:salmon;
}

@linewidth: 0;

@stop0: 0;
@stop1: 0.0001;
@stop2: 10;
@stop3: 100;
@stop4: 500;
@stop5: 1000;
@stop6: 3000;
@stop7: 10000;
@stop8: 50000;
@stop9: 100000;

#glcount00 {
  comp-op: lighten;
  raster-opacity: 1;
  raster-scaling: near;
  raster-colorizer-default-mode:linear;
  raster-colorizer-default-color: transparent;
  raster-colorizer-epsilon:0.41;
  // For some reason there are negative values? this will help us spot them.
  // dark gray for zero population... ocean mainly. But also northern canada and greenland
  // black for very low population, siberia, australia, etc

  raster-colorizer-stops:
    stop(@stop0,transparent)
    stop(@stop4,darken(#cd570c,20))
    stop(@stop7,#cd570c)
    stop(@stop9,white)
}

.raster {
  raster-opacity:1;
  comp-op: overlay;
  raster-scaling: near;
  raster-colorizer-default-mode:linear;
  raster-colorizer-default-color: transparent;
  raster-colorizer-epsilon:0.41;
  raster-colorizer-stops:
    stop(0,transparent)
    stop(10,red)
    stop(500,blue)
    stop(1000,white)
}


changing default styles for prod

changing default styles for prod

@land: lighten(#080,20%);
@line: #1abc9c;

#point {
  marker-fill: #2c3e50;
  marker-line-color: lighten(#2c3e50, 30%);
  marker-width:4;
  marker-line-width:1;
  marker-opacity:1;
  marker-allow-overlap:true;
}

#polygon {
  polygon-fill: #16a085;
  line-color: @line;
  line-width: 1;
}

#linestring {
  line-color: @line;
  line-width: 2;
}

@land: lighten(#080,20%);
@line: #1abc9c;
@blue: #2c3e50;

#point {
  marker-fill: @blue;
  marker-line-color: lighten(@blue, 30%);
  marker-width:4;
  marker-line-width:1;
  marker-opacity:1;
  marker-allow-overlap:true;
}

#polygon {
  polygon-fill: #16a085;
  line-color: @line;
  line-width: 1;
}

#linestring {
  line-color: @line;
  line-width: 2;
}


Inverting all label color and halo

Inverting all label color and halo

/* ****************************************************************** */
/* OSM HYBRID for Imposm                                              */
/* ****************************************************************** */

/* For basic style customization you can simply edit the colors and
 * fonts defined in this file. For more detailed / advanced
 * adjustments explore the other files.
 *
 * GENERAL NOTES
 *
 * There is a slight performance cost in rendering line-caps.  An
 * effort has been made to restrict line-cap definitions to styles
 * where the results will be visible (lines at least 2 pixels thick).
 */

/* ================================================================== */
/* FONTS
/* ================================================================== */

/* directory to load fonts from in addition to the system directories */
Map { font-directory: url(./fonts); }

/* set up font sets for various weights and styles */
@sans_lt:	"Open Sans Regular", "DejaVu Sans Book", "Arundina Sans Regular", "Padauk Regular",
		"Khmer OS Metal Chrieng Regular", "Mukti Narrow Regular", "gargi Medium", "TSCu_Paranar Regular",
		"Tibetan Machine Uni Regular", "Mallige Normal", "Droid Sans Fallback Regular", "Unifont Medium",
		"unifont Medium";

@sans:		"Open Sans Semibold", "DejaVu Sans Book", "Arundina Sans Regular", "Padauk Regular",
		"Khmer OS Metal Chrieng Regular", "Mukti Narrow Regular", "gargi Medium", "TSCu_Paranar Regular",
		"Tibetan Machine Uni Regular", "Mallige Normal", "Droid Sans Fallback Regular", "Unifont Medium",
		"unifont Medium";

@sans_italic:	"Open Sans Semibold Italic", "DejaVu Sans Italic", "DejaVu Sans Oblique", "Arundina Sans Italic",
		"TSCu_Paranar Italic", "Mallige NormalItalic", "DejaVu Sans Book", "Arundina Sans Regular",
		"Padauk Regular", "Khmer OS Metal Chrieng Regular", "Mukti Narrow Regular", "gargi Medium",
		"TSCu_Paranar Regular", "Tibetan Machine Uni Regular", "Mallige Normal", "Droid Sans Fallback Regular",
		"Unifont Medium", "unifont Medium";

@sans_bold:	"Open Sans Bold", "DejaVu Sans Bold", "DejaVu Sans Bold", "Arundina Sans Bold", "Padauk Bold",
		"Mukti Narrow Bold", "TSCu_Paranar Bold", "Mallige Bold", "DejaVu Sans Book", "Arundina Sans Regular",
		"Padauk Regular", "Khmer OS Metal Chrieng Regular","Mukti Narrow Regular", "gargi Medium",
		"TSCu_Paranar Regular", "Tibetan Machine Uni Regular", "Mallige Normal", "Droid Sans Fallback Regular",
		"Unifont Medium", "unifont Medium";

@sans_lt_italic:	"Open Sans Italic", "DejaVu Sans Italic", "DejaVu Sans Oblique", "Arundina Sans Italic",
			"TSCu_Paranar Italic", "Mallige NormalItalic", "DejaVu Sans Book", "Arundina Sans Regular",
			"Padauk Regular", "Khmer OS Metal Chrieng Regular", "Mukti Narrow Regular", "gargi Medium",
			"TSCu_Paranar Regular", "Tibetan Machine Uni Regular", "Mallige Normal",
			"Droid Sans Fallback Regular", "Unifont Medium", "unifont Medium";

@sans_bold_italic:	"Open Sans Bold Italic", "DejaVu Sans Bold Italic", "DejaVu Sans Bold", "Arundina Sans Bold",
			"Padauk Bold", "Mukti Narrow Bold", "TSCu_Paranar Bold", "Mallige Bold", "DejaVu Sans Book",
			"Arundina Sans Regular", "Padauk Regular", "Khmer OS Metal Chrieng Regular",
                	"Mukti Narrow Regular", "gargi Medium", "TSCu_Paranar Regular", "Tibetan Machine Uni Regular",
                	"Mallige Normal", "Droid Sans Fallback Regular", "Unifont Medium", "unifont Medium";

/* Some fonts are larger or smaller than others. Use this variable to
   globally increase or decrease the font sizes. */
/* Note this is only implemented for certain things so far */
@text_adjust: 0;

/* ================================================================== */
/* LANDUSE & LANDCOVER COLORS
/* ================================================================== */

@land:              #FCFBE7;
@water:             #C4DFF6;
@grass:             #E6F2C1;
@beach:             #FFEEC7;
@park:              #DAF2C1;
@cemetery:          #D6DED2;
@wooded:            #C3D9AD;
@agriculture:       #F2E8B6;

@building:          #E4E0E0;
@hospital:          rgb(229,198,195);
@school:            #FFF5CC;
@sports:            #B8E6B8;

@residential:       @land * 0.98;
@commercial:        @land * 0.97;
@industrial:        @land * 0.96;
@parking:           #EEE;

/* ================================================================== */
/* ROAD COLORS
/* ================================================================== */

/* For each class of road there are three color variables:
 * - line: for lower zoomlevels when the road is represented by a
 *         single solid line.
 * - case: for higher zoomlevels, this color is for the road's
 *         casing (outline).
 * - fill: for higher zoomlevels, this color is for the road's
 *         inner fill (inline).
 */

@motorway_line:     #E65C5C;
@motorway_fill:     lighten(@motorway_line,10%);
@motorway_case:     @motorway_line * 0.9;

@trunk_line:        #E68A5C;
@trunk_fill:        lighten(@trunk_line,10%);
@trunk_case:        @trunk_line * 0.9;

@primary_line:      #FFC859;
@primary_fill:      lighten(@primary_line,10%);
@primary_case:      @primary_line * 0.9;

@secondary_line:    #FFE873;
@secondary_fill:    lighten(@secondary_line,10%);
@secondary_case:    @secondary_line * 0.9;

@standard_line:     @land * 0.85;
@standard_fill:     #fff;
@standard_case:     @land * 0.9;

@pedestrian_line:   @standard_line;
@pedestrian_fill:   #FAFAF5;
@pedestrian_case:   @land;

@cycle_line:        @standard_line;
@cycle_fill:        #FAFAF5;
@cycle_case:        @land;

@rail_line:         #999;
@rail_fill:         #fff;
@rail_case:         @land;

@aeroway:           #ddd;

/* ================================================================== */
/* BOUNDARY COLORS
/* ================================================================== */

@admin_2:           #eee;
@admin_3:           #999;
@admin_4:           #60f;

/* ================================================================== */
/* LABEL COLORS
/* ================================================================== */

/* We set up a default halo color for places so you can edit them all
   at once or override each individually. */
@place_halo:        fadeout(#fff,30%);
@place_halo:        fadeout(#000,30%);

@country_text:      #eee;
@country_halo:      @place_halo;

@state_text:        #eee;
@state_halo:        @place_halo;

@city_text:         #eee;
@city_halo:         @place_halo;

@town_text:         #ccc;
@town_halo:         @place_halo;

@poi_text:          #aaa;

@road_text:         #777;
@road_halo:         #fff;

@other_text:        #aaa;
@other_halo:        @place_halo;

@locality_text:     #aaa;
@locality_halo:     @land;

/* Also used for other small places: hamlets, suburbs, localities */
@village_text:      #60f;
@village_halo:      @place_halo;

/* ****************************************************************** */

/* ****************************************************************** */
/* OSM HYBRID for Imposm                                              */
/* ****************************************************************** */

/* For basic style customization you can simply edit the colors and
 * fonts defined in this file. For more detailed / advanced
 * adjustments explore the other files.
 *
 * GENERAL NOTES
 *
 * There is a slight performance cost in rendering line-caps.  An
 * effort has been made to restrict line-cap definitions to styles
 * where the results will be visible (lines at least 2 pixels thick).
 */

/* ================================================================== */
/* FONTS
/* ================================================================== */

/* directory to load fonts from in addition to the system directories */
Map { font-directory: url(./fonts); }

/* set up font sets for various weights and styles */
@sans_lt:	"Open Sans Regular", "DejaVu Sans Book", "Arundina Sans Regular", "Padauk Regular",
		"Khmer OS Metal Chrieng Regular", "Mukti Narrow Regular", "gargi Medium", "TSCu_Paranar Regular",
		"Tibetan Machine Uni Regular", "Mallige Normal", "Droid Sans Fallback Regular", "Unifont Medium",
		"unifont Medium";

@sans:		"Open Sans Semibold", "DejaVu Sans Book", "Arundina Sans Regular", "Padauk Regular",
		"Khmer OS Metal Chrieng Regular", "Mukti Narrow Regular", "gargi Medium", "TSCu_Paranar Regular",
		"Tibetan Machine Uni Regular", "Mallige Normal", "Droid Sans Fallback Regular", "Unifont Medium",
		"unifont Medium";

@sans_italic:	"Open Sans Semibold Italic", "DejaVu Sans Italic", "DejaVu Sans Oblique", "Arundina Sans Italic",
		"TSCu_Paranar Italic", "Mallige NormalItalic", "DejaVu Sans Book", "Arundina Sans Regular",
		"Padauk Regular", "Khmer OS Metal Chrieng Regular", "Mukti Narrow Regular", "gargi Medium",
		"TSCu_Paranar Regular", "Tibetan Machine Uni Regular", "Mallige Normal", "Droid Sans Fallback Regular",
		"Unifont Medium", "unifont Medium";

@sans_bold:	"Open Sans Bold", "DejaVu Sans Bold", "DejaVu Sans Bold", "Arundina Sans Bold", "Padauk Bold",
		"Mukti Narrow Bold", "TSCu_Paranar Bold", "Mallige Bold", "DejaVu Sans Book", "Arundina Sans Regular",
		"Padauk Regular", "Khmer OS Metal Chrieng Regular","Mukti Narrow Regular", "gargi Medium",
		"TSCu_Paranar Regular", "Tibetan Machine Uni Regular", "Mallige Normal", "Droid Sans Fallback Regular",
		"Unifont Medium", "unifont Medium";

@sans_lt_italic:	"Open Sans Italic", "DejaVu Sans Italic", "DejaVu Sans Oblique", "Arundina Sans Italic",
			"TSCu_Paranar Italic", "Mallige NormalItalic", "DejaVu Sans Book", "Arundina Sans Regular",
			"Padauk Regular", "Khmer OS Metal Chrieng Regular", "Mukti Narrow Regular", "gargi Medium",
			"TSCu_Paranar Regular", "Tibetan Machine Uni Regular", "Mallige Normal",
			"Droid Sans Fallback Regular", "Unifont Medium", "unifont Medium";

@sans_bold_italic:	"Open Sans Bold Italic", "DejaVu Sans Bold Italic", "DejaVu Sans Bold", "Arundina Sans Bold",
			"Padauk Bold", "Mukti Narrow Bold", "TSCu_Paranar Bold", "Mallige Bold", "DejaVu Sans Book",
			"Arundina Sans Regular", "Padauk Regular", "Khmer OS Metal Chrieng Regular",
                	"Mukti Narrow Regular", "gargi Medium", "TSCu_Paranar Regular", "Tibetan Machine Uni Regular",
                	"Mallige Normal", "Droid Sans Fallback Regular", "Unifont Medium", "unifont Medium";

/* Some fonts are larger or smaller than others. Use this variable to
   globally increase or decrease the font sizes. */
/* Note this is only implemented for certain things so far */
@text_adjust: 0;

/* ================================================================== */
/* LANDUSE & LANDCOVER COLORS
/* ================================================================== */

@land:              #FCFBE7;
@water:             #C4DFF6;
@grass:             #E6F2C1;
@beach:             #FFEEC7;
@park:              #DAF2C1;
@cemetery:          #D6DED2;
@wooded:            #C3D9AD;
@agriculture:       #F2E8B6;

@building:          #E4E0E0;
@hospital:          rgb(229,198,195);
@school:            #FFF5CC;
@sports:            #B8E6B8;

@residential:       @land * 0.98;
@commercial:        @land * 0.97;
@industrial:        @land * 0.96;
@parking:           #EEE;

/* ================================================================== */
/* ROAD COLORS
/* ================================================================== */

/* For each class of road there are three color variables:
 * - line: for lower zoomlevels when the road is represented by a
 *         single solid line.
 * - case: for higher zoomlevels, this color is for the road's
 *         casing (outline).
 * - fill: for higher zoomlevels, this color is for the road's
 *         inner fill (inline).
 */

@motorway_line:     #E65C5C;
@motorway_fill:     lighten(@motorway_line,10%);
@motorway_case:     @motorway_line * 0.9;

@trunk_line:        #E68A5C;
@trunk_fill:        lighten(@trunk_line,10%);
@trunk_case:        @trunk_line * 0.9;

@primary_line:      #FFC859;
@primary_fill:      lighten(@primary_line,10%);
@primary_case:      @primary_line * 0.9;

@secondary_line:    #FFE873;
@secondary_fill:    lighten(@secondary_line,10%);
@secondary_case:    @secondary_line * 0.9;

@standard_line:     @land * 0.85;
@standard_fill:     #fff;
@standard_case:     @land * 0.9;

@pedestrian_line:   @standard_line;
@pedestrian_fill:   #FAFAF5;
@pedestrian_case:   @land;

@cycle_line:        @standard_line;
@cycle_fill:        #FAFAF5;
@cycle_case:        @land;

@rail_line:         #999;
@rail_fill:         #fff;
@rail_case:         @land;

@aeroway:           #ddd;

/* ================================================================== */
/* BOUNDARY COLORS
/* ================================================================== */

@admin_2:           #eee;
@admin_3:           #999;
@admin_4:           #60f;

/* ================================================================== */
/* LABEL COLORS
/* ================================================================== */

/* We set up a default halo color for places so you can edit them all
   at once or override each individually. */
@place_halo:        fadeout(#fff,30%);
@place_halo_rev:    fadeout(#000,30%);

@country_text:      #435;
@country_halo:      @place_halo;

@state_text:        #546;
@state_halo:        @place_halo;

@city_text:         #eee;
@city_halo:         @place_halo_rev;

@town_text:         #444;
@town_halo:         @place_halo;

@poi_text:          #666;

@road_text:         #777;
@road_halo:         #fff;

@other_text:        #888;
@other_halo:        @place_halo;

@locality_text:     #aaa;
@locality_halo:     @land;

/* Also used for other small places: hamlets, suburbs, localities */
@village_text:      #60f;
@village_halo:      @place_halo;

/* ****************************************************************** */


#17 add marine water body labels at low zooms

@text_font_transport: 'PT Sans Narrow Regular', 'Unifont Medium';
@text_font_administrative: 'PT Sans Narrow Regular', 'Unifont Medium';
@text_font_city: 'PT Sans Narrow Regular', 'Unifont Medium';
@text_font_parks: 'PT Sans Narrow Regular', 'Unifont Medium';
@text_font_water: 'PT Sans Narrow Regular', 'Unifont Medium';
@text_font_water_bold: 'PT Sans Narrow Bold', 'Unifont Bold';

@label_color_transport: #524c4c;
@label_color_administrative: #2e2115;
@label_color_city: #2e2115;

@text_font_size_xxsm: 12;
@text_font_size_xsm: 14;
@text_font_size_sm: 15;
@text_font_size_medium: 17;
@text_font_size_medium_plus: 18;
@text_font_size_large: 20;

@text_font_halo_radius_sm: 1;
@text_font_halo_radius_large: 2;

@label_color_administrative_halo: #fff;
@label_color_physical: #000;
@label_color_physical_halo: #fff;
@label_color_transport_halo: #F7F7E6;
@label_color_places_halo_low: fadeout(rgba(255,255,255, 0.7), 30%);
@label_color_places_halo_high: fadeout(rgba(255,255,255, 1), 30%);

@label_color_green_area: #374c30;
@label_color_green_area_halo: #c0d3b5;
@label_color_water: darken(@color_water,20);
@label_color_water_halo: @color_water;

Map {
  font-directory: url("fonts/");
  buffer-size: 128;
}

#minor_road_labels,
#major_road_labels,
{
  text-name: [name];
  text-face-name: @text_font_transport;
  text-size: 16;
  text-placement: line;
  text-max-char-angle-delta: 20;
  text-fill: #444;
  text-spacing: 256;
  text-avoid-edges: true;
  text-halo-fill: @label_color_transport_halo;
  text-halo-radius: 2;
}

#shields {
  [zoom>=11] {

    /* tmp place holder for hwy shields */

  }
}

#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];
    [namealt!=''] {
      text-name: [name] + '\n(' + [namealt] + ')';
    }
  text-face-name: @text_font_water_bold;
    text-wrap-width: 80;
    text-size: @text_font_size_medium;
    text-fill: @label_color_water;
    text-halo-radius: @text_font_halo_radius_sm;
    text-halo-fill: @label_color_water_halo;
}

#ne_50m_geography_marine_polys[zoom=5][changed!=''],
#ne_10m_geography_marine_polys[zoom>=6][zoom<=8][changed!='']
{
    text-name: [name];
    [namealt!=''] {
      text-name: [name] + '\n(' + [namealt] + ')';
    }
    [name = 'Hecate Straight'] {
      text-name: 'Hecate Strait' + [namealt]; // Becase we know namealt is empty
    }
    [name = 'Queen Charlotte Straight'] {
      text-name: 'Queen Charlotte Strait' + [namealt]; // Becase we know namealt is empty
    }
    text-face-name: @text_font_water;
    text-wrap-width: 80;
    text-size: @text_font_size_medium;
    text-fill: @label_color_water;
    text-halo-radius: @text_font_halo_radius_sm;
    text-halo-fill: @label_color_water_halo;
}

#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: interior;
    text-max-char-angle-delta: 30;
    text-wrap-width: 40;
    text-halo-radius: @text_font_halo_radius_large;
    text-fill: @label_color_water;
    text-halo-fill: @label_color_water_halo;
    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=8][area>100000000],
  [zoom=9][area>100000000],
  [zoom=10][area>100000000],
  [zoom=11][area>5000000],
  [zoom=12][area>1000000],
  [zoom=13][area>400000],
  [zoom=14][area>200000],
  [zoom=15][area>50000],
  [zoom=16][area>10000],
  [zoom>=17] {
    text-name: [name];
    text-face-name: @text_font_parks;
    text-placement: interior;
    text-wrap-width: 96;
    text-wrap-before: true;
    text-line-spacing: -3;
    text-fill: @label_color_green_area;
    text-size: 15;

    [zoom>=11] {
      text-fill: #586e50;
    }

    [zoom>=15] {
      text-size: 20;
      text-line-spacing: -7;
    }

    [zoom>=11] {
      text-halo-radius: @text_font_halo_radius_sm;
      text-halo-fill: @label_color_green_area_halo;
    }
    [zoom>=15] {
      text-halo-radius: @text_font_halo_radius_large;
    }
  }
}

#continents
{
  text-name: [name];
  text-face-name: @text_font_administrative;
  text-wrap-width: 32;
  text-size: 24;
  text-line-spacing: -12;
  text-fill: #2e2115;
}

#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: 18;
    text-fill: @label_color_administrative;
    text-min-distance: 5;
}

#admin0-labels-z3[longfrom<=3] {
    text-name: "[name]";
    text-face-name: @text_font_administrative;
    text-size: 22;
    text-line-spacing: -8;
    text-wrap-width: 100;
    text-fill: @label_color_administrative;
}

#admin0-labels-z4 {
    text-name: [name];
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-size: 22;
    text-min-distance: 15;
    text-fill: @label_color_administrative;
}

#admin0-labels-z5 {
  text-name: [name];
  text-face-name: @text_font_administrative;
  text-wrap-width: 80;
  text-size: 24;
  text-fill: @label_color_administrative;
}

#admin0-labels-z6 {
  text-name: [name];
  text-face-name: @text_font_administrative;
  text-wrap-width: 80;
  text-size: 24;
  text-fill: @label_color_administrative;
}

#city_labels_z4,
#city_labels_z5,
#city_labels_z6 {
  // for debugging
  //::outline {
  //  polygon-fill: #fff;
  //  polygon-opacity: 0.1;
  //}
  text-name: [name];
  text-face-name: @text_font_city;
  text-fill: @label_color_city;
  text-placement: interior;
  text-vertical-alignment: bottom;
  text-min-distance: 5;
  text-dy: -5;

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

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

  [zoom>=4]  {
    text-size: @text_font_size_xxsm;
  }

  [zoom>=5] {
    text-size: @text_font_size_xsm;
  }

  [font_size>=14] {
    text-size: @text_font_size_medium;
  }

  [font_size>=16] {
    text-size: @text_font_size_medium_plus;
  }

  [font_size>=18] {
    text-size: @text_font_size_large;
  }
}

#city_labels_z7,
#city_labels_z8, {
  // for debugging
  //::outline {
  //  polygon-fill: #fff;
  //  polygon-opacity: 0.3;
  //}
  [justified='left'] {
    text-horizontal-alignment: left;
    text-dx: 15;
  }

  [justified='right'] {
    text-horizontal-alignment: right;
    text-dx: -15;
  }

  text-name: [name];
  text-face-name: @text_font_city;
  text-fill: @label_color_city;
  text-size: @text_font_size_sm;
  text-min-distance: 5;
  text-allow-overlap: true;

  [font_size>=14] {
    text-size: @text_font_size_medium;
  }

  [font_size>=20] {
    text-size: @text_font_size_large;
  }
}

#city_labels_z9,
#city_labels_z10 {
  text-name: [name];
  text-face-name: @text_font_city;
  text-fill: @label_color_city;
  text-size: @text_font_size_medium_plus;
  text-halo-radius: 2;
  text-halo-fill: @label_color_places_halo_high;
  // text-comp-op: src;

  [font_size>=20] {
    text-size: @text_font_size_large;
  }

  [zoom>=11] {
    text-halo-fill: @label_color_places_halo_low;
  }
}

#city_points_z4,
#city_points_z5,
#city_points_z6,
#city_points_z7,
#city_points_z8 {
  marker-ignore-placement: true;
  marker-width: 5;
  marker-fill: #2e2115;
  marker-line-width: 0;
}

#airports {
  [zoom>=10] {
    text-name: [abbrev];
    text-face-name: @text_font_transport;
    text-fill: #444;
    text-size: @text_font_size_medium_plus;

    text-halo-fill: #f7f7e6;
    text-halo-radius: 2;

    text-wrap-width: 128;
    text-dy: 14;
  }

  [zoom>=13] {
    text-name: [name];
  }

  [zoom=14][natlscale>.04],
  [zoom=15][natlscale>.02],
  [zoom>=16][natlscale>.01]
  {
      text-dy: 20;
  }

  [zoom=8][natlscale>2.3][type='major'],
  [zoom=9][natlscale>1.2][type='major'],
  [zoom=10][natlscale>0.57][type='major'],
  [zoom=11][natlscale>0.29][type='major'],
  [zoom=12][natlscale>0.29][type='major'],
  [zoom=13][natlscale>0.29][type='major']
  {
    point-file: url('icons/airport_major_l.png');
  }

  [zoom=14][natlscale>.29][type='major'],
  [zoom=15][natlscale>.29][type='major'],
  [zoom>=16][natlscale>.29][type='major']
  {
      point-file: url('icons/airport_major_xl.png');
  }

  [zoom=8][natlscale>2.3][type='small'],
  [zoom=9][natlscale>1.2][type='small'],
  [zoom=10][natlscale>.57][type='small'],
  [zoom=11][natlscale>.29][type='small'],
  [zoom=12][natlscale>.29][type='small'],
  [zoom=13][natlscale>.29][type='small']
  {
      point-file: url('icons/airport_small_l.png');
  }

  [zoom=14][natlscale>.29][type='small'],
  [zoom=15][natlscale>.29][type='small'],
  [zoom>=16][natlscale>.29][type='small']
  {
      point-file: url('icons/airport_small_xl.png');
  }

  [zoom=8][natlscale>2.3][type='military'],
  [zoom=9][natlscale>1.2][type='military'],
  [zoom=10][natlscale>.57][type='military'],
  [zoom=11][natlscale>.29][type='military'],
  [zoom=12][natlscale>.29][type='military'],
  [zoom=13][natlscale>.29][type='military']
  {
      point-file: url('icons/airport_military_l.png');
  }

  [zoom=14][natlscale>.29][type='military'],
  [zoom=15][natlscale>.29][type='military'],
  [zoom>=16][natlscale>.29][type='military']
  {
      point-file: url('icons/airport_military_xl.png');
  }

  [zoom=8][natlscale>2.3][type='spaceport'],
  [zoom=9][natlscale>1.2][type='spaceport'],
  [zoom=10][natlscale>.57][type='spaceport'],
  [zoom=11][natlscale>.29][type='spaceport'],
  [zoom=12][natlscale>.29][type='spaceport'],
  [zoom=13][natlscale>.29][type='spaceport']
  {
      point-file: url('icons/intergalactic_l.png');
  }

  [zoom=14][natlscale>.29][type='spaceport'],
  [zoom=15][natlscale>.29][type='spaceport'],
  [zoom>=16][natlscale>.29][type='spaceport']
  {
      point-file: url('icons/intergalactic_xl.png');
  }
}

@text_font_transport: 'PT Sans Narrow Regular', 'Unifont Medium';
@text_font_administrative: 'PT Sans Narrow Regular', 'Unifont Medium';
@text_font_city: 'PT Sans Narrow Regular', 'Unifont Medium';
@text_font_parks: 'PT Sans Narrow Regular', 'Unifont Medium';
@text_font_water: 'PT Sans Narrow Regular', 'Unifont Medium';

@label_color_transport: #524c4c;
@label_color_administrative: #2e2115;
@label_color_city: #2e2115;

@text_font_size_xxsm: 12;
@text_font_size_xsm: 14;
@text_font_size_sm: 15;
@text_font_size_medium: 17;
@text_font_size_medium_plus: 18;
@text_font_size_large: 20;

@text_font_halo_radius_sm: 1;
@text_font_halo_radius_large: 2;

@label_color_administrative_halo: #fff;
@label_color_transport_halo: #F7F7E6;
@text_font_halo_places_fill_low: fadeout(rgba(255,255,255, 0.7), 30%);
@text_font_halo_places_fill_high: fadeout(rgba(255,255,255, 1), 30%);

@label_color_green_area: #374c30;
@label_color_green_area_halo: #c0d3b5;
@label_color_water: darken(@color_water,20);
@label_color_water_halo: @color_water;

Map {
  font-directory: url("fonts/");
  buffer-size: 128;
}

#minor_road_labels,
#major_road_labels,
{
  text-name: [name];
  text-face-name: @text_font_transport;
  text-size: 16;
  text-placement: line;
  text-max-char-angle-delta: 20;
  text-fill: #444;
  text-spacing: 256;
  text-avoid-edges: true;
  text-halo-fill: @label_color_transport_halo;
  text-halo-radius: 2;
}

#shields {
  [zoom>=11] {

    /* tmp place holder for hwy shields */

  }
}

#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: interior;
    text-max-char-angle-delta: 30;
    text-wrap-width: 40;
    text-halo-radius: @text_font_halo_radius_large;
    text-fill: @label_color_water;
    text-halo-fill: @label_color_water_halo;
    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=8][area>100000000],
  [zoom=9][area>100000000],
  [zoom=10][area>100000000],
  [zoom=11][area>5000000],
  [zoom=12][area>1000000],
  [zoom=13][area>400000],
  [zoom=14][area>200000],
  [zoom=15][area>50000],
  [zoom=16][area>10000],
  [zoom>=17] {
    text-name: [name];
    text-face-name: @text_font_parks;
    text-placement: interior;
    text-wrap-width: 96;
    text-wrap-before: true;
    text-line-spacing: -3;
    text-fill: @label_color_green_area;
    text-size: 15;

    [zoom>=11] {
      text-fill: #586e50;
    }

    [zoom>=15] {
      text-size: 20;
      text-line-spacing: -7;
    }

    [zoom>=11] {
      text-halo-radius: @text_font_halo_radius_sm;
      text-halo-fill: @label_color_green_area_halo;
    }
    [zoom>=15] {
      text-halo-radius: @text_font_halo_radius_large;
    }
  }
}

#continents
{
  text-name: [name];
  text-face-name: @text_font_administrative;
  text-wrap-width: 32;
  text-size: 24;
  text-line-spacing: -12;
  text-fill: #2e2115;
}

#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: 18;
    text-fill: @label_color_administrative;
    text-min-distance: 5;
}

#admin0-labels-z3[longfrom<=3] {
    text-name: "[name]";
    text-face-name: @text_font_administrative;
    text-size: 22;
    text-line-spacing: -8;
    text-wrap-width: 100;
    text-fill: @label_color_administrative;
}

#admin0-labels-z4 {
    text-name: [name];
    text-face-name: @text_font_administrative;
    text-wrap-width: 80;
    text-size: 22;
    text-min-distance: 15;
    text-fill: @label_color_administrative;
}

#admin0-labels-z5 {
  text-name: [name];
  text-face-name: @text_font_administrative;
  text-wrap-width: 80;
  text-size: 24;
  text-fill: @label_color_administrative;
}

#admin0-labels-z6 {
  text-name: [name];
  text-face-name: @text_font_administrative;
  text-wrap-width: 80;
  text-size: 24;
  text-fill: @label_color_administrative;
}

#city_labels_z4,
#city_labels_z5,
#city_labels_z6 {
  // for debugging
  //::outline {
  //  polygon-fill: #fff;
  //  polygon-opacity: 0.1;
  //}
  text-name: [name];
  text-face-name: @text_font_city;
  text-fill: @label_color_city;
  text-placement: interior;
  text-vertical-alignment: bottom;
  text-min-distance: 5;
  text-dy: -5;

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

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

  [zoom>=4]  {
    text-size: @text_font_size_xxsm;
  }

  [zoom>=5] {
    text-size: @text_font_size_xsm;
  }

  [font_size>=14] {
    text-size: @text_font_size_medium;
  }

  [font_size>=16] {
    text-size: @text_font_size_medium_plus;
  }

  [font_size>=18] {
    text-size: @text_font_size_large;
  }
}

#city_labels_z7,
#city_labels_z8, {
  // for debugging
  //::outline {
  //  polygon-fill: #fff;
  //  polygon-opacity: 0.3;
  //}
  [justified='left'] {
    text-horizontal-alignment: left;
    text-dx: 15;
  }

  [justified='right'] {
    text-horizontal-alignment: right;
    text-dx: -15;
  }

  text-name: [name];
  text-face-name: @text_font_city;
  text-fill: @label_color_city;
  text-size: @text_font_size_sm;
  text-min-distance: 5;
  text-allow-overlap: true;

  [font_size>=14] {
    text-size: @text_font_size_medium;
  }

  [font_size>=20] {
    text-size: @text_font_size_large;
  }
}

#city_labels_z9,
#city_labels_z10 {
  text-name: [name];
  text-face-name: @text_font_city;
  text-fill: @label_color_city;
  text-size: @text_font_size_medium_plus;
  text-halo-radius: 2;
  text-halo-fill: @text_font_halo_places_fill_high;
  // text-comp-op: src;

  [font_size>=20] {
    text-size: @text_font_size_large;
  }

  [zoom>=11] {
    text-halo-fill: @text_font_halo_places_fill_low;
  }
}

#city_points_z4,
#city_points_z5,
#city_points_z6,
#city_points_z7,
#city_points_z8 {
  marker-ignore-placement: true;
  marker-width: 5;
  marker-fill: #2e2115;
  marker-line-width: 0;
}

#airports {
  [zoom>=10] {
    text-name: [abbrev];
    text-face-name: @text_font_transport;
    text-fill: #444;
    text-size: @text_font_size_medium_plus;

    text-halo-fill: #f7f7e6;
    text-halo-radius: 2;

    text-wrap-width: 128;
    text-dy: 14;
  }

  [zoom>=13] {
    text-name: [name];
  }

  [zoom=14][natlscale>.04],
  [zoom=15][natlscale>.02],
  [zoom>=16][natlscale>.01]
  {
      text-dy: 20;
  }

  [zoom=8][natlscale>2.3][type='major'],
  [zoom=9][natlscale>1.2][type='major'],
  [zoom=10][natlscale>0.57][type='major'],
  [zoom=11][natlscale>0.29][type='major'],
  [zoom=12][natlscale>0.29][type='major'],
  [zoom=13][natlscale>0.29][type='major']
  {
    point-file: url('icons/airport_major_l.png');
  }

  [zoom=14][natlscale>.29][type='major'],
  [zoom=15][natlscale>.29][type='major'],
  [zoom>=16][natlscale>.29][type='major']
  {
      point-file: url('icons/airport_major_xl.png');
  }

  [zoom=8][natlscale>2.3][type='small'],
  [zoom=9][natlscale>1.2][type='small'],
  [zoom=10][natlscale>.57][type='small'],
  [zoom=11][natlscale>.29][type='small'],
  [zoom=12][natlscale>.29][type='small'],
  [zoom=13][natlscale>.29][type='small']
  {
      point-file: url('icons/airport_small_l.png');
  }

  [zoom=14][natlscale>.29][type='small'],
  [zoom=15][natlscale>.29][type='small'],
  [zoom>=16][natlscale>.29][type='small']
  {
      point-file: url('icons/airport_small_xl.png');
  }

  [zoom=8][natlscale>2.3][type='military'],
  [zoom=9][natlscale>1.2][type='military'],
  [zoom=10][natlscale>.57][type='military'],
  [zoom=11][natlscale>.29][type='military'],
  [zoom=12][natlscale>.29][type='military'],
  [zoom=13][natlscale>.29][type='military']
  {
      point-file: url('icons/airport_military_l.png');
  }

  [zoom=14][natlscale>.29][type='military'],
  [zoom=15][natlscale>.29][type='military'],
  [zoom>=16][natlscale>.29][type='military']
  {
      point-file: url('icons/airport_military_xl.png');
  }

  [zoom=8][natlscale>2.3][type='spaceport'],
  [zoom=9][natlscale>1.2][type='spaceport'],
  [zoom=10][natlscale>.57][type='spaceport'],
  [zoom=11][natlscale>.29][type='spaceport'],
  [zoom=12][natlscale>.29][type='spaceport'],
  [zoom=13][natlscale>.29][type='spaceport']
  {
      point-file: url('icons/intergalactic_l.png');
  }

  [zoom=14][natlscale>.29][type='spaceport'],
  [zoom=15][natlscale>.29][type='spaceport'],
  [zoom>=16][natlscale>.29][type='spaceport']
  {
      point-file: url('icons/intergalactic_xl.png');
  }
}


allow syllables on chords

allow syllables on chords

function ProcessScore () {
    //$module(ExportProcessors.mss)
    // processors are a bit like a workflow manager -- they orchestrate the
    // generators, which in turn use the converters to convert specific values from sibelius
    // to MEI.
    score = Self._property:ActiveScore;

    mei = libmei.Mei();
    libmei.setDocumentRoot(mei);

    libmei.AddAttribute(mei, 'xmlns:xlink', 'http://www.w3.org/1999/xlink');
    libmei.AddAttribute(mei, 'xmlns', 'http://www.music-encoding.org/ns/mei');
    libmei.AddAttribute(mei, 'meiversion', '4.0.1');

    header = GenerateMEIHeader();
    libmei.AddChild(mei, header);

    music = GenerateMEIMusic();
    libmei.AddChild(mei, music);

}  //$end

function ProcessBeam (bobj, layer, normalizedBeamProp) {
    //$module(ExportProcessors.mss)
    /*
        Returns the active beam, if any, and creates new beam elements
        at the start of a beam.
    */
    switch (normalizedBeamProp)
    {
        case (NoBeam)
        {
            if (bobj.GraceNote)
            {
                if (layer._property:ActiveGraceBeam != null)
                {
                    layer._property:ActiveGraceBeam = null;
                }
                // If there is an active non-grace beam, we have a normal beam spanning
                // over a non-beamed grace note that will be added as a child of that beam.
                return GetNongraceParentBeam(bobj, layer);
            }
            else
            {
                if (layer._property:ActiveBeam != null)
                {
                    layer._property:ActiveBeam = null;
                }
                return null;
            }
        }
        case (StartBeam)
        {
            newBeam = libmei.Beam();
            if (bobj.GraceNote)
            {
                layer._property:ActiveGraceBeam = newBeam;
                nonGraceParentBeam = GetNongraceParentBeam(bobj, layer);
                if (nonGraceParentBeam != null)
                {
                    newBeam._property:ParentBeam = nonGraceParentBeam;
                }
            }
            else
            {
                layer._property:ActiveBeam = newBeam;
            }
            return newBeam;
        }
        default {
            // ContinueBeam and SingleBeam
            if (bobj.GraceNote)
            {
                return layer._property:ActiveGraceBeam;
            }
            else
            {
                return layer._property:ActiveBeam;
            }
        }
    }
}  //$end

function ProcessTuplet (noteRest, meielement, layer) {
    //$module(ExportProcessors.mss)
    if (noteRest.ParentTupletIfAny = null)
    {
        return null;
    }

    /*
       We encode inner tuplets of nested tuplet structures as <tupletSpan>s.
       Therefore we always return the outermost MEI tuplet for content to be added.
       Still, we need to keep track of the inner tuplets to assign the @endid.
       layer._property:ActiveMeiTuplet always points to the innermost tuplet.
    */
    activeMeiTuplet = layer._property:ActiveMeiTuplet;

    tupletIsContinued = activeMeiTuplet != null and TupletsEqual(noteRest.ParentTupletIfAny, activeMeiTuplet._property:SibTuplet);

    if (not(tupletIsContinued))
    {
        // New tuplets need to be added
        noteRestTupletStack = GetTupletStack(noteRest);
        sibTuplet = null;
        meiTupletDepth = GetMeiTupletDepth(layer);

        for i = meiTupletDepth to noteRestTupletStack.Length
        {
            sibTuplet = noteRestTupletStack[i];
            nextActiveMeiTuplet = GenerateTuplet(sibTuplet);
            if (meiTupletDepth > 0 or i > meiTupletDepth)
            {
                // We have an inner tuplet that we encode as <tupletSpan>
                nextActiveMeiTuplet = ShiftTupletToTupletSpan(nextActiveMeiTuplet, layer);
            }
            libmei.AddAttribute(nextActiveMeiTuplet, 'startid', '#' & meielement._id);
            // We basically create a linked list of tuplets
            nextActiveMeiTuplet._property:ParentTuplet = activeMeiTuplet;
            nextActiveMeiTuplet._property:SibTuplet = sibTuplet;
            activeMeiTuplet = nextActiveMeiTuplet;
        }
        layer._property:ActiveMeiTuplet = activeMeiTuplet;
    }

    meiTuplet = activeMeiTuplet;
    for i = 0 to CountTupletsEndingAtNoteRest(noteRest)
    {
        libmei.AddAttribute(meiTuplet, 'endid', '#' & meielement._id);
        meiTuplet = meiTuplet._property:ParentTuplet;
    }
    layer._property:ActiveMeiTuplet = meiTuplet;

    outermostMeiTuplet = activeMeiTuplet;
    while (outermostMeiTuplet._property:ParentTuplet)
    {
        outermostMeiTuplet = outermostMeiTuplet._property:ParentTuplet;
    }
    return outermostMeiTuplet;
}  //$end

function ShiftTupletToTupletSpan (tuplet) {
    //$module(ExportProcessors.mss)
    /*
        Shifts the tuplet object to a tupletSpan object. This is
        useful if we need to define a tuplet outside of a hierarchy;
        for example, if a tuplet is only on part of a beam group.

        A tupletSpan supports many of the same attributes as a tuplet
        object, so we can copy the attributes verbatim. Functionally,
        it should behave the same way as a tuplet, except that it
        takes no child elements and the parent element is the measure,
        not the layer. These two things get handled higher up the
        processing chain, however, so we don't have to worry about them here.
    */

    tupletSpan = libmei.TupletSpan();
    libmei.SetAttributes(tupletSpan, tuplet.attrs);

    if (tuplet._parent != null)
    {
        // if the tuplet has already been added to the tree,
        // remove it now. (Unfortunately, we can't delete the object,
        // but disowning it from the tree should be enough to keep it from
        // appearing in the output.)
        pobj = libmei.getElementById(tuplet._parent);
        libmei.RemoveChild(pobj, tuplet);
        tuplet._parent = null;
    }

    mobjs = Self._property:MeasureObjects;
    mobjs.Push(tupletSpan._id);
    Self._property:MeasureObjects = mobjs;

    return tupletSpan;
}  //$end

function ProcessLyric (lyricobj, objectPositions) {
    //$module(ExportProcessors.mss)
    /*
        We need to track initial, medial, and terminal lyrics. Sibelius
        only allows us to know the medial and terminal, so we store all the
        syllables in an array until we reach the end of the word, and then
        attach them to the notes.
    */

    if (lyricobj.Text = '')
    {
        return null;
    }

    styleparts = MSplitString(lyricobj.StyleId, '.');
    verse_id = styleparts[5];
    verse_id_arr = MSplitString(verse_id, false);
    verse_num = verse_id_arr[5];
    bar_num = lyricobj.ParentBar.BarNumber;
    staff_num = lyricobj.ParentBar.ParentStaff.StaffNum;
    voicenum = lyricobj.VoiceNumber;

    if (voicenum = 0)
    {
        // assign it to the first voice, since we don't have any notes in voice 0.
        voicenum = 1;
        warnings = Self._property:warnings;
        warnings.Push(utils.Format(_ObjectAssignedToAllVoicesWarning, bar_num, voicenum, 'Lyric object'));
    }

    lyricwords = Self._property:LyricWords;

    if (lyricwords.PropertyExists(staff_num) = False)
    {
        lyricwords[staff_num] = CreateDictionary();
    }

    lyricstaff = lyricwords[staff_num];

    if (lyricstaff.PropertyExists(voicenum) = False)
    {
        lyricstaff[voicenum] = CreateDictionary();
    }

    lyricvoice = lyricstaff[voicenum];

    if (lyricvoice.PropertyExists(verse_num) = False)
    {
        lyricvoice[verse_num] = CreateSparseArray();
    }

    if (lyricobj.SyllableType = MiddleOfWord)
    {
        lyricvoice[verse_num].Push(lyricobj);
        // we haven't reached the end of the word yet, so just return
        // and keep going.
        return null;
    }

    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    // anything past here is in the EndOfWord condition.
    // this should return a sparse array containing the syllables of the word.
    lyricvoice[verse_num].Push(lyricobj);
    lyric_word = lyricvoice[verse_num];
    objects = objectPositions[voicenum];

    obj_id = null;
    obj = null;

    for j = 0 to lyric_word.Length
    {
        syl = lyric_word[j];

        verse = libmei.Verse();
        libmei.AddAttribute(verse, 'n', verse_num);
        sylel = libmei.Syl();
        // In the case of elisions, we create multiple syl elements from one
        // LyricItem. We have to distinguish between the first and the last syl
        // element we created. In the common, simple case, both are identical.
        sylel_last = sylel;
        libmei.SetText(sylel, syl.Text);
        libmei.AddChild(verse, sylel);

        if (utils.Pos('_', syl.Text) > -1)
        {
            // Syllable elision. split this syllable element by underscore.
            syllables = MSplitString(syl.Text, '_');

            // reset the text of the first syllable element to the first half of the syllable.
            libmei.SetText(sylel, syllables[0]);
            libmei.AddAttribute(sylel, 'con', 'b');

            for s = 1 to syllables.Length
            {
                sylel_last = libmei.Syl();
                libmei.SetText(sylel_last, syllables[s]);
                libmei.AddChild(verse, sylel_last);
            }
        }

        if (j = 0)
        {
            //add a wordpos only for partial words
            if (lyric_word.Length > 1)
            {
                libmei.AddAttribute(sylel_last, 'wordpos', 'i'); // 'initial'

                libmei.AddAttribute(sylel_last, 'con', 'd'); //dash syllable connector
            }

            //it is also possible, that an initial syllable has an underscore as an extender, if it is the only syllable of a word
            if (lyric_word.Length = 1)
            {
                if (syl.NumNotes > 1)
                {
                    libmei.AddAttribute(sylel_last, 'con', 'u'); // 'underscore'
                }
            }
        }
        else
        {
            if (syl.SyllableType = EndOfWord)
            {
                libmei.AddAttribute(sylel, 'wordpos', 't'); // 'terminal'

                if (syl.NumNotes > 1)
                {
                    libmei.AddAttribute(sylel, 'con', 'u'); // 'underscore'
                }

            }
            else
            {
                libmei.AddAttribute(sylel, 'wordpos', 'm'); // medial
                libmei.AddAttribute(sylel, 'con', 'd');
            }
        }

        obj = GetNoteObjectAtPosition(syl);

        if (obj != null)
        {
            name = libmei.GetName(obj);

            if (name = 'rest')
            {
                warnings = Self._property:warnings;
                warnings.Push(utils.Format(_ObjectIsOnAnIllogicalObject, bar_num, voicenum, 'Lyric', 'rest'));
            }

            libmei.AddChild(obj, verse);
        }
        else
        {
            Log('Could not find note object for syl ' & syl);
        }
    }

    // now reset the syllable array for this voice
    lyricvoice[verse_num] = CreateSparseArray();
}  //$end

function ProcessSystemStaff (score) {
    //$module(ExportProcessors.mss)
    systf = score.SystemStaff;

    for each bar in systf
    {
        for each bobj in bar
        {
            switch (bobj.Type)
            {
                case ('SpecialBarline')
                {
                    spclbarlines = Self._property:SpecialBarlines;
                    if (spclbarlines.PropertyExists(bar.BarNumber) = False)
                    {
                        spclbarlines[bar.BarNumber] = CreateSparseArray();
                    }

                    spclbarlines[bar.BarNumber].Push(ConvertBarline(bobj.BarlineInternalType));
                }
                case ('SystemTextItem')
                {
                    if (bobj.OnNthBlankPage < 0)
                    {
                        ProcessFrontMatter(bobj);
                    }

                    systemtext = Self._property:SystemText;

                    if (systemtext.PropertyExists(bar.BarNumber) = False)
                    {
                        systemtext[bar.BarNumber] = CreateSparseArray();
                    }

                    systemtext[bar.BarNumber].Push(bobj);
                }
                case ('Graphic')
                {
                    Log('Found a graphic!');
                    Log('is object? ' & IsObject(bobj));
                }
                case ('RepeatTimeLine')
                {
                    RegisterVolta(bobj);
                }
            }
        }
    }
}  //$end

function ProcessFrontMatter (bobj) {
    //$module(ExportProcessors.mss)
    /*
        For example, if page 2 (0-indexed) is the first page of music,
        then 'OnNthPage' will be 2, but the system staff items for
        the first page of text will be -2, so 2 + (-2) = 0 + 1;
    */
    bar = bobj.ParentBar;
    text = '';

    pnum = (bar.OnNthPage + bobj.OnNthBlankPage) + 1;
    frontmatter = Self._property:FrontMatter;

    if (frontmatter.PropertyExists(pnum) = False)
    {
        pb = libmei.Pb();
        libmei.AddAttribute(pb, 'n', pnum);
        frontmatter[pnum] = CreateSparseArray(pb);
    }
    pagematter = frontmatter[pnum];

    text = GenerateFormattedString(bobj);
    frontmatter[pnum] = pagematter.Concat(text);

}  //$end

function RegisterVolta (bobj) {
    //$module(ExportProcessors.mss)
    voltabars = Self._property:VoltaBars;
    style = MSplitString(bobj.StyleId, '.');

    if (style[2] = 'repeat')
    {
        voltabars[bobj.ParentBar.BarNumber] = bobj;
    }
}  //$end

function ProcessVolta (mnum) {
    //$module(ExportProcessors.mss)
    voltabars = Self._property:VoltaBars;

    if (voltabars.PropertyExists(mnum))
    {
        voltaElement = libmei.Ending();

        Self._property:VoltaElement = voltaElement;

        voltaObject = voltabars[mnum];
        voltainfo = ConvertEndingValues(voltaObject.StyleId);

        libmei.AddAttribute(voltaElement, 'n', voltainfo[0]);
        libmei.AddAttribute(voltaElement, 'label', voltainfo[1]);
        libmei.AddAttribute(voltaElement, 'type', voltainfo[2]);

        if (voltaObject.EndBarNumber != mnum)
        {
            Self._property:ActiveVolta = voltaObject;
        }

        return voltaElement;
    }
    else
    {
        if (Self._property:ActiveVolta != null)
        {
            // we have an unresolved volta, so
            // we'll keep the previous parentElement
            // active.
            activeVolta = Self._property:ActiveVolta;
            voltaElement = Self._property:VoltaElement;

            // if the end bar is the current bar OR if the end
            // bar is the next bar, but the end position is 0, we're escaping the
            // volta the next time around.
            if ((activeVolta.EndBarNumber = mnum) or
                (activeVolta.EndBarNumber = (mnum + 1) and activeVolta.EndPosition = 0))
            {
                Self._property:ActiveVolta = null;
                Self._property:VoltaElement = null;
            }
            return null;
        }
    }

    return null;
}  //$end

function ProcessTremolo (bobj) {
    //$module(ExportProcessors.mss)
    if (bobj.DoubleTremolos = 0)
    {
        return null;
    }

    Log('Fingered tremolo: ' & bobj.DoubleTremolos);
    tremEl = libmei.FTrem();
    libmei.AddAttribute(tremEl, 'beams', bobj.DoubleTremolos);
    libmei.AddAttribute(tremEl, 'unitdur');

} //$end

function ProcessSymbol (sobj) {
    //$module(ExportProcessors.mss)
    Log('symbol index: ' & sobj.Index & ' name: ' & sobj.Name);
    Log(sobj.VoiceNumber);
    voicenum = sobj.VoiceNumber;
    bar = sobj.ParentBar;

    if (voicenum = 0)
    {
        // assign it to the first voice, since we don't have any notes in voice/layer 0.
        sobj.VoiceNumber = 1;
        warnings = Self._property:warnings;
        warnings.Push(utils.Format(_ObjectAssignedToAllVoicesWarning, bar.BarNumber, voicenum, 'Symbol'));
    }

    switch (sobj.Index)
    {
        case ('32')
        {
            // trill
            trill = GenerateTrill(sobj);
            mlines = Self._property:MeasureObjects;
            mlines.Push(trill._id);
        }

        case ('36')
        {
            // inverted mordent
            mordent = libmei.Mordent();
            libmei.AddAttribute(mordent, 'form', 'lower');
            mordent = AddBarObjectInfoToElement(sobj, mordent);
            mlines = Self._property:MeasureObjects;
            mlines.Push(mordent._id);
        }

        case ('37')
        {
            // mordent
            mordent = libmei.Mordent();
            libmei.AddAttribute(mordent, 'form', 'upper');
            mordent = AddBarObjectInfoToElement(sobj, mordent);
            mlines = Self._property:MeasureObjects;
            mlines.Push(mordent._id);
        }

        case ('38')
        {
            // turn
            turn = libmei.Turn();
            libmei.AddAttribute(turn, 'form', 'upper');
            turn = AddBarObjectInfoToElement(sobj, turn);
            mlines = Self._property:MeasureObjects;
            mlines.Push(turn._id);
        }

        case ('39')
        {
            // inverted turn
            turn = libmei.Turn();
            libmei.AddAttribute(turn, 'form', 'lower');
            turn = AddBarObjectInfoToElement(sobj, turn);
            mlines = Self._property:MeasureObjects;
            mlines.Push(turn._id);
        }
        case ('52')
        {
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'heel');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('53')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'heel');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('54')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'toe');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('55')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'toe');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('160')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'stop');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('162')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'open');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('163')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'damp');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('164')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'damp');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('165')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'damp');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('166')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'damp');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('212')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'ten');
                libmei.AddAttribute(artic, 'place', 'above');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('214')
        {
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'marc');
                libmei.AddAttribute(artic, 'place', 'above');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('217')
        {
            // up-bow above
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'upbow');
                libmei.AddAttribute(artic, 'place', 'above');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('218')
        {
            // down-bow above
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'dnbow');
                libmei.AddAttribute(artic, 'place', 'above');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('233')
        {
            // up-bow below
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'upbow');
                libmei.AddAttribute(artic, 'place', 'below');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('234')
        {
            // down-bow below
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'dnbow');
                libmei.AddAttribute(artic, 'place', 'below');
                libmei.AddChild(nobj, artic);
            }
            else
            {
                warnings = Self._property:warnings;
                warnings.Push(utils.Format(_ObjectCouldNotFindAttachment, bar.BarNumber, voicenum, sobj.Name));
            }
        }
        case ('240')
        {
            // double staccato
            return null;
        }
        case ('241')
        {
            // triple staccato
            return null;
        }
        case ('242')
        {
            // quadruple staccato
            return null;
        }
        case ('243')
        {
            // snap
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttributeValue(artic, 'artic', 'snap');
                libmei.AddChild(nobj, artic);
            }
            else
            {
                warnings = Self._property:warnings;
                warnings.Push(utils.Format(_ObjectCouldNotFindAttachment, bar.BarNumber, voicenum, sobj.Name));
            }
        }
        case ('480')
        {
            //scoop
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttributeValue(artic, 'artic', 'scoop');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('481')
        {
            //fall
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttributeValue(artic, 'artic', 'fall');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('490')
        {
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttributeValue(artic, 'artic', 'fingernail');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('494')
        {
            //doit
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttributeValue(artic, 'artic', 'doit');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('495')
        {
            //plop
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttributeValue(artic, 'artic', 'plop');
                libmei.AddChild(nobj, artic);
            }

        }

    }
} //$end

function ProcessEndingSlurs (bar) {
    //$module(ExportProcessors.mss)
    slur_resolver = Self._property:SlurResolver;
    for voiceNumber = 1 to 5
    {
        endingSlurs = slur_resolver[LayerHash(bar, voiceNumber)];
        if (endingSlurs != null)
        {
            for each slur in endingSlurs
            {
                end_obj = GetNoteObjectAtEndPosition(slur);
                if (end_obj != null)
                {
                    libmei.AddAttribute(slur._property:mobj, 'endid', '#' & end_obj._id);
                }
            }
        }
    }
}  //$end

function ProcessScore () {
    //$module(ExportProcessors.mss)
    // processors are a bit like a workflow manager -- they orchestrate the
    // generators, which in turn use the converters to convert specific values from sibelius
    // to MEI.
    score = Self._property:ActiveScore;

    mei = libmei.Mei();
    libmei.setDocumentRoot(mei);

    libmei.AddAttribute(mei, 'xmlns:xlink', 'http://www.w3.org/1999/xlink');
    libmei.AddAttribute(mei, 'xmlns', 'http://www.music-encoding.org/ns/mei');
    libmei.AddAttribute(mei, 'meiversion', '4.0.1');

    header = GenerateMEIHeader();
    libmei.AddChild(mei, header);

    music = GenerateMEIMusic();
    libmei.AddChild(mei, music);

}  //$end

function ProcessBeam (bobj, layer, normalizedBeamProp) {
    //$module(ExportProcessors.mss)
    /*
        Returns the active beam, if any, and creates new beam elements
        at the start of a beam.
    */
    switch (normalizedBeamProp)
    {
        case (NoBeam)
        {
            if (bobj.GraceNote)
            {
                if (layer._property:ActiveGraceBeam != null)
                {
                    layer._property:ActiveGraceBeam = null;
                }
                // If there is an active non-grace beam, we have a normal beam spanning
                // over a non-beamed grace note that will be added as a child of that beam.
                return GetNongraceParentBeam(bobj, layer);
            }
            else
            {
                if (layer._property:ActiveBeam != null)
                {
                    layer._property:ActiveBeam = null;
                }
                return null;
            }
        }
        case (StartBeam)
        {
            newBeam = libmei.Beam();
            if (bobj.GraceNote)
            {
                layer._property:ActiveGraceBeam = newBeam;
                nonGraceParentBeam = GetNongraceParentBeam(bobj, layer);
                if (nonGraceParentBeam != null)
                {
                    newBeam._property:ParentBeam = nonGraceParentBeam;
                }
            }
            else
            {
                layer._property:ActiveBeam = newBeam;
            }
            return newBeam;
        }
        default {
            // ContinueBeam and SingleBeam
            if (bobj.GraceNote)
            {
                return layer._property:ActiveGraceBeam;
            }
            else
            {
                return layer._property:ActiveBeam;
            }
        }
    }
}  //$end

function ProcessTuplet (noteRest, meielement, layer) {
    //$module(ExportProcessors.mss)
    if (noteRest.ParentTupletIfAny = null)
    {
        return null;
    }

    /*
       We encode inner tuplets of nested tuplet structures as <tupletSpan>s.
       Therefore we always return the outermost MEI tuplet for content to be added.
       Still, we need to keep track of the inner tuplets to assign the @endid.
       layer._property:ActiveMeiTuplet always points to the innermost tuplet.
    */
    activeMeiTuplet = layer._property:ActiveMeiTuplet;

    tupletIsContinued = activeMeiTuplet != null and TupletsEqual(noteRest.ParentTupletIfAny, activeMeiTuplet._property:SibTuplet);

    if (not(tupletIsContinued))
    {
        // New tuplets need to be added
        noteRestTupletStack = GetTupletStack(noteRest);
        sibTuplet = null;
        meiTupletDepth = GetMeiTupletDepth(layer);

        for i = meiTupletDepth to noteRestTupletStack.Length
        {
            sibTuplet = noteRestTupletStack[i];
            nextActiveMeiTuplet = GenerateTuplet(sibTuplet);
            if (meiTupletDepth > 0 or i > meiTupletDepth)
            {
                // We have an inner tuplet that we encode as <tupletSpan>
                nextActiveMeiTuplet = ShiftTupletToTupletSpan(nextActiveMeiTuplet, layer);
            }
            libmei.AddAttribute(nextActiveMeiTuplet, 'startid', '#' & meielement._id);
            // We basically create a linked list of tuplets
            nextActiveMeiTuplet._property:ParentTuplet = activeMeiTuplet;
            nextActiveMeiTuplet._property:SibTuplet = sibTuplet;
            activeMeiTuplet = nextActiveMeiTuplet;
        }
        layer._property:ActiveMeiTuplet = activeMeiTuplet;
    }

    meiTuplet = activeMeiTuplet;
    for i = 0 to CountTupletsEndingAtNoteRest(noteRest)
    {
        libmei.AddAttribute(meiTuplet, 'endid', '#' & meielement._id);
        meiTuplet = meiTuplet._property:ParentTuplet;
    }
    layer._property:ActiveMeiTuplet = meiTuplet;

    outermostMeiTuplet = activeMeiTuplet;
    while (outermostMeiTuplet._property:ParentTuplet)
    {
        outermostMeiTuplet = outermostMeiTuplet._property:ParentTuplet;
    }
    return outermostMeiTuplet;
}  //$end

function ShiftTupletToTupletSpan (tuplet) {
    //$module(ExportProcessors.mss)
    /*
        Shifts the tuplet object to a tupletSpan object. This is
        useful if we need to define a tuplet outside of a hierarchy;
        for example, if a tuplet is only on part of a beam group.

        A tupletSpan supports many of the same attributes as a tuplet
        object, so we can copy the attributes verbatim. Functionally,
        it should behave the same way as a tuplet, except that it
        takes no child elements and the parent element is the measure,
        not the layer. These two things get handled higher up the
        processing chain, however, so we don't have to worry about them here.
    */

    tupletSpan = libmei.TupletSpan();
    libmei.SetAttributes(tupletSpan, tuplet.attrs);

    if (tuplet._parent != null)
    {
        // if the tuplet has already been added to the tree,
        // remove it now. (Unfortunately, we can't delete the object,
        // but disowning it from the tree should be enough to keep it from
        // appearing in the output.)
        pobj = libmei.getElementById(tuplet._parent);
        libmei.RemoveChild(pobj, tuplet);
        tuplet._parent = null;
    }

    mobjs = Self._property:MeasureObjects;
    mobjs.Push(tupletSpan._id);
    Self._property:MeasureObjects = mobjs;

    return tupletSpan;
}  //$end

function ProcessLyric (lyricobj, objectPositions) {
    //$module(ExportProcessors.mss)
    /*
        We need to track initial, medial, and terminal lyrics. Sibelius
        only allows us to know the medial and terminal, so we store all the
        syllables in an array until we reach the end of the word, and then
        attach them to the notes.
    */

    if (lyricobj.Text = '')
    {
        return null;
    }

    styleparts = MSplitString(lyricobj.StyleId, '.');
    verse_id = styleparts[5];
    verse_id_arr = MSplitString(verse_id, false);
    verse_num = verse_id_arr[5];
    bar_num = lyricobj.ParentBar.BarNumber;
    staff_num = lyricobj.ParentBar.ParentStaff.StaffNum;
    voicenum = lyricobj.VoiceNumber;

    if (voicenum = 0)
    {
        // assign it to the first voice, since we don't have any notes in voice 0.
        voicenum = 1;
        warnings = Self._property:warnings;
        warnings.Push(utils.Format(_ObjectAssignedToAllVoicesWarning, bar_num, voicenum, 'Lyric object'));
    }

    lyricwords = Self._property:LyricWords;

    if (lyricwords.PropertyExists(staff_num) = False)
    {
        lyricwords[staff_num] = CreateDictionary();
    }

    lyricstaff = lyricwords[staff_num];

    if (lyricstaff.PropertyExists(voicenum) = False)
    {
        lyricstaff[voicenum] = CreateDictionary();
    }

    lyricvoice = lyricstaff[voicenum];

    if (lyricvoice.PropertyExists(verse_num) = False)
    {
        lyricvoice[verse_num] = CreateSparseArray();
    }

    if (lyricobj.SyllableType = MiddleOfWord)
    {
        lyricvoice[verse_num].Push(lyricobj);
        // we haven't reached the end of the word yet, so just return
        // and keep going.
        return null;
    }

    // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    // anything past here is in the EndOfWord condition.
    // this should return a sparse array containing the syllables of the word.
    lyricvoice[verse_num].Push(lyricobj);
    lyric_word = lyricvoice[verse_num];
    objects = objectPositions[voicenum];

    obj_id = null;
    obj = null;

    for j = 0 to lyric_word.Length
    {
        syl = lyric_word[j];

        verse = libmei.Verse();
        libmei.AddAttribute(verse, 'n', verse_num);
        sylel = libmei.Syl();
        // In the case of elisions, we create multiple syl elements from one
        // LyricItem. We have to distinguish between the first and the last syl
        // element we created. In the common, simple case, both are identical.
        sylel_last = sylel;
        libmei.SetText(sylel, syl.Text);
        libmei.AddChild(verse, sylel);

        if (utils.Pos('_', syl.Text) > -1)
        {
            // Syllable elision. split this syllable element by underscore.
            syllables = MSplitString(syl.Text, '_');

            // reset the text of the first syllable element to the first half of the syllable.
            libmei.SetText(sylel, syllables[0]);
            libmei.AddAttribute(sylel, 'con', 'b');

            for s = 1 to syllables.Length
            {
                sylel_last = libmei.Syl();
                libmei.SetText(sylel_last, syllables[s]);
                libmei.AddChild(verse, sylel_last);
            }
        }

        if (j = 0)
        {
            //add a wordpos only for partial words
            if (lyric_word.Length > 1)
            {
                libmei.AddAttribute(sylel_last, 'wordpos', 'i'); // 'initial'

                libmei.AddAttribute(sylel_last, 'con', 'd'); //dash syllable connector
            }

            //it is also possible, that an initial syllable has an underscore as an extender, if it is the only syllable of a word
            if (lyric_word.Length = 1)
            {
                if (syl.NumNotes > 1)
                {
                    libmei.AddAttribute(sylel_last, 'con', 'u'); // 'underscore'
                }
            }
        }
        else
        {
            if (syl.SyllableType = EndOfWord)
            {
                libmei.AddAttribute(sylel, 'wordpos', 't'); // 'terminal'

                if (syl.NumNotes > 1)
                {
                    libmei.AddAttribute(sylel, 'con', 'u'); // 'underscore'
                }

            }
            else
            {
                libmei.AddAttribute(sylel, 'wordpos', 'm'); // medial
                libmei.AddAttribute(sylel, 'con', 'd');
            }
        }

        obj = GetNoteObjectAtPosition(syl);

        if (obj != null)
        {
            name = libmei.GetName(obj);

            if (name = 'rest')
            {
                warnings = Self._property:warnings;
                warnings.Push(utils.Format(_ObjectIsOnAnIllogicalObject, bar_num, voicenum, 'Lyric', 'rest'));
            }

            if (name = 'chord')
            {
                warnings = Self._property:warnings;
                warnings.Push(utils.Format(_ObjectIsOnAnIllogicalObject, bar_num, voicenum, 'Lyric', 'chord'));
            }

            libmei.AddChild(obj, verse);
        }
        else
        {
            Log('Could not find note object for syl ' & syl);
        }
    }

    // now reset the syllable array for this voice
    lyricvoice[verse_num] = CreateSparseArray();
}  //$end

function ProcessSystemStaff (score) {
    //$module(ExportProcessors.mss)
    systf = score.SystemStaff;

    for each bar in systf
    {
        for each bobj in bar
        {
            switch (bobj.Type)
            {
                case ('SpecialBarline')
                {
                    spclbarlines = Self._property:SpecialBarlines;
                    if (spclbarlines.PropertyExists(bar.BarNumber) = False)
                    {
                        spclbarlines[bar.BarNumber] = CreateSparseArray();
                    }

                    spclbarlines[bar.BarNumber].Push(ConvertBarline(bobj.BarlineInternalType));
                }
                case ('SystemTextItem')
                {
                    if (bobj.OnNthBlankPage < 0)
                    {
                        ProcessFrontMatter(bobj);
                    }

                    systemtext = Self._property:SystemText;

                    if (systemtext.PropertyExists(bar.BarNumber) = False)
                    {
                        systemtext[bar.BarNumber] = CreateSparseArray();
                    }

                    systemtext[bar.BarNumber].Push(bobj);
                }
                case ('Graphic')
                {
                    Log('Found a graphic!');
                    Log('is object? ' & IsObject(bobj));
                }
                case ('RepeatTimeLine')
                {
                    RegisterVolta(bobj);
                }
            }
        }
    }
}  //$end

function ProcessFrontMatter (bobj) {
    //$module(ExportProcessors.mss)
    /*
        For example, if page 2 (0-indexed) is the first page of music,
        then 'OnNthPage' will be 2, but the system staff items for
        the first page of text will be -2, so 2 + (-2) = 0 + 1;
    */
    bar = bobj.ParentBar;
    text = '';

    pnum = (bar.OnNthPage + bobj.OnNthBlankPage) + 1;
    frontmatter = Self._property:FrontMatter;

    if (frontmatter.PropertyExists(pnum) = False)
    {
        pb = libmei.Pb();
        libmei.AddAttribute(pb, 'n', pnum);
        frontmatter[pnum] = CreateSparseArray(pb);
    }
    pagematter = frontmatter[pnum];

    text = GenerateFormattedString(bobj);
    frontmatter[pnum] = pagematter.Concat(text);

}  //$end

function RegisterVolta (bobj) {
    //$module(ExportProcessors.mss)
    voltabars = Self._property:VoltaBars;
    style = MSplitString(bobj.StyleId, '.');

    if (style[2] = 'repeat')
    {
        voltabars[bobj.ParentBar.BarNumber] = bobj;
    }
}  //$end

function ProcessVolta (mnum) {
    //$module(ExportProcessors.mss)
    voltabars = Self._property:VoltaBars;

    if (voltabars.PropertyExists(mnum))
    {
        voltaElement = libmei.Ending();

        Self._property:VoltaElement = voltaElement;

        voltaObject = voltabars[mnum];
        voltainfo = ConvertEndingValues(voltaObject.StyleId);

        libmei.AddAttribute(voltaElement, 'n', voltainfo[0]);
        libmei.AddAttribute(voltaElement, 'label', voltainfo[1]);
        libmei.AddAttribute(voltaElement, 'type', voltainfo[2]);

        if (voltaObject.EndBarNumber != mnum)
        {
            Self._property:ActiveVolta = voltaObject;
        }

        return voltaElement;
    }
    else
    {
        if (Self._property:ActiveVolta != null)
        {
            // we have an unresolved volta, so
            // we'll keep the previous parentElement
            // active.
            activeVolta = Self._property:ActiveVolta;
            voltaElement = Self._property:VoltaElement;

            // if the end bar is the current bar OR if the end
            // bar is the next bar, but the end position is 0, we're escaping the
            // volta the next time around.
            if ((activeVolta.EndBarNumber = mnum) or
                (activeVolta.EndBarNumber = (mnum + 1) and activeVolta.EndPosition = 0))
            {
                Self._property:ActiveVolta = null;
                Self._property:VoltaElement = null;
            }
            return null;
        }
    }

    return null;
}  //$end

function ProcessTremolo (bobj) {
    //$module(ExportProcessors.mss)
    if (bobj.DoubleTremolos = 0)
    {
        return null;
    }

    Log('Fingered tremolo: ' & bobj.DoubleTremolos);
    tremEl = libmei.FTrem();
    libmei.AddAttribute(tremEl, 'beams', bobj.DoubleTremolos);
    libmei.AddAttribute(tremEl, 'unitdur');

} //$end

function ProcessSymbol (sobj) {
    //$module(ExportProcessors.mss)
    Log('symbol index: ' & sobj.Index & ' name: ' & sobj.Name);
    Log(sobj.VoiceNumber);
    voicenum = sobj.VoiceNumber;
    bar = sobj.ParentBar;

    if (voicenum = 0)
    {
        // assign it to the first voice, since we don't have any notes in voice/layer 0.
        sobj.VoiceNumber = 1;
        warnings = Self._property:warnings;
        warnings.Push(utils.Format(_ObjectAssignedToAllVoicesWarning, bar.BarNumber, voicenum, 'Symbol'));
    }

    switch (sobj.Index)
    {
        case ('32')
        {
            // trill
            trill = GenerateTrill(sobj);
            mlines = Self._property:MeasureObjects;
            mlines.Push(trill._id);
        }

        case ('36')
        {
            // inverted mordent
            mordent = libmei.Mordent();
            libmei.AddAttribute(mordent, 'form', 'lower');
            mordent = AddBarObjectInfoToElement(sobj, mordent);
            mlines = Self._property:MeasureObjects;
            mlines.Push(mordent._id);
        }

        case ('37')
        {
            // mordent
            mordent = libmei.Mordent();
            libmei.AddAttribute(mordent, 'form', 'upper');
            mordent = AddBarObjectInfoToElement(sobj, mordent);
            mlines = Self._property:MeasureObjects;
            mlines.Push(mordent._id);
        }

        case ('38')
        {
            // turn
            turn = libmei.Turn();
            libmei.AddAttribute(turn, 'form', 'upper');
            turn = AddBarObjectInfoToElement(sobj, turn);
            mlines = Self._property:MeasureObjects;
            mlines.Push(turn._id);
        }

        case ('39')
        {
            // inverted turn
            turn = libmei.Turn();
            libmei.AddAttribute(turn, 'form', 'lower');
            turn = AddBarObjectInfoToElement(sobj, turn);
            mlines = Self._property:MeasureObjects;
            mlines.Push(turn._id);
        }
        case ('52')
        {
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'heel');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('53')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'heel');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('54')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'toe');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('55')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'toe');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('160')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'stop');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('162')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'open');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('163')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'damp');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('164')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'damp');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('165')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'damp');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('166')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'damp');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('212')
        {
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'ten');
                libmei.AddAttribute(artic, 'place', 'above');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('214')
        {
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'marc');
                libmei.AddAttribute(artic, 'place', 'above');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('217')
        {
            // up-bow above
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'upbow');
                libmei.AddAttribute(artic, 'place', 'above');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('218')
        {
            // down-bow above
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'dnbow');
                libmei.AddAttribute(artic, 'place', 'above');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('233')
        {
            // up-bow below
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'upbow');
                libmei.AddAttribute(artic, 'place', 'below');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('234')
        {
            // down-bow below
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttribute(artic, 'artic', 'dnbow');
                libmei.AddAttribute(artic, 'place', 'below');
                libmei.AddChild(nobj, artic);
            }
            else
            {
                warnings = Self._property:warnings;
                warnings.Push(utils.Format(_ObjectCouldNotFindAttachment, bar.BarNumber, voicenum, sobj.Name));
            }
        }
        case ('240')
        {
            // double staccato
            return null;
        }
        case ('241')
        {
            // triple staccato
            return null;
        }
        case ('242')
        {
            // quadruple staccato
            return null;
        }
        case ('243')
        {
            // snap
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttributeValue(artic, 'artic', 'snap');
                libmei.AddChild(nobj, artic);
            }
            else
            {
                warnings = Self._property:warnings;
                warnings.Push(utils.Format(_ObjectCouldNotFindAttachment, bar.BarNumber, voicenum, sobj.Name));
            }
        }
        case ('480')
        {
            //scoop
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttributeValue(artic, 'artic', 'scoop');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('481')
        {
            //fall
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttributeValue(artic, 'artic', 'fall');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('490')
        {
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttributeValue(artic, 'artic', 'fingernail');
                libmei.AddChild(nobj, artic);
            }
        }
        case ('494')
        {
            //doit
            nobj = GetNoteObjectAtPosition(sobj);
            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttributeValue(artic, 'artic', 'doit');
                libmei.AddChild(nobj, artic);
            }

        }
        case ('495')
        {
            //plop
            nobj = GetNoteObjectAtPosition(sobj);

            if (nobj != null)
            {
                artic = libmei.Artic();
                libmei.AddAttributeValue(artic, 'artic', 'plop');
                libmei.AddChild(nobj, artic);
            }

        }

    }
} //$end

function ProcessEndingSlurs (bar) {
    //$module(ExportProcessors.mss)
    slur_resolver = Self._property:SlurResolver;
    for voiceNumber = 1 to 5
    {
        endingSlurs = slur_resolver[LayerHash(bar, voiceNumber)];
        if (endingSlurs != null)
        {
            for each slur in endingSlurs
            {
                end_obj = GetNoteObjectAtEndPosition(slur);
                if (end_obj != null)
                {
                    libmei.AddAttribute(slur._property:mobj, 'endid', '#' & end_obj._id);
                }
            }
        }
    }
}  //$end