Fix shape of y-ogonek (used by Elfdalian) (#1437).
This commit is contained in:
parent
0c9b46ac9b
commit
b3b7646f5b
7 changed files with 70 additions and 125 deletions
1
changes/16.3.6.md
Normal file
1
changes/16.3.6.md
Normal file
|
@ -0,0 +1 @@
|
|||
* Fix shape of y-ogonek (used by Elfdalian) (#1437).
|
|
@ -1,7 +1,7 @@
|
|||
$$include '../../../meta/macros.ptl'
|
||||
|
||||
import [mix linreg clamp fallback] from"../../../support/utils.mjs"
|
||||
import [LowerYDotAtBelow Dotless CvDecompose MathSansSerif] from"../../../support/gr.mjs"
|
||||
import [LowerYDotAtBelow Dotless CvDecompose MathSansSerif OgonekTrY] from"../../../support/gr.mjs"
|
||||
|
||||
glyph-module
|
||||
|
||||
|
@ -64,7 +64,18 @@ glyph-block Letter-Latin-Lower-Y : begin
|
|||
curl x (top - ds) [widths.heading hl hr Downward]
|
||||
quadControls 0 dpy1 16
|
||||
|
||||
define [yBaseKnots top bottom shrink hooktop ogonek] : begin
|
||||
define [yOgonekAttach top bottom shrink hooktop] : glyph-proc
|
||||
define {ds ds2} : CalcDS top bottom
|
||||
define coJoinX : if (straightBar && (! hooktop)) yrstroker [mix yrstrokel yrstroker px1]
|
||||
define coJoinY : if (straightBar && (! hooktop)) top [mix (bottom + ds2) (top - ds) py1]
|
||||
define joinX : mix yrstrokel yrstroker (1 - px2)
|
||||
define joinY : mix (bottom + ds2) (top - ds) (1 - py2)
|
||||
|
||||
define anchorX : mix coJoinX joinX ((0 - coJoinY) / (joinY - coJoinY))
|
||||
set-base-anchor 'trailing' anchorX 0
|
||||
OgonekTrY.set currentGlyph
|
||||
|
||||
define [yBaseKnots top bottom shrink hooktop] : begin
|
||||
define {ds ds2} : CalcDS top bottom
|
||||
define coJoinX : mix yrstrokel yrstroker px1
|
||||
define coJoinY : mix (bottom + ds2) (top - ds) py1
|
||||
|
@ -72,30 +83,12 @@ glyph-block Letter-Latin-Lower-Y : begin
|
|||
define joinY : mix (bottom + ds2) (top - ds) (1 - py2)
|
||||
define [ConnectZ shrink] : curl joinX joinY [widths.rhs : Stroke * shrink]
|
||||
|
||||
define [ogonekKnots] : begin
|
||||
|
||||
local stopX : mix joinX coJoinX ((0 - joinY) / (coJoinY - joinY))
|
||||
local stopY 0
|
||||
|
||||
local depth : 0 - Descender - markStroke
|
||||
local extL : (0.5 * 0.75 * depth / coJoinY) * depth + 0.25 * markStress
|
||||
local extR : Math.max (0.5 * markExtend) (1.5 * TanSlope * markStroke)
|
||||
local turnSlope : 0.5 * ((markStroke - Stroke) / markStroke - (ArchDepthB - ArchDepth) / ArchDepth)
|
||||
|
||||
list
|
||||
curl stopX stopY [widths.rhs : Stroke * [if useStraightBottom shrink 1]]
|
||||
g4.down.mid (stopX - extL) (stopY - 0.75 * depth) [widths.rhs.heading [mix Stroke markStroke 0.25] {.x HVContrast .y (-turnSlope)}]
|
||||
arcvh [widths.rhs markStroke]
|
||||
g4 (stopX + [mix (-extL) extR (11/16)]) (stopY - depth + O) [heading Rightward]
|
||||
g4 (stopX + extR) (stopY - depth + 0.5 * O) [heading Rightward]
|
||||
|
||||
return : list
|
||||
if (straightBar && (! hooktop))
|
||||
then : list
|
||||
else : list [flat coJoinX coJoinY]
|
||||
|
||||
piecewise
|
||||
ogonek : ogonekKnots
|
||||
useStraightBottom : list
|
||||
ConnectZ shrink
|
||||
curl [mix yrstroker joinX ((top - bottom) / (top - joinY))] bottom [widths.heading 0 (Stroke * [yDiagCor (top - bottom)]) Downward]
|
||||
|
@ -159,6 +152,8 @@ glyph-block Letter-Latin-Lower-Y : begin
|
|||
define [SmallYShape top bottom] : glyph-proc
|
||||
local {ds ds2} : CalcDS top bottom
|
||||
|
||||
include : yOgonekAttach top bottom yshrink
|
||||
|
||||
include : intersection
|
||||
SmallYStrokeSplitMask top bottom false 1
|
||||
dispiro
|
||||
|
@ -183,39 +178,12 @@ glyph-block Letter-Latin-Lower-Y : begin
|
|||
if doSlabBottom : include : yBaseSerif top bottom
|
||||
if doSlabMotion : include : LeftwardTopSerif SB top SideJut
|
||||
|
||||
define [SmallYOgonekShape top bottom] : glyph-proc
|
||||
local {ds ds2} : CalcDS top bottom
|
||||
|
||||
include : intersection
|
||||
union
|
||||
SmallYStrokeSplitMask top bottom false 1
|
||||
MaskBelow 0
|
||||
dispiro
|
||||
yTopKnots yrstroker top bottom ds 1
|
||||
yBaseKnots top bottom 1 false true
|
||||
|
||||
include : difference
|
||||
dispiro
|
||||
yTopKnots yrstroker top bottom ds 1
|
||||
yBaseKnots top bottom yshrink false true
|
||||
SmallYStrokeSplitMask top bottom false 1 1
|
||||
MaskBelow 0
|
||||
|
||||
include : difference
|
||||
dispiro
|
||||
yTopKnots (Width - yrstroker) top bottom ds (-1)
|
||||
yJoinKnots ds ds2 top bottom
|
||||
SmallYStrokeSplitMask top bottom false (-1)
|
||||
Rect (bottom + HalfStroke) (bottom - top) 0 Width
|
||||
|
||||
if doSlabTop : include : let [sf : SerifFrame top bottom SB RightSB]
|
||||
composite-proc sf.lt.full sf.rt.full
|
||||
if doSlabMotion : include : LeftwardTopSerif SB top SideJut
|
||||
|
||||
define [SmallYHookTopShape top bottom] : glyph-proc
|
||||
local {ds ds2} : CalcDS top bottom
|
||||
local joinHeight : yJoinHeight ds ds2 top bottom true
|
||||
|
||||
include : yOgonekAttach top bottom yshrink true
|
||||
|
||||
include : intersection
|
||||
SmallYStrokeSplitMask top bottom true 1
|
||||
dispiro
|
||||
|
@ -248,7 +216,7 @@ glyph-block Letter-Latin-Lower-Y : begin
|
|||
include : Scale 1 (-1)
|
||||
include : Translate 0 (+[mix bottom top 0.5])
|
||||
|
||||
return : object SmallYShape SmallYOgonekShape SmallYHookTopShape SmallLambdaShape
|
||||
return : object SmallYShape SmallYHookTopShape SmallLambdaShape
|
||||
|
||||
create-glyph : glyph-proc
|
||||
include : MarkSet.p
|
||||
|
@ -271,19 +239,6 @@ glyph-block Letter-Latin-Lower-Y : begin
|
|||
create-forked-glyph 'y.curlyTurnMotionSerifed' : glyph-proc
|
||||
include : [GenSmallYShape false true SLAB-MOTION].SmallYShape XH Descender
|
||||
|
||||
create-glyph : glyph-proc
|
||||
include : MarkSet.p
|
||||
set-base-anchor 'overlay' Middle (XH / 2)
|
||||
set-base-anchor 'yBelowDot' (RightSB - 0.5 * DotRadius) (Descender + AccentStackOffset + DotRadius)
|
||||
create-forked-glyph 'yOgonek.straight' : glyph-proc
|
||||
include : [GenSmallYShape true false SLAB-AUTO].SmallYOgonekShape XH Descender
|
||||
create-forked-glyph 'yOgonek.curly' : glyph-proc
|
||||
include : [GenSmallYShape false false SLAB-AUTO].SmallYOgonekShape XH Descender
|
||||
create-forked-glyph 'yOgonek.straightMotionSerifed' : glyph-proc
|
||||
include : [GenSmallYShape true false SLAB-MOTION].SmallYOgonekShape XH Descender
|
||||
create-forked-glyph 'yOgonek.curlyMotionSerifed' : glyph-proc
|
||||
include : [GenSmallYShape false false SLAB-MOTION].SmallYOgonekShape XH Descender
|
||||
|
||||
define [SmallYCursiveArc top bottom] : new-glyph : glyph-proc
|
||||
include : nShoulder
|
||||
top -- top
|
||||
|
@ -343,25 +298,8 @@ glyph-block Letter-Latin-Lower-Y : begin
|
|||
include : LeftwardTopSerif SB XH SideJut
|
||||
set-base-anchor 'overlay' Middle (XH / 2)
|
||||
|
||||
create-glyph 'yOgonek.cursive' : glyph-proc
|
||||
include [refer-glyph 'y.cursive'] AS_BASE ALSO_METRICS
|
||||
include [refer-glyph 'ogonekBelow']
|
||||
|
||||
create-glyph 'yOgonek.cursiveFlatHook' : glyph-proc
|
||||
include [refer-glyph 'y.cursiveFlatHook'] AS_BASE ALSO_METRICS
|
||||
include [refer-glyph 'ogonekBelow']
|
||||
|
||||
create-glyph 'yOgonek.cursiveMotionSerifed' : glyph-proc
|
||||
include [refer-glyph 'y.cursiveMotionSerifed'] AS_BASE ALSO_METRICS
|
||||
include [refer-glyph 'ogonekBelow']
|
||||
|
||||
create-glyph 'yOgonek.cursiveFlatHookMotionSerifed' : glyph-proc
|
||||
include [refer-glyph 'y.cursiveFlatHookMotionSerifed'] AS_BASE ALSO_METRICS
|
||||
include [refer-glyph 'ogonekBelow']
|
||||
|
||||
select-variant 'y' 'y'
|
||||
link-reduced-variant 'y/sansSerif' 'y' MathSansSerif
|
||||
select-variant 'yOgonek' 0xE011
|
||||
alias 'cyrl/u' 0x443 'y'
|
||||
|
||||
foreach { suffix { DrawAt kdr } } [Object.entries DotVariants] : do
|
||||
|
|
|
@ -150,26 +150,32 @@ glyph-block Mark-Horn-And-Angle : begin
|
|||
include : refer-glyph "leftHalfCircleBelow"
|
||||
include : FlipAround markMiddle (XH / 2)
|
||||
|
||||
create-glyph 'ogonekTR' : glyph-proc
|
||||
set-width 0
|
||||
define ogonekTrConfig : object
|
||||
'ogonekTR' { (7/16) (1/8) 1 }
|
||||
'ogonekTR_Y' { (3/16) 1 6 }
|
||||
|
||||
local fine : AdviceStroke 8
|
||||
local depth : 0 - Descender - markStroke
|
||||
local extL : (7 / 16) * depth + 0.125 * markStress
|
||||
local extR : Math.max (0.125 * markExtend) (1.5 * TanSlope * markStroke)
|
||||
foreach { glyphName { pExtL pExtR cwMidStrokeWidth } } [Object.entries ogonekTrConfig] : do
|
||||
create-glyph glyphName : glyph-proc
|
||||
set-width 0
|
||||
|
||||
local turnSlope : 0.5 * ((markStroke - fine) / markStroke - (ArchDepthB - ArchDepth) / ArchDepth)
|
||||
local fine : AdviceStroke 8
|
||||
local depth : 0 - Descender - markStroke
|
||||
local extL : pExtL * depth + 0.125 * markStress
|
||||
local extR : Math.max (pExtR * markExtend) (1.5 * TanSlope * markStroke)
|
||||
|
||||
include : difference
|
||||
dispiro
|
||||
g4 markMiddle 0 [widths.rhs.heading fine Leftward]
|
||||
alsoThru 0.5 (0.375 - 0.2 * markStroke / depth) [widths.rhs : mix fine markStroke 0.25]
|
||||
g4.down.mid (markMiddle - extL) (-0.75 * depth) [widths.rhs.heading markStroke {.x HVContrast .y turnSlope}]
|
||||
arcvh [widths.rhs markStroke]
|
||||
g4 (markMiddle + [mix (-extL) extR (11/16)]) (-depth + O) [heading Rightward]
|
||||
g4 (markMiddle + extR) (-depth + 0.5 * O) [heading Rightward]
|
||||
intersection
|
||||
MaskAbove 0
|
||||
MaskRight markMiddle
|
||||
local turnSlope : 0.5 * ((markStroke - fine) / markStroke - (ArchDepthB - ArchDepth) / ArchDepth)
|
||||
local swMid : Math.min markStroke [AdviceStroke cwMidStrokeWidth]
|
||||
|
||||
set-mark-anchor 'trailing' markMiddle 0 (markMiddle + extR) (-depth - 0.5 * O - markStroke)
|
||||
include : difference
|
||||
dispiro
|
||||
g4 markMiddle 0 [widths.rhs.heading fine Leftward]
|
||||
alsoThru 0.5 (0.375 - 0.2 * markStroke / depth) [widths.rhs : mix fine swMid 0.25]
|
||||
g4.down.mid (markMiddle - extL) (-0.75 * depth) [widths.rhs.heading swMid {.x HVContrast .y turnSlope}]
|
||||
arcvh
|
||||
g4 (markMiddle + [mix (-extL) extR (11/16)]) (-depth + O) [widths.rhs.heading markStroke Rightward]
|
||||
g4 (markMiddle + extR) (-depth + 0.5 * O) [heading Rightward]
|
||||
intersection
|
||||
MaskAbove 0
|
||||
MaskRight markMiddle
|
||||
|
||||
set-mark-anchor 'trailing' markMiddle 0 (markMiddle + extR) (-depth - 0.5 * O - markStroke)
|
||||
|
|
|
@ -4,6 +4,9 @@ export : define iotaBelowToLfTf : object
|
|||
export : define ogonekBelowToTRTf : object
|
||||
'ogonekBelow' 'ogonekTR'
|
||||
|
||||
export : define ogonekBelowToTRTf_Y : object
|
||||
'ogonekBelow' 'ogonekTR_Y'
|
||||
|
||||
export : define upperGrekMarkToTonosTf : object
|
||||
'variaAbove' 'variaGrekUpperTonos'
|
||||
'oxiaAbove' 'oxiaGrekUpperTonos'
|
||||
|
@ -30,8 +33,6 @@ export : define markCompositionTf : object
|
|||
'perispomeniAbove' 'dasiaPerispomeni'
|
||||
'cyrlPsiliAbove' : object
|
||||
'cyrlPokrytieAbove' 'cyrlPsiliPokrytieAbove'
|
||||
'y' : object
|
||||
'ogonekBelow' 'yOgonek'
|
||||
|
||||
export : define decompositionOverrides : object
|
||||
# Latvians use comma instead of cedillas in several letters.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import [AddCommonFeature AddFeature AddLookup AddFeatureLookup ChainRuleBuilder BeginLookupBlock EndLookupBlock UkMapToLookup UkMap2ToLookup] from"./table-util.mjs"
|
||||
import [AnyCv Dotless TieMark TieGlyph CcmpDecompose] from"../support/gr.mjs"
|
||||
import [AnyCv Dotless TieMark TieGlyph CcmpDecompose OgonekTrY] from"../support/gr.mjs"
|
||||
import as UnicodeKnowledge from"../meta/unicode-knowledge.mjs"
|
||||
|
||||
extern Set
|
||||
|
@ -234,22 +234,32 @@ export : define [buildCCMPPostCvSs sink ccmpFeature glyphStore markGlyphs] : beg
|
|||
define ccmp : AddFeature sink 'ccmp'
|
||||
define {chain-rule} : ChainRuleBuilder sink
|
||||
|
||||
define groupTR {}
|
||||
define triggerGlyphs_Normal { }
|
||||
define triggerGlyphs_Y { }
|
||||
foreach { gid g } [glyphStore.namedEntries] : if (gid.(0) !== "."): begin
|
||||
if g.baseAnchors.trailing : groupTR.push gid
|
||||
if g.baseAnchors.trailing : piecewise
|
||||
[OgonekTrY.get g] : triggerGlyphs_Y.push gid
|
||||
true : triggerGlyphs_Normal.push gid
|
||||
|
||||
define [OgonekTrailing] : UkMapToLookup UnicodeKnowledge.ogonekBelowToTRTf
|
||||
define [markTransform_Normal] : UkMapToLookup UnicodeKnowledge.ogonekBelowToTRTf
|
||||
define [markTransform_Y] : UkMapToLookup UnicodeKnowledge.ogonekBelowToTRTf_Y
|
||||
|
||||
define [pushTransforms sink triggers tf] : begin
|
||||
sink.push : chain-rule triggers [tf]
|
||||
sink.push : chain-rule triggers markGlyphs.all [tf]
|
||||
sink.push : chain-rule triggers markGlyphs.all markGlyphs.all [tf]
|
||||
sink.push : chain-rule triggers markGlyphs.all markGlyphs.all markGlyphs.all [tf]
|
||||
sink.push : chain-rule triggers markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all [tf]
|
||||
sink.push : chain-rule triggers markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all [tf]
|
||||
sink.push : chain-rule triggers markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all [tf]
|
||||
|
||||
define ogonekTransforms {}
|
||||
pushTransforms ogonekTransforms triggerGlyphs_Normal markTransform_Normal
|
||||
pushTransforms ogonekTransforms triggerGlyphs_Y markTransform_Y
|
||||
|
||||
define lookupMarks1 : AddLookup sink : object
|
||||
.type 'gsub_chaining'
|
||||
.rules : list
|
||||
# Ogonek transform (max 6 middle marks are supported)
|
||||
chain-rule groupTR [OgonekTrailing]
|
||||
chain-rule groupTR markGlyphs.all [OgonekTrailing]
|
||||
chain-rule groupTR markGlyphs.all markGlyphs.all [OgonekTrailing]
|
||||
chain-rule groupTR markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all [OgonekTrailing]
|
||||
chain-rule groupTR markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all [OgonekTrailing]
|
||||
chain-rule groupTR markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all markGlyphs.all [OgonekTrailing]
|
||||
.rules ogonekTransforms
|
||||
|
||||
ccmpFeature.lookups.push lookupMarks1
|
||||
EndLookupBlock rec sink
|
||||
|
|
|
@ -107,6 +107,7 @@ function BoolProp(id) {
|
|||
export const Radical = BoolProp("Radical");
|
||||
export const RequireCcmpDecompose = BoolProp("RequireCcmpDecompose");
|
||||
export const NeqLigationSlashDotted = BoolProp("NeqLigationSlashDotted");
|
||||
export const OgonekTrY = BoolProp("OgonekTrY");
|
||||
|
||||
export const Joining = {
|
||||
get(glyph) {
|
||||
|
|
|
@ -4270,7 +4270,6 @@ rank = 1
|
|||
description = "Letter `y` that is fully straight"
|
||||
selector.y = "straight"
|
||||
selector."y/sansSerif" = "straight"
|
||||
selector.yOgonek = "straight"
|
||||
selector.yHookTop = "straight"
|
||||
|
||||
[prime.y.variants.straight-turn]
|
||||
|
@ -4278,7 +4277,6 @@ rank = 2
|
|||
description = "Letter `y` with straight upper and a tail turns leftward"
|
||||
selector.y = "straightTurn"
|
||||
selector."y/sansSerif" = "straightTurn"
|
||||
selector.yOgonek = "straight"
|
||||
selector.yHookTop = "straightTurn"
|
||||
|
||||
[prime.y.variants.curly]
|
||||
|
@ -4286,7 +4284,6 @@ rank = 3
|
|||
description = "More curly letter `y`, like Iosevka 2.x"
|
||||
selector.y = "curly"
|
||||
selector."y/sansSerif" = "curly"
|
||||
selector.yOgonek = "curly"
|
||||
selector.yHookTop = "curly"
|
||||
|
||||
[prime.y.variants.curly-turn]
|
||||
|
@ -4294,7 +4291,6 @@ rank = 4
|
|||
description = "More curly letter `y`, like Iosevka 2.x, with a tail turns leftward"
|
||||
selector.y = "curlyTurn"
|
||||
selector."y/sansSerif" = "curlyTurn"
|
||||
selector.yOgonek = "curly"
|
||||
selector.yHookTop = "curlyTurn"
|
||||
|
||||
[prime.y.variants.cursive]
|
||||
|
@ -4302,7 +4298,6 @@ rank = 5
|
|||
description = "Cursive-like `y`"
|
||||
selector.y = "cursive"
|
||||
selector."y/sansSerif" = "cursive"
|
||||
selector.yOgonek = "cursive"
|
||||
selector.yHookTop = "cursive"
|
||||
|
||||
[prime.y.variants.cursive-flat-hook]
|
||||
|
@ -4310,7 +4305,6 @@ rank = 6
|
|||
description = "Cursive-like `y` with flat terminal hook"
|
||||
selector.y = "cursiveFlatHook"
|
||||
selector."y/sansSerif" = "cursiveFlatHook"
|
||||
selector.yOgonek = "cursiveFlatHook"
|
||||
selector.yHookTop = "cursiveFlatHook"
|
||||
|
||||
[prime.y.variants.straight-motion-serifed]
|
||||
|
@ -4318,7 +4312,6 @@ rank = 7
|
|||
description = "Letter `y` that is fully straight, with motion serifs"
|
||||
selector.y = "straightMotionSerifed"
|
||||
selector."y/sansSerif" = "straight"
|
||||
selector.yOgonek = "straightMotionSerifed"
|
||||
selector.yHookTop = "straight"
|
||||
|
||||
[prime.y.variants.straight-turn-motion-serifed]
|
||||
|
@ -4326,7 +4319,6 @@ rank = 8
|
|||
description = "Letter `y` with straight upper and a tail turns leftward, and motion serifs"
|
||||
selector.y = "straightTurnMotionSerifed"
|
||||
selector."y/sansSerif" = "straightTurn"
|
||||
selector.yOgonek = "straightMotionSerifed"
|
||||
selector.yHookTop = "straightTurn"
|
||||
|
||||
[prime.y.variants.curly-motion-serifed]
|
||||
|
@ -4334,7 +4326,6 @@ rank = 9
|
|||
description = "More curly letter `y`, like Iosevka 2.x, with motion serifs"
|
||||
selector.y = "curlyMotionSerifed"
|
||||
selector."y/sansSerif" = "curly"
|
||||
selector.yOgonek = "curlyMotionSerifed"
|
||||
selector.yHookTop = "curly"
|
||||
|
||||
[prime.y.variants.curly-turn-motion-serifed]
|
||||
|
@ -4342,7 +4333,6 @@ rank = 10
|
|||
description = "More curly letter `y`, like Iosevka 2.x, with a tail turns leftward and motion serifs"
|
||||
selector.y = "curlyTurnMotionSerifed"
|
||||
selector."y/sansSerif" = "curlyTurn"
|
||||
selector.yOgonek = "curlyMotionSerifed"
|
||||
selector.yHookTop = "curlyTurn"
|
||||
|
||||
[prime.y.variants.cursive-motion-serifed]
|
||||
|
@ -4350,7 +4340,6 @@ rank = 11
|
|||
description = "Cursive-like `y`, with motion serifs"
|
||||
selector.y = "cursiveMotionSerifed"
|
||||
selector."y/sansSerif" = "cursive"
|
||||
selector.yOgonek = "cursiveMotionSerifed"
|
||||
selector.yHookTop = "cursive"
|
||||
|
||||
[prime.y.variants.cursive-flat-hook-motion-serifed]
|
||||
|
@ -4358,7 +4347,6 @@ rank = 12
|
|||
description = "Cursive-like `y` with flat terminal hook, and motion serifs"
|
||||
selector.y = "cursiveFlatHookMotionSerifed"
|
||||
selector."y/sansSerif" = "cursiveFlatHook"
|
||||
selector.yOgonek = "cursiveFlatHookMotionSerifed"
|
||||
selector.yHookTop = "cursiveFlatHook"
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue