Breaking Down ISO 8583 Data Elements

ASSI Avatar

In my previous blog post, I already discussed a high-level overview of ISO 8583 Data Elements. If you haven’t read it yet, I highly recommend checking it out first, as this current post will build on some of those concepts without going into the same level of detail—to keep this article focused and concise. Understanding Data Elements

This post is part of a blog series where I dive into the details of commonly used ISO 8583 data elements in the industry. If you’re a developer, this series will be especially helpful to you—I’ll walk you through how to parse and construct these data elements based on their specific formats.

So without further ado, let’s break down the most essential data elements you’ll encounter and see how to handle them in code.


Common Data Elements

Now let’s go through the common Data Elements one by one. I’ll explain their purpose and how you can parse and construct them. I’ll be using .NET in this blog post, but the logic and implementation should be mostly the same no matter what programming language or framework you’re using.

DE 1 – Secondary Bitmap

  • Format: Bitmap (64 bits)
  • Purpose: Indicates that a Secondary Bitmap is present if bit 1 of the Primary Bitmap is set to 1.
  • How it Works:
    • The Primary Bitmap is always 64 bits (8 bytes).
    • If bit 1 of the Primary Bitmap is 1, a Secondary Bitmap (another 64 bits) immediately follows.
    • DE 1 itself represents the presence and content of the Secondary Bitmap.
  • Developer Tip:
  • If bit 1 is 1, read another 64 bits (Secondary Bitmap).
  • If bit 1 is 0, there is no Secondary Bitmap and the message has only fields 2 to 64.
  • Quick Example: Primary Bitmap: 8238000000000000
  • First bit = 1 > Secondary Bitmap is present.
  • After the Primary Bitmap, another 64 bits (Secondary Bitmap) follows.
  • Important Reminder: If you are setting any fields above DE 64 (like DE 102, DE 123), you must set bit 1 in the Primary Bitmap to 1, otherwise the message will be invalid. In short, DE 1 is the Secondary Bitmap itself—a structural field, not a value field.

DE 2 – Primary Account Number (PAN)

  • Format: LLVAR (Variable length, up to 19 digits)
  • Example: 4111111111111111
  • Purpose: This is the card number (PAN) used to identify the cardholder’s account. It’s a critical and sensitive part of the message.
  • How to Parse:
C#
// Example parsing a PAN field
string rawData = "164111111111111111"; // '16' indicates next 16 digits are the PAN
int len = int.Parse(rawData.Substring(0, 2));
string pan = rawData.Substring(2, len);
Console.WriteLine($"PAN: {pan}");
// Output: PAN: 4111111111111111
  • How to Build:
C#
// Example of building DE 2 using card number "4111111111111111"
string pan = "4111111111111111"; // PAN value
string de2 = pan.Length.ToString("D2") + pan;
Console.WriteLine($"DE2: {de2}");
// Output: "164111111111111111"
  • Important Tip: LLVAR means Length + Value. The length must always be two digits. For example:
    • Length of 4111111111111111 = 16, write it as “16”
    • Then concatenate it directly with the PAN value.
    • Final result = 16 + 4111111111111111 = 164111111111111111
    • Note: You should always mask or encrypt PAN when logging or storing it.

DE 3 – Processing Code

  • Format: Fixed (6 digits)
  • Example: 000000 = Purchase, 200000 = Refund
  • Purpose: Tells the system what kind of transaction is being processed.
  • How to Parse:
C#
// Example parsing Processing Code
string rawData = "000000";
string processingCode = rawData.Substring(0, 6);
Console.WriteLine($"Processing Code: {processingCode}");
// Output: Processing Code: 000000
  • How to Build:
C#
// Example of building DE 3 with purchase processing code
string processingCode = "000000"; // 000000 = Purchase
string de3 = processingCode;
Console.WriteLine($"DE3: {de3}");
// Output: "000000"
  • Structure: Usually composed of 3 parts: transaction type, account type (from/to), and transaction qualifier.

DE 4 – Amount Transaction

  • Format: Fixed (12 digits)
  • Example: 000000010000 (means 1,000.00)
  • Purpose: This field holds the amount of the transaction, expressed in the smallest currency unit (e.g., cents).
  • How to Parse:
C#
// Example parsing a transaction amount
string rawData = "000000010000";
decimal amount = decimal.Parse(rawData) / 100;
Console.WriteLine($"Amount: {amount:C2}");
// Output: Amount: 1,000.00
  • How to Build:
C#
// Example of building DE 4 with an amount of 1,000.00
decimal amountValue = 1000.00m;
string de4 = ((int)(amountValue * 100)).ToString("D12");
Console.WriteLine($"DE4: {de4}");
// Output: "000000010000"
  • Important Tip: Always store and process the amount in the smallest unit (like cents). When building the field:
    • Multiply the amount by 100 to get the amount in cents.
    • Format it as a 12-digit string, left-padded with zeros.
    • Note: Always divide by 100 when parsing to convert from cents to whole currency units (e.g., PHP 1000.00).

DE 11 – Systems Trace Audit Number (STAN)

  • Format: Fixed (6 digits)
  • Example: 123456
  • Purpose: Used to uniquely identify a transaction throughout its lifecycle, helpful for matching requests and responses.
  • How to Parse:
C#
// Example parsing STAN
string rawData = "123456";
string stan = rawData.Substring(0, 6);
Console.WriteLine($"STAN: {stan}");
// Output: STAN: 123456
  • How to Build:
C#
// Example of building DE 11 with a STAN
string stan = "123456"; // Example system trace audit number
string de11 = stan.PadLeft(6, '0');
Console.WriteLine($"DE11: {de11}");
// Output: "123456"
  • Important Tip: The STAN should be unique per transaction within a short time window to help easily trace and match transaction flows.

DE 12 – Time, Local Transaction

  • Format: Fixed (6 digits)
  • Example: 142355 (2:23:55 PM)
  • Purpose: Indicates the local time when the transaction was initiated, based on the terminal’s clock.
  • How to Parse:
C#
// Example parsing local transaction time
string rawData = "142355";
string hour = rawData.Substring(0, 2);
string minute = rawData.Substring(2, 2);
string second = rawData.Substring(4, 2);
Console.WriteLine($"Time: {hour}:{minute}:{second}");
// Output: Time: 14:23:55
  • How to Build:
C#
// Example of building DE 12 with 2:23:55 PM
DateTime transactionTime = new DateTime(2025, 4, 17, 14, 23, 55);
string de12 = transactionTime.ToString("HHmmss");
Console.WriteLine($"DE12: {de12}");
// Output: "142355"
  • Important Tip: Always use 24-hour format (HHmmss) when building this field.

DE 13 – Date, Local Transaction

  • Format: Fixed (4 digits)
  • Example: 0417 (April 17)
  • Purpose: Indicates the local date when the transaction was initiated, based on the terminal’s clock.
  • How to Parse:
C#
// Example parsing local transaction date
string rawData = "0417";
string month = rawData.Substring(0, 2);
string day = rawData.Substring(2, 2);
Console.WriteLine($"Date: {month}/{day}");
// Output: Date: 04/17
  • How to Build:
C#
// Example of building DE 13 with April 17
DateTime transactionDate = new DateTime(2025, 4, 17);
string de13 = transactionDate.ToString("MMdd");
Console.WriteLine($"DE13: {de13}");
// Output: "0417"
  • Important Tip: Make sure you use the terminal’s local date (MonthDay format) when building this field.

DE 22 – Point of Service Entry Mode

  • Format: Fixed (3 digits)
  • Example: 051 (Chip card, read)
  • Purpose: Indicates how the card data was entered into the system.
  • How to Parse:
C#
// Example parsing POS Entry Mode
string rawData = "051";
string posEntryMode = rawData;
Console.WriteLine($"POS Entry Mode: {posEntryMode}");
// Output: POS Entry Mode: 051
  • How to Build:
C#
// Example of building DE 22 with manual entry
string posEntryMode = "010"; // 01 = manual entry, 0 = no cardholder authentication
Console.WriteLine($"DE22: {posEntryMode}");
// Output: "010"
  • Detailed Breakdown: Each digit in DE 22 has a specific meaning:
  • 1st digit: Method used to input card data
    • 01 = Manual entry
    • 02 = Magnetic stripe read
    • 05 = Integrated chip read
    • 07= Contactless chip read
    • 08 = Fallback
  • 2nd digit: Method used for cardholder authentication
    • 0 = No authentication
    • 1 = PIN entry capability
    • 2 = Signature
  • 3rd digit: Reserved for future use or for proprietary needs (sometimes left as 0)
  • Important Tip: Knowing how to set the POS Entry Mode correctly is important because it affects how issuers and payment networks validate the transaction (especially for EMV and contactless transactions).

DE 23 – Card Sequence Number

  • Format: Fixed (3 digits)
  • Example: 001
  • Purpose: Identifies and differentiates multiple cards issued for the same account number (PAN). This is especially important when an account has multiple cards (for example, primary and supplementary cards).
  • How to Parse:
C#
// Example parsing Card Sequence Number
string rawData = "001";
string cardSequence = rawData.Substring(0, 3);
Console.WriteLine($"Card Sequence Number: {cardSequence}");
// Output: Card Sequence Number: 001
  • How to Build:
C#
// Example of building DE 23 with Card Sequence Number
string cardSequence = "001"; // Example: first card issued for account
string de23 = cardSequence.PadLeft(3, '0');
Console.WriteLine($"DE23: {de23}");
// Output: "001"
  • Where the Value Comes From: The Card Sequence Number usually comes from the chip data (EMV tag 5F34) or is stored during card personalization. It’s used to uniquely identify the physical card when multiple cards share the same account number.
  • Important Tip: If not provided by the card or issuer, some systems default to 001 for the first issued card.

DE 24 – Function Code

  • Format: Fixed (3 digits)
  • Example: 200 (Financial transaction)
  • Purpose: Defines the type of function that the transaction is requesting (such as authorization, reversal, or network management).
  • How to Parse:
C#
// Example parsing Function Code
string rawData = "200";
string functionCode = rawData.Substring(0, 3);
Console.WriteLine($"Function Code: {functionCode}");
// Output: Function Code: 200
  • How to Build:
C#
// Example of building DE 24 with Function Code
string functionCode = "200"; // 200 = Financial transaction request
string de24 = functionCode.PadLeft(3, '0');
Console.WriteLine($"DE24: {de24}");
// Output: "200"
  • Important Tip: Function codes help differentiate between transaction types at the network or host level, especially when using the same MTI for different flows.

DE 25 – Point of Service Condition Code

  • Format: Fixed (2 digits)
  • Example: 00 (Normal transaction)
  • Purpose: Indicates the condition under which the transaction is performed.
  • How to Parse:
C#
// Example parsing DE 25 - POS Condition Code
string rawData = "01";
int posConditionCode = int.Parse(rawData);
Console.WriteLine($"POS Condition Code: {posConditionCode:D2}");

// Output: POS Condition Code: 01
  • How to Build:
C#
// Example of building DE 25 with condition 'Customer not present'
int conditionCode = 1;  // 01 = Customer not present (e.g., ecommerce)
string de25 = conditionCode.ToString("D2");
Console.WriteLine($"DE25: {de25}");

// Output: "01"
  • Common Values:
    • 00 = Normal transaction
    • 01 = Customer not present (e.g., ecommerce)
    • 02 = Unattended terminal (e.g., vending machine)
    • 08 = Mail/Phone order
    • 59 = Suspected fraud
  • Source of Value: The POS Condition Code is usually set by the terminal or application depending on the transaction environment. It reflects the scenario in which the cardholder and card were present or not.
  • Important Tip: Setting the correct POS Condition Code helps acquirers and issuers know the transaction environment, which can affect fraud scoring and authorization rules. Setting the correct POS Condition Code helps acquirers and issuers know the transaction environment, which can affect fraud scoring and authorization rules.

DE 28 – Amount, Transaction Fee

  • Format: Fixed (8 digits)
  • Purpose: Indicates the fee amount charged for processing the transaction.
  • How to Parse:
C#
// Example parsing a transaction fee
string rawData = "00000050";
decimal feeAmount = decimal.Parse(rawData) / 100;
Console.WriteLine($"Transaction Fee: {feeAmount:C2}");
// Output: Transaction Fee: 0.50
  • How to Build:
C#
// Example of building DE 28 with a fee of 0.50
decimal feeValue = 0.50m;
string de28 = ((int)(feeValue * 100)).ToString("D8");
Console.WriteLine($"DE28: {de28}");
// Output: "00000050"
  • Important Tip: Always express the fee in the smallest unit (cents) and pad it to 8 digits with leading zeros.

