aboutsummaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
authorSam Anthony <sam@samanthony.xyz>2026-05-21 17:55:54 -0400
committerSam Anthony <sam@samanthony.xyz>2026-05-21 17:55:54 -0400
commit9d5cc798f82ff4a899984fa73014bd604d44ee32 (patch)
treea1553de298afe38fdec18ac847e7a32c6e376c21 /cmd
parent922c7f326382aa06f8bc4c9b5dcb2c0098160adb (diff)
downloadlulu-9d5cc798f82ff4a899984fa73014bd604d44ee32.zip
cli: print and cancel commands
Diffstat (limited to 'cmd')
-rw-r--r--cmd/lulu/cancel.go11
-rw-r--r--cmd/lulu/cli.go56
-rw-r--r--cmd/lulu/cost.go15
-rw-r--r--cmd/lulu/job.go76
-rw-r--r--cmd/lulu/print.go71
-rwxr-xr-xcmd/lulu/test14
-rw-r--r--cmd/lulu/testchecks/job6
-rw-r--r--cmd/lulu/testchecks/print1
-rw-r--r--cmd/lulu/testdata/cancel0
-rw-r--r--cmd/lulu/tests/cancel5
-rw-r--r--cmd/lulu/tests/job6
-rw-r--r--cmd/lulu/tests/print3
12 files changed, 191 insertions, 73 deletions
diff --git a/cmd/lulu/cancel.go b/cmd/lulu/cancel.go
new file mode 100644
index 0000000..4e5d3b1
--- /dev/null
+++ b/cmd/lulu/cancel.go
@@ -0,0 +1,11 @@
+package main
+
+import "git.samanthony.xyz/lulu"
+
+type CancelCmd struct {
+ Id uint64 `arg help:"ID of the job to cancel"`
+}
+
+func (cmd CancelCmd) Run(clnt *lulu.Client) error {
+ return clnt.Cancel(cmd.Id)
+}
diff --git a/cmd/lulu/cli.go b/cmd/lulu/cli.go
index 0ff077a..9f384c6 100644
--- a/cmd/lulu/cli.go
+++ b/cmd/lulu/cli.go
@@ -2,6 +2,7 @@ package main
import (
"fmt"
+ "regexp"
"strings"
"github.com/alecthomas/kong"
@@ -10,15 +11,42 @@ import (
)
var helpVars = kong.Vars{
- "cost_item_help": "Line items. Run 'lulu list cost-item' for format",
- "default_timeout": defaultTimeout.String(),
- "mfg_help": "Manufacturing settings. Run 'lulu list mfg' for format",
- "npages_help": "Number of interior pages",
- "order_status_help": fmt.Sprintf("Filter by order status %s", lulu.OrderStatusValues()),
- "ship_level_help": fmt.Sprint(lulu.ShippingLevelValues()),
- "unit_help": fmt.Sprintf("Unit of measurement: %s", lulu.UnitValues()),
+ "contact_help": "Email address that should be contacted if questions regarding the print job arise. Lulu recommends to use the email of a person who is responsible for placing the Print-Job like a developer or business owner.",
+ "cost_item_help": "Line items. Run 'lulu list cost-item' for format",
+ "default_timeout": defaultTimeout.String(),
+ "mfg_help": "Manufacturing settings. Run 'lulu list mfg' for format",
+ "npages_help": "Number of interior pages",
+ "order_status_help": fmt.Sprintf("Filter by order status %s", lulu.OrderStatusValues()),
+ "printable_help": "Line items. Run 'lulu list printable' for format",
+ "production_delay_help": fmt.Sprintf("Delay before job is sent to production after it is paid for (%s-%s)", lulu.MinProductionDelay, lulu.MaxProductionDelay),
+ "ship_level_help": fmt.Sprint(lulu.ShippingLevelValues()),
+ "unit_help": fmt.Sprintf("Unit of measurement: %s", lulu.UnitValues()),
}
+var (
+ pkgIdExpr = regexp.MustCompile(
+ `[0-9]{4}X[0-9]{4}\.[A-Z]{2}\.[A-Z]{3}\.[A-Z]{2}\.[A-Z0-9]{5,8}\.[A-Z]{3}`)
+
+ printJobCostLineItemExpr = regexp.MustCompile(
+ `([1-9][0-9]*)x_(` + pkgIdExpr.String() + `)_p([1-9][0-9]*)`)
+
+ printJobCostLineItemFmt = `ITEM: <quantity> 'x_' <mfg> '_p' <npages>
+<quantity>: positive number
+<mfg>: run 'lulu list mfg' for valid values
+<npages>: positive number
+E.g., "10x_0600X0900.BW.STD.PB.060UW444.MXX_p250" is 10 copies with these manufacturing options and 250 pages.`
+
+ printableExpr = regexp.MustCompile(
+ `^quantity\{([1-9][0-9]*)\}_extid\{([^},]+)\}_title\{([^},]+)\}_cover\{([^},]+)\}_interior\{([^},]+)\}_mfg\{(` + pkgIdExpr.String() + `)\}`)
+
+ printableFmt = `PRINTABLE: quantity{<num>}_extid{<string>}_title{<string>}_cover{<url>}_interior{<url>}_mfg{<mfg>}
+<n>: positive number
+<string>: string of any characters except } and ,
+<url>: location of a file on the internet
+<mfg>: run 'lulu list mfg' for valid values
+E.g., "quantity{1}_extid{sku01}_title{The Title of the Book}_cover{https://example.com/cover.pdf}_interior{https://example.com/interior.pdf}_mfg{0600X0900.BW.STD.PB.060UW444.MXX}"`
+)
+
type CLI struct {
Globals
@@ -26,8 +54,10 @@ type CLI struct {
ValidateCover ValidateCoverCmd `cmd name:"vc" help:"Validate cover file"`
CoverDimensions CoverDimensionsCmd `cmd name:"cd" help:"Calculate cover dimensions"`
Cost CostCmd `cmd help:"Calculate the cost of a print job"`
+ Print PrintCmd `cmd help:"Submit a print job"`
Jobs JobsCmd `cmd help:"Retrieve past print jobs"`
Job JobCmd `cmd help:"Retrieve information about a particular print job"`
+ Cancel CancelCmd `cmd help:"Cancel a print job"`
List ListCmd `cmd help:"Print a list of valid argument values"`
}
@@ -39,8 +69,9 @@ type Globals struct {
}
type ListCmd struct {
- Mfg ListMfgCmd `cmd help:"List <mfg> format"`
- CostItem ListCostItemCmd `cmd help:"List cost --items format"`
+ Mfg ListMfgCmd `cmd help:"List <mfg> format"`
+ CostItem ListCostItemCmd `cmd help:"List cost --items format"`
+ Printable ListPrintableCmd `cmd help:"List PRINTABLE format"`
}
type ListMfgCmd struct{}
@@ -75,3 +106,10 @@ func typeName(v any) string {
}
return parts[0]
}
+
+type ListPrintableCmd struct{}
+
+func (l ListPrintableCmd) Run() error {
+ fmt.Printf("%s\n", printableFmt)
+ return nil
+}
diff --git a/cmd/lulu/cost.go b/cmd/lulu/cost.go
index 1826a5c..26f641e 100644
--- a/cmd/lulu/cost.go
+++ b/cmd/lulu/cost.go
@@ -5,7 +5,6 @@ import (
"fmt"
"io"
"os"
- "regexp"
"strconv"
"text/tabwriter"
@@ -14,18 +13,6 @@ import (
"git.samanthony.xyz/lulu"
)
-var (
- pkgIdExpr = regexp.MustCompile(
- `[0-9]{4}X[0-9]{4}\.[A-Z]{2}\.[A-Z]{3}\.[A-Z]{2}\.[A-Z0-9]{5,8}\.[A-Z]{3}`)
- printJobCostLineItemExpr = regexp.MustCompile(
- `([1-9][0-9]*)x_(` + pkgIdExpr.String() + `)_p([1-9][0-9]*)`)
- printJobCostLineItemFmt = `ITEM: <quantity> 'x_' <mfg> '_p' <npages>
-<quantity>: positive number
-<mfg>: run 'lulu list mfg' for valid values
-<npages>: positive number
-E.g., "10x_0600X0900.BW.STD.PB.060UW444.MXX_p250" is 10 copies with these manufacturing options and 250 pages.`
-)
-
type CostCmd struct {
ShippingAddress
Ship lulu.ShippingLevel `required help:"${ship_level_help}"`
@@ -62,7 +49,7 @@ type PrintJobCostLineItem struct {
func (item *PrintJobCostLineItem) UnmarshalText(text []byte) error {
s := string(text)
groups := printJobCostLineItemExpr.FindStringSubmatch(s)
- if len(groups) != 4 {
+ if len(groups) != 3+1 {
return fmt.Errorf("malformed %T: %q", *item, s)
}
diff --git a/cmd/lulu/job.go b/cmd/lulu/job.go
index e58ec19..0678337 100644
--- a/cmd/lulu/job.go
+++ b/cmd/lulu/job.go
@@ -20,26 +20,31 @@ func (cmd JobCmd) Run(clnt *lulu.Client) error {
}
w := newIndentTabWriter(os.Stdout, 0)
+ print := func(w io.Writer, label string, val any) {
+ if s := fmt.Sprint(val); s != "" {
+ fmt.Fprintf(w, "%s:\t%s\t\n", label, s)
+ }
+ }
fmtTime := func(t time.Time) string { return t.UTC().Format(time.RFC3339) }
- fmt.Fprintf(w, "extid:\t%s\t\n", job.ExternalId)
- fmt.Fprintf(w, "id:\t%d\t\n", job.Id)
- fmt.Fprintf(w, "orderid:\t%s\t\n", job.OrderId)
- fmt.Fprintf(w, "contact:\t%s\t\n", job.Contact)
- fmt.Fprintf(w, "created:\t%s\t\n", fmtTime(job.Created))
- fmt.Fprintf(w, "modified:\t%s\t\n", fmtTime(job.Modified))
+ print(w, "extid", job.ExternalId)
+ print(w, "id", job.Id)
+ print(w, "orderid", job.OrderId)
+ print(w, "contact", job.Contact)
+ print(w, "created", fmtTime(job.Created))
+ print(w, "modified", fmtTime(job.Modified))
fmt.Fprintf(w, "items:\t\n")
if err := w.Indent(); err != nil {
return err
}
for _, item := range job.LineItems {
- fmt.Fprintf(w, "extid:\t%s\t\n", item.ExternalId)
- fmt.Fprintf(w, "id:\t%d\t\n", item.Id)
- fmt.Fprintf(w, "printable-id:\t%s\t\n", item.PrintableId)
- fmt.Fprintf(w, "mfg:\t%s\t\n", item.Mfg)
- fmt.Fprintf(w, "quantity:\t%d\t\n", item.Quantity)
- fmt.Fprintf(w, "npages:\t%d\t\n", item.NPages)
- fmt.Fprintf(w, "title:\t%s\t\n", item.Title)
+ print(w, "extid", item.ExternalId)
+ print(w, "id", item.Id)
+ print(w, "printable-id", item.PrintableId)
+ print(w, "mfg", item.Mfg)
+ print(w, "quantity", item.Quantity)
+ print(w, "npages", item.NPages)
+ print(w, "title", item.Title)
if !isEmptyNormalization(item.PrintableNormalization.Interior) {
fmt.Fprintf(w, "interior-normalization:\t\n")
if err := w.Indent(); err != nil {
@@ -60,9 +65,7 @@ func (cmd JobCmd) Run(clnt *lulu.Client) error {
return err
}
}
- if item.TrackingId != "" {
- fmt.Fprintf(w, "tracking-id:\t%s\t\n", item.TrackingId)
- }
+ print(w, "tracking-id", item.TrackingId)
if len(item.TrackingUrls) == 1 {
fmt.Fprintf(w, "tracking-url:\t%s\t\n", item.TrackingUrls[0])
} else if len(item.TrackingUrls) > 1 {
@@ -70,9 +73,8 @@ func (cmd JobCmd) Run(clnt *lulu.Client) error {
fmt.Fprintf(w, "tracking-url-%d:\t%s\t\n", i, url)
}
}
- if item.Carrier != "" {
- fmt.Fprintf(w, "carrier:\t%s\t\n", item.Carrier)
- }
+ print(w, "carrier", item.Carrier)
+ print(w, "status", item.Status)
}
if err := w.Unindent(); err != nil {
return err
@@ -87,39 +89,29 @@ func (cmd JobCmd) Run(clnt *lulu.Client) error {
return err
}
- fmt.Fprintf(w, "production-delay:\t%s\t\n", job.ProductionDelay)
- if !job.ProductionDue.IsZero() {
- fmt.Fprintf(w, "production-due:\t%s\t\n", fmtTime(job.ProductionDue))
- }
- fmt.Fprintf(w, "shipping-level:\t%s\t\n", job.ShipOpt)
- if job.TaxCountry != "" {
- fmt.Fprintf(w, "tax-country:\t%s\t\n", job.TaxCountry)
- }
- fmt.Fprintf(w, "status:\t%s\t\n", job.Status.Status)
- fmt.Fprintf(w, "status-msg:\t%s\t\n", job.Status.Msg)
- fmt.Fprintf(w, "status-changed:\t%s\t\n", fmtTime(job.Status.Changed))
+ print(w, "production-delay", job.ProductionDelay)
+ print(w, "production-due", fmtTime(job.ProductionDue))
+ print(w, "shipping-level", job.ShipOpt)
+ print(w, "tax-country", job.TaxCountry)
+ print(w, "status", job.Status.Status)
+ print(w, "status-msg", job.Status.Msg)
+ print(w, "status-changed", fmtTime(job.Status.Changed))
return w.Flush()
}
+func isEmptyNormalization(n lulu.NormalizationJob) bool {
+ return n.JobId == 0 && n.SrcMd5Sum == "" && n.SrcUrl == ""
+}
+
func printNormalization(w io.Writer, n lulu.NormalizationJob) {
if n.JobId != 0 {
fmt.Fprintf(w, "jobid:\t%d\t\n", n.JobId)
}
- if n.NormalizedFile.Id != 0 {
- fmt.Fprintf(w, "normalized-file-id:\t%d\t\n", n.NormalizedFile.Id)
- }
- if n.NormalizedFile.Name != "" {
- fmt.Fprintf(w, "normalized-file-name:\t%s\t\n", n.NormalizedFile.Name)
+ if n.SrcUrl != "" {
+ fmt.Fprintf(w, "src-url:\t%s\t\n", n.SrcUrl)
}
if n.SrcMd5Sum != "" {
fmt.Fprintf(w, "src-md5:\t%s\t\n", n.SrcMd5Sum)
}
- if n.SrcUrl != "" {
- fmt.Fprintf(w, "src-url:\t%s\t\n", n.SrcUrl)
- }
-}
-
-func isEmptyNormalization(n lulu.NormalizationJob) bool {
- return n.JobId == 0 && n.NormalizedFile.Id == 0 && n.NormalizedFile.Name == "" && n.SrcMd5Sum == "" && n.SrcUrl == ""
}
diff --git a/cmd/lulu/print.go b/cmd/lulu/print.go
new file mode 100644
index 0000000..cbd536e
--- /dev/null
+++ b/cmd/lulu/print.go
@@ -0,0 +1,71 @@
+package main
+
+import (
+ "fmt"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+
+ "git.samanthony.xyz/lulu"
+)
+
+type PrintCmd struct {
+ Contact lulu.EmailAddress `required help:"${contact_help}"`
+ ExtId string `required name:"extid" help:"External ID"`
+ ProductionDelay time.Duration `required help:"${production_delay_help}"`
+ ShippingAddress
+ Ship lulu.ShippingLevel `required help:"${ship_level_help}"`
+ Items []Printable `required placeholder:"PRINTABLE" help:"${printable_help}"`
+}
+
+func (cmd PrintCmd) Run(clnt *lulu.Client) error {
+ items := make([]lulu.Printable, len(cmd.Items))
+ for i := range cmd.Items {
+ items[i] = lulu.Printable(cmd.Items[i])
+ }
+ job, err := clnt.Print(cmd.Contact, cmd.ExtId, cmd.ProductionDelay, cmd.ShippingAddress.Addr(), cmd.Ship, items)
+ if err != nil {
+ return err
+ }
+ fmt.Println(job.Id)
+ return nil
+}
+
+type Printable lulu.Printable
+
+func (p *Printable) UnmarshalText(text []byte) error {
+ s := strings.TrimSpace(string(text))
+ groups := printableExpr.FindStringSubmatch(s)
+ if len(groups) != 6+1 {
+ return fmt.Errorf("malformed %T: %q", *p, s)
+ }
+
+ quantity, err := strconv.ParseUint(groups[1], 10, 32)
+ if err != nil {
+ return fmt.Errorf("invalid quantity in %T %q: %w", *p, s, err)
+ }
+ p.Quantity = uint(quantity)
+
+ p.ExternalId = groups[2]
+
+ p.Title = groups[3]
+
+ cover, err := url.Parse(groups[4])
+ if err != nil {
+ return fmt.Errorf("invalid cover URL in %T %q: %w", *p, s, err)
+ }
+ p.CoverUrl = cover.String()
+
+ interior, err := url.Parse(groups[5])
+ if err != nil {
+ return fmt.Errorf("invalid interior URL in %T %q: %w", *p, s, err)
+ }
+ p.InteriorUrl = interior.String()
+
+ if err := p.Mfg.UnmarshalText([]byte(groups[6])); err != nil {
+ return fmt.Errorf("invalid %T in %T %q: %w", p.Mfg, *p, s, err)
+ }
+
+ return nil
+}
diff --git a/cmd/lulu/test b/cmd/lulu/test
index ee6b18d..3aacc99 100755
--- a/cmd/lulu/test
+++ b/cmd/lulu/test
@@ -10,6 +10,8 @@ export money='[0-9]+(\.[0-9]+)? [A-Z]{3}'
export pkgid='[0-9]{4}X[0-9]{4}\.[A-Z]{2}\.[A-Z]{3}\.[A-Z]{2}\.[A-Z0-9]{5,8}\.[A-Z]{3}'
export time='[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z'
+
+
[[ ! -d testout ]] && mkdir testout
[[ ! -d testerr ]] && mkdir testerr
@@ -23,7 +25,11 @@ do
out=testout/$base
err=testerr/$base
if [ -f $want ]; then # check against expected output
- sh ${flags} $test >$out 2>$err
+ if ! sh ${flags} $test >$out 2>$err
+ then
+ echo "FAIL $test: error: $err"
+ exit 1
+ fi
if ! cmp -s $want $out
then
echo "FAIL $test: <Expected >Actual"
@@ -31,7 +37,11 @@ do
exit 1
fi
elif [ -f $check ]; then # use script to check output
- sh ${flags} $test >$out 2>$err
+ if ! sh ${flags} $test >$out 2>$err
+ then
+ echo "FAIL $test: error: $err"
+ exit 1
+ fi
echo "checking with $check..." >>$err
if ! sh ${flags} $check $out >>$err
then
diff --git a/cmd/lulu/testchecks/job b/cmd/lulu/testchecks/job
index 80d6cf9..1877251 100644
--- a/cmd/lulu/testchecks/job
+++ b/cmd/lulu/testchecks/job
@@ -1,6 +1,5 @@
grep -E '^extid: +[0-9a-zA-Z_-]+' $1
grep -E '^id: +[0-9]+' $1
-grep -E '^orderid: +[0-9]+' $1
grep -E "$(printf '^contact: +%s' "$email")" $1
grep -E "$(printf '^created: +%s' "$time")" $1
grep -E "$(printf '^modified: +%s' "$time")" $1
@@ -8,16 +7,15 @@ grep -E "$(printf '^modified: +%s' "$time")" $1
grep -E '^items: *$' $1
grep -E '^ extid: +[0-9a-zA-Z_-]+' $1
grep -E '^ id: +[0-9]+' $1
-grep -E '^ printable-id: +[0-9a-z-]+' $1
grep -E "$(printf '^ mfg: +%s' "$pkgid")" $1
grep -E '^ quantity: +[0-9]+' $1
grep -E '^ npages: +[0-9]+' $1
grep -E '^ title: +.+' $1
grep -E '^cost: *$' $1
-for field in "item-0" "shipping" "fulfillment" "discount" "tax" "total"
+for field in "shipping" "fulfillment" "discount" "tax" "total"
do
- grep -E "$(printf '^ %s: +%s *$' "${field}" "${money}")" $1
+ grep -E "$(printf '^ %s: +[0-9]+' "${field}")" $1
done
grep -E "$(printf '^production-delay: +%s' "$duration")" $1
diff --git a/cmd/lulu/testchecks/print b/cmd/lulu/testchecks/print
new file mode 100644
index 0000000..a1f5b73
--- /dev/null
+++ b/cmd/lulu/testchecks/print
@@ -0,0 +1 @@
+grep -E '^[1-9][0-9]*$' $1
diff --git a/cmd/lulu/testdata/cancel b/cmd/lulu/testdata/cancel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmd/lulu/testdata/cancel
diff --git a/cmd/lulu/tests/cancel b/cmd/lulu/tests/cancel
new file mode 100644
index 0000000..bafb5ad
--- /dev/null
+++ b/cmd/lulu/tests/cancel
@@ -0,0 +1,5 @@
+# Create a job and cancel it.
+lulu -s print --contact admin@example.com --extid cancel-test --production-delay 2h \
+ --country DE --city Lübeck --street1 'Holstenstr. 40' --postcode '23552' --name 'Hans Dampf' --phone 844-212-0689 --ship EXPRESS \
+ --items 'quantity{1}_extid{cancel-test-sku01}_title{The Title of the Book}_cover{https://www.dropbox.com/sh/p3zh22vzsaegiri/AADP367j0bTWlt8fCu-_tm2ia/161025/139056_cover.pdf?dl=1}_interior{https://www.dropbox.com/sh/p3zh22vzsaegiri/AACOUn3LFKsITDzylh13bQpsa/161025/thesis2.pdf?dl=1}_mfg{0600X0900.BW.STD.PB.060UW444.MXX}' \
+ | xargs lulu -s cancel
diff --git a/cmd/lulu/tests/job b/cmd/lulu/tests/job
index ac39591..236a2b1 100644
--- a/cmd/lulu/tests/job
+++ b/cmd/lulu/tests/job
@@ -1,3 +1,5 @@
-# Get info on the most recent job.
-lulu -s jobs | tail -n1 | awk '{id=$3; print id}' \
+# Create a job and retrieve its information.
+lulu -s print --contact admin@example.com --extid job-test --production-delay 2h \
+ --country DE --city Lübeck --street1 'Holstenstr. 40' --postcode '23552' --name 'Hans Dampf' --phone 844-212-0689 --ship EXPRESS \
+ --items 'quantity{1}_extid{job-test-sku01}_title{The Title of the Book}_cover{https://www.dropbox.com/sh/p3zh22vzsaegiri/AADP367j0bTWlt8fCu-_tm2ia/161025/139056_cover.pdf?dl=1}_interior{https://www.dropbox.com/sh/p3zh22vzsaegiri/AACOUn3LFKsITDzylh13bQpsa/161025/thesis2.pdf?dl=1}_mfg{0600X0900.BW.STD.PB.060UW444.MXX}' \
| xargs lulu -s job
diff --git a/cmd/lulu/tests/print b/cmd/lulu/tests/print
new file mode 100644
index 0000000..894534b
--- /dev/null
+++ b/cmd/lulu/tests/print
@@ -0,0 +1,3 @@
+lulu -s print --contact admin@example.com --extid print-test --production-delay 2h \
+ --country DE --city Lübeck --street1 'Holstenstr. 40' --postcode '23552' --name 'Hans Dampf' --phone 844-212-0689 --ship EXPRESS \
+ --items 'quantity{1}_extid{print-test-sku01}_title{The Title of the Book}_cover{https://www.dropbox.com/s/7bv6mg2tj0h3l0r/lulu_trade_perfect_template.pdf?dl=1&raw=1}_interior{https://www.dropbox.com/s/r20orb8umqjzav9/lulu_trade_interior_template-32.pdf?dl=1&raw=1}_mfg{0600X0900.BW.STD.PB.060UW444.MXX},quantity{5}_extid{print-multi-test-sku02}_title{Another Title}_cover{https://www.dropbox.com/sh/p3zh22vzsaegiri/AADP367j0bTWlt8fCu-_tm2ia/161025/139056_cover.pdf?dl=1&raw=1}_interior{https://www.dropbox.com/sh/p3zh22vzsaegiri/AACOUn3LFKsITDzylh13bQpsa/161025/thesis2.pdf?dl=1&raw=1}_mfg{0600X0900.BW.STD.PB.060UW444.MXX}'