feat: Seam allowance in breanna back part
This commit is contained in:
parent
0b27046444
commit
65e1d05b80
11 changed files with 115 additions and 59 deletions
|
@ -104,6 +104,7 @@ export default {
|
|||
breannaFitCollar: true,
|
||||
//collarFactor: 4.8,
|
||||
//backNeckCutout: 0.05,
|
||||
armholeDepthBase: 0.6,
|
||||
|
||||
// Percentages
|
||||
acrossBackFactor: { pct: 97, min: 93, max: 100 },
|
||||
|
@ -139,7 +140,7 @@ export default {
|
|||
'16:00',
|
||||
'17:00'
|
||||
],
|
||||
dflt: '06:00'
|
||||
dflt: '14:00'
|
||||
},
|
||||
secondaryBustDart: {
|
||||
list: [
|
||||
|
@ -160,7 +161,7 @@ export default {
|
|||
'16:00',
|
||||
'17:00'
|
||||
],
|
||||
dflt: '14:00'
|
||||
dflt: '15:00'
|
||||
},
|
||||
primaryBustDartShaping: { pct: 50, min: 25, max: 75 },
|
||||
primaryBustDartLength: { pct: 85, min: 65, max: 95 },
|
||||
|
|
|
@ -28,18 +28,19 @@ export default part => {
|
|||
points.hps,
|
||||
options.shoulderDartSize
|
||||
)
|
||||
points.shoulderDart1 = points.shoulderDart1.rotate(180, points.shoulderDartCenter)
|
||||
points.shoulderDart1 = points.shoulderDart2.rotate(180, points.shoulderDartCenter)
|
||||
points.shoulderDartTip = points.shoulderDartCenter.shiftFractionTowards(
|
||||
points.shoulderDartTarget,
|
||||
options.shoulderDartLength
|
||||
)
|
||||
points.shoulderDart1 = points.shoulderDart1.rotate(options.shoulderDartSize * 10, points.hps)
|
||||
points.shoulderDart2 = points.shoulderDart2.rotate(
|
||||
options.shoulderDartSize * -10,
|
||||
points.shoulder
|
||||
points.shoulderDartEdge = utils.beamsIntersect(
|
||||
points.shoulderDart1,
|
||||
points.shoulderDartTip.rotate(90, points.shoulderDart1),
|
||||
points.shoulderDart2,
|
||||
points.shoulderDartTip.rotate(90, points.shoulderDart2)
|
||||
)
|
||||
let angle = points.hps.angle(points.shoulder)
|
||||
let extra = points.hps.dist(points.shoulder) - points.hps.dist(points.shoulderDart1) * 2
|
||||
let extra = points.shoulderDart1.dist(points.shoulderDart2)
|
||||
points.shoulder = points.shoulder.shift(angle, extra)
|
||||
points.shoulderCp1 = points.shoulderCp1.shift(angle, extra)
|
||||
points.armholePitch = utils.beamIntersectsY(
|
||||
|
@ -67,34 +68,69 @@ export default part => {
|
|||
)
|
||||
points.waistDart2 = points.waistDart1.rotate(180, points.waistDartCenter)
|
||||
points.waist = points.waist.shift(0, points.waist.x * options.waistDartSize)
|
||||
points.waistDart1 = points.waistDart1.rotate(options.waistDartSize * -10, points.cbWaist)
|
||||
points.waistDart2 = points.waistDart2.rotate(options.waistDartSize * 10, points.waist)
|
||||
points.waistDartEdge = utils.beamsIntersect(
|
||||
points.waistDart1,
|
||||
points.waistDartTarget.rotate(90, points.waistDart1),
|
||||
points.waistDart2,
|
||||
points.waistDartTarget.rotate(90, points.waistDart2)
|
||||
)
|
||||
}
|
||||
|
||||
// Paths
|
||||
paths.seam = new Path().move(points.cbNeck).line(points.cbWaist)
|
||||
if (options.waistDart) {
|
||||
paths.seam
|
||||
.line(points.waistDart1)
|
||||
.line(points.waistDartTip)
|
||||
.line(points.waistDart2)
|
||||
}
|
||||
paths.seam
|
||||
paths.seam = new Path()
|
||||
.move(points.cbNeck)
|
||||
.line(points.cbWaist)
|
||||
.noop('waistDart')
|
||||
.line(points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
|
||||
.noop('shoulderDart')
|
||||
.line(points.hps)
|
||||
.curve_(points.hpsCp2, points.cbNeck)
|
||||
paths.saBase = paths.seam.clone()
|
||||
|
||||
// Insert darts
|
||||
if (options.waistDart) {
|
||||
let dart = new Path()
|
||||
.line(points.waistDart1)
|
||||
.line(points.waistDartTip)
|
||||
.line(points.waistDart2)
|
||||
paths.seam = paths.seam.insop('waistDart', dart)
|
||||
let saDart = new Path()
|
||||
.line(points.waistDart1)
|
||||
.line(points.waistDartEdge)
|
||||
.line(points.waistDart2)
|
||||
paths.saBase = paths.saBase.insop('waistDart', saDart)
|
||||
paths.waistDartHint = new Path()
|
||||
.move(points.waistDart1)
|
||||
.line(points.waistDartEdge)
|
||||
.line(points.waistDart2)
|
||||
.attr('class', 'fabric dotted')
|
||||
}
|
||||
|
||||
// Shoulder dart
|
||||
if (options.shoulderDart) {
|
||||
paths.seam
|
||||
let dart = new Path()
|
||||
.line(points.shoulderDart2)
|
||||
.line(points.shoulderDartTip)
|
||||
.line(points.shoulderDart1)
|
||||
paths.seam = paths.seam.insop('shoulderDart', dart)
|
||||
let saDart = new Path()
|
||||
.line(points.shoulderDart2)
|
||||
.line(points.shoulderDartEdge)
|
||||
.line(points.shoulderDart1)
|
||||
paths.saBase = paths.seam.insop('shoulderDart', saDart)
|
||||
paths.shoulderDartHint = new Path()
|
||||
.move(points.shoulderDart1)
|
||||
.line(points.shoulderDartEdge)
|
||||
.line(points.shoulderDart2)
|
||||
.attr('class', 'fabric dotted')
|
||||
}
|
||||
paths.seam
|
||||
.line(points.hps)
|
||||
.curve_(points.hpsCp2, points.cbNeck)
|
||||
.close()
|
||||
.attr('class', 'fabric stroke-xl')
|
||||
|
||||
paths.seam.close().attr('class', 'fabric')
|
||||
paths.saBase.close()
|
||||
paths.saBase.render = false
|
||||
|
||||
// Store data
|
||||
if (options.shoulderDart) {
|
||||
|
@ -132,7 +168,16 @@ export default part => {
|
|||
|
||||
// Complete pattern?
|
||||
if (complete) {
|
||||
// Logo
|
||||
points.logo = new Point(points.armhole.x / 2, points.armhole.y)
|
||||
snippets.logo = new Snippet('logo', points.logo)
|
||||
|
||||
// Scalebox
|
||||
points.scalebox = new Point(points.cbNeck.x + 60, points.cbNeck.y + 40)
|
||||
macro('scalebox', { at: points.scalebox })
|
||||
|
||||
if (sa) {
|
||||
paths.sa = paths.saBase.offset(sa).attr('class', 'sa')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ export default part => {
|
|||
// Armhhole
|
||||
points.armhole = new Point(
|
||||
((measurements.highBust - measurements.highBustFront) * (1 + options.chestEase)) / 2,
|
||||
(points.shoulder.y + measurements.bicepsCircumference / 2) *
|
||||
(points.shoulder.y + measurements.bicepsCircumference * options.armholeDepthBase) *
|
||||
options.armholeDepthFactor *
|
||||
(1 + options.verticalEase)
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@ export default part => {
|
|||
.move(points.primaryBustDart1)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
|
||||
|
@ -20,7 +20,7 @@ export default part => {
|
|||
.move(points.primaryBustDart1)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
|
||||
|
@ -34,7 +34,7 @@ export default part => {
|
|||
.move(points.primaryBustDart1)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
|
||||
|
@ -47,7 +47,7 @@ export default part => {
|
|||
.move(points.primaryBustDart1)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.noop('secondary')
|
||||
|
@ -60,7 +60,7 @@ export default part => {
|
|||
.move(points.primaryBustDart1)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.noop('secondary')
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
|
@ -75,7 +75,7 @@ export default part => {
|
|||
.move(points.primaryBustDart1)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.secondaryBustDart1)
|
||||
.noop('secondary')
|
||||
.line(points.armhole)
|
||||
|
@ -89,7 +89,7 @@ export default part => {
|
|||
.move(points.primaryBustDart1)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.noop('secondary')
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
|
|
|
@ -6,7 +6,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
|
||||
|
@ -20,7 +20,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
|
||||
|
@ -33,7 +33,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.noop('secondary')
|
||||
|
@ -46,7 +46,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.noop('secondary')
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
|
@ -61,7 +61,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.secondaryBustDart1)
|
||||
.noop('secondary')
|
||||
.line(points.armhole)
|
||||
|
@ -75,7 +75,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.noop('secondary')
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
|
|
|
@ -6,7 +6,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
|
||||
|
@ -20,7 +20,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.noop('secondary')
|
||||
|
@ -34,7 +34,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.noop('secondary')
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
|
@ -50,7 +50,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.secondaryBustDart1)
|
||||
.noop('secondary')
|
||||
.line(points.armhole)
|
||||
|
@ -65,7 +65,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.noop('secondary')
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
|
|
|
@ -6,7 +6,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.noop('secondary')
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
|
@ -21,7 +21,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.secondaryBustDart1)
|
||||
.noop('secondary')
|
||||
.line(points.armhole)
|
||||
|
@ -35,7 +35,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.noop('secondary')
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
|
|
|
@ -8,7 +8,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.secondaryBustDart1)
|
||||
.noop('secondary')
|
||||
.line(points.armhole)
|
||||
|
@ -22,7 +22,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.noop('secondary')
|
||||
.line(points.armhole)
|
||||
.noop('primary')
|
||||
|
|
|
@ -7,7 +7,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.secondaryBustDart1)
|
||||
.noop('secondary')
|
||||
.noop('primary')
|
||||
|
@ -21,7 +21,7 @@ export default part => {
|
|||
return new Path()
|
||||
.move(points.cfNeck)
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.noop('secondary')
|
||||
.noop('primary')
|
||||
.line(points.armhole)
|
||||
|
|
|
@ -10,7 +10,7 @@ export default part => {
|
|||
.line(points.primaryBustDart1)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
|
||||
|
@ -24,7 +24,7 @@ export default part => {
|
|||
.line(points.primaryBustDart1)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
|
||||
|
@ -37,7 +37,7 @@ export default part => {
|
|||
.line(points.primaryBustDart1)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
|
||||
|
@ -50,7 +50,7 @@ export default part => {
|
|||
.move(points.cfNeck)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
|
||||
|
@ -64,7 +64,7 @@ export default part => {
|
|||
.move(points.cfNeck)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder)
|
||||
|
@ -77,7 +77,7 @@ export default part => {
|
|||
.move(points.cfNeck)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
.noop('secondary')
|
||||
|
@ -90,7 +90,7 @@ export default part => {
|
|||
.move(points.cfNeck)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.armhole)
|
||||
.noop('secondary')
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
|
@ -105,7 +105,7 @@ export default part => {
|
|||
.move(points.cfNeck)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.line(points.secondaryBustDart1)
|
||||
.noop('secondary')
|
||||
.line(points.armhole)
|
||||
|
@ -119,7 +119,7 @@ export default part => {
|
|||
.move(points.cfNeck)
|
||||
.noop('primary')
|
||||
.line(points.cfWaist)
|
||||
.line(points.waist)
|
||||
.curve(points.cfWaistCp2, points.waistCp1, points.waist)
|
||||
.noop('secondary')
|
||||
.line(points.armhole)
|
||||
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
|
||||
|
|
|
@ -92,6 +92,16 @@ export default part => {
|
|||
// Apply correct bust dart length
|
||||
applyBustDarts(points, options, utils)
|
||||
|
||||
// Redraw the waist
|
||||
points.cfWaistCp2 = points.cfWaist.shiftFractionTowards(points.origBustDart2, 0.5)
|
||||
points.waistCp1 = points.waist.shiftFractionTowards(points.origBustDart2, 0.5)
|
||||
|
||||
// Let's keep the center front vertical as it is the grainline/cut-on-fold
|
||||
if (true || loc1 >= 1100) {
|
||||
let tilt = 270 - points.cfNeck.angle(points.cfWaist)
|
||||
for (let p in points) points[p] = points[p].rotate(tilt, points.cfNeck)
|
||||
}
|
||||
|
||||
// Load path template
|
||||
let template
|
||||
if (loc1 <= 600) template = frontWithPrimaryAt600(part)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue