###### Automatic builds
$$include '../meta/macros.ptl'

import 'unorm' as unorm
import [mix linreg clamp fallback suggestGC] from '../support/utils'
import [designParameters] from '../meta/aesthetics'

define customDecompositions : object
	# Latvians use comma instead of cedillas in several letters.
	# Record them as custom decomposition.
	."\u0156" "R\u0326"
	."\u0157" "r\u0326"
	."\u0136" "K\u0326"
	."\u0137" "k\u0326"
	."\u0145" "N\u0326"
	."\u0146" "n\u0326"
	."\u013B" "L\u0326"
	."\u013C" "l\u0326"
	."\u0122" "G\u0326"
	."\u0123" "g\u0312"
	
	# autobuild Latin glyphs
	."\u0197" "I\u0335"
	."\u019A" "l\u0335"
	."\u0248" "J\u0335"
	."\u0249" "j\u0335"
	."\u0268" "i\u0335"
	."\u024C" "R\u0335"
	."\u024D" "r\u0335"
	."\u01B5" "Z\u0335"
	."\u01B6" "z\u0335"
	."\u1D7B" "\u026A\u0335"
	."\u1D7C" "\u0269\u0335"
 	
	."\u1D7F" "\u028A\u0336"
	."\u0289" "u\u0336"
	."\u0244" "U\u0336"
	."\u01E5" "g\u0336"
	."\u01BB" "2\u0336"
	."\u024E" "Y\u0336"
	."\u04B0" "\u04AE\u0335"
	."\u04B1" "\u04AF\u0335"
	."\u024F" "y\u0336"
	."\uAB30" "\uAB64\u0336"
	."\u1D7D" "p\u0336"
 	
	."\u0142" "l\uE090"
	."\u013E" "l\u0315"
	."\u0165" "t\u0315"
 	
	."\u023A" "A\u0338"
	."\u023B" "C\u0338"
	."\u023C" "c\u0337"
	."\u023E" "T\u0338"
	."\u0246" "E\u0338"
	."\u0247" "e\u0337"

	."\u0290" "z\u0322"
	."\u0256" "d\u0322"
	."\u0273" "n\u0322"
	."\u01AE" "T\u0322"
	."\u1D8F" "a\u0322"
	."\u1D90" "\u0251\u0322"
	."\u1D91" "\u0257\u0322"
	."\u1D99" "u\u0322"
 	
	."\u1E9A" "a\u0357"
	."\u1E9C" "\u017F\uE090"
	."\u1E9D" "\u017F\u0335"
 	
 	# Cyrillic composite characters
	."\u0498" "\u0417\u0327"
	."\u0499" "\u0437\u0327"
	."\u04AA" "\u0421\u0327"
	."\u04AB" "\u0441\u0327"

	# Spacing modifers
	."\u02CB" " \u0300"
	."\u02CA" " \u0301"
	."\u02C6" " \u0302"
	."\u02DC" " \u0303"
	."\u00AF" " \u0304"
	."\u02C9" " \u0304"
	."\u02D8" " \u0306"
	."\u02D9" " \u0307"
	."\u00A8" " \u0308"
	."\u02DA" " \u030A"
	."\u02C7" " \u030C"
	."\u00B8" " \u0327"
	."\u02CD" " \u0331"
	."\u02CE" " \u0316"
	."\u02CF" " \u0317"
	."\u02D2" " \u0339"
	."\u02D3" " \u031C"
	."\u02D4" " \u031D"
	."\u02D5" " \u031E"
	."\u02D6" " \u031F"
	."\u02D7" " \u0320"
	."\u02DB" " \u0328"
	."\u02DD" " \u030B"
	."\u02DF" " \u033D"
	."\u02EC" " \u032C"
	."\u02ED" " \u033F"
	."\u02F3" " \u0325"
	."\u02F7" " \u0330"

	."\u1FED" " \u0308\u0300"
	."\u1FEE" " \u0308\u0301"
	."\u1FEF" " \u0300"
	."\u1FFD" " \u0301"
	."\u1FFE" " \u0314"
	."\u1FBD" " \u0313"
	."\u1FBE" " \u0345"
	."\u1FBF" " \u0313"
	."\u1FC0" " \u0342"
	."\u1FC1" " \u0308\u0342"
	."\u0384" " \u0301"
	."\u0385" " \u0308\u0301"
	."\u037A" " \u0345"
	
	# Suppress incorrect slashed arrows... so far
	."\u219A" ""
	."\u219B" ""
	."\u21AE" ""





