code: def _convert_to_folder(self, packages):
          
          url = 'http://packagist.org/p/%s.json'
          with ThreadPoolExecutor(max_workers=12) as executor:
              futures = []
              for package in packages:
                  future = executor.submit(self._get, url, package)
                  futures.append({
                      'future': future,
                      'package': package
                  })
  
              folders = []
              for i, future in enumerate(futures, start=1):
                  r = future['future'].result()
                  package = future['package']
  
                  if not 'installer-name' in r.text:
                      folder_name = package.split('/')[1]
                  else:
                      splat = list(filter(None, re.split(r'[^a-zA-Z0-9-_.,]', r.text)))
                      folder_name = splat[splat.index('installer-name') + 1]
  
                  if not folder_name in folders:
                      folders.append(folder_name)
                  else:
                      print("Folder %s is duplicated (current %s, previous %s)" % (folder_name,
                          package, folders.index(folder_name)))
  
                  if i % 25 == 0:
                      print("Done %s." % i)
  
          return folders
docs: Silverstripe's page contains a list of composer packages. This
              function converts those to folder names. These may be different due
              to installer-name.
  
              Implemented exponential backoff in order to prevent packager from
              being overly sensitive about the number of requests I was making.
  
              @see: https://github.com/composer/installers#custom-install-names
              @see: https://github.com/richardsjoqvist/silverstripe-localdate/issues/7