рд╣рд╛рдЗрдкрд░рд▓реЗрдЧрд░ рдлреИрдмреНрд░рд┐рдХ рдЪрд┐рдирдХреЛрдб рдХреЗ рд▓рд┐рдП рдирдпрд╛ рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ рдореЙрдбрд▓



рдмрд╣реБрдд рдкрд╣рд▓реЗ рдирд╣реАрдВ, рдлреИрдмреНрд░рд┐рдХ-рдХреЙрдиреНрдЯреНрд░реИрдХреНрдЯ-рдПрдкреА-рдЧреЛ рдХреА рдкрд╣рд▓реА рд░рд┐рд▓реАрдЬ рдЬрд╛рд░реА рдХреА рдЧрдИ рдереА - рдЖрд░рдПрдлрд╕реА 0001 рдЪреЗрдирдХреЛрдб рдХреЗ рд▓рд┐рдП рдирдП рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ рдореЙрдбрд▓ рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди ред рдЖрдЗрдП рджреЗрдЦреЗрдВ рдХрд┐ рдпрд╣ рдХреНрдпрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдХреИрд╕реЗ рдХрд░рдирд╛ рд╣реИред

рдпрд╣рд╛рдВ рдореИрдВрдиреЗ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдлреИрдмреНрд░рд┐рдХ рдиреЗрдЯрд╡рд░реНрдХ рдХреЗ рд╕рд╛рде рдПрдХ рднрдВрдбрд╛рд░ рддреИрдпрд╛рд░ рдХрд┐рдпрд╛, рдЬрд╣рд╛рдВ рд╕рд╣рдХрд░реНрдореА рджреЗрд╡ рдореЛрдб рдореЗрдВ рдЪрд▓рддреЗ рд╣реИрдВред рдиреЗрдЯрд╡рд░реНрдХ рд╢реБрд░реВ рдХрд░рдиреЗ рдФрд░ рд▓реМрдЯрдиреЗ рдХреЗ рд▓рд┐рдП рднрдВрдбрд╛рд░ рд╕реЗ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХрд╛ рдкрд╛рд▓рди рдХрд░реЗрдВ (рдЗрд╕рдореЗрдВ 5 рдорд┐рдирдЯ рд╕реЗ рдЕрдзрд┐рдХ рдирд╣реАрдВ рд▓рдЧреЗрдЧрд╛)ред

рдЕрдм рдЬрдм рдЖрдкрдХреЗ рдкрд╛рд╕ рдиреЗрдЯрд╡рд░реНрдХ рдЪрд▓ рд░рд╣рд╛ рд╣реИ рдФрд░ рдЪреИрдВрдХреЛрдб рд╕реНрдерд╛рдкрд┐рдд рд╣реИ, рддреЛ рдЖрдЗрдП рдирдП рдореЙрдбрд▓ рдореЗрдВ рдХрд╛рдо рдХрд░ рд░рд╣реЗ рдЪрд┐рдирдХреЛрдб рдХреЗ рдЗрдирд╕рд╛рдЗрдб рдХреЛ рджреЗрдЦреЗрдВред

рдореЗрдВ SimpleContract.go, рд╣рдо рдирдИ рдПрдкреАрдЖрдИ рдХреЗ рд╕рд╛рде рдореЙрдбреНрдпреВрд▓ рдЖрдпрд╛рдд:

github.com/hyperledger/fabric-contract-api-go/contractapi

рдЕрдЧрд▓рд╛, рд╣рдо рдЕрдкрдиреЗ рдЕрдиреБрдмрдВрдз рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рдХрд╛ рд╡рд░реНрдгрди SimpleContract рд╕рдВрд░рдЪрдирд╛ рдЬрд┐рд╕рдореЗрдВ рдЕрдиреБрдмрдВрдз рд╕рдВрд░рдЪрдирд╛ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рд╣реИ :

type SimpleContract struct {
	contractapi.Contract
}


