func (i *Info) GetFolders() []string {
	var folders []string
	for _, dtree := range i.DeviceTrees {
		dt, _ := dtree.Summary()
		folders = append(folders, fmt.Sprintf("%s_%s_%s", dt.Model, strings.ToUpper(dt.BoardConfig), i.Plists.BuildManifest.ProductBuildVersion))
	}
	return folders
}
GetFolders returns a list of the IPSW name folders
package info
import (
	"archive/zip"
	_ "embed"
	"encoding/json"
	"fmt"
	"log"
	"path/filepath"
	"strings"
	"github.com/blacktop/ipsw/internal/utils"
	"github.com/blacktop/ipsw/pkg/devicetree"
	"github.com/blacktop/ipsw/pkg/plist"
	"github.com/blacktop/ipsw/pkg/xcode"
	"github.com/pkg/errors"
)
var (
	procsData []byte
	keysJSONData []byte
	t8030APKeysJSONData []byte  
	t8101APKeysJSONData []byte  
)
type apKey struct {
	Device   string
	Build    string
	Type     string
	Filename string
	KBag     string
	Key      string
}
type Info struct {
	Plists      *plist.Plists
	DeviceTrees map[string]*devicetree.DeviceTree
}
type processors struct {
	Name          string
	Model         string
	Semiconductor string
	DieSize       string
	Transistors   string
	CPUISA        string
	CPU           string
	CPUID         string
	CPUCache      []string
	GPU           string
	AIAccelerator string
	Memory        string
	Introduced    string
	Devices       []string
}
func getProcessor(cpuid string) processors {
	var ps []processors
	err := json.Unmarshal(procsData, &ps)
	if err != nil {
		log.Fatal(err)
	}
	for _, p := range ps {
		if strings.ToLower(p.CPUID) == strings.ToLower(cpuid) {
			return p
		}
	}
	return processors{}
}
func getFirmwareKeys(device, build string) map[string]string {
	var keys map[string]map[string]map[string]string
	err := json.Unmarshal(keysJSONData, &keys)
	if err != nil {
		log.Fatal(err)
	}
	return keys[device][build]
}
func getApFirmwareKey(device, build, filename string) (string, string, error) {
	var a13Keys []apKey
	var a14Keys []apKey
	err := json.Unmarshal(t8030APKeysJSONData, &a13Keys)
	if err != nil {
		log.Fatal(err)
	}
	for _, key := range a13Keys {
		if key.Device == device && key.Build == build && key.Filename == filename {
			return key.KBag, key.Key, nil
		}
	}
	err = json.Unmarshal(t8101APKeysJSONData, &a14Keys)
	if err != nil {
		log.Fatal(err)
	}
	for _, key := range a14Keys {
		if key.Device == device && key.Build == build && key.Filename == filename {
			return key.KBag, key.Key, nil
		}
	}
	return "", "", fmt.Errorf("failed to find key for device: %s, build: %s, filename: %s", device, build, filename)
}
func (i *Info) String() string {
	var iStr string
	iStr += fmt.Sprintf(
		"Version        = %s\n"+
			"BuildVersion   = %s\n"+
			"OS Type        = %s\n",
		i.Plists.BuildManifest.ProductVersion,
		i.Plists.BuildManifest.ProductBuildVersion,
		i.Plists.GetOSType(),
	)
	if i.Plists.Restore != nil {
		iStr += fmt.Sprintf("FileSystem     = ")
		for file, fsType := range i.Plists.Restore.SystemRestoreImageFileSystems {
			iStr += fmt.Sprintf("%s (Type: %s)\n", file, fsType)
		}
	}
	kcs := i.Plists.BuildManifest.GetKernelCaches()
	bls := i.Plists.BuildManifest.GetBootLoaders()
	iStr += fmt.Sprintf("\nDevices\n")
	iStr += fmt.Sprintf("-------\n")
	for _, dtree := range i.DeviceTrees {
		dt, _ := dtree.Summary()
		prodName := dt.ProductName
		if len(prodName) == 0 {
			devices, err := xcode.GetDevices()
			if err == nil {
				for _, device := range devices {
					if device.ProductType == dt.Model {
						prodName = device.ProductDescription
						break
					}
				}
			} else {
				prodName = dt.Model
			}
		}
		iStr += fmt.Sprintf("\n%s\n", prodName)
		iStr += fmt.Sprintf(" > %s_%s_%s\n", dt.Model, strings.ToUpper(dt.BoardConfig), i.Plists.BuildManifest.ProductBuildVersion)
		if len(kcs[strings.ToLower(dt.BoardConfig)]) > 0 {
			iStr += fmt.Sprintf("   - KernelCache: %s\n", kcs[strings.ToLower(dt.BoardConfig)])
		}
		if i.Plists.Restore != nil {
			for _, device := range i.Plists.Restore.DeviceMap {
				if strings.ToLower(device.BoardConfig) == strings.ToLower(dt.BoardConfig) {
					proc := getProcessor(device.Platform)
					iStr += fmt.Sprintf("   - CPU: %s (%s), ID: %s\n", proc.Name, proc.CPUISA, device.Platform)
				}
			}
		}
		if len(bls[strings.ToLower(dt.BoardConfig)]) > 0 {
			iStr += fmt.Sprintf("   - BootLoaders\n")
			for _, bl := range bls[strings.ToLower(dt.BoardConfig)] {
				if _, key, err := getApFirmwareKey(dt.Model, i.Plists.BuildManifest.ProductBuildVersion, filepath.Base(bl)); err != nil {
					iStr += fmt.Sprintf("       * %s\n", filepath.Base(bl))
				} else {
					iStr += fmt.Sprintf("       * %s 🔑 -> %s\n", filepath.Base(bl), key)
				}
			}
		}
	}
	return iStr
}
func (i *Info) GetOsDmg() string {
	return i.Plists.BuildIdentities[0].Manifest["OS"].Info.Path
}
func (i *Info) GetFolder() string {
	var devs []string
	for _, dtree := range i.DeviceTrees {
		dt, _ := dtree.Summary()
		devs = append(devs, dt.Model)
	}
	devs = utils.SortDevices(utils.Unique(devs))
	return fmt.Sprintf("%s__%s", i.Plists.BuildManifest.ProductBuildVersion, getAbbreviatedDevList(devs))
}