export : define [apply] : begin
	glyph-module-entry commonShapes overmarks
	# Build accented glyphs
	let : begin
		if [not recursive] : suggestGC
		define [isAboveMark mark] : mark && mark.anchors && mark.anchors.above && mark.anchors.above.type === MARK
		define [iotaBelowToLF p j parts] : if (p === glyphs.iotaBelow) : set parts.(j) glyphs.iotaLF
		define [ogonekBelowToTR p j parts] : if (p === glyphs.ogonekBelow) : set parts.(j) glyphs.ogonekTR
		define [subParts parts] : begin
			local hasMarkAbove false
			foreach p [items-of parts] : if [isAboveMark p] : set hasMarkAbove true
			
			# replace dotted-i and dotted-j with dotless equalivents
			if ((parts.0 === glyphs.i || parts.0 === glyphs.cyrUkrainiani) && hasMarkAbove) : parts.0 = glyphs.dotlessi
			if (parts.0 === glyphs.j && hasMarkAbove) : parts.0 = glyphs.dotlessj
			
			# replace below marks with trailing marks
			if parts.0.anchors.lf : parts.forEach iotaBelowToLF
			if parts.0.anchors.trailing : parts.forEach ogonekBelowToTR
			
			# composite greek overmarks
			for [local j 0] (j < parts.length) [inc j] : piecewise
				(parts.(j) === glyphs.commaAbove) : begin
					piecewise
						(parts.(j + 1) === glyphs.graveAbove) : begin
							set parts.(j) null; set parts.(j + 1) glyphs.psilivaria
						(parts.(j + 1) === glyphs.acuteAbove) : begin
							set parts.(j) null; set parts.(j + 1) glyphs.psilioxia
						(parts.(j + 1) === glyphs.perispomeniAbove) : begin
							set parts.(j) null; set parts.(j + 1) glyphs.psiliperispomeni
				(parts.(j) === glyphs.revCommaAbove) : begin
					piecewise
						(parts.(j + 1) === glyphs.graveAbove) : begin
							set parts.(j) null; set parts.(j + 1) glyphs.dasiavaria
						(parts.(j + 1) === glyphs.acuteAbove) : begin
							set parts.(j) null; set parts.(j + 1) glyphs.dasiaoxia
						(parts.(j + 1) === glyphs.perispomeniAbove) : begin
							set parts.(j) null; set parts.(j + 1) glyphs.dasiaperispomeni
			return parts

		define [pad _s n] : begin
			local s _s
			while (s.length < n) : s = '0' + s
			return s
		local nComposed 0
		local foundDecompositions {.}
		define [decideName namingParts parts code] : begin
			local baseName namingParts.0.name
			local glyphName baseName
			foreach [part : namingParts.slice 1] : if part : glyphName = glyphName + [fallback part.shortName part.name]
			if foundDecompositions.(glyphName) : begin
				local j 2
				while foundDecompositions.(glyphName + j) [inc j]
				set glyphName (glyphName + j)
			if (glyphName.length > 27) : set glyphName ('uni' + [pad [[code.toString 16].toUpperCase] 4])
			return glyphName
		local [buildForCode code] : if [not unicodeGlyphs.(code)] : begin
			local str : String.fromCharCode code
			local nfd : fallback customDecompositions.(str) : unorm.nfd str
			if (nfd.length > 1) : begin
				local parts {}
				local allFound true
				foreach j [range 0 nfd.length] : begin
					local part unicodeGlyphs.([nfd.charCodeAt j])
					if [not part] : then : set allFound false
					: else : set parts.(j) unicodeGlyphs.([nfd.charCodeAt j])
				if allFound : begin
					local namingParts : parts.slice 0
					set parts : subParts parts
					local glyphName : decideName namingParts parts code
					set foundDecompositions.(glyphName) {glyphName code parts}

		if recursiveCodes : recursiveCodes.forEach buildForCode
		: else : foreach code [range 0x0000 0xFFFF] : buildForCode code
		suggestGC
		
		local {glyphName code parts} {}
		define construction : glyph-construction
			if code : assign-unicode code
			include parts.0 AS_BASE
			set-width parts.0.advanceWidth
			
			local names {parts.0.name}
			foreach part [items-of : parts.slice 1] : if part : begin
				include part
				names.push part.name
				if (part.name === 'rtailBR') : eject-contour 'serifRB'
			inc nComposed
		
		define [cfv glyphName _pa] : if (!recursive && _pa.0.featureSelector) : begin
			local h {.}
			foreach [feature : items-of : Object.keys _pa.0.featureSelector] : begin
				local variant _pa.0.featureSelector.(feature)
				local variantRoot glyphs.(variant)
				if variantRoot : begin
					set parts {variantRoot :: [_pa.slice 1]}
					set code null
					create-glyph (glyphName + '.' + feature) construction

					set h.(feature) (glyphName + '.' + feature)
			if glyphs.(glyphName) : set glyphs.(glyphName).featureSelector h
		
		foreach [_id : items-of : Object.keys foundDecompositions] : begin
			set {glyphName code parts} foundDecompositions.(_id)
			create-glyph glyphName construction
			cfv glyphName parts

		suggestGC


	define [suggestName _name] : begin
		local name _name
		if glyphs.(name) : begin
			local j 2
			while glyphs.(name + j) : inc j
			set name (name + j)
		return name
	# Build miniature clyphs : circled, superscripts, subscripts...
	define [createCircledGlyphs records] : if [not recursive] : begin
		local dscale 0.55
		local pendingGlyphs : records.map : [record] => record.1
		local miniatureFont : Miniature 
			glyphs -- pendingGlyphs
			crowd  -- [fallback para.smallCrowd 3.75]
			scale  -- 0.65
			unfair -- true
		
		foreach {unicode glyphid w} [items-of records] : create-glyph [suggestName : 'circle' + glyphid] : glyph-construction
			local width : fallback w WIDTH
			set-width width
			local sw [adviceBlackness 5]
			if unicode : assign-unicode unicode
			include : create-glyph [suggestName : 'circleinner' + glyphid] : glyph-construction
				local g miniatureFont.(glyphid)
				include g
				local shift 0
				if (g.anchors.above && g.anchors.below) : set shift : CAP / 2 -  [mix g.anchors.above.y g.anchors.below.y 0.5]
				apply-transform : Upright
				apply-transform : Translate (-WIDTH / 2) (-CAP / 2 + shift)
				apply-transform : Scale dscale
				apply-transform : Translate (width / 2) (CAP / 2 * dscale)
				apply-transform : Italify
				set currentGlyph.cmpPriority 12
				refair this
			
			include : OShape
				* (CAP * dscale + [Math.max (CAP * 0.175) (sw * 3)])
				* (-[Math.max (CAP * 0.175) (sw * 3)])
				* [Math.max (SB + O * 3) (width / 2 - CAP / 2 * dscale - sw * 2.5)]
				* [Math.min (width - SB - O * 3) (width / 2 + CAP / 2 * dscale + sw * 2.5)]
				* sw
				* (SMALLSMOOTHA * width / WIDTH)
				* (SMALLSMOOTHB * width / WIDTH)
			apply-transform : Upright
			apply-transform : Translate 0 (parenMid - CAP * dscale / 2)
			apply-transform : Italify

	define [createBracedGlyphs records] : if [not recursive] : begin
		local dscale 0.55
		local pscale 0.6
		local pendingGlyphs : records.map : [record] => record.1
		local miniatureFont : Miniature 
			glyphs  -- pendingGlyphs
			crowd   -- [fallback para.smallCrowd 3.75]
			scale   -- 0.65
			sbscale -- 1 
			unfair  -- true
		
		foreach {unicode glyphid w} [items-of records] : sketch
			local width : fallback w WIDTH
			set-width width
			local sw [adviceBlackness 5]
			local l : [Math.max (SB + O * 3) (width / 2 - CAP / 2 * dscale - sw * 2.5)] + OX
			local r : width - l
			
			include : create-glyph [suggestName : 'braceinner' + glyphid] : glyph-construction
				include miniatureFont.(glyphid)
				apply-transform : Upright
				apply-transform : Translate (-WIDTH / 2) 0
				apply-transform : Scale dscale
				apply-transform : Translate (width / 2) 0
				apply-transform : Italify
				set currentGlyph.cmpPriority 11
				refair this
			
			include : dispiro
				widths.lhs sw
				g4 [mix l r 0.15] (parenTop * pscale)
				g4.down.mid l     (parenMid * pscale)
				g4 [mix l r 0.15] (parenBot * pscale)
			
			include : dispiro
				widths.rhs sw
				g4 [mix r l 0.15] (parenTop * pscale)
				g4.down.mid r     (parenMid * pscale)
				g4 [mix r l 0.15] (parenBot * pscale)
				
			include : Upright
			include : Translate 0 (parenMid - parenMid * pscale)
			include : Italify
			
			save [suggestName : 'braced' + glyphid] unicode

	define [createSuperscripts records] : if [not recursive] : begin
		local pendingGlyphs : records.map : [record] => record.1
		local miniatureFont : Miniature
			glyphs -- pendingGlyphs
			crowd  -- [fallback para.smallCrowd 3.5]
			scale  -- 0.7
			unfair -- true
		foreach {unicode glyphid pri} [items-of records] : create-glyph [suggestName : 'sup' + glyphid] : glyph-construction
			if unicode : assign-unicode unicode
			include miniatureFont.(glyphid) AS_BASE
			apply-transform [Upright] true
			apply-transform [Translate (-MIDDLE) (-CAP)] true
			apply-transform [Scale 0.7] true
			apply-transform [Translate MIDDLE (CAP + ACCENT / 2)] true
			apply-transform [Italify] true
			if pri : set currentGlyph.cmpPriority pri
			refair this

	define [createSubscripts records] : if [not recursive] : begin
		local pendingGlyphs : records.map : [record] => record.1
		local miniatureFont : Miniature
			glyphs -- pendingGlyphs
			crowd  -- [fallback para.smallCrowd 3.5]
			scale  -- 0.7
			unfair -- true
		foreach {unicode glyphid pri} [items-of records] : create-glyph [suggestName : 'sub' + glyphid] : glyph-construction
			if unicode : assign-unicode unicode
			include miniatureFont.(glyphid) AS_BASE
			apply-transform [Upright] true
			apply-transform [Translate (-MIDDLE) 0] true
			apply-transform [Scale 0.7] true
			apply-transform [Translate MIDDLE (DESCENDER / 2)] true
			apply-transform [Italify] true
			if pri : set currentGlyph.cmpPriority pri
			refair this

	define [createSMCPs records] : if [not recursive] : begin
		local pendingGlyphs : records.map : [record] => record.1
		local forkedParams : Object.create para
		set forkedParams.cap0 para.cap
		set forkedParams.cap XH
		set forkedParams.xheight (XH * XH / CAP)
		local sf : Fork pendingGlyphs forkedParams
		foreach {unicode glyphid tfm} [items-of records] : create-glyph [suggestName : 'smcp' + glyphid] : glyph-construction
			if unicode : assign-unicode unicode
			include sf.(glyphid) AS_BASE
			if tfm : include tfm

	define [createMedievalCombs records] : if [not recursive] : begin
		local pendingGlyphs : records.map : [record] => record.1
		local miniatureFont : Miniature
			glyphs -- pendingGlyphs
			crowd  -- [fallback para.smallCrowd2 3.5]
			scale  -- 0.7
			unfair -- true
		foreach {unicode glyphid} [items-of records] : create-glyph [suggestName : 'comb' + glyphid] : glyph-construction
			set-width 0
			if unicode : assign-unicode unicode
			include miniatureFont.(glyphid)
			apply-transform : Upright
			apply-transform : Translate (-MIDDLE) 0
			apply-transform : Scale 0.4
			apply-transform : Translate markMiddle aboveMarkBot
			apply-transform : Italify 
			refair this
			set-anchor 'above' MARK markMiddle XH markMiddle aboveMarkTop

	define [createFractions records] : if [not recursive] : begin
		local pendingGlyphs : [records.map : [record] => record.1].concat : records.map : [record] => record.2
		local miniatureFont : Miniature
			glyphs -- pendingGlyphs
			crowd  -- 4
			scale  -- 0.6
			unfair -- true
		foreach {unicode numid denid height} [items-of records] : create-glyph [suggestName : numid + 'over' + denid] : glyph-construction
			if unicode : assign-unicode unicode
			local fine : adviceBlackness 3
			local dist : XH * 0.4
			include : create-glyph : glyph-construction
				include : create-glyph [suggestName : 'num' + numid] : glyph-construction
					include miniatureFont.(numid)
					apply-transform : Upright
					apply-transform : Translate (- miniatureFont.(numid).advanceWidth / 2) 0
					apply-transform : Scale (CAP / [fallback height CAP] * 0.55)
					apply-transform : Translate MIDDLE 0
					apply-transform : Italify
					refair this
				apply-transform : Upright
				apply-transform : Translate 0 (CAP * 0.55 + dist)
				apply-transform : Italify
				include : create-glyph [suggestName : 'den' + denid] : glyph-construction
					include miniatureFont.(denid)
					apply-transform : Upright
					apply-transform : Translate (- miniatureFont.(denid).advanceWidth / 2) 0
					apply-transform : Scale (CAP / [fallback height CAP] * 0.55)
					apply-transform : Translate MIDDLE 0
					apply-transform : Italify
					refair this
				apply-transform : Upright
				apply-transform : Translate (-MIDDLE) (-CAP * 0.55 - dist / 2)
				apply-transform : Translate MIDDLE parenMid
				apply-transform : Italify
			include : HBar SB RIGHTSB parenMid (fine * 0.75)


	if [not recursive] : let : begin
		local compositions : list
			list 0xA9   'C'
			list 0xAE   'R'
			list 0x2117 'P'
			list 0x24EA 'zero' FULLWIDTH1
			list null   'space' FULLWIDTH1
		foreach [j : range 1 till 9] : compositions.push {(0x2460 + j - 1) unicodeGlyphs.(['0'.charCodeAt 0] + j).name FULLWIDTH1}
		foreach [j : range 0 26] : compositions.push {(0x24B6 + j) unicodeGlyphs.(['A'.charCodeAt 0] + j).name FULLWIDTH1}
		foreach [j : range 0 26] : compositions.push {(0x24D0 + j) unicodeGlyphs.(['a'.charCodeAt 0] + j).name FULLWIDTH1}
		createCircledGlyphs compositions

		local compositions : list
			list null   'space' FULLWIDTH1
		foreach [j : range 1 till 9] : compositions.push {(0x2474 + j - 1) unicodeGlyphs.(['0'.charCodeAt 0] + j).name FULLWIDTH1}
		foreach [j : range 0 26] : compositions.push {(0x249C + j) unicodeGlyphs.(['a'.charCodeAt 0] + j).name FULLWIDTH1}
		createBracedGlyphs compositions

	createSMCPs : list
		list 0x1D00 'A'
		list 0x1D01 'AE'
		list 0x1D03 'Bbar'
		list 0x1D04 'C'
		list 0x1D05 'D'
		list 0x1D06 'Dcroat'
		list 0x1D07 'E'
		list 0x1D08 'cyrZe'
		list 0x1D0A 'J'
		list 0x1D0B 'K'
		list 0x1D0C 'Lslash'
		list 0x1D0D 'M'
		list 0x1D0E 'cyrI'
		list 0x1D0F 'O'
		list 0x1D10 'turnC'
		list 0x1D15 'OU'
		list 0x1D18 'P'
		list 0x1D19 'cyrYa'
		list 0x1D1A 'R' [FlipAround MIDDLE (XH / 2)]
		list 0x1D1B 'T'
		list 0x1D20 'V'
		list 0x1D21 'W'
		list 0x1D22 'Z'
		list 0x1D23 'Ezh'
		list 0x1D26 'Gamma'
		list 0x1D27 'Lambda'
		list 0x1D28 'Pi'
		list 0x1D29 'Rho'
		list 0x1D2B 'cyrEl'

	createSuperscripts : list
		list 0x2070 'zero'
		list 0x00B9 'one'
		list 0x00B2 'two'
		list 0x00B3 'three'
		list 0x2074 'four'
		list 0x2075 'five'
		list 0x2076 'six'
		list 0x2077 'seven'
		list 0x2078 'eight'
		list 0x2079 'nine'
		list 0x02B0 'h'
		list 0x02B1 'hhooktop'
		list 0x02B2 'j'
		list 0x02B3 'r'
		list 0x02B4 'turnr'
		list 0x02B5 'turnrrtail'
		list 0x02B6 'invsmcpR'
		list 0x02B7 'w'
		list 0x02B8 'y'
		list 0x02C0 'fineglottalstop'
		list 0x02C1 'finerevglottalstop'
		list 0x02E0 'latingamma'
		list 0x02E1 'l'
		list 0x02E2 's'
		list 0x02E3 'x'
		list 0x02E4 'revglottalstop'
		list 0x2071 'i'
		list 0x207F 'n'
		list 0x1D43 'a'
		list 0x1D44 'turna'
		list 0x1D45 'scripta'
		list 0x1D46 'turnae'
		list 0x1D47 'b'
		list 0x1D48 'd'
		list 0x1D49 'e'
		list 0x1D4A 'turne'
		list 0x1D4B 'epsilon'
		list 0x1D4C 'cyrze'
		list 0x1D4D 'g'
		list 0x1D4E 'turni'
		list 0x1D4F 'k'
		list 0x1D50 'm'
		list 0x1D51 'eng'
		list 0x1D52 'o'
		list 0x1D53 'turnc'
		list 0x1D54 'oupperhalf'
		list 0x1D55 'olowerhalf'
		list 0x1D56 'p'
		list 0x1D57 't'
		list 0x1D58 'u'
		list 0x1D5A 'turnm'
		list 0x1D5B 'v'
		list 0x1D5C 'latinayin'
		list 0x1D5D 'beta'
		list 0x1D5E 'gamma'
		list 0x1D5F 'delta'
		list 0x1D60 'phi'
		list 0x1D61 'chi'
		list 0x1D78 'smcpH'
		list 0x1D9B 'turnscripta'
		list 0x1D9C 'c'
		list 0x1D9D 'ccurlytail'
		list 0x1D9E 'eth'
		list 0x1D9F 'revlatinepsilon'
		list 0x1DA0 'f'
		list 0x1DA1 'turnf'
		list 0x1DA2 'scriptg'
		list 0x1DA3 'turnh'
		list 0x1DA4 'ibarOver'
		list 0x1DA5 'latiniota'
		list 0x1DA6 'smcpI'
		list 0x1DA7 'smcpIbarOver'
		list 0x1DA8 'jcurlytail'
		list 0x1DAB 'smcpL'
		list 0x1DA9 'lrtail'
		list 0x1DAC 'mltail'
		list 0x1DAD 'turnmleg'
		list 0x1DAE 'nltail'
		list 0x1DAF 'nrtailBR'
		list 0x1DB0 'smcpN'
		list 0x1DB1 'obar'
		list 0x1DB2 'varphi'
		list 0x1DB3 'srtail'
		list 0x1DB4 'esh'
		list 0x1DB5 'tltail'
		list 0x1DB6 'ulongBarOver'
		list 0x1DB7 'latinupsilon1'
		list 0x1DB8 'smcpU'
		list 0x1DB9 'latinupsilon2'
		list 0x1DBA 'turnv'
		list 0x1DBC 'zrtailBR'
		list 0x1DBD 'zcurlytail'
		list 0x1DBE 'ezh'
		list 0x1DBF 'theta'
		list 0x1DBB 'z'
		list 0x1D2C 'A'
		list 0x1D2D 'AE'
		list 0x1D2E 'B'
		list 0x1D2F 'Bbar'
		list 0x1D30 'D'
		list 0x1D31 'E'
		list 0x1D32 'turnE'
		list 0x1D33 'G'
		list 0x1D34 'H'
		list 0x1D35 'I'
		list 0x1D36 'J'
		list 0x1D37 'K'
		list 0x1D38 'L'
		list 0x1D39 'M'
		list 0x1D3A 'N'
		list 0x1D3B 'cyrI'
		list 0x1D3C 'O'
		list 0x1D3D 'OU'
		list 0x1D3E 'P'
		list 0x1D3F 'R'
		list null   'S' # there is no superscript S in unicode, but is is used for the SM symbol
		list 0x1D40 'T'
		list 0x1D41 'U'
		list 0x1D42 'W'
		list 0x2C7D 'V'
		list 0x207A 'plus' (-11)
		list 0x207B 'minus' (-11)
		list 0x207C 'equal' (-11)
		list 0x207D 'parenLeft' (-11)
		list 0x207E 'parenRight' (-11)
	if [not recursive] : let [df : Miniature {'a' 'o'} 3.5 0.7] : begin
		sketch # ordfeminine
			include df.a
			include : HBarBottom SB RIGHTSB DESCENDER
			apply-transform : Upright
			apply-transform : Translate (-MIDDLE) (-XH)
			apply-transform : Scale 0.7
			apply-transform : Translate MIDDLE CAP
			apply-transform : Italify
			save 'ordfeminine' 0xAA

		sketch # ordmasculine
			include df.o
			include : HBarBottom SB RIGHTSB DESCENDER
			apply-transform : Upright
			apply-transform : Translate (-MIDDLE) (-XH)
			apply-transform : Scale 0.7
			apply-transform : Translate MIDDLE CAP
			apply-transform : Italify
			save 'ordmasculine' 0xBA

	createSubscripts : list
		list 0x2080 'zero'
		list 0x2081 'one'
		list 0x2082 'two'
		list 0x2083 'three'
		list 0x2084 'four'
		list 0x2085 'five'
		list 0x2086 'six'
		list 0x2087 'seven'
		list 0x2088 'eight'
		list 0x2089 'nine'
		list 0x2090 'a'
		list 0x2091 'e'
		list 0x2092 'o'
		list 0x2093 'x'
		list 0x2094 'turne'
		list 0x2095 'h'
		list 0x2096 'k'
		list 0x2097 'l'
		list 0x2098 'm'
		list 0x2099 'n'
		list 0x209A 'p'
		list 0x209B 's'
		list 0x209C 't'
		list 0x1D62 'i'
		list 0x1D63 'r'
		list 0x1D64 'u'
		list 0x1D65 'v'
		list 0x1D66 'beta'
		list 0x1D67 'gamma'
		list 0x1D68 'rho'
		list 0x1D69 'phi'
		list 0x1D6A 'chi'
		list 0x2C7C 'j'
		list 0x208A 'plus' (-11)
		list 0x208B 'minus' (-11)
		list 0x208C 'equal' (-11)
		list 0x208D 'parenLeft' (-11)
		list 0x208E 'parenRight' (-11)

	createFractions : list
		list 0x00BC 'one' 'four'
		list 0x00BD 'one' 'two'
		list 0x00BE 'three' 'four'
		list 0x2150 'one' 'seven'
		list 0x2151 'one' 'nine'
		list 0x2152 'one' 'ten'
		list 0x2153 'one' 'three'
		list 0x2154 'two' 'three'
		list 0x2155 'one' 'five'
		list 0x2156 'two' 'five'
		list 0x2157 'three' 'five'
		list 0x2158 'four' 'five'
		list 0x2159 'one' 'six'
		list 0x215A 'five' 'six'
		list 0x215B 'one' 'eight'
		list 0x215C 'three' 'eight'
		list 0x215D 'five' 'eight'
		list 0x215E 'seven' 'eight'
		list 0x2189 'zero' 'three'
		# care-of
		list 0x2105 'C' 'O'
		list 0x2106 'C' 'U'
		# Powerline LN symbol
		list 0xE0A1 'L' 'N'
		list 0xE0A3 'C' 'N'
		# fraction bar
		list null 'space' 'space'

	createMedievalCombs : list
		list 0x363 'a'
		list 0x364 'e'
		list 0x365 'i'
		list 0x366 'o'
		list 0x367 'u'
		list 0x368 'c'
		list 0x369 'd'
		list 0x36A 'h'
		list 0x36B 'm'
		list 0x36C 'r'
		list 0x36D 't'
		list 0x36E 'v'
		list 0x36F 'x'
		list 0x1DD4 'ae'
		list 0x1DD7 'ccedillaBelow'
		list 0x1DD8 'cyrde.italic'
		list 0x1DD9 'eth'
		list 0x1DDA 'g'
		list 0x1DDB 'G'
		list 0x1DDC 'k'
		list 0x1DDD 'l'
		list 0x1DDE 'L'
		list 0x1DDF 'M'
		list 0x1DE0 'n'
		list 0x1DE1 'N'
		list 0x1DE2 'R'
		list 0x1DE3 'rrotunda'
		list 0x1DE4 's'
		list 0x1DE5 'longs'
		list 0x1DE6 'z'
		list 0x1DE7 'alpha'
		list 0x1DE8 'b'
		list 0x1DE9 'beta'
		list 0x1DEA 'turne'
		list 0x1DEB 'f'
		list 0x1DEE 'p'
		list 0x1DEF 'esh'
		list 0x1DF0 'mu'
		list 0x1DF1 'w'
		list 0x1DF2 'adieresis'
		list 0x1DF3 'odieresis'
		list 0x1DF4 'udieresis'

	# Unicode Ligatures
	let : begin
		define stdShrink : clamp 0.75 0.9 : linreg 72 0.75 108 0.9 STROKE
		define [createLigatures shrink1 shrink2 wadj1 wadj2 records] : if [not recursive] : begin
			local pendingGlyphs1 : records.map : [record] => record.1
			local pendingGlyphs2 : records.map : [record] => record.2
			local df1 : Thinner pendingGlyphs1 [if (para.spacing == 3) 1 shrink1]
			local df2 : Thinner pendingGlyphs2 [if (para.spacing == 3) 1 shrink2]

			foreach [{unicode c1 c2 mark} : items-of records] : begin
				local glyphName "\(c1)_\(c2)"
				if glyphs.(glyphName) : begin
					local j 2
					while glyphs.(glyphName + j) : inc j
					set glyphName (glyphName + j)
				if (para.spacing == 3) : begin
					sketch
						include df2.(c2)
						include : Translate WIDTH 0
						include df1.(c1)
						set-width FULLWIDTH
						save glyphName unicode
				: else
					local kern : SB * 7/8 * (shrink1 + shrink2)
					local refw : WIDTH * (shrink1 * wadj1 + shrink2 * wadj2) - kern
					sketch
						include df2.(c2)
						include : Translate (WIDTH * shrink1 * wadj1 - kern) 0
						include df1.(c1)
						include : Translate (-WIDTH * shrink1 * (1 - wadj1) / 2) 0
						include : Upright
						include : Translate (-refw / 2) 0
						include : Scale ((WIDTH - SB * 1.25) / (WIDTH - SB * 2) * WIDTH / refw) 1
						include : Translate (WIDTH / 2) 0
						include : Italify
						
						if mark : include mark
						save glyphName unicode

		createLigatures stdShrink stdShrink 1 1 : list
			list 0x1C4 'D' 'Zcaron'
			list 0x1C5 'D' 'zcaron'
			list 0x1C6 'd' 'zcaron'
			list 0x1C7 'L' 'J'
			list 0x1C8 'L' 'j'
			list 0x1C9 'l' 'j'
			list 0x1CA 'N' 'J'
			list 0x1CB 'N' 'j'
			list 0x1CC 'n' 'j'
			list 0x2A3 'd' 'z'
			list 0x1F1 'D' 'Z'
			list 0x1F2 'D' 'z'
			list 0x1F3 'd' 'z'
			list 0x2A4 'd' 'ezh'
			list 0x2A5 'd' 'zcurlytail'
			list 0x2A6 't' 's'
			list 0x2A7 't' 'esh'
			list 0x2A8 't' 'ccurlytail'
			list 0x2A9 'f' 'eng'
			list 0x2AA 'l' 's'
			list 0x2AB 'l' 'z'
			list 0x478 'O' 'y' markset.if
			list 0x479 'o' 'y' markset.p
			list 0x20A7 'P' 's'
			list 0x20A8 'R' 's'
		createLigatures 0.7 0.8 0.75 0.9 : list
			list 0x2103 'degree' 'C'
			list 0x2109 'degree' 'F'

	# Composite superscripts and subscripts
	let : begin
		define [doubleSuperscript a b] : glyph-construction
			include a
			apply-transform : Translate (-WIDTH * 0.6) 0
			include b
			apply-transform : Upright
			apply-transform : Translate (-WIDTH * 0.2) (-CAP)
			apply-transform : Scale 0.8
			apply-transform : Translate MIDDLE CAP
			apply-transform : Italify
		
		sketch # trademark
			include : doubleSuperscript glyphs.supT glyphs.supM
			save 'trademark' 0x2122
		
		sketch # servicemark
			include : doubleSuperscript glyphs.supS glyphs.supM
			save 'servicemark' 0x2120

	# CJK double width letters
	if [not recursive] : let : begin
		define [createDoubleWidth records] : begin
			local scale 1.25
			local pendingGlyphs : records.map : [record] => record.1
			local widenFont : Widen pendingGlyphs scale (scale * 1.1)
			foreach {unicode glyphid} [items-of records] : begin
				if [not unicodeGlyphs.(unicode)] : then : create-glyph [suggestName : 'dw' + glyphid] : glyph-construction
					set-width UPM
					if unicode : assign-unicode unicode
					include widenFont.(glyphid) AS_BASE
					apply-transform [Translate (UPM / 2 - (WIDTH * scale) / 2) 0] true
				: else : let [this-glyph widenFont.(glyphid)] [that-glyph unicodeGlyphs.(unicode)] : if (this-glyph && that-glyph) : begin
					set that-glyph.advanceWidth FULLWIDTH
					set that-glyph.anchors this-glyph.anchors
					set that-glyph.contours this-glyph.contours
					that-glyph.include : Translate (FULLWIDTH / 2 - this-glyph.advanceWidth / 2) 0
		
		createDoubleWidth : let [a {}] : begin
			foreach [j : range 1 0x5f] : if [not unicodeGlyphs.(0xff00 + j)] : a.push {(0xff00 + j) unicodeGlyphs.(0x20 + j).name}
			if para.fullwidth_codes : foreach [j : items-of para.fullwidth_codes] : if (unicodeGlyphs.(j) && unicodeGlyphs.(j).advanceWidth < 1000) : begin
				a.push {j unicodeGlyphs.(j).name}
			a.push {0xFFE0 'cent'}
			a.push {0xFFE1 'sterling'}
			a.push {0xFFE5 'yen'}
			* a
		
		if (para.spacing == 0) : begin
			set font.glyf : font.glyf.filter [lambda [g] : g.advanceWidth <= WIDTH]
			set glyphList.length font.glyf.length
			for [local j 0] (j < font.glyf.length) [inc j] : set glyphList.(j) font.glyf.(j)
