func FromReader(r io.Reader, basePath string, loaders ...validator.RegistryLoader) (*Package, error) {
	b, err := ioutil.ReadAll(bufio.NewReader(r))
	if err != nil {
		return nil, err
	}
	var descriptor map[string]interface{}
	if err := json.Unmarshal(b, &descriptor); err != nil {
		return nil, err
	}
	return New(descriptor, basePath, loaders...)
}
FromReader creates a data package from an io.Reader.
package datapackage
import (
	"archive/zip"
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"reflect"
	"strings"
	"github.com/frictionlessdata/datapackage-go/clone"
	"github.com/frictionlessdata/datapackage-go/validator"
)
const (
	resourcePropName              = "resources"
	profilePropName               = "profile"
	encodingPropName              = "encoding"
	defaultDataPackageProfile     = "data-package"
	defaultResourceEncoding       = "utf-8"
	defaultResourceProfile        = "data-resource"
	tabularDataPackageProfileName = "tabular-data-package"
	descriptorFileNameWithinZip   = "datapackage.json"
)
type resourceFactory func(map[string]interface{}) (*Resource, error)
type Package struct {
	resources []*Resource
	basePath    string
	descriptor  map[string]interface{}
	valRegistry validator.Registry
}
func (p *Package) GetResource(name string) *Resource {
	for _, r := range p.resources {
		if r.name == name {
			return r
		}
	}
	return nil
}
func (p *Package) ResourceNames() []string {
	s := make([]string, len(p.resources))
	for i, r := range p.resources {
		s[i] = r.name
	}
	return s
}
func (p *Package) Resources() []*Resource {
	cpy, _ := clone.Descriptor(p.descriptor)
	res, _ := buildResources(cpy[resourcePropName], p.basePath, p.valRegistry)
	return res
}
func (p *Package) AddResource(d map[string]interface{}) error {
	resDesc, err := clone.Descriptor(d)
	if err != nil {
		return err
	}
	fillResourceDescriptorWithDefaultValues(resDesc)
	rSlice, ok := p.descriptor[resourcePropName].([]interface{})
	if !ok {
		return fmt.Errorf("invalid resources property:\"%v\"", p.descriptor[resourcePropName])
	}
	rSlice = append(rSlice, resDesc)
	r, err := buildResources(rSlice, p.basePath, p.valRegistry)
	if err != nil {
		return err
	}
	p.descriptor[resourcePropName] = rSlice
	p.resources = r
	return nil
}
func (p *Package) RemoveResource(name string) {
	index := -1
	rSlice, ok := p.descriptor[resourcePropName].([]interface{})
	if !ok {
		return
	}
	for i := range rSlice {
		r := rSlice[i].(map[string]interface{})
		if r["name"] == name {
			index = i
			break
		}
	}
	if index > -1 {
		newSlice := append(rSlice[:index], rSlice[index+1:]...)
		r, err := buildResources(newSlice, p.basePath, p.valRegistry)
		if err != nil {
			return
		}
		p.descriptor[resourcePropName] = newSlice
		p.resources = r
	}
}
func (p *Package) Descriptor() map[string]interface{} {
	c, _ := clone.Descriptor(p.descriptor)
	return c
}
func (p *Package) Update(newDescriptor map[string]interface{}, loaders ...validator.RegistryLoader) error {
	newP, err := New(newDescriptor, p.basePath, loaders...)
	if err != nil {
		return err
	}
	*p = *newP
	return nil
}
func (p *Package) write(w io.Writer) error {
	b, err := json.MarshalIndent(p.descriptor, "", "  ")
	if err != nil {
		return err
	}
	_, err = w.Write(b)
	if err != nil {
		return err
	}
	return nil
}
func (p *Package) SaveDescriptor(path string) error {
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	defer f.Close()
	return p.write(f)
}
func (p *Package) Zip(path string) error {
	dir, err := ioutil.TempDir("", "datapackage_zip")
	if err != nil {
		return err
	}
	defer os.RemoveAll(dir)
	descriptorPath := filepath.Join(dir, descriptorFileNameWithinZip)
	if err := p.SaveDescriptor(descriptorPath); err != nil {
		return err
	}
	fPaths := []string{descriptorPath}
	for _, r := range p.resources {
		for _, p := range r.path {
			c, err := read(filepath.Join(r.basePath, p))
			if err != nil {
				return err
			}
			fDir := filepath.Join(dir, filepath.Dir(p))
			if err := os.MkdirAll(fDir, os.ModePerm); err != nil {
				return err
			}
			fPath := filepath.Join(fDir, filepath.Base(p))
			if err := ioutil.WriteFile(fPath, c, os.ModePerm); err != nil {
				return err
			}
			fPaths = append(fPaths, fPath)
		}
	}
	return zipFiles(path, dir, fPaths)
}
func zipFiles(filename string, basePath string, files []string) error {
	newfile, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer newfile.Close()
	zipWriter := zip.NewWriter(newfile)
	defer zipWriter.Close()
	for _, file := range files {
		zipfile, err := os.Open(file)
		if err != nil {
			return err
		}
		defer zipfile.Close()
		info, err := zipfile.Stat()
		if err != nil {
			return err
		}
		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}
		t := strings.TrimPrefix(file, basePath)
		if strings.HasPrefix(t, "/") {
			t = t[1:]
		}
		if filepath.Dir(t) != "." {
			header.Name = t
		}
		writer, err := zipWriter.CreateHeader(header)
		if err != nil {
			return err
		}
		_, err = io.Copy(writer, zipfile)
		if err != nil {
			return err
		}
	}
	return nil
}
func New(descriptor map[string]interface{}, basePath string, loaders ...validator.RegistryLoader) (*Package, error) {
	cpy, err := clone.Descriptor(descriptor)
	if err != nil {
		return nil, err
	}
	fillPackageDescriptorWithDefaultValues(cpy)
	loadPackageSchemas(cpy)
	profile, ok := cpy[profilePropName].(string)
	if !ok {
		return nil, fmt.Errorf("%s property MUST be a string", profilePropName)
	}
	registry, err := validator.NewRegistry(loaders...)
	if err != nil {
		return nil, err
	}
	if err := validator.Validate(cpy, profile, registry); err != nil {
		return nil, err
	}
	resources, err := buildResources(cpy[resourcePropName], basePath, registry)
	if err != nil {
		return nil, err
	}
	return &Package{
		resources:   resources,
		descriptor:  cpy,
		valRegistry: registry,
		basePath:    basePath,
	}, nil
}