рдЕрдиреБрдмрдВрдз рдореЗрдВ рдирд┐рд░реНрдорд╛рдг рдХрд░рдирд╛ рдЕрдирд┐рд╡рд╛рд░реНрдп рд╣реИ рддрд╛рдХрд┐ рд╣рдорд╛рд░рд╛ рдЕрдиреБрдмрдВрдз рдЕрдиреБрдмрдВрдзрдЗрдВрдЯрд░рдлреЗрд╕ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд╕рдВрддреБрд╖реНрдЯ рдХрд░реЗ ред рдпрд╣рд╛рдВ рдЖрдкрдХреЛ рдПрдХ рдЖрд░рдХреНрд╖рдг рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП рдФрд░ рдХрд╣рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдЕрдиреБрдмрдВрдз! = рдЪрд┐рдирдХреЛрдбред рдПрдХ рдЪреИрдВрдХреЛрдб рдПрдХ рдЕрдирд┐рд╢реНрдЪрд┐рдд рд╕рдВрдЦреНрдпрд╛ рдХреЗ рдЕрдиреБрдмрдВрдзреЛрдВ рдХрд╛ рдПрдХ рдХрдВрдЯреЗрдирд░ рд╣реИред рдЗрд╕ рд╕реВрдЪреА рдореЗрдВ рджреЗрдЦрд╛ рдЧрдпрд╛, рдЪрд┐рдирдХреЛрдб рдирдХреНрд╢реЗ рдореЗрдВ рдЕрдкрдиреЗ рдЕрдиреБрдмрдВрдзреЛрдВ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИ:


type ContractChaincode struct {
	DefaultContract       string
	contracts             map[string]contractChaincodeContract
	metadata              metadata.ContractChaincodeMetadata
	Info                  metadata.InfoMetadata
	TransactionSerializer serializer.TransactionSerializer
}

рдорд╛рд░реНрдЧ рдЕрдиреБрдмрдВрдз рдХреЗ рд▓рд┐рдП рдЪрд╛рд▓рд╛рди рджреНрд╡рд╛рд░рд╛ рдорд╛рдирдЪрд┐рддреНрд░ рдЕрдиреБрдмрдВрдзреЛрдВ рдХрд╛ рдЖрдВрддрд░рд┐рдХ рд░реВрдк рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ :

func (cc *ContractChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {

	nsFcn, params := stub.GetFunctionAndParameters()

	li := strings.LastIndex(nsFcn, ":")

	var ns string
	var fn string

	if li == -1 {
		ns = cc.DefaultContract
		fn = nsFcn
	} else {
		ns = nsFcn[:li]
		fn = nsFcn[li+1:]
	}
       ...
       nsContract := cc.contracts[ns]
       ...
       successReturn, successIFace, errorReturn = nsContract.functions[fn].Call(ctx, transactionSchema, &cc.metadata.Components, serializer, params...)
       ...
       return shim.Success([]byte(successReturn))
}  

рддреЛ рд╡рд╛рдкрд╕ SimpleContract рдХреЗ рд▓рд┐рдПред рд╕рднреА рд╡рд┐рдзрд┐рдпреЛрдВ рдореЗрдВ рдПрдХ ctx рдкреИрд░рд╛рдореАрдЯрд░ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдЬреЛ TransactionContextInterface рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд╕рдВрддреБрд╖реНрдЯ рдХрд░рддрд╛ рд╣реИ ред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ, рд╕рднреА рд╡рд┐рдзрд┐рдпреЛрдВ рдореЗрдВ рдПрдХ рдорд╛рдирдХ TransactionContext рдорд┐рд▓рддрд╛ рд╣реИ , рдЬреЛ рдХрд┐ рдЬреНрдпрд╛рджрд╛рддрд░ рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдкрд░реНрдпрд╛рдкреНрдд рд╣реЛрддрд╛ рд╣реИред

рдпрд╣ рд╕рдВрджрд░реНрдн рд╣рдореЗрдВ рдХреНрд▓рд╛рдЗрдВрдЯрдЖрдИрдбреЗрдВрдЯрд┐рдЯреА рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ , рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрд╕ рддрд░рд╣:

func (sc *SimpleContract) Whois(ctx contractapi.TransactionContextInterface) (string, error) {
	return ctx.GetClientIdentity().GetID()
}

рдпрд╛ рдкрд░рд┐рдЪрд┐рдд рд╕реНрдЯрдм (shim.ChaincodeStubInterface) рдХреЛ рд▓реЗрдб рдХреЗ рд╕рд╛рде рдмрд╛рддрдЪреАрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рднреА рд╕рд╛рдорд╛рдиреНрдп рдХреНрд░рд┐рдпрд╛рдПрдВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ:

func (sc *SimpleContract) Write(ctx contractapi.TransactionContextInterface, key string, value []byte) error {
	return ctx.GetStub().PutState(key, value)
}

рдкрд░рдВрддреБ! рд╣рдорд╛рд░реЗ рдбреЗрдореЛ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рдХреЗ рдХреЛрдб рдореЗрдВ, рдЖрдк рд╡рд┐рдзрд┐рдпреЛрдВ рдореЗрдВ рдПрдХ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдЕрд▓рдЧ рд╕рдВрджрд░реНрдн рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ:

func (sc *SimpleContract) Create(ctx CustomTransactionContextInterface, key string, value string) error {
	existing := ctx.GetData()

	if existing != nil {
		return fmt.Errorf("Cannot create world state pair with key %s. Already exists", key)
	}

	err := ctx.GetStub().PutState(key, []byte(value))

	if err != nil {
		return errors.New("Unable to interact with world state")
	}

	return nil
}

рдпрд╣ рдПрдХ рдХрд╕реНрдЯрдо рд╕рдВрджрд░реНрдн рд╣реИред рдпрд╣ рдмрд╣реБрдд рд╣реА рд╕рд░рд▓рддрд╛ рд╕реЗ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╣рдорд╛рд░реЗ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рд╕рдВрджрд░реНрдн рдкрд░ рдзреНрдпрд╛рди рджреЗрдВ :

1. рд╣рдо рдХреЙрдиреНрдЯреНрд░реИрдХреНрдЯреА рдХреЗ рд╕рд╛рде рд╕рдВрдЧрдд рдЗрдВрдЯрд░рдлреЗрд╕ рдХреА рдШреЛрд╖рдгрд╛ рдХрд░рддреЗ рд╣реИрдВред

type CustomTransactionContextInterface interface {
	contractapi.TransactionContextInterface
	GetData() []byte
	SetData([]byte)
}

2. рдЬрд┐рд╕ рд╕рдВрд░рдЪрдирд╛ рдореЗрдВ рд╣рдо рдХреЙрдиреНрдЯреНрд░реИрдХреНрдЯреА рдПрдореНрдмреЗрдб рдХрд░рддреЗ рд╣реИрдВ

type CustomTransactionContext struct {
	contractapi.TransactionContext
	data []byte
}

3. рд╣рдо рдШреЛрд╖рд┐рдд рддрд░реАрдХреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ

// GetData return set data
func (ctc *CustomTransactionContext) GetData() []byte {
	return ctc.data
}

// SetData provide a value for data
func (ctc *CustomTransactionContext) SetData(data []byte) {
	ctc.data = data
}

рдЕрдм, рдЕрдиреБрдмрдВрдз рдХреЛ рд╢реБрд░реВ рдХрд░рддреЗ рд╕рдордп, рд╣рдо рдмрд╕ рдЗрд╕ рд╕рдВрд░рдЪрдирд╛ рдХреЛ рдПрдХ рд╣реИрдВрдбрд▓рд░ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВ:

simpleContract := new(SimpleContract)

simpleContract.TransactionContextHandler = new(CustomTransactionContext)

рдФрд░ ctx contractapi.TransactionContextInterface рдХреЗ рдмрдЬрд╛рдп рдЕрдм рд╣рдорд╛рд░реЗ рдЕрдиреБрдмрдВрдз рдХреЗ рд╕рднреА рддрд░реАрдХреЛрдВ рдХреЛ ctx CustomTransactionContextInterface рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддреЗ рд╣реИрдВ ред

рдПрдХ рдХрд╕реНрдЯрдо рд╕рдВрджрд░реНрдн рдХреЛ рдПрдХ рд░рд╛рдЬреНрдп рдХреЛ рдЯреНрд░рд╛рдВрдЬреЗрдХреНрд╢рдирд▓ рд╣реБрдХ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдзрдХреЗрд▓рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ ред Transactional рд╣реБрдХ рдорд┐рдбрд┐рд▓рд╡реЗрдпрд░ рдХрд╛ рдПрдХ рд╕реБрдВрджрд░ рдирд╛рдо рд╣реИ рдЬреЛ рдЕрдиреБрдмрдВрдз рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдпрд╛ рдмрд╛рдж рдореЗрдВ рдлрд╛рдпрд░ рдХрд░рддрд╛ рд╣реИред

рдПрдХ рд╣реБрдХ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ рдХрд┐, рдПрдХ рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рд▓реЗрди-рджреЗрди рдореЗрдВ рдкрд╣рд▓реЗ рдкреИрд░рд╛рдореАрдЯрд░ рджреНрд╡рд╛рд░рд╛ рдкрд╛рд░рд┐рдд рдХреБрдВрдЬреА рдХреЗ рдореВрд▓реНрдп рдХреЛ рдЕрд░реНрдХ рд╕реЗ рдирд┐рдХрд╛рд▓рддрд╛ рд╣реИ:

SimpleContract.go
func GetWorldState(ctx CustomTransactionContextInterface) error {
	_, params := ctx.GetStub().GetFunctionAndParameters()

	if len(params) < 1 {
		return errors.New("Missing key for world state")
	}

	existing, err := ctx.GetStub().GetState(params[0])

	if err != nil {
		return errors.New("Unable to interact with world state")
	}

	ctx.SetData(existing)

	return nil
}

main.go
simpleContract.BeforeTransaction = GetWorldState

рдЕрдм рд╣рдо рд╡рд┐рдзрд┐рдпреЛрдВ рдореЗрдВ рдЕрдиреБрд░реЛрдзрд┐рдд рдХреБрдВрдЬреА рдХрд╛ рдореВрд▓реНрдп рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд░реВрдк рдореЗрдВ рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

SimpleContract.go
func (sc *SimpleContract) Read(ctx CustomTransactionContextInterface, key string) (string, error) {
	existing := ctx.GetData()

	if existing == nil {
		return "", fmt.Errorf("Cannot read world state pair with key %s. Does not exist", key)
	}

	return string(existing), nil
}

рд╡рд┐рдзрд┐ рдХреЙрд▓ рдХреЗ рдмрд╛рдж рд╣реБрдХ рд▓рдЧрднрдЧ рд╕рдорд╛рди рд╣реИ, рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рд╕рдВрджрд░реНрдн рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпрд╣ рдПрдХ рдЦрд╛рд▓реА рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рддрд╛ рд╣реИ (рд╣рдореЗрдВ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рд╣реИ, рд╣рдо рдмрд╛рдж рдореЗрдВ рдЗрд╕рдХрд╛ рдкрддрд╛ рд▓рдЧрд╛рдПрдВрдЧреЗ ):

YetAnotherContract.go
func After(ctx contractapi.TransactionContextInterface, beforeValue interface{}) error {
	fmt.Println(ctx.GetStub().GetTxID())
	fmt.Println("beforeValue", beforeValue)
	return nil
}

рдпрд╣ рд╣реБрдХ рдЯреНрд░рд╛рдВрдЬреЗрдХреНрд╢рди рдЖрдИрдбреА рдФрд░ рдЙрд╕ рдореВрд▓реНрдп рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддрд╛ рд╣реИ рдЬреЛ рд╡рд┐рдзрд┐ рд╣реБрдХ рд╕реЗ рдкрд╣рд▓реЗ рд▓реМрдЯрд╛ рд╣реИ ред рдЗрд╕ рдкреЛрд╕реНрдЯрд╣реВрдХ рдХреА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдк рд╕реАрдПрд▓рдЖрдИ рдХрдВрдЯреЗрдирд░ рдореЗрдВ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЕрдиреБрдмрдВрдз рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ: рдЙрд╕ рдЯрд░реНрдорд┐рдирд▓ рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд░реЗрдВ рдЬрд╣рд╛рдВ рдХреЛрдб рдЪрд▓ рд░рд╣рд╛ рд╣реИ, рдЖрдЙрдЯрдкреБрдЯ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:

docker exec -it cli sh
peer chaincode query -n mycc -c '{"Args":["YetAnotherContract:SayHi"]}' -C myc




e503e98e4c71285722f244a481fbcbf0ff4120adcd2f9067089104e5c3ed0efe # txid рдкрд╣рд▓реЗValue
рд╣рд╛рдп рд╡рд╣рд╛рдБ # рдкрд┐рдЫрд▓реА рд╡рд┐рдзрд┐ рд╕реЗ # рдорд╛рди

рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рд╣рдо рдПрдХ рдЧреИрд░-рдореМрдЬреВрдж рдлрд╝рдВрдХреНрд╢рди рдирд╛рдо рдХреЗ рд╕рд╛рде рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ? рдЗрд╕рдХреЗ рд▓рд┐рдП, рдХрд┐рд╕реА рднреА рдЕрдиреБрдмрдВрдз рдореЗрдВ рдПрдХ рдЕрдЬреНрдЮрд╛рдд рдХреНрд╖реЗрддреНрд░ рд╣реИ :

Unknown_handler.go
func UnknownTransactionHandler(ctx CustomTransactionContextInterface) error {
	fcn, args := ctx.GetStub().GetFunctionAndParameters()
	return fmt.Errorf("Invalid function %s passed with args %v", fcn, args)
}

main.go
simpleContract.UnknownTransaction = UnknownTransactionHandler

рдпрд╣ рднреА CLI рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рддреНрдпрд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ: рдирд┐рд╖реНрдХрд░реНрд╖:

docker exec -it cli sh
peer chaincode query -n mycc -c '{"Args":["BadRequest", "BadKey"]}' -C myc




рддреНрд░реБрдЯрд┐: рдХреНрд╡реЗрд░реА рдХреЗ рджреМрд░рд╛рди рд╕рдорд░реНрдерди рд╡рд┐рдлрд▓рддрд╛ред рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛: рд╕реНрдерд┐рддрд┐: 500 рд╕рдВрджреЗрд╢: "рдЕрдорд╛рдиреНрдп рдлрд╝рдВрдХреНрд╢рди BadRequest args [BadKey] рдХреЗ рд╕рд╛рде рдкрд╛рд░рд┐рдд рд╣реБрдЖ"

рд╕рд╣рдХрд░реНрдореА рдкрд░ рдХреЛрдб рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЕрдкрдиреЗ рд╕рднреА рдЕрдиреБрдмрдВрдзреЛрдВ рдХреЛ рдХреЛрдб рдореЗрдВ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдкрд╣рд▓реЗ рдХреА рддрд░рд╣ рд╕реНрдЯрд╛рд░реНрдЯ () рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ :

main.go
cc, err := contractapi.NewChaincode(simpleContract, yetAnotherContract)

	if err != nil {
		panic(err.Error())
	}

	if err := cc.Start(); err != nil {
		panic(err.Error())
	}

рд╕рдВрдкреВрд░реНрдг


рдХреЛрдбреЗрдХреНрд╕ рдХреЗ рдирдП рдореЙрдбрд▓ рдиреЗ рд░реВрдЯрд┐рдВрдЧ, рдорд┐рдбрд▓рд╡реЗрдпрд░, рд░рд┐рдЯрд░реНрди рд╡реИрд▓реНрдпреВрдЬрд╝ рдХреЗ рдХреНрд░рдорд╛рдВрдХрди, рд╕реНрдЯреНрд░рд┐рдВрдЧ рддрд░реНрдХреЛрдВ рдХреЗ рдбрд┐рд╕реЗрд░рд▓рд╛рдЗрдЬрд╝реЗрд╢рди ( рдЗрдВрдЯрд░рдлрд╝реЗрд╕ {} рдХреЛ рдЫреЛрдбрд╝рдХрд░ рдХрд┐рд╕реА рднреА рдкреНрд░рдХрд╛рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ ) рдХреА рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд┐рдпрд╛ ред рдЕрдм рдпрд╣ рдЧреЛ рдПрд╕рдбреАрдХреЗ рдХреЗ рд▓рд┐рдП рдирдП рдореЙрдбрд▓ рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рд▓рд┐рдП рдЗрдВрддрдЬрд╛рд░ рдХрд░рдирд╛ рдмрд╛рдХреА рд╣реИред

рдзреНрдпрд╛рди рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдзрдиреНрдпрд╡рд╛рджред

рднрд╛рдЧ рджреЛ

All Articles