diff --git a/CHANGELOG.md b/CHANGELOG.md index f8a2390f5..4c505c134 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p - `net`: added `SandboxAuthorities` (defaulting to `lookup.sandbox.gobl.org`) and `WithSandbox`. Sandbox and live trust lists remain separate. +- `sk`: Slovakia tax regime with VAT categories for standard (23%), reduced (19%) and super-reduced (5%) rates per zákon č. 222/2004 Z. z. § 27, EUR currency, `Europe/Bratislava` timezone, and IČ DPH tax identity validation (10 digits, modulo-11 check). ### Changed diff --git a/data/regimes/sk.json b/data/regimes/sk.json new file mode 100644 index 000000000..11c39146d --- /dev/null +++ b/data/regimes/sk.json @@ -0,0 +1,197 @@ +{ + "$schema": "https://gobl.org/draft-0/tax/regime-def", + "name": { + "en": "Slovakia", + "sk": "Slovensko" + }, + "description": { + "en": "Slovakia's tax system is administered by the Financial Administration of the\nSlovak Republic (Finančná správa Slovenskej republiky). As an EU member state,\nSlovakia follows the EU VAT Directive.\n\nVAT (daň z pridanej hodnoty, DPH) applies at a standard rate, with reduced rates\nfor certain goods and services such as foodstuffs, medicines, medical devices,\nbooks, and accommodation. Exports and intra-EU supplies to VAT-registered buyers\nare zero-rated.\n\nBusinesses registered for VAT are identified by their IČ DPH, formed by the\nprefix SK followed by ten digits (e.g. SK2020273893)." + }, + "sources": [ + { + "title": { + "en": "Finančná správa - Daň z pridanej hodnoty (VAT)" + }, + "url": "https://www.financnasprava.sk/sk/podnikatelia/dane/dan-z-pridanej-hodnoty", + "at": "2026-08-06T00:00:00" + }, + { + "title": { + "en": "Slov-Lex - Zákon č. 222/2004 Z. z. o dani z pridanej hodnoty" + }, + "url": "https://www.slov-lex.sk/ezbierky/pravne-predpisy/SK/ZZ/2004/222/", + "at": "2026-08-06T00:00:00" + }, + { + "title": { + "en": "Financial Administration of the Slovak Republic (English)" + }, + "url": "https://www.financnasprava.sk/en/", + "at": "2026-08-06T00:00:00" + } + ], + "time_zone": "Europe/Bratislava", + "country": "SK", + "currency": "EUR", + "tax_scheme": "VAT", + "scenarios": [ + { + "schema": "bill/invoice", + "list": [ + { + "tags": [ + "reverse-charge" + ], + "cat": [ + "VAT" + ], + "note": { + "cat": "VAT", + "key": "reverse-charge", + "text": "Reverse charge: Customer to account for VAT to the relevant tax authority." + } + } + ] + } + ], + "categories": [ + { + "code": "VAT", + "name": { + "en": "VAT", + "sk": "DPH" + }, + "title": { + "en": "Value Added Tax", + "sk": "Daň z pridanej hodnoty" + }, + "keys": [ + { + "key": "standard", + "name": { + "en": "Standard" + } + }, + { + "key": "zero", + "name": { + "en": "Zero" + } + }, + { + "key": "reverse-charge", + "name": { + "en": "Reverse charge" + }, + "no_percent": true + }, + { + "key": "exempt", + "name": { + "en": "Exempt" + }, + "no_percent": true + }, + { + "key": "export", + "name": { + "en": "Export" + }, + "no_percent": true + }, + { + "key": "intra-community", + "name": { + "en": "Intra-community" + }, + "no_percent": true + }, + { + "key": "outside-scope", + "name": { + "en": "Outside scope" + }, + "no_percent": true + } + ], + "rates": [ + { + "rate": "general", + "keys": [ + "standard" + ], + "name": { + "en": "Standard Rate", + "sk": "Základná sadzba" + }, + "values": [ + { + "since": "2025-01-01", + "percent": "23.0%" + }, + { + "since": "2011-01-01", + "percent": "20.0%" + } + ] + }, + { + "rate": "reduced", + "keys": [ + "standard" + ], + "name": { + "en": "Reduced Rate", + "sk": "Znížená sadzba" + }, + "desc": { + "en": "Non-basic foodstuffs, electricity and certain catering services.", + "sk": "Potraviny okrem základných, elektrina a niektoré reštauračné služby." + }, + "values": [ + { + "since": "2025-01-01", + "percent": "19.0%" + } + ] + }, + { + "rate": "super-reduced", + "keys": [ + "standard" + ], + "name": { + "en": "Super-reduced Rate", + "sk": "Druhá znížená sadzba" + }, + "desc": { + "en": "Basic foodstuffs, medicines, medical devices, books, and accommodation.", + "sk": "Základné potraviny, lieky, zdravotnícke pomôcky, knihy a ubytovanie." + }, + "values": [ + { + "since": "2025-01-01", + "percent": "5.0%" + } + ] + } + ], + "sources": [ + { + "title": { + "en": "Slov-Lex - Zákon č. 222/2004 Z. z. § 27 (Sadzba dane)" + }, + "url": "https://www.slov-lex.sk/ezbierky/pravne-predpisy/SK/ZZ/2004/222/", + "at": "2026-08-06T00:00:00" + }, + { + "title": { + "en": "Slov-Lex - Zákon č. 490/2010 Z. z. (novela zákona č. 222/2004 Z. z.)" + }, + "url": "https://www.slov-lex.sk/ezbierky/pravne-predpisy/SK/ZZ/2010/490/", + "at": "2026-08-06T00:00:00" + } + ] + } + ] +} \ No newline at end of file diff --git a/data/rules/sk.json b/data/rules/sk.json new file mode 100644 index 000000000..221a1a5c4 --- /dev/null +++ b/data/rules/sk.json @@ -0,0 +1,42 @@ +{ + "id": "GOBL-SK", + "package": "sk", + "subsets": [ + { + "id": "GOBL-SK-TAX-IDENTITY", + "object": "tax.Identity", + "subsets": [ + { + "guard": "code in [SK]", + "subsets": [ + { + "field": "code", + "subsets": [ + { + "guard": "present", + "assert": [ + { + "id": "GOBL-SK-TAX-IDENTITY-01", + "desc": "tax identity code for SK must be 10 digits starting with 1-9", + "tests": "matches ^[1-9]\\d{9}$" + } + ] + }, + { + "guard": "present", + "assert": [ + { + "id": "GOBL-SK-TAX-IDENTITY-02", + "desc": "tax identity code for SK failed the checksum: the 10 digit number must be divisible by 11", + "tests": "checksum" + } + ] + } + ] + } + ] + } + ] + } + ] +} diff --git a/data/schemas/tax/regime-code.json b/data/schemas/tax/regime-code.json index 585a84591..707c6e08b 100644 --- a/data/schemas/tax/regime-code.json +++ b/data/schemas/tax/regime-code.json @@ -109,6 +109,10 @@ "const": "SG", "title": "Singapore" }, + { + "const": "SK", + "title": "Slovakia" + }, { "const": "US", "title": "United States of America" diff --git a/examples/sk/invoice-sk-sk.yaml b/examples/sk/invoice-sk-sk.yaml new file mode 100644 index 000000000..593f70859 --- /dev/null +++ b/examples/sk/invoice-sk-sk.yaml @@ -0,0 +1,55 @@ +$schema: "https://gobl.org/draft-0/bill/invoice" +uuid: "b3d5f7a1-2c4e-4b6a-8d9f-1a2b3c4d5e6f" +series: "SAMPLE" +code: "001" +issue_date: "2025-03-01" + +supplier: + name: "Vzorová s.r.o." + tax_id: + country: "SK" + code: "2020273893" + addresses: + - num: "12" + street: "Hlavná" + locality: "Bratislava" + code: "81101" + country: "SK" + emails: + - addr: "fakturacia@example.sk" + +customer: + name: "Zákazník s.r.o." + tax_id: + country: "SK" + code: "7120001713" + addresses: + - num: "5" + street: "Štúrova" + locality: "Košice" + code: "04001" + country: "SK" + +lines: + - quantity: "10" + item: + name: "Softvérové služby" + price: "120.00" + unit: "h" + taxes: + - cat: VAT + rate: "standard" + - quantity: "100" + item: + name: "Elektrina" + price: "0.25" + taxes: + - cat: VAT + rate: "reduced" + - quantity: "5" + item: + name: "Knihy" + price: "20.00" + taxes: + - cat: VAT + rate: "super-reduced" diff --git a/examples/sk/out/invoice-sk-sk.json b/examples/sk/out/invoice-sk-sk.json new file mode 100644 index 000000000..e5ad39d72 --- /dev/null +++ b/examples/sk/out/invoice-sk-sk.json @@ -0,0 +1,150 @@ +{ + "$schema": "https://gobl.org/draft-0/envelope", + "head": { + "uuid": "8a51fd30-2a27-11ee-be56-0242ac120002", + "dig": { + "alg": "sha256", + "val": "2e59c41a0a403e18ea546660126c31142267955460446e819c662c1ca539272e" + } + }, + "doc": { + "$schema": "https://gobl.org/draft-0/bill/invoice", + "$regime": "SK", + "uuid": "b3d5f7a1-2c4e-4b6a-8d9f-1a2b3c4d5e6f", + "type": "standard", + "series": "SAMPLE", + "code": "001", + "issue_date": "2025-03-01", + "currency": "EUR", + "supplier": { + "name": "Vzorová s.r.o.", + "tax_id": { + "country": "SK", + "code": "2020273893" + }, + "addresses": [ + { + "num": "12", + "street": "Hlavná", + "locality": "Bratislava", + "code": "81101", + "country": "SK" + } + ], + "emails": [ + { + "addr": "fakturacia@example.sk" + } + ] + }, + "customer": { + "name": "Zákazník s.r.o.", + "tax_id": { + "country": "SK", + "code": "7120001713" + }, + "addresses": [ + { + "num": "5", + "street": "Štúrova", + "locality": "Košice", + "code": "04001", + "country": "SK" + } + ] + }, + "lines": [ + { + "i": 1, + "quantity": "10", + "item": { + "name": "Softvérové služby", + "price": "120.00", + "unit": "h" + }, + "sum": "1200.00", + "taxes": [ + { + "cat": "VAT", + "key": "standard", + "rate": "general", + "percent": "23.0%" + } + ], + "total": "1200.00" + }, + { + "i": 2, + "quantity": "100", + "item": { + "name": "Elektrina", + "price": "0.25" + }, + "sum": "25.00", + "taxes": [ + { + "cat": "VAT", + "key": "standard", + "rate": "reduced", + "percent": "19.0%" + } + ], + "total": "25.00" + }, + { + "i": 3, + "quantity": "5", + "item": { + "name": "Knihy", + "price": "20.00" + }, + "sum": "100.00", + "taxes": [ + { + "cat": "VAT", + "key": "standard", + "rate": "super-reduced", + "percent": "5.0%" + } + ], + "total": "100.00" + } + ], + "totals": { + "sum": "1325.00", + "total": "1325.00", + "taxes": { + "categories": [ + { + "code": "VAT", + "rates": [ + { + "key": "standard", + "base": "1200.00", + "percent": "23.0%", + "amount": "276.00" + }, + { + "key": "standard", + "base": "25.00", + "percent": "19.0%", + "amount": "4.75" + }, + { + "key": "standard", + "base": "100.00", + "percent": "5.0%", + "amount": "5.00" + } + ], + "amount": "285.75" + } + ], + "sum": "285.75" + }, + "tax": "285.75", + "total_with_tax": "1610.75", + "payable": "1610.75" + } + } +} \ No newline at end of file diff --git a/regimes/regimes.go b/regimes/regimes.go index a6b6d7203..dbae5997a 100644 --- a/regimes/regimes.go +++ b/regimes/regimes.go @@ -31,5 +31,6 @@ import ( _ "github.com/invopop/gobl/regimes/sa" _ "github.com/invopop/gobl/regimes/se" _ "github.com/invopop/gobl/regimes/sg" + _ "github.com/invopop/gobl/regimes/sk" _ "github.com/invopop/gobl/regimes/us" ) diff --git a/regimes/sk/sk.go b/regimes/sk/sk.go new file mode 100644 index 000000000..809977e7e --- /dev/null +++ b/regimes/sk/sk.go @@ -0,0 +1,75 @@ +// Package sk provides tax regime support for Slovakia. +package sk + +import ( + "github.com/invopop/gobl/bill" + "github.com/invopop/gobl/cal" + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/currency" + "github.com/invopop/gobl/i18n" + "github.com/invopop/gobl/norm" + "github.com/invopop/gobl/pkg/here" + "github.com/invopop/gobl/rules" + "github.com/invopop/gobl/tax" +) + +// CountryCode is the ISO 3166-1 alpha-2 code for Slovakia. +const CountryCode = "SK" + +func init() { + tax.RegisterRegimeDef(New()) + rules.Register("sk", rules.GOBL.Add(CountryCode), + taxIdentityRules(), + ) + norm.Register( + norm.When(tax.IdentityIn(CountryCode), norm.For(func(tID *tax.Identity) { tax.NormalizeIdentity(tID) })), + ) +} + +// New instantiates a new Slovakia regime. +func New() *tax.RegimeDef { + return &tax.RegimeDef{ + Country: CountryCode, + Currency: currency.EUR, + TaxScheme: tax.CategoryVAT, + Name: i18n.String{ + i18n.EN: "Slovakia", + i18n.SK: "Slovensko", + }, + Description: i18n.String{ + i18n.EN: here.Doc(` + Slovakia's tax system is administered by the Financial Administration of the + Slovak Republic (Finančná správa Slovenskej republiky). As an EU member state, + Slovakia follows the EU VAT Directive. + + VAT (daň z pridanej hodnoty, DPH) applies at a standard rate, with reduced rates + for certain goods and services such as foodstuffs, medicines, medical devices, + books, and accommodation. Exports and intra-EU supplies to VAT-registered buyers + are zero-rated. + + Businesses registered for VAT are identified by their IČ DPH, formed by the + prefix SK followed by ten digits (e.g. SK2020273893). + `), + }, + Sources: []*cbc.Source{ + { + Title: i18n.NewString("Finančná správa - Daň z pridanej hodnoty (VAT)"), + URL: "https://www.financnasprava.sk/sk/podnikatelia/dane/dan-z-pridanej-hodnoty", + At: cal.NewDateTime(2026, 8, 6, 0, 0, 0), + }, + { + Title: i18n.NewString("Slov-Lex - Zákon č. 222/2004 Z. z. o dani z pridanej hodnoty"), + URL: "https://www.slov-lex.sk/ezbierky/pravne-predpisy/SK/ZZ/2004/222/", + At: cal.NewDateTime(2026, 8, 6, 0, 0, 0), + }, + { + Title: i18n.NewString("Financial Administration of the Slovak Republic (English)"), + URL: "https://www.financnasprava.sk/en/", + At: cal.NewDateTime(2026, 8, 6, 0, 0, 0), + }, + }, + TimeZone: "Europe/Bratislava", + Categories: taxCategories, + Scenarios: []*tax.ScenarioSet{bill.InvoiceScenarios()}, + } +} diff --git a/regimes/sk/tax_categories.go b/regimes/sk/tax_categories.go new file mode 100644 index 000000000..2a59fc796 --- /dev/null +++ b/regimes/sk/tax_categories.go @@ -0,0 +1,101 @@ +package sk + +import ( + "github.com/invopop/gobl/cal" + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/i18n" + "github.com/invopop/gobl/num" + "github.com/invopop/gobl/tax" +) + +// Slovakia's VAT rates. +// Only the standard rate carries a pre-2025 value (20%, in force since 2011). The +// reduced and super-reduced rates are deliberately not backfilled: before 2025 there +// was a single 10% reduced rate on príloha č. 7 goods (medicines, books), whose scope +// sits closer to today's 5% super-reduced than to the new 19% tier, so attaching that +// history to either rate would misrepresent which goods were taxed at which rate. +var taxCategories = []*tax.CategoryDef{ + { + Code: tax.CategoryVAT, + Name: i18n.String{ + i18n.EN: "VAT", + i18n.SK: "DPH", + }, + Title: i18n.String{ + i18n.EN: "Value Added Tax", + i18n.SK: "Daň z pridanej hodnoty", + }, + Sources: []*cbc.Source{ + { + Title: i18n.NewString("Slov-Lex - Zákon č. 222/2004 Z. z. § 27 (Sadzba dane)"), + URL: "https://www.slov-lex.sk/ezbierky/pravne-predpisy/SK/ZZ/2004/222/", + At: cal.NewDateTime(2026, 8, 6, 0, 0, 0), + }, + { + // Source of the 20% standard rate, introduced from 2011-01-01 by § 85j and + // carried in § 27 itself from 2015-01-01. + Title: i18n.NewString("Slov-Lex - Zákon č. 490/2010 Z. z. (novela zákona č. 222/2004 Z. z.)"), + URL: "https://www.slov-lex.sk/ezbierky/pravne-predpisy/SK/ZZ/2010/490/", + At: cal.NewDateTime(2026, 8, 6, 0, 0, 0), + }, + }, + Retained: false, + Keys: tax.GlobalVATKeys(), + Rates: []*tax.RateDef{ + { + Keys: []cbc.Key{tax.KeyStandard}, + Rate: tax.RateGeneral, + Name: i18n.String{ + i18n.EN: "Standard Rate", + i18n.SK: "Základná sadzba", + }, + Values: []*tax.RateValueDef{ + { + Since: cal.NewDate(2025, 1, 1), + Percent: num.MakePercentage(230, 3), // 23.0% + }, + { + Since: cal.NewDate(2011, 1, 1), + Percent: num.MakePercentage(200, 3), // 20.0% + }, + }, + }, + { + Keys: []cbc.Key{tax.KeyStandard}, + Rate: tax.RateReduced, + Name: i18n.String{ + i18n.EN: "Reduced Rate", + i18n.SK: "Znížená sadzba", + }, + Description: i18n.String{ + i18n.EN: "Non-basic foodstuffs, electricity and certain catering services.", + i18n.SK: "Potraviny okrem základných, elektrina a niektoré reštauračné služby.", + }, + Values: []*tax.RateValueDef{ + { + Since: cal.NewDate(2025, 1, 1), + Percent: num.MakePercentage(190, 3), // 19.0% + }, + }, + }, + { + Keys: []cbc.Key{tax.KeyStandard}, + Rate: tax.RateSuperReduced, + Name: i18n.String{ + i18n.EN: "Super-reduced Rate", + i18n.SK: "Druhá znížená sadzba", + }, + Description: i18n.String{ + i18n.EN: "Basic foodstuffs, medicines, medical devices, books, and accommodation.", + i18n.SK: "Základné potraviny, lieky, zdravotnícke pomôcky, knihy a ubytovanie.", + }, + Values: []*tax.RateValueDef{ + { + Since: cal.NewDate(2025, 1, 1), + Percent: num.MakePercentage(50, 3), // 5.0% + }, + }, + }, + }, + }, +} diff --git a/regimes/sk/tax_identity.go b/regimes/sk/tax_identity.go new file mode 100644 index 000000000..c3567f075 --- /dev/null +++ b/regimes/sk/tax_identity.go @@ -0,0 +1,50 @@ +package sk + +import ( + "regexp" + "strconv" + + "github.com/invopop/gobl/rules" + "github.com/invopop/gobl/rules/is" + "github.com/invopop/gobl/tax" +) + +// taxCodeRegexp matches a normalized Slovak IČ DPH: exactly 10 digits, the first +// of which is non-zero. The "SK" country prefix, spaces and hyphens are removed +// during normalization (tax.NormalizeIdentity), so only the digits reach this +// validation. +var taxCodeRegexp = regexp.MustCompile(`^[1-9]\d{9}$`) + +func taxIdentityRules() *rules.Set { + return rules.For(new(tax.Identity), + rules.When(tax.IdentityIn(CountryCode), + rules.Field("code", + rules.AssertIfPresent("01", "tax identity code for SK must be 10 digits starting with 1-9", + is.MatchesRegexp(taxCodeRegexp), + ), + rules.AssertIfPresent("02", "tax identity code for SK failed the checksum: the 10 digit number must be divisible by 11", + is.StringFunc("checksum", validateTaxCodeChecksum), + ), + ), + ), + ) +} + +// validateTaxCodeChecksum applies the Slovak IČ DPH checksum: the whole 10-digit +// number must be divisible by 11. Each assertion is evaluated independently, so a +// code that already failed the format rule still reaches this function; ParseInt +// rejects anything that is not a plain integer. +// +// Note: the Slovak tax authority does not publish this algorithm; the modulo-11 +// rule is consistently documented by EU VAT-number validators and matches all +// known valid identifiers (e.g. SK2020273893). +// +// Reference: https://github.com/ltns35/go-vat/blob/main/countries/slovakia.go +// Reference: https://vatdb.com/guides/validate-sk-vat-number/ +func validateTaxCodeChecksum(code string) bool { + n, err := strconv.ParseInt(code, 10, 64) + if err != nil { + return false + } + return n%11 == 0 +} diff --git a/regimes/sk/tax_identity_test.go b/regimes/sk/tax_identity_test.go new file mode 100644 index 000000000..d257034fa --- /dev/null +++ b/regimes/sk/tax_identity_test.go @@ -0,0 +1,141 @@ +package sk_test + +import ( + "slices" + "testing" + + "github.com/invopop/gobl/cbc" + "github.com/invopop/gobl/norm" + "github.com/invopop/gobl/rules" + "github.com/invopop/gobl/tax" + "github.com/stretchr/testify/assert" +) + +func TestTaxIdentityRules(t *testing.T) { + // The format and checksum rules are asserted separately, so a code may + // trigger either or both. Codes not listed must NOT be reported. + allCodes := []string{"IDENTITY-01", "IDENTITY-02"} + + tests := []struct { + name string + inputCode cbc.Code + expectedErrs []string + }{ + { + name: "valid divisible by 11", + inputCode: "2020273893", + }, + { + name: "valid divisible by 11, natural person", + inputCode: "7120001713", + }, + { + name: "empty code", + inputCode: "", + }, + { + name: "leading zero, checksum still valid", + inputCode: "0000000011", + expectedErrs: []string{"IDENTITY-01"}, + }, + { + name: "all zeros, checksum still valid", + inputCode: "0000000000", + expectedErrs: []string{"IDENTITY-01"}, + }, + { + name: "well formed but not divisible by 11", + inputCode: "2020273894", + expectedErrs: []string{"IDENTITY-02"}, + }, + { + name: "too short", + inputCode: "202027389", + expectedErrs: []string{"IDENTITY-01", "IDENTITY-02"}, + }, + { + name: "too long", + inputCode: "20202738931", + expectedErrs: []string{"IDENTITY-01", "IDENTITY-02"}, + }, + { + name: "contains letters", + inputCode: "202027389A", + expectedErrs: []string{"IDENTITY-01", "IDENTITY-02"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tID := &tax.Identity{Country: "SK", Code: tt.inputCode} + err := rules.Validate(tID) + if len(tt.expectedErrs) == 0 { + assert.NoError(t, err) + return + } + if !assert.Error(t, err) { + return + } + for _, code := range allCodes { + if slices.Contains(tt.expectedErrs, code) { + assert.Contains(t, err.Error(), code) + } else { + assert.NotContains(t, err.Error(), code) + } + } + }) + } +} + +func TestNormalizeTaxIdentity(t *testing.T) { + tests := []struct { + name string + inputCode cbc.Code + expectedCode cbc.Code + }{ + { + name: "strips SK prefix", + inputCode: "SK2020273893", + expectedCode: "2020273893", + }, + { + name: "strips lowercase prefix", + inputCode: "sk2020273893", + expectedCode: "2020273893", + }, + { + name: "strips spaces", + inputCode: "2020 2738 93", + expectedCode: "2020273893", + }, + { + name: "strips hyphen", + inputCode: "20202-73893", + expectedCode: "2020273893", + }, + { + name: "already normalized", + inputCode: "2020273893", + expectedCode: "2020273893", + }, + { + name: "empty", + inputCode: "", + expectedCode: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tID := &tax.Identity{Country: "SK", Code: tt.inputCode} + norm.Normalize(tID) + assert.Equal(t, tt.expectedCode, tID.Code) + }) + } + + t.Run("nil identity", func(t *testing.T) { + assert.NotPanics(t, func() { + norm.Normalize((*tax.Identity)(nil)) + }) + }) +}