DE 35 – Track 2 Data

  • Format: LLVAR (Variable length)
  • Example: 411111XXXXXX1111=251220100000000000
  • Purpose: Contains the card data read from the magnetic stripe, including the card number, expiration date, service code, and discretionary data.
  • How to Parse:
C#
// Example parsing Track 2 Data
string rawData = "37411111XXXXXX1111=251220100000000000";
int len = int.Parse(rawData.Substring(0, 2));
string track2Data = rawData.Substring(2, len);
Console.WriteLine($"Track 2 Data: {track2Data}");
// Output: Track 2 Data: 411111XXXXXX1111=251220100000000000
  • How to Build:
C#
// Example of building DE 35 with Track 2 data
string track2 = "411111XXXXXX1111=251220100000000000";
string de35 = track2.Length.ToString("D2") + track2;
Console.WriteLine($"DE35: {de35}");
// Output: "37411111XXXXXX1111=251220100000000000"
  • Important Tip: Track 2 data usually follows this format:
    • PAN (Primary Account Number)
    • Separator =
    • Expiry Date (YYMM)
    • Service Code
    • Discretionary Data
  • Make sure sensitive data is always properly masked or encrypted according to PCI DSS standards.
  • Quick Note on Discretionary Data:
    • This is the part after the Service Code in the Track 2 data.
    • It can include issuer-specific information like loyalty program numbers, customer IDs, or even the CVV1.
    • CVV1 (Card Verification Value 1) is sometimes embedded inside discretionary data for magnetic stripe transactions.
    • CVV1 is used for verifying card authenticity during swipe transactions at POS.
    • Important: CVV2 (the printed 3-digit code for online use) is never included in Track 2 or DE 35.
    • You must never log or store CVV1 or CVV2 information, following PCI DSS rules.
    • Discretionary data length and content can vary depending on the issuer’s customization.

DE 41 – Card Acceptor Terminal ID

  • Format: Fixed (8 characters)
  • Example: TERMID01
  • Purpose: Identifies the terminal where the transaction originated.
  • How to Parse:
C#
// Example parsing Terminal ID
string rawData = "TERMID01";
string terminalId = rawData.Substring(0, 8);
Console.WriteLine($"Terminal ID: {terminalId}");
// Output: Terminal ID: TERMID01
  • How to Build:
C#
// Example of building DE 41 with Terminal ID
string terminalId = "TERMID01";
string de41 = terminalId.PadRight(8, ' ');
Console.WriteLine($"DE41: {de41}");
// Output: "TERMID01"
  • Important Tip: Make sure the Terminal ID is exactly 8 characters. If shorter, pad with spaces on the right.

DE 42 – Card Acceptor ID Code

  • Format: Fixed (15 characters)
  • Example: MERCHANT1234567
  • Purpose: Identifies the merchant (or card acceptor) processing the transaction.
  • How to Parse:
C#
// Example parsing Card Acceptor ID Code
string rawData = "MERCHANT1234567";
string cardAcceptorId = rawData.Substring(0, 15);
Console.WriteLine($"Card Acceptor ID: {cardAcceptorId}");
// Output: Card Acceptor ID: MERCHANT1234567
  • How to Build:
C#
// Example of building DE 42 with Card Acceptor ID
string cardAcceptorId = "MERCHANT1234567";
string de42 = cardAcceptorId.PadRight(15, ' ');
Console.WriteLine($"DE42: {de42}");
// Output: "MERCHANT1234567"
  • Important Tip: DE 42 must always be 15 characters long. Pad with spaces if the merchant ID is shorter.

DE 52 – Personal Identification Number (PIN) Data

  • Format: Fixed (16 hexadecimal characters)
  • Example: 5F2A6B7C8D1E9F00
  • Purpose: Contains the encrypted PIN block entered by the cardholder.
  • How to Parse:
C#
// Example parsing PIN Data
string rawData = "5F2A6B7C8D1E9F00";
string pinData = rawData.Substring(0, 16);
Console.WriteLine($"PIN Data: {pinData}");
// Output: PIN Data: 5F2A6B7C8D1E9F00
  • How to Build:
C#
// Example of building DE 52 with encrypted PIN block
string pinBlock = "5F2A6B7C8D1E9F00";
string de52 = pinBlock;
Console.WriteLine($"DE52: {de52}");
// Output: "DE52: 5F2A6B7C8D1E9F00"
  • Important Tip: PIN blocks must always be handled securely. Never log or expose raw PIN data in your systems.

