Introduction

Synthetic data is valuable for testing data import, data manipulation, and data analysis programs and databases. This tutorial shows how to generate synthetic data in R and saves them as linked CSV and XML files.

Generate Synthetic Data

Data Values

drugs <- c('Xipramin','Colophrazen','Diaprogenix','Xinoprozen','Alaraphosol',
           'Gerantrazeophem','Clobromizen','Bhiktarvizem')
cost.per.tablet <- c(0.72,1.23,0.04,2.82,0.92,1.87,1.44,3.87)
customers <- data.frame(
  custName = c('Erat Pharma', 
             'Eleifend GMBH', 
             'Varius Plc', 
             'Luctus Aliquet Plc', 
             'Eu Dolor Companie', 
             'Lorem Luctus', 
             'At Pretium LLC', 
             'Enim PC', 
             'Adipiscing Mauris Inc.', 
             'Proin Dolor Institut', 
             'Nisl Quisque', 
             'Vitae Risus Incorporated',
             'Plaxus Medical',
             'Eastern Hospital Group'),
  custCountry = c('Germany',
                  'Germany',
                  'Brazil',
                  'Brazil',
                  'Brazil',
                  'USA',
                  'USA',
                  'USA',
                  'USA',
                  'Germany',
                  'Brazil',
                  'USA',
                  'USA',
                  'USA'),
  custRep = c(100,
              100,
              887,
              887,
              887,
              332,
              332,
              203,
              203,
              221,
              887,
              203,
              119,
              119)
)
df.Reps <- data.frame(repID = c(100,887,332,203,221,655,119,988),
                      repFN = c('Helmut','Walison','Lynette','Aneeta','Veronika','Ralph','Prasad','Xi'),
                      repLN = c('Schwab','da Silva','McRowe','Kappoorthy','Sixt','Klinger','Patel','Zheng'),
                      repTR = c('EMEA','South America',
                                'East','West','EMEA',
                                'West','EMEA','EMEA'))

Generate sales transactions.

numTxns <- 100
df.Sales <- data.frame(
  txnID = (1:numTxns) + 1000,
  date = vector(mode = "character", numTxns),
  cust = vector(mode = "character", numTxns),
  prod = vector(mode = "character", numTxns),
  qty = vector(mode = "numeric", numTxns),
  amount = vector(mode = "numeric", numTxns),
  country = vector(mode = "character", numTxns),
  repID = vector(mode = "numeric", numTxns),
  row.names = NULL
)

yearsMin <- 2020
yearsMax <- 2022

for (t in 1:numTxns)
{
  # generate date
  month <- round(runif(1, min = 1, max = 12),0)
  day <- round(runif(1, min = 1, max = 28),0)
  year <- round(runif(1, min = yearsMin, max = yearsMin),0)
  date <- paste0(month, '/', day, '/', year)
  
  df.Sales$date[t] <- date
  
  # generate product info
  prodIndex <- round(runif(1, min = 1, max = (length(drugs))), 0)
  df.Sales$prod[t] <- drugs[prodIndex]
  df.Sales$qty[t] <- round(runif(1, min = 1, max = 20), 0) * 100
  df.Sales$amount[t] <- df.Sales$qty[t] * cost.per.tablet[prodIndex]
  
  # generate customer info
  custIndex <- round(runif(1, min = 1, max = (nrow(customers))), 0)
  df.Sales$cust[t] <- customers$custName[custIndex]
  df.Sales$repID[t] <- customers$custRep[custIndex]
  df.Sales$country[t] <- customers$custCountry[custIndex]
}

Save Data

Save as CSV

csv.fn <- "pharmaSalesTxn.csv"
write.csv(df.Sales, csv.fn, row.names = F)

csv.fn <- "pharmaReps.csv"
write.csv(df.Reps, csv.fn, row.names = F)

Save as XML

xml.fn <- "pharmaSalesTxn.xml"
xml <- '<?xml version="1.0" encoding="UTF-8"?>\n\n'
xml <- paste0(xml, '<txns>', '\n')

for (r in 1:nrow(df.Sales))
{
  xml <- paste0(xml, '  <txn>', '\n')
  for (c in names(df.Sales))
  {
    xml <- paste0(xml, '    ', '<', c, '>')
    xml <- paste0(xml, df.Sales[r,c])
    xml <- paste0(xml, '</', c, '>', '\n')
  }
  xml <- paste0(xml, '  </txn>', '\n')
}

xml <- paste0(xml, '</txns>')

conn <- file(xml.fn)
writeLines(xml, conn)
xml.fn <- "pharmaReps.xml"
xml <- '<?xml version="1.0" encoding="UTF-8"?>\n\n'
xml <- paste0(xml, '<salesteam>', '\n')

for (r in 1:nrow(df.Reps))
{
  xml <- paste0(xml, '  <rep ', 'rID="r', df.Reps[r,1], '">\n')
  xml <- paste0(xml, '    <firstName>', df.Reps[r,2], '</firstName>\n')
  xml <- paste0(xml, '    <lastName>', df.Reps[r,3], '</lastName>\n')
  xml <- paste0(xml, '    <territory>', df.Reps[r,4], '</territory>\n')
  xml <- paste0(xml, '  </rep>', '\n')
}

xml <- paste0(xml, '</salesteam>')

conn <- file(xml.fn)
writeLines(xml, conn)

Conclusion

This tutorial provided an example on how to generate synthetic data as CSV and XML files.

Tutorial


Files & Resources

All Files for Lesson 6.182

References

No references.

Errata

Let us know.

LS0tCnRpdGxlOiAiR2VuZXJhdGUgU3ludGhldGljIFBoYXJtYSBTYWxlcyBEYXRhIGZvciBDU1YgYW5kIFhNTCBpbiBSIgpwYXJhbXM6CiAgY2F0ZWdvcnk6IDYKICBudW1iZXI6IDE4MgogIHRpbWU6IDMwCiAgbGV2ZWw6IGJlZ2lubmVyCiAgdGFnczogInIseHBhdGgseG1sIgogIGRlc2NyaXB0aW9uOiAiU2hvd3MgaG93IHRvIGdlbmVyYXRlIHN5bnRoZXRpYyBkYXRhIGZvciBDU1YgYW5kIFhNTCB3aXRoCiAgICAgICAgICAgICAgICBhbiBleGFtcGxlIHRoYXQgZ2VuZXJhdGVzIHBoYXJtYSBzYWxlcyBkYXRhLiIKZGF0ZTogIjxzbWFsbD5gciBTeXMuRGF0ZSgpYDwvc21hbGw+IgphdXRob3I6ICI8c21hbGw+TWFydGluIFNjaGVkbGJhdWVyPC9zbWFsbD4iCmVtYWlsOiAibS5zY2hlZGxiYXVlckBuZXUuZWR1IgphZmZpbGl0YXRpb246ICJOb3J0aGVhc3Rlcm4gVW5pdmVyc2l0eSIKb3V0cHV0OiAKICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29sbGFwc2VkOiBmYWxzZQogICAgbnVtYmVyX3NlY3Rpb25zOiBmYWxzZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IHNwYWNlbGFiCiAgICBoaWdobGlnaHQ6IHRhbmdvCi0tLQoKLS0tCnRpdGxlOiAiPHNtYWxsPmByIHBhcmFtcyRjYXRlZ29yeWAuYHIgcGFyYW1zJG51bWJlcmA8L3NtYWxsPjxici8+PHNwYW4gc3R5bGU9J2NvbG9yOiAjMkU0MDUzOyBmb250LXNpemU6IDAuOWVtJz5gciBybWFya2Rvd246Om1ldGFkYXRhJHRpdGxlYDwvc3Bhbj4iCi0tLQoKYGBge3IgY29kZT14ZnVuOjpyZWFkX3V0ZjgocGFzdGUwKGhlcmU6OmhlcmUoKSwnL1IvX2luc2VydDJEQi5SJykpLCBpbmNsdWRlID0gRkFMU0V9CmBgYAoKIyMgSW50cm9kdWN0aW9uCgpTeW50aGV0aWMgZGF0YSBpcyB2YWx1YWJsZSBmb3IgdGVzdGluZyBkYXRhIGltcG9ydCwgZGF0YSBtYW5pcHVsYXRpb24sIGFuZCBkYXRhIGFuYWx5c2lzIHByb2dyYW1zIGFuZCBkYXRhYmFzZXMuIFRoaXMgdHV0b3JpYWwgc2hvd3MgaG93IHRvIGdlbmVyYXRlIHN5bnRoZXRpYyBkYXRhIGluIFIgYW5kIHNhdmVzIHRoZW0gYXMgbGlua2VkIENTViBhbmQgWE1MIGZpbGVzLgoKIyMgR2VuZXJhdGUgU3ludGhldGljIERhdGEKCiMjIyBEYXRhIFZhbHVlcwoKYGBge3IgZGF0YUNvbmZpZ3N9CmRydWdzIDwtIGMoJ1hpcHJhbWluJywnQ29sb3BocmF6ZW4nLCdEaWFwcm9nZW5peCcsJ1hpbm9wcm96ZW4nLCdBbGFyYXBob3NvbCcsCiAgICAgICAgICAgJ0dlcmFudHJhemVvcGhlbScsJ0Nsb2Jyb21pemVuJywnQmhpa3RhcnZpemVtJykKY29zdC5wZXIudGFibGV0IDwtIGMoMC43MiwxLjIzLDAuMDQsMi44MiwwLjkyLDEuODcsMS40NCwzLjg3KQpjdXN0b21lcnMgPC0gZGF0YS5mcmFtZSgKICBjdXN0TmFtZSA9IGMoJ0VyYXQgUGhhcm1hJywgCiAgICAgICAgICAgICAnRWxlaWZlbmQgR01CSCcsIAogICAgICAgICAgICAgJ1Zhcml1cyBQbGMnLCAKICAgICAgICAgICAgICdMdWN0dXMgQWxpcXVldCBQbGMnLCAKICAgICAgICAgICAgICdFdSBEb2xvciBDb21wYW5pZScsIAogICAgICAgICAgICAgJ0xvcmVtIEx1Y3R1cycsIAogICAgICAgICAgICAgJ0F0IFByZXRpdW0gTExDJywgCiAgICAgICAgICAgICAnRW5pbSBQQycsIAogICAgICAgICAgICAgJ0FkaXBpc2NpbmcgTWF1cmlzIEluYy4nLCAKICAgICAgICAgICAgICdQcm9pbiBEb2xvciBJbnN0aXR1dCcsIAogICAgICAgICAgICAgJ05pc2wgUXVpc3F1ZScsIAogICAgICAgICAgICAgJ1ZpdGFlIFJpc3VzIEluY29ycG9yYXRlZCcsCiAgICAgICAgICAgICAnUGxheHVzIE1lZGljYWwnLAogICAgICAgICAgICAgJ0Vhc3Rlcm4gSG9zcGl0YWwgR3JvdXAnKSwKICBjdXN0Q291bnRyeSA9IGMoJ0dlcm1hbnknLAogICAgICAgICAgICAgICAgICAnR2VybWFueScsCiAgICAgICAgICAgICAgICAgICdCcmF6aWwnLAogICAgICAgICAgICAgICAgICAnQnJhemlsJywKICAgICAgICAgICAgICAgICAgJ0JyYXppbCcsCiAgICAgICAgICAgICAgICAgICdVU0EnLAogICAgICAgICAgICAgICAgICAnVVNBJywKICAgICAgICAgICAgICAgICAgJ1VTQScsCiAgICAgICAgICAgICAgICAgICdVU0EnLAogICAgICAgICAgICAgICAgICAnR2VybWFueScsCiAgICAgICAgICAgICAgICAgICdCcmF6aWwnLAogICAgICAgICAgICAgICAgICAnVVNBJywKICAgICAgICAgICAgICAgICAgJ1VTQScsCiAgICAgICAgICAgICAgICAgICdVU0EnKSwKICBjdXN0UmVwID0gYygxMDAsCiAgICAgICAgICAgICAgMTAwLAogICAgICAgICAgICAgIDg4NywKICAgICAgICAgICAgICA4ODcsCiAgICAgICAgICAgICAgODg3LAogICAgICAgICAgICAgIDMzMiwKICAgICAgICAgICAgICAzMzIsCiAgICAgICAgICAgICAgMjAzLAogICAgICAgICAgICAgIDIwMywKICAgICAgICAgICAgICAyMjEsCiAgICAgICAgICAgICAgODg3LAogICAgICAgICAgICAgIDIwMywKICAgICAgICAgICAgICAxMTksCiAgICAgICAgICAgICAgMTE5KQopCmRmLlJlcHMgPC0gZGF0YS5mcmFtZShyZXBJRCA9IGMoMTAwLDg4NywzMzIsMjAzLDIyMSw2NTUsMTE5LDk4OCksCiAgICAgICAgICAgICAgICAgICAgICByZXBGTiA9IGMoJ0hlbG11dCcsJ1dhbGlzb24nLCdMeW5ldHRlJywnQW5lZXRhJywnVmVyb25pa2EnLCdSYWxwaCcsJ1ByYXNhZCcsJ1hpJyksCiAgICAgICAgICAgICAgICAgICAgICByZXBMTiA9IGMoJ1NjaHdhYicsJ2RhIFNpbHZhJywnTWNSb3dlJywnS2FwcG9vcnRoeScsJ1NpeHQnLCdLbGluZ2VyJywnUGF0ZWwnLCdaaGVuZycpLAogICAgICAgICAgICAgICAgICAgICAgcmVwVFIgPSBjKCdFTUVBJywnU291dGggQW1lcmljYScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0Vhc3QnLCdXZXN0JywnRU1FQScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1dlc3QnLCdFTUVBJywnRU1FQScpKQpgYGAKCkdlbmVyYXRlIHNhbGVzIHRyYW5zYWN0aW9ucy4KCmBgYHtyIGdlblNhbGVzVHhuc30KbnVtVHhucyA8LSAxMDAKZGYuU2FsZXMgPC0gZGF0YS5mcmFtZSgKICB0eG5JRCA9ICgxOm51bVR4bnMpICsgMTAwMCwKICBkYXRlID0gdmVjdG9yKG1vZGUgPSAiY2hhcmFjdGVyIiwgbnVtVHhucyksCiAgY3VzdCA9IHZlY3Rvcihtb2RlID0gImNoYXJhY3RlciIsIG51bVR4bnMpLAogIHByb2QgPSB2ZWN0b3IobW9kZSA9ICJjaGFyYWN0ZXIiLCBudW1UeG5zKSwKICBxdHkgPSB2ZWN0b3IobW9kZSA9ICJudW1lcmljIiwgbnVtVHhucyksCiAgYW1vdW50ID0gdmVjdG9yKG1vZGUgPSAibnVtZXJpYyIsIG51bVR4bnMpLAogIGNvdW50cnkgPSB2ZWN0b3IobW9kZSA9ICJjaGFyYWN0ZXIiLCBudW1UeG5zKSwKICByZXBJRCA9IHZlY3Rvcihtb2RlID0gIm51bWVyaWMiLCBudW1UeG5zKSwKICByb3cubmFtZXMgPSBOVUxMCikKCnllYXJzTWluIDwtIDIwMjAKeWVhcnNNYXggPC0gMjAyMgoKZm9yICh0IGluIDE6bnVtVHhucykKewogICMgZ2VuZXJhdGUgZGF0ZQogIG1vbnRoIDwtIHJvdW5kKHJ1bmlmKDEsIG1pbiA9IDEsIG1heCA9IDEyKSwwKQogIGRheSA8LSByb3VuZChydW5pZigxLCBtaW4gPSAxLCBtYXggPSAyOCksMCkKICB5ZWFyIDwtIHJvdW5kKHJ1bmlmKDEsIG1pbiA9IHllYXJzTWluLCBtYXggPSB5ZWFyc01pbiksMCkKICBkYXRlIDwtIHBhc3RlMChtb250aCwgJy8nLCBkYXksICcvJywgeWVhcikKICAKICBkZi5TYWxlcyRkYXRlW3RdIDwtIGRhdGUKICAKICAjIGdlbmVyYXRlIHByb2R1Y3QgaW5mbwogIHByb2RJbmRleCA8LSByb3VuZChydW5pZigxLCBtaW4gPSAxLCBtYXggPSAobGVuZ3RoKGRydWdzKSkpLCAwKQogIGRmLlNhbGVzJHByb2RbdF0gPC0gZHJ1Z3NbcHJvZEluZGV4XQogIGRmLlNhbGVzJHF0eVt0XSA8LSByb3VuZChydW5pZigxLCBtaW4gPSAxLCBtYXggPSAyMCksIDApICogMTAwCiAgZGYuU2FsZXMkYW1vdW50W3RdIDwtIGRmLlNhbGVzJHF0eVt0XSAqIGNvc3QucGVyLnRhYmxldFtwcm9kSW5kZXhdCiAgCiAgIyBnZW5lcmF0ZSBjdXN0b21lciBpbmZvCiAgY3VzdEluZGV4IDwtIHJvdW5kKHJ1bmlmKDEsIG1pbiA9IDEsIG1heCA9IChucm93KGN1c3RvbWVycykpKSwgMCkKICBkZi5TYWxlcyRjdXN0W3RdIDwtIGN1c3RvbWVycyRjdXN0TmFtZVtjdXN0SW5kZXhdCiAgZGYuU2FsZXMkcmVwSURbdF0gPC0gY3VzdG9tZXJzJGN1c3RSZXBbY3VzdEluZGV4XQogIGRmLlNhbGVzJGNvdW50cnlbdF0gPC0gY3VzdG9tZXJzJGN1c3RDb3VudHJ5W2N1c3RJbmRleF0KfQpgYGAKCiMjIFNhdmUgRGF0YQoKIyMjIFNhdmUgYXMgQ1NWCgpgYGB7ciB3cml0ZVNhbGVzRGF0YTJDU1Z9CmNzdi5mbiA8LSAicGhhcm1hU2FsZXNUeG4uY3N2Igp3cml0ZS5jc3YoZGYuU2FsZXMsIGNzdi5mbiwgcm93Lm5hbWVzID0gRikKCmNzdi5mbiA8LSAicGhhcm1hUmVwcy5jc3YiCndyaXRlLmNzdihkZi5SZXBzLCBjc3YuZm4sIHJvdy5uYW1lcyA9IEYpCmBgYAoKIyMjIFNhdmUgYXMgWE1MCgpgYGB7ciB3cml0ZVNhbGVzRGF0YTJYTUx9CnhtbC5mbiA8LSAicGhhcm1hU2FsZXNUeG4ueG1sIgp4bWwgPC0gJzw/eG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9IlVURi04Ij8+XG5cbicKeG1sIDwtIHBhc3RlMCh4bWwsICc8dHhucz4nLCAnXG4nKQoKZm9yIChyIGluIDE6bnJvdyhkZi5TYWxlcykpCnsKICB4bWwgPC0gcGFzdGUwKHhtbCwgJyAgPHR4bj4nLCAnXG4nKQogIGZvciAoYyBpbiBuYW1lcyhkZi5TYWxlcykpCiAgewogICAgeG1sIDwtIHBhc3RlMCh4bWwsICcgICAgJywgJzwnLCBjLCAnPicpCiAgICB4bWwgPC0gcGFzdGUwKHhtbCwgZGYuU2FsZXNbcixjXSkKICAgIHhtbCA8LSBwYXN0ZTAoeG1sLCAnPC8nLCBjLCAnPicsICdcbicpCiAgfQogIHhtbCA8LSBwYXN0ZTAoeG1sLCAnICA8L3R4bj4nLCAnXG4nKQp9Cgp4bWwgPC0gcGFzdGUwKHhtbCwgJzwvdHhucz4nKQoKY29ubiA8LSBmaWxlKHhtbC5mbikKd3JpdGVMaW5lcyh4bWwsIGNvbm4pCmBgYAoKYGBge3Igd3JpdGVSZXBzRGF0YTJYTUx9CnhtbC5mbiA8LSAicGhhcm1hUmVwcy54bWwiCnhtbCA8LSAnPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz5cblxuJwp4bWwgPC0gcGFzdGUwKHhtbCwgJzxzYWxlc3RlYW0+JywgJ1xuJykKCmZvciAociBpbiAxOm5yb3coZGYuUmVwcykpCnsKICB4bWwgPC0gcGFzdGUwKHhtbCwgJyAgPHJlcCAnLCAncklEPSJyJywgZGYuUmVwc1tyLDFdLCAnIj5cbicpCiAgeG1sIDwtIHBhc3RlMCh4bWwsICcgICAgPGZpcnN0TmFtZT4nLCBkZi5SZXBzW3IsMl0sICc8L2ZpcnN0TmFtZT5cbicpCiAgeG1sIDwtIHBhc3RlMCh4bWwsICcgICAgPGxhc3ROYW1lPicsIGRmLlJlcHNbciwzXSwgJzwvbGFzdE5hbWU+XG4nKQogIHhtbCA8LSBwYXN0ZTAoeG1sLCAnICAgIDx0ZXJyaXRvcnk+JywgZGYuUmVwc1tyLDRdLCAnPC90ZXJyaXRvcnk+XG4nKQogIHhtbCA8LSBwYXN0ZTAoeG1sLCAnICA8L3JlcD4nLCAnXG4nKQp9Cgp4bWwgPC0gcGFzdGUwKHhtbCwgJzwvc2FsZXN0ZWFtPicpCgpjb25uIDwtIGZpbGUoeG1sLmZuKQp3cml0ZUxpbmVzKHhtbCwgY29ubikKYGBgCgojIyBDb25jbHVzaW9uCgpUaGlzIHR1dG9yaWFsIHByb3ZpZGVkIGFuIGV4YW1wbGUgb24gaG93IHRvIGdlbmVyYXRlIHN5bnRoZXRpYyBkYXRhIGFzIENTViBhbmQgWE1MIGZpbGVzLgoKIyMgVHV0b3JpYWwKCmBgYHs9aHRtbH0KPGlmcmFtZSBzcmM9IiIgd2lkdGg9IjQ4MCIgaGVpZ2h0PSIyNzAiIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYXV0b3BsYXk7IGZ1bGxzY3JlZW47IHBpY3R1cmUtaW4tcGljdHVyZSIgYWxsb3dmdWxsc2NyZWVuIGRhdGEtZXh0ZXJuYWw9IjEiPjwvaWZyYW1lPgpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgRmlsZXMgJiBSZXNvdXJjZXMKCmBgYHtyIHppcEZpbGVzLCBlY2hvPUZBTFNFfQp6aXBOYW1lID0gc3ByaW50ZigiTGVzc29uRmlsZXMtJXMtJXMuemlwIiwgCiAgICAgICAgICAgICAgICAgcGFyYW1zJGNhdGVnb3J5LAogICAgICAgICAgICAgICAgIHBhcmFtcyRudW1iZXIpCgp0ZXh0QUxpbmsgPSBwYXN0ZTAoIkFsbCBGaWxlcyBmb3IgTGVzc29uICIsIAogICAgICAgICAgICAgICBwYXJhbXMkY2F0ZWdvcnksIi4iLHBhcmFtcyRudW1iZXIpCgojIGRvd25sb2FkRmlsZXNMaW5rKCkgaXMgaW5jbHVkZWQgZnJvbSBfaW5zZXJ0MkRCLlIKa25pdHI6OnJhd19odG1sKGRvd25sb2FkRmlsZXNMaW5rKCIuIiwgemlwTmFtZSwgdGV4dEFMaW5rKSkKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIFJlZmVyZW5jZXMKCk5vIHJlZmVyZW5jZXMuCgojIyBFcnJhdGEKCltMZXQgdXMga25vd10oaHR0cHM6Ly9mb3JtLmpvdGZvcm0uY29tLzIxMjE4NzA3Mjc4NDE1Nyl7dGFyZ2V0PSJfYmxhbmsifS4K