рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рд░рд┐рдПрдХреНрдЯрдЬрд╕ рдРрдк рд▓рд┐рдЦрдиреЗ рдХреЗ рд▓рд┐рдП рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╕рд╛рдЭрд╛ рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рдЖ рдЧрдпрд╛ рд╣реИ,
рдореИрдВ рдЕрджреНрд╡рд┐рддреАрдп рд╣реЛрдиреЗ рдХрд╛ рджрд╛рд╡рд╛ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реВрдВредрдкрд╣рд▓реЗ рдкреИрд░рд╛рдЧреНрд░рд╛рдл рдХреЛ рдЫреЛрдбрд╝ рджрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ ред рдореИрдВ рд▓рдВрдмреЗ рд╕рдордп рд╕реЗ рд╡реЗрдм рд╡рд┐рдХрд╛рд╕ рдореЗрдВ рд▓рдЧрд╛ рд╣реБрдЖ рдерд╛, рд▓реЗрдХрд┐рди рдкрд┐рдЫрд▓реЗ рдЪрд╛рд░ рд╡рд░реНрд╖реЛрдВ рд╕реЗ рдореИрдВ рд░рд┐рдПрдХреНрдЯрдЬреЗрд╕ рдкрд░ рддрдВрдЧ рдмреИрдард╛ рд╣реВрдВ рдФрд░ рдореБрдЭреЗ рд╕рдм рдХреБрдЫ рд╕реВрдЯ рдХрд░рддрд╛ рд╣реИ, рдореИрдВрдиреЗ рдЕрдкрдиреЗ рдЬреАрд╡рди рдореЗрдВ рд░рд┐рдбреНрдпреВрдХреНрд╕ рдХрд┐рдпрд╛ рдерд╛, рд▓реЗрдХрд┐рди рд▓рдЧрднрдЧ рджреЛ рд╕рд╛рд▓ рдкрд╣рд▓реЗ рдореИрдВ рдПрдордПрдХреНрд╕рдПрдХреНрд╕ рд╕реЗ рдорд┐рд▓рд╛ рдерд╛, рдЕрднреА рдХреБрдЫ рдорд╣реАрдиреЗ рдкрд╣рд▓реЗ рд╣реА рдореИрдВрдиреЗ рд░рд┐рдбрдХреНрд╕ рдореЗрдВ рд▓реМрдЯрдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рдереА, рд▓реЗрдХрд┐рди рдореИрдВрдиреЗ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдореИрдВ рдХрд░ рд╕рдХрддрд╛ рдерд╛, рдореБрдЭреЗ рд▓рдЧ рд░рд╣рд╛ рдерд╛ рдХрд┐ рдореИрдВ рдХреБрдЫ рд╢рд╛рдирджрд╛рд░ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ, рд╢рд╛рдпрдж рдХреБрдЫ рд╕рд╣реА рдирд╣реАрдВ рдерд╛, рд╕рд░реНрд╡рд░ рдкрд░ рдмрд╣реБрдд рд╕рд╛рд░реЗ рдмрд╛рдЗрдЯреНрд╕ рдЗрд╕ рд╡рд┐рд╖рдп рдкрд░ рдкрд╣рд▓реЗ рд╣реА рдЕрдиреБрд╡рд╛рджрд┐рдд рд╣реЛ рдЪреБрдХреЗ рдереЗ, рд▓реЗрдЦ рдПрдХ рд╕реЗ рдкрд╣рд▓реЗ рдПрдХ рдХреА рдардВрдбрдХ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд╣реАрдВ рдерд╛, рдпрд╣ рд╕рд┐рд░реНрдл рдореЗрд░реА рд╕рд░реНрд╡реЛрддреНрддрдо рдкреНрд░рдерд╛рдУрдВ рдХреЛ рд╕рд╛рдЭрд╛ рдХрд░рдиреЗ рдХрд╛ рдПрдХ рдкреНрд░рдпрд╛рд╕ рд╣реИ, рд╢рд╛рдпрдж рдХреЛрдИ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдЬрд╛рдПрдЧрд╛, рдФрд░ рдЗрд╕реА рддрд░рд╣ред
рдЬрд┐рди рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╣рдо рд╣рд▓ рдХрд░реЗрдВрдЧреЗ:- di рдХрдиреЗрдХреНрд╢рди рдШрдЯрдХреЛрдВ рдХреЗ рд▓рд┐рдП
- рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдбреЗрдЯрд╛ рд▓реЛрдбрд┐рдВрдЧ рдХреЗ рд╕рд╛рде рд╕рд░реНрд╡рд░ рд░реЗрдВрдбрд░рд┐рдВрдЧ
рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреА рд╕рдВрд░рдЪрдирд╛
рдЧрд┐рдереБрдм рдкрд░ рджреЗрдЦреА рдЬрд╛ рд╕рдХрддреА рд╣реИред рдЗрд╕рд▓рд┐рдП, рдореИрдВ рдЫреЛрдбрд╝ рджреВрдВрдЧрд╛ рдХрд┐ рдХреИрд╕реЗ рдПрдХ рдЖрджрд┐рдо рдЖрд╡реЗрджрди рд▓рд┐рдЦрдирд╛ рд╣реИ рдФрд░ рд▓реЗрдЦ рдХреЗрд╡рд▓ рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдХрд░реЗрдЧрд╛
рд╣рдо рдЗрд╕ рддрд░рд╣ рдХреА рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рдХреЛ рдкреЗрд╢ рдХрд░рддреЗ рд╣реИрдВ: рдбреЗрдЯрд╛ рдореЙрдбрд▓, рд╕реЗрд╡рд╛, рдкрдХреНрд╖ред
рдЪрд▓реЛ рдПрдХ рд╕рд░рд▓ рдореЙрдбрд▓ рдорд┐рд▓рддрд╛ рд╣реИ
TodoModel.tsimport { observable, action } from 'mobx'; export class TodoModel { @observable public id: number; @observable public text: string = ''; @observable public isCompleted: boolean = false; @action public set = (key: 'text' | 'isCompleted', value: any): void => { this[key] = value; }; }
рдЖрдк рдЬреЛ рджреЗрдЦрддреЗ рд╣реИрдВ рд╡рд╣ рд╕реЗрдЯ рдПрдХреНрд╢рди рд╣реИ, рдореЙрдбрд▓ рдореЗрдВ рдпрд╣ рдПрдХ рдЕрдЪреНрдЫреЗ рдЯреЛрди рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдЕрдзрд┐рдХ рдПрдХ рдЕрдкрд╡рд╛рдж рд╣реИ, рдЖрдорддреМрд░ рдкрд░ рдПрдХ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдПрдХ рдореВрд▓ рдореЙрдбрд▓ рд╣реИ рдЬреЛ рдХрд┐ рдЖрджрд┐рдо рд╕рд╣рд╛рдпрдХреЛрдВ рдХреЗ рд╕рд╛рде рд╣реИ рдФрд░ рдпрд╣ рд╕рд┐рд░реНрдл рдЗрд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓рд╛ рд╣реИ, рдореЙрдбрд▓ рдореЗрдВ рдЕрдЪреНрдЫреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдирд╣реАрдВ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред
рдЕрдм рд╣рдореЗрдВ рдпрд╣ рд╕реАрдЦрдиреЗ рдХреА рдЬрд░реВрд░рдд рд╣реИ рдХрд┐ рдЗрд╕ рдореЙрдбрд▓ рдХреЗ рд╕рд╛рде рдХреИрд╕реЗ рдХрд╛рдо рдХрд░реЗрдВ, рдПрдХ рд╕реЗрд╡рд╛ рд╢реБрд░реВ рдХрд░реЗрдВ:
TodoService.ts import { Service, Inject } from 'typedi'; import { plainToClass, classToClass } from 'class-transformer'; import { DataStorage } from '../storage/DataStorage'; import { action } from 'mobx'; import { TodoModel } from '../models/TodoModel'; const responseMock = { items: [ { id: 1, isCompleted: false, text: 'Item 1' }, { id: 2, isCompleted: true, text: 'Item 2' } ] }; @Service('TodoService') export class TodoService { @Inject('DataStorage') public dataStorage: DataStorage; @action public load = async () => { await new Promise(resolve => setTimeout(resolve, 300)); this.dataStorage.todos = plainToClass(TodoModel, responseMock.items); }; @action public save(todo: TodoModel): void { if (todo.id) { const idx = this.dataStorage.todos.findIndex(item => todo.id === item.id); this.dataStorage.todos[idx] = classToClass(todo); } else { const todos = this.dataStorage.todos.slice(); todo.id = Math.floor(Math.random() * Math.floor(100000)); todos.push(todo); this.dataStorage.todos = todos; } this.clearTodo(); } @action public edit(todo: TodoModel): void { this.dataStorage.todo = classToClass(todo); } @action public clearTodo(): void { this.dataStorage.todo = new TodoModel(); } }
рд╣рдорд╛рд░реА рд╕реЗрд╡рд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд┐рдВрдХ рд╣реИ
DataStorage.ts import { Service } from 'typedi'; import { observable } from 'mobx'; import { TodoModel } from '../models/TodoModel'; @Service('DataStorage') export class DataStorage { @observable public todos: TodoModel[] = []; @observable public todo: TodoModel = new TodoModel(); }
рдЗрд╕ рд╕реНрдЯреЛрд░ рдореЗрдВ рд╣рдо рдЕрдкрдиреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреА рд╕реНрдерд┐рддрд┐ рдХреЛ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░реЗрдВрдЧреЗ, рдРрд╕реЗ рдХрдИ рд╕реНрдЯреЛрд░ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЬреИрд╕рд╛ рдХрд┐ рдЕрднреНрдпрд╛рд╕ рд╕реЗ рдкрддрд╛ рдЪрд▓рд╛ рд╣реИ, рдпрд╣ рдХрдИ рдЫреЛрдЯреЗ рд╕реНрдЯреЛрд░реЛрдВ рдХреЛ рддреЛрдбрд╝рдиреЗ рдХрд╛ рдХреЛрдИ рдорддрд▓рдм рдирд╣реАрдВ рд╣реИред рд╕реНрдЯреЛрд░ рдореЗрдВ, рд╕рд╛рде рд╣реА рд╕рд╛рде рдореЙрдбрд▓ рдореЗрдВ, рдХреЛрдИ рдХрд╛рд░реНрд░рд╡рд╛рдИ рдирд╣реАрдВ рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред
рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд▓рдЧрднрдЧ рд╕рдм рдХреБрдЫ рддреИрдпрд╛рд░ рд╣реИ, рдпрд╣ рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рд╕реЗ рд╕рдм рдХреБрдЫ рдЬреЛрдбрд╝рддрд╛ рд╣реИ, рдЗрд╕рдХреЗ рд▓рд┐рдП рд╣рдо mobx-react рд╕реЗ рдЗрдВрдЬреЗрдХреНрдЯрд░ рдХреЛ рдереЛрдбрд╝рд╛ рдХрд╕рддреЗ рд╣реИрдВ:
рдбрд┐ import { inject } from 'mobx-react'; export function DI(...classNames: string[]) { return (target: any) => { return inject((props: any) => { const data: any = {}; classNames.forEach(className => { const name = className.charAt(0).toLowerCase() + className.slice(1); data[name] = props.container.get(className); }); data.container = props.container; return data; })(target); }; }
рдФрд░ рд╣рдорд╛рд░реЗ DI рдХреЗ рд▓рд┐рдП рдПрдХ рдХрдВрдЯреЗрдирд░ рд▓реЗрдВ
browser.tsx import 'reflect-metadata'; import * as React from 'react'; import { hydrate } from 'react-dom'; import { renderRoutes } from 'react-router-config'; import { Provider } from 'mobx-react'; import { BrowserRouter } from 'react-router-dom'; import { Container } from 'typedi'; import '../application'; import { routes } from '../application/route'; hydrate( <Provider container={Container}> <BrowserRouter>{renderRoutes(routes)}</BrowserRouter> </Provider>, document.getElementById('root') );
рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд╣рдореЗрд╢рд╛ рдПрдХ рдХрдВрдЯреЗрдирд░ рд╣реЛрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рд╕рд░реНрд╡рд░ рдХреЗ рд▓рд┐рдП рдЖрдкрдХреЛ рдЬреЛ рджреЗрдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ, рдЙрд╕рдХреЗ рд▓рд┐рдП рдкреНрд░рддреНрдпреЗрдХ рдЕрдиреБрд░реЛрдз рдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рдХрдВрдЯреЗрдирд░ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реЛрддрд╛ рд╣реИ:
server.tsx import * as express from 'express'; import * as React from 'react'; import { Container } from 'typedi'; import '../application';
рд╕рд░реНрд╡рд░ рд░реЗрдВрдбрд░ рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдПрдХ рдирд╛рдЬреБрдХ рдЪреАрдЬ рд╣реИ, рдПрдХ рддрд░рдл рдореИрдВ рдЗрд╕рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╕рдм рдХреБрдЫ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ,
рд▓реЗрдХрд┐рди рдмреЙрдЯреНрд╕ рдХреЛ рдХрдВрдЯреЗрдВрдЯ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдЗрд╕рдХрд╛ рдХреЗрд╡рд▓ рдПрдХ рд╣реА рд╡реНрдпрд╡рд╕рд╛рдп рдХрд╛рд░реНрдп рд╣реИ , рдЗрд╕рд▓рд┐рдП "рдХреБрдЫ рдХреЗ рд▓рд┐рдП рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд▓реЙрдЧ рдЗрди рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реИ рдЬреИрд╕реЗ рдХрд┐ рд╕рд╛рдЗрдЯ рдкрд░ рдХрдо рд╕реЗ рдХрдо рдПрдХ рдмрд╛рд░"ред , рдФрд░ рд╕рд░реНрд╡рд░ рдкрд░ рдХрдВрдЯреЗрдирд░ рдмрдирд╛рдиреЗ рдХреЗ рд╕рд╛рде рд╕рд░реНрд╡рд░ рд░реЗрдВрдбрд░ рдХреЛ рдЫреЛрдбрд╝реЗрдВред
рдЦреИрд░, рдЕрдм рд╣рдорд╛рд░реЗ рдШрдЯрдХреЛрдВ рдХреЗ рд▓рд┐рдП:
MainRoute.tsx import * as React from 'react'; import { TodoService } from '../service/TodoService'; import { observer } from 'mobx-react'; import { DI } from '../annotation/DI'; import { DataStorage } from '../storage/DataStorage'; import { Todo } from '../component/todo'; import { Form } from '../component/form/Form'; import { ContainerInstance } from 'typedi'; interface IProps { todoService?: TodoService; dataStorage?: DataStorage; } @DI('TodoService', 'DataStorage') @observer export class MainRoute extends React.Component<IProps> { public static async loadData(container: ContainerInstance) { const todoService: TodoService = container.get('TodoService'); await todoService.load(); } public componentDidMount() { this.props.todoService.load(); } public render() { return ( <div> <Form /> <ul> {this.props.dataStorage.items.map(item => ( <li key={item.id} ><Todo model={item} /></li> ))} </ul> </div> ); } }
рдпрд╣рд╛рдВ рд╕рдм рдХреБрдЫ рдмрд╣реБрдд рддрд╛рд░реНрдХрд┐рдХ рдФрд░ рд╕реБрдВрджрд░ рдирд┐рдХрд▓рд╛, рдбреНрд░рд╛рдЗрдВрдЧ рдХреЗ рд▓рд┐рдП рд╣рдорд╛рд░рд╛ "рд░реЗрдВрдбрд░" рджреГрд╢реНрдп рд╣рдорд╛рд░реЗ рд╕реНрдЯреЛрд░ рд╕реЗ рдбреЗрдЯрд╛ рд▓реЗрддрд╛ рд╣реИ, рдШрдЯрдХ рд╣реБрдХ рдХрд╣рддреЗ рд╣реИрдВ рдХрд┐ рд╣рдореЗрдВ рдХрд┐рд╕ рд╕рдордп рдбреЗрдЯрд╛ рд▓реЛрдб рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
Todo.tsx import * as React from 'react'; import { TodoModel } from '../../models/TodoModel'; import { TodoService } from '../../service/TodoService'; import { DI } from '../../annotation/DI'; import { observer } from 'mobx-react'; interface IProps { model: TodoModel; todoService?: TodoService; } @DI('TodoService') @observer export class Todo extends React.Component<IProps> { public render() { const { model, todoService } = this.props; return ( <> <input type='checkbox' checked={model.isCompleted} onChange={e => model.set('isCompleted', e.target.checked)} /> <h4>{model.text}</h4> <button type='button' onClick={() => todoService.edit(model)}>Edit</button> </> ); } }
Form.tsx import * as React from 'react'; import { observer } from 'mobx-react'; import { DI } from '../../annotation/DI'; import { TodoService } from '../../service'; import { DataStorage } from '../../storage'; import { TextField } from '../text-field'; interface IProps { todoService?: TodoService; dataStorage?: DataStorage; } @DI('TodoService', 'DataStorage') @observer export class Form extends React.Component<IProps> { public handleSave = (e: any) => { e.preventDefault(); this.props.todoService.save(this.props.dataStorage.todo); }; public handleClear = () => { this.props.todoService.clearTodo(); }; public render() { const { dataStorage } = this.props; return ( <form onSubmit={this.handleSave}> <TextField name='text' model={dataStorage.todo} /> <button>{dataStorage.todo.id ? 'Save' : 'Create'}</button> <button type='button' onClick={this.handleClear}> Clear </button> </form> ); } }
рдореЗрд░реА рд░рд╛рдп рдореЗрдВ, рд░реВрдкреЛрдВ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдореЙрдбрд▓ / рдбреАрдЯреАрдУ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдмрд╣реБрдд рдЕрдзрд┐рдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рд╣реИ, рдЖрдк рд╕рд╛рдорд╛рдиреНрдп рджреЗрд╢реА рд░реВрдкреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдФрд░ рдбреЗрдЯрд╛ рдореЙрдбрд▓ рдХреЛ рдЕрдкрдбреЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рдЬреЛ рдХреЛрдИ рднреА рдЗрд╕реЗ рд╕реБрдирддрд╛ рд╣реИ рдЙрд╕реЗ рддреБрд░рдВрдд рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдореИрдВ рдкреБрд╕реНрддрдХрд╛рд▓рдпреЛрдВ рдХреЗ рдЗрд╕ рд╕рдореВрд╣ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ: рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛, рд╡рд░реНрдЧ-рдЯреНрд░рд╛рдВрд╕рдлрд╛рд░реНрдорд░, рдореЛрдмрд╛рдЗрд▓, рдЯрд╛рдЗрдкрд╕реА
рдЕрдм рд╣рдо рдЙрддреНрдкрд╛рджреЛрдВ рдореЗрдВ рдЗрд╕ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдпреЗ рдЖрдо рдХреЙрдорди рдШрдЯрдХреЛрдВ рдФрд░ рд╕реЗрд╡рд╛рдУрдВ рдХреЗ рд╕рд╛рде рдмрд╣реБрдд рдмрдбрд╝реА рдкрд░рд┐рдпреЛрдЬрдирд╛рдПрдВ рд╣реИрдВред
рдпрджрд┐ рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рджрд┐рд▓рдЪрд╕реНрдк рд╣реИ, рддреЛ рдореИрдВ рдЖрдкрдХреЛ рдмрддрд╛рддрд╛ рд╣реВрдВ рдХрд┐ рдХреИрд╕реЗ, рдЙрд╕реА рдирд╕ рдореЗрдВ, рд╣рдо рдЙрдиреНрд╣реЗрдВ рд╕рд░реНрд╡рд░ рдкрд░ рднреЗрдЬрдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдореЙрдбрд▓ рдХреЛ рдорд╛рдиреНрдп рдХрд░рддреЗ рд╣реИрдВ, рд╣рдо рд╕рд░реНрд╡рд░ рддреНрд░реБрдЯрд┐рдпреЛрдВ рдХреЛ рдХреИрд╕реЗ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рд╣рдо рдмреНрд░рд╛рдЙрдЬрд╝рд░ рдЯреИрдм рдХреЗ рдмреАрдЪ рд╣рдорд╛рд░реЗ рд░рд╛рдЬреНрдп рдХреЛ рдХреИрд╕реЗ рд╕рд┐рдВрдХреНрд░рдирд╛рдЗрдЬрд╝ рдХрд░рддреЗ рд╣реИрдВред
рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╕рдм рдХреБрдЫ рдмрд╣реБрдд рд╣реА рдмреЛрдирд╕ рд╣реИ: "рдХреНрд▓рд╛рд╕-рд╡реИрд▓рд┐рдбреЗрдЯрд░", "рд▓реЛрдХрд▓рд╕реНрдЯреЛрд░реЗрдЬ + рд╡рд┐рдВрдбреЛред рдПрдбрдбреЗрдВрдЯрд╡реЗрдВрдЯрд┐рд╕реНрдЯрдирд░ ('рд╕реНрдЯреЛрд░реЗрдЬ')"
рдкрдврд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж :-)
рдЙрджрд╛рд╣рд░рдг