DE 55 – ICC System Related Data

  • Format: LLLVAR (Variable length)
  • Example: EMV data block (e.g., 9F2608AABBCCDDEEFF0010)
  • Purpose: Carries EMV (chip card) data like cryptograms, certificates, and issuer application data.
  • How to Parse:
C#
// Example parsing ICC System Related Data
string rawData = "04009F2608AABBCCDDEEFF00";
int len = int.Parse(rawData.Substring(0, 3));
string iccData = rawData.Substring(3, len);
Console.WriteLine($"ICC Data: {iccData}");
// Output: ICC Data: 9F2608AABBCCDDEEFF00
  • How to Build:
C#
// Example of building DE 55 with ICC data
string iccBlock = "9F2608AABBCCDDEEFF00";
string de55 = iccBlock.Length.ToString("D3") + iccBlock;
Console.WriteLine($"DE55: {de55}");
// Output: "DE55: 0209F2608AABBCCDDEEFF00"
  • Important Tip: Always properly handle and encrypt EMV/ICC data. Many fields inside the ICC block are critical for transaction security.

Below is the ISO 8583 Data Elements table or mapping. Please note that this is a generic reference—some fields may vary depending on your payment scheme or implementation (e.g., Visa, Mastercard, or local acquirers like BancNet).

DEDescriptionFormatExample
1Secondary BitmapBitmapPresent if more than 64 fields use
2Primary Account Number (PAN)LLVAR16 digit card number
3Processing CodeFixed (6)000000 = purchase
4Amount, TransactionFixed(12)000000010000 = 1,000.00
5Amount, SettlementFixed(12)Optional for clearing
6Amount, Cardholder BillingFixed(12)Currency-converted billing amount
7Transmission Date & TimeFixed(10)MMDDhhmmss
8Amount, Cardholder Billing FeeFixed(8)Optional
9Conversion Rate, SettlementFixed(8)Optional
10Conversion Rate, Cardholder BillingFixed(8)Optional
11Systems Trace Audit Number (STAN)Fixed(6)Unique per transaction
12Time, Local TransactionFixed(6)hhmmss
13Date, Local TransactionFixed(4)MMDD
14Date, ExpirationFixed(4)YYMM
15Date, SettlementFixed(4)MMDD
16Date, ConversionFixed(4)MMDD
17Date, CaptureFixed(4)MMDD
18Merchant Category Code (MCC)Fixed(4)5411 = Grocery
19Acquiring Institution Country CodeFixed(3)608 = Philippines
20PAN Extended, Country CodeFixed(3)Optional
21Forwarding Institution Country CodeFixed(3)Optional
22Point of Service Entry ModeFixed(3)021 = manual entry
23Card Sequence NumberFixed(3)Used for chip cards
24Function CodeFixed(3)Optional
25Point of Service Condition CodeFixed(2)00 = normal
26Point of Service Capture CodeFixed(2)Optional
27Authorization ID Response LengthFixed(1)Optional
28Amount, Transaction FeeFixed(8)Optional
29Amount, Settlement FeeFixed(8)Optional
30Amount, Transaction Processing FeeFixed(8)Optional
31Amount, Settlement Processing FeeFixed(8)Optional
32Acquiring Institution ID CodeLLVARAcquirer BIN
33Forwarding Institution ID CodeLLVAROptional
34Primary Account Number, ExtendedLLVAROptional
35Track 2 DataLLVAROptional
36Track 3 DataLLLVAR411111******1111=251220100000000000
37Retrieval Reference NumberFixed(12)Unique per transaction
38Authorization Identification ResponseFixed(6)Code returned from host
39Response CodeFixed(2)00 = approved
40Service Restriction CodeFixed(3)Optional
41Card Acceptor Terminal IDFixed(8)Terminal’s unique ID
42Card Acceptor ID CodeFixed(15)Merchant ID
43Card Acceptor Name/LocationFixed(40)Merchant name and address
44Additional Response DataLLVARHost response messages
45Track 1 DataLLVAROptional
46Additional Data – ISOLLLVAROptional
47Additional Data – NationalLLLVAROptional
48Additional Data – PrivateLLLVARUsed for custom data
49Currency Code, TransactionFixed(3)608 = PHP
50Currency Code, SettlementFixed(3)Optional
51Currency Code, Cardholder BillingFixed(3)Optional
52Personal Identification Number (PIN)Fixed(16)Encrypted block
53Security Related Control InformationFixed(16)Optional
54Additional AmountsLLLVAROptional
55ICC System Related DataLLLVARChip data
56Reserved for ISO UseLLLVAROptional
57Reserved for National UseLLLVAROptional
58Reserved for National UseLLLVAROptional
59Reserved for National UseLLLVAROptional
60Reserved for Private UseLLLVAROften used in Asian networks
61Reserved for Private UseLLLVAROptional
62Reserved for Private UseLLLVAROften used for promo codes or QR
63Reserved for Private UseLLLVARCan contain structured custom data
64Message Authentication Code (MAC)Fixed(8)Hash value or cryptographic checksum
65Secondary Bitmap IndicatorBitmapUsed if fields 65–128 are present
66Settlement CodeFixed(1)Optional
67Extended Payment CodeFixed(2)Optional
68Receiving Institution Country CodeFixed(3)Optional
69Settlement Institution Country CodeFixed(3)Optional
70Network Management Information CodeFixed(3)001 = sign-on, 301 = key change
71Message NumberFixed(4)Optional
72Last Message NumberFixed(4)Optional
73Date, ActionFixed(6)YYMMDD
74Credits, NumberFixed(10)Optional
75Credits, Reversal NumberFixed(10)Optional
76Debits, NumberFixed(10)Optional
77Debits, Reversal NumberFixed(10)Optional
78Transfer, NumberFixed(10)Optional
79Transfer, Reversal NumberFixed(10)Optional
80Inquiries, NumberFixed(10)Optional
81Authorizations, NumberFixed(10)Optional
82Credits, Processing Fee AmountFixed(12)Optional
83Credits, Transaction Fee AmountFixed(12)Optional
84Debits, Processing Fee AmountFixed(12)Optional
85Debits, Transaction Fee AmountFixed(12)Optional
86Credits, AmountFixed(16)Optional
87Credits, Reversal AmountFixed(16)Optional
88Debits, AmountFixed(16)Optional
89Debits, Reversal AmountFixed(16)Optional
90Original Data ElementsFixed(42)MTI, DE3, DE11, DE7, DE32
91File Update CodeFixed(1)Optional
92File Security CodeFixed(2)Optional
93Response IndicatorFixed(5)Optional
94Service IndicatorFixed(7)Optional
95Replacement AmountsFixed(42)Optional
96Message Security CodeLLLVAROptional
97Amount, Net SettlementFixed(17)Optional
98PayeeFixed(25)Optional
99Settlement Institution ID CodeLLVAROptional
100Receiving Institution ID CodeLLVAROptional
101File NameLLVAROptional
102Account Identification 1LLVAROften used in balance inquiry
103Account Identification 2LLVAROptional
104Transaction DescriptionLLLVAROptional
105Reserved for ISO UseLLLVAROptional
106Reserved for ISO UseLLLVAROptional
107Reserved for ISO UseLLLVAROptional
108Reserved for ISO UseLLLVAROptional
109Reserved for ISO UseLLLVAROptional
110Reserved for ISO UseLLLVAROptional
111Reserved for ISO UseLLLVAROptional
112Reserved for National UseLLLVAROptional
113Reserved for National UseLLLVAROptional
114Reserved for National UseLLLVAROptional
115Reserved for National UseLLLVAROptional
116Reserved for National UseLLLVAROptional
117Reserved for National UseLLLVAROptional
118Reserved for National UseLLLVAROptional
119Reserved for National UseLLLVAROptional
120Reserved for Private UseLLLVAROften used by switch or network
121Reserved for Private UseLLLVAROptional
122Reserved for Private UseLLLVAROptional
123Reserved for Private UseLLLVAROptional
124Reserved for Private UseLLLVAROptional
125Reserved for Private UseLLLVAROptional
126Reserved for Private UseLLLVAROptional
127Reserved for Private Use (Structured)LLLVARSometimes subdivided into subfields

This wraps up our deep dive for now! I hope you find this breakdown helpful, especially when working with ISO 8583 message parsing or building.

Further Reading & Resources

Here are some links that helped me: