2011 рдореЗрдВ, рдЯреНрд╡рд┐рдЯрд░ рдиреЗ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛,
рдПрдХреНрд▓рд┐рдкреНрд╕ рдкрдмреНрд▓рд┐рдХ рд▓рд╛рдЗрд╕реЗрдВрд╕ рдХреЗ рддрд╣рдд,
рд╕реНрдЯреЙрд░реНрдо рдбрд┐рд╕реНрдЯреНрд░реАрдмреНрдпреВрдЯреЗрдб рдХрдВрдкреНрдпреВрдЯрд┐рдВрдЧ рдкреНрд░реЛрдЬреЗрдХреНрдЯред рддреВрдлрд╛рди BackType рдкрд░ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рдерд╛ рдФрд░ рдЦрд░реАрдж рдХреЗ рдмрд╛рдж рдЯреНрд╡рд┐рдЯрд░ рдкрд░ рд╕реНрд╡рд┐рдЪ рдХрд░ рджрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред
рд╕реНрдЯреЙрд░реНрдо рдПрдХ рдкреНрд░рдгрд╛рд▓реА рд╣реИ рдЬреЛ
рдЕрдкрд╛рдЪреЗ рд╣рдбреЛрдк рдХреЗ рд╕рдорд╛рди рдмрдбрд╝реЗ рдбреЗрдЯрд╛ рдзрд╛рд░рд╛рдУрдВ рдХреЗ рд╡рд┐рддрд░рд┐рдд рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдкрд░ рдХреЗрдВрджреНрд░рд┐рдд рд╣реИ, рд▓реЗрдХрд┐рди рд╡рд╛рд╕реНрддрд╡рд┐рдХ рд╕рдордп рдореЗрдВред
рддреВрдлрд╛рди рдХреА рдореБрдЦреНрдп рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ:
- рд╕реНрдХреЗрд▓реЗрдмрд┐рд▓рд┐рдЯреА ред рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХрд╛рд░реНрдп рдкреНрд░рддреНрдпреЗрдХ рдиреЛрдб рдкрд░ рдХреНрд▓рд╕реНрдЯрд░ рдиреЛрдбреНрд╕ рдФрд░ рдереНрд░реЗрдбреНрд╕ рдореЗрдВ рд╡рд┐рддрд░рд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред
- рдбреЗрдЯрд╛ рд╣рд╛рдирд┐ рдХреЗ рдЦрд┐рд▓рд╛рдл рд╕реБрд░рдХреНрд╖рд╛ рдХреА рдЧрд╛рд░рдВрдЯреАред
- рддреИрдирд╛рдд рдХрд░рдиреЗ рдФрд░ рдмрдирд╛рдП рд░рдЦрдиреЗ рдореЗрдВ рдЖрд╕рд╛рдиред
- рдХреНрд░реИрд╢ рд░рд┐рдХрд╡рд░реАред рдпрджрд┐ рдХреЛрдИ рднреА рд╣реИрдВрдбрд▓рд░ рд╡рд┐рдлрд▓ рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдХрд╛рд░реНрдп рдЕрдиреНрдп рд╣реИрдВрдбрд▓рд░ рдкрд░ рдкреБрдирд░реНрдирд┐рд░реНрджреЗрд╢рд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред
- рдЬрд╛рд╡рд╛ рдореЗрдВ рди рдХреЗрд╡рд▓ рдШрдЯрдХреЛрдВ рдХреЛ рд▓рд┐рдЦрдиреЗ рдХреА рдХреНрд╖рдорддрд╛ред JSON рдСрдмреНрдЬреЗрдХреНрдЯреНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рд░рд▓ рдорд▓реНрдЯреАрд▓реИрдВрдЧ рдкреНрд░реЛрдЯреЛрдХреЙрд▓ ред рдкрд╛рдЗрдерди, рд░реВрдмреА рдФрд░ рдлреИрдВрд╕реА рднрд╛рд╖рд╛рдУрдВ рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рдПрдбреЗрдкреНрдЯрд░ рд╣реИрдВред
рдкрд╣рд▓рд╛ рднрд╛рдЧ рд╕реНрдЯреЙрд░реНрдо рд╕рдВрд╕реНрдХрд░рдг 0.8.2 рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдиреЗ рдХреА рдореВрд▓ рдЕрд╡рдзрд╛рд░рдгрд╛рдУрдВ рдФрд░ рдмреБрдирд┐рдпрд╛рджреА рдмрд╛рддреЛрдВ рдкрд░ рдЪрд░реНрдЪрд╛ рдХрд░рддрд╛ рд╣реИред
рддреВрдлрд╛рди рдХреЗ рддрддреНрд╡
рдЯрдкрд▓рдбреЗрдЯрд╛ рдкреНрд░рд╕реНрддреБрддрд┐ рддрддреНрд╡ред рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд░реВрдк рд╕реЗ рдЗрд╕рдореЗрдВ рд▓реЙрдиреНрдЧ, рдЗрдВрдЯреЗрдЧрд░, рд╢реЙрд░реНрдЯ, рдмрд╛рдЗрдЯ, рд╕реНрдЯреНрд░рд┐рдВрдЧ, рдбрдмрд▓, рдлреНрд▓реЛрдЯ, рдмреБрд▓рд┐рдпрди рдФрд░ рдмрд╛рдЗрдЯ [] рдХреНрд╖реЗрддреНрд░ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рдЯрдкрд▓ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рдЬрд╛рдиреЗ рд╡рд╛рд▓реЗ рдХрд╕реНрдЯрдо рдкреНрд░рдХрд╛рд░ рдХреНрд░рдордмрджреНрдз рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдПред
рдзрд╛рд░рд╛рдЯрдкрд▓ рдХреА рдЕрдиреБрдХреНрд░рдоред рдЯрдкрд▓ рдореЗрдВ рдЦреЗрддреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдирд╛рдордХрд░рдг рдпреЛрдЬрдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИред
рдЯреЛрдВрдЯреАрд╕реНрдЯреНрд░реАрдо рдХреЗ рд▓рд┐рдП рдбреЗрдЯрд╛ рдкреНрд░рджрд╛рддрд╛ред рдпрд╣ рдмрд╛рд╣рд░реА рд╕реНрд░реЛрддреЛрдВ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рддрд╛ рд╣реИ, рдЙрдирд╕реЗ рдПрдХ рдЯрдкрд▓ рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рдЗрд╕реЗ рд╕реНрдЯреНрд░реАрдо рдореЗрдВ рднреЗрдЬрддрд╛ рд╣реИред Tuple рдХреЛ рдХрдИ рдЕрд▓рдЧ-рдЕрд▓рдЧ рд╕реНрдЯреНрд░реАрдо рдореЗрдВ рднреЗрдЬ рд╕рдХрддреЗ рд╣реИрдВред рд▓реЛрдХрдкреНрд░рд┐рдп рдореИрд╕реЗрдЬрд┐рдВрдЧ рд╕рд┐рд╕реНрдЯрдо рдХреЗ рд▓рд┐рдП рддреИрдпрд╛рд░ рд╣реИрдВ:
RabbitMQ / AMQP ,
Kestrel ,
JMS ,
Kafka ред
рдкреЗрдВрдЪрдбрд╛рдЯрд╛ рд╣реИрдВрдбрд▓рд░ред рдЗрдирдкреБрдЯ рдЯреНрдпреВрдкрд▓ рд╣реИред рдЖрдЙрдЯрдкреБрдЯ рдкрд░ 0 рдпрд╛ рдЕрдзрд┐рдХ рдЯрдкрд▓ рднреЗрдЬрддрд╛ рд╣реИред
рдЯреЛрдкреЛрд▓реЙрдЬреАрдЙрдирдХреЗ рд╕рдВрдмрдВрдзреЛрдВ рдХреЗ рд╡рд┐рд╡рд░рдг рдХреЗ рд╕рд╛рде рддрддреНрд╡реЛрдВ рдХрд╛ рдПрдХ рд╕рдВрдЧреНрд░рд╣ред Hadoop рдореЗрдВ MapReduce рдЬреЙрдм рдХрд╛ рдПрдХ рдПрдирд╛рд▓реЙрдЧред MapReduce рдЬреЙрдм рдХреЗ рд╡рд┐рдкрд░реАрдд, рдпрд╣ рдЗрдирдкреБрдЯ рдбреЗрдЯрд╛ рд╕реНрдЯреНрд░реАрдо рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рдмрдВрдж рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред рдЯреЛрдВрдЯреА рдкрд░рд┐рд╡рд╣рди рдХреЛ рдЯреЛрдВрдЯреА рдФрд░ рдмреЛрд▓реНрдЯ рддрддреНрд╡реЛрдВ рдХреЗ рдмреАрдЪ рд▓реЗ рдЬрд╛рддрд╛ рд╣реИред рдЗрд╕реЗ рд╕реНрдерд╛рдиреАрдп рд░реВрдк рд╕реЗ рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдпрд╛ рд╕реНрдЯреЙрд░реНрдо рдХреНрд▓рд╕реНрдЯрд░ рдореЗрдВ рд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
рдЙрджрд╛рд╣рд░рдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВ
рдХрд╛рд░реНрдп
рдПрдХ
Cdr рдлреЛрди рдХреЙрд▓ рдбреЗрдЯрд╛ рд╕реНрдЯреНрд░реАрдо рд╣реИред рд╕реНрд░реЛрдд рд╕рдВрдЦреНрдпрд╛ рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдХреНрд▓рд╛рдЗрдВрдЯ рдЖрдИрдбреА рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХреА рдЬрд╛рддреА рд╣реИред рдЧрдВрддрд╡реНрдп рд╕рдВрдЦреНрдпрд╛ рдФрд░ рдЧреНрд░рд╛рд╣рдХ рдЖрдИрдбреА рдХреЗ рдЖрдзрд╛рд░ рдкрд░, рдЯреИрд░рд┐рдл рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдХреЙрд▓ рдХреА рд▓рд╛рдЧрдд рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдкреНрд░рддреНрдпреЗрдХ рдЪрд░рдг рдХреЛ рдХрдИ рдереНрд░реЗрдбреНрд╕ рдореЗрдВ рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдЗрд╕рдХрд╛ рдЙрджрд╛рд╣рд░рдг рд╕реНрдерд╛рдиреАрдп рдорд╢реАрди рдкрд░ рд╣реЛрдЧрд╛ред
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдмрд╕
BasicApp рдЗрдирдкреБрдЯ рдХрд╛ рдкреНрд░рд┐рдВрдЯ рдЖрдЙрдЯ
рд▓реЗрдВ ред
рдПрдХ рдирдИ рдЯреЛрдкреЛрд▓реЙрдЬреА рдмрдирд╛рдПрдВ:
TopologyBuilder builder = new TopologyBuilder();
рдПрдХ
рд╕реНрдкрд╛рдЙрдЯ CdrSpout рдЬрдирд░реЗрдЯрд┐рдВрдЧ рдЗрдирдкреБрдЯ рдЬреЛрдбрд╝реЗрдВ:
builder.setSpout("CdrReader", new CdrSpout());
рдмреЛрд▓реНрдЯ рдХреЛ рджреЛ рдзрд╛рд░рд╛рдУрдВ рдХреЗ рд╕рд╛рде рдЬреЛрдбрд╝реЗрдВ рдФрд░ рдЗрдВрдЧрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдЖрдЙрдЯрдкреБрдЯ рд╕реНрдЯреНрд░реАрдо CdrReader рд╣реИред shuffleGrouping рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ CdrReader рдХрд╛ рдбреЗрдЯрд╛ рдмреЗрддрд░рддреАрдм рдврдВрдЧ рд╕реЗ рдЪрдпрдирд┐рдд PrintOutBolt рдХреЛ рдЦрд┐рд▓рд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
builder.setBolt("PrintOutBolt", new PrintOutBolt(), 2).shuffleGrouping("CdrReader");
рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░реЗрдВ рдФрд░ рд╕реНрдерд╛рдиреАрдп рд╕реНрдЯреЙрд░реНрдо рдХреНрд▓рд╕реНрдЯрд░ рд╢реБрд░реВ рдХрд░реЗрдВ:
Config config = new Config();
рдЖрдЙрдЯрдкреБрдЯ рд▓рдЧрднрдЧ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╣реИ:
рдЫрд┐рдкрд╛ рд╣реБрдЖ рдкрд╛рда OUT >> [80] Cdr {callSource = '78119990005', callDestination = '8313610698077174239'
рдХреЙрд▓ рдЯрд╛рдЗрдо = 7631, рдХреНрд▓рд╛рдЗрдВрдЯрдЖрдИрдбреА = 0, рдореВрд▓реНрдп = 0}
OUT >> [78] Cdr {callSource = '78119990006', callDestination = '2238707710336895468'
callTime = 20738, clientId = 0, рдореВрд▓реНрдп = 0}
OUT >> [78] Cdr {callSource = '78119990007', callDestination = '579372726495390920'
callTime = 31544, clientId = 0, рдореВрд▓реНрдп = 0}
OUT >> [80] Cdr {callSource = '78119990006', callDestination = '2010724447342634423'
рдХреЙрд▓рдЯрд╛рдЗрдо = 10268, рдХреНрд▓рд╛рдЗрдВрдЯрдЖрдИрдб = 0, рдореВрд▓реНрдп = 0}
рд╡рд░реНрдЧ рдХреЛрд╖реНрдардХ рдореЗрдВ рд╕рдВрдЦреНрдпрд╛ рдереНрд░реЗрдб рдЖрдИрдбреА рд╣реИ, рдпрд╣ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рд╕рдорд╛рдирд╛рдВрддрд░ рдореЗрдВ рдЖрдпреЛрдЬрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рдЖрдЧреЗ рдХреЗ рдкреНрд░рдпреЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдХрдИ рд╣реИрдВрдбрд▓рд░ рдХреЗ рдмреАрдЪ рдЗрдирдкреБрдЯ рдбреЗрдЯрд╛ рдХреЗ рд╡рд┐рддрд░рдг рд╕реЗ рдирд┐рдкрдЯрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдКрдкрд░ рдХреЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, рдПрдХ рдпрд╛рджреГрдЪреНрдЫрд┐рдХ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рд▓реЗрдХрд┐рди рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдЙрдкрдпреЛрдЧ рдореЗрдВ, рдмреЛрд▓реНрдЯ рд╢рд╛рдпрдж рдмрд╛рд╣рд░реА рдорджрдж рдкреНрд░рдгрд╛рд▓реА рдФрд░ рдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдЧрд╛ред рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╣ рд╡рд╛рдВрдЫрдиреАрдп рд╣реИ рдХрд┐ рдкреНрд░рддреНрдпреЗрдХ рдмреЛрд▓реНрдЯ рдЗрдирдкреБрдЯ рдбреЗрдЯрд╛ рдХреЗ рдЕрдкрдиреЗ рд╕рдмрд╕реЗрдЯ рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддрд╛ рд╣реИред рддрдм рдмрд╛рд╣рд░реА рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рд╕реЗ рдбреЗрдЯрд╛ рдХреЗ рдкреНрд░рднрд╛рд╡реА рдХреИрд╢рд┐рдВрдЧ рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реЛрдЧрд╛ред
рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рддреВрдлрд╛рди CustomStreamGrouping рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИред
CdrGrouper рдХреЛ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВред рдЗрд╕рдХрд╛ рдХрд╛рд░реНрдп рдЯреБрдкрд▓ рдХреЛ рд╕рдорд╛рди рд╕реНрд░реЛрдд рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЗ рд╕рд╛рде рдПрдХ рд╣реА рдмреЛрд▓реНрдЯ рдкрд░ рднреЗрдЬрдирд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, CustomStreamGrouping рджреЛ рдХреЙрд▓ рдкреНрд░рджрд╛рди рдХрд░рддрд╛ рд╣реИ:
рддреИрдпрд╛рд░ - рдкрд╣рд▓реЗ рдЙрдкрдпреЛрдЧ рд╕реЗ рдкрд╣рд▓реЗ рдмреБрд▓рд╛рдпрд╛:
@Override public void prepare(WorkerTopologyContext workerTopologyContext, GlobalStreamId globalStreamId, List<Integer> integers) { tasks = new ArrayList<>(integers);
рдФрд░
рдЪреБрдирд┐рдВрджрд╛ рдХрд╛рд░реНрдп - рдЬрд╣рд╛рдВ рдЯреНрдпреВрдкрд▓ рд╕реЗ рдПрдХ рд╕реВрдЪреА рдЗрдирдкреБрдЯ рдХреЛ рдЦрд┐рд▓рд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдФрд░ рдПрдХ рд╕реВрдЪреА рдЬрд┐рд╕рдореЗрдВ рдЯреБрдкрд▓ рд╕реВрдЪреА рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рд╕реНрдерд┐рддрд┐ рдХреЗ рд▓рд┐рдП рдмреЛрд▓реНрдЯ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рд╢рд╛рдорд┐рд▓ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:
@Override public List<Integer> chooseTasks(int i, List<Object> objects) { List<Integer> rvalue = new ArrayList<>(objects.size()); for(Object o: objects) { Cdr cdr = (Cdr) o; rvalue.add(tasks.get(Math.abs(cdr.getCallSource().hashCode()) % tasks.size())); } return rvalue; }
рдмрджрд▓реЗрдВ рд╢реНрд░рдЧрдЧреНрд░реБрдкрд┐рдВрдЧ рдХреЛ CdrGrouper BasicGroupApp рдХреЗ рд╕рд╛рде рдмрджрд▓реЗрдВ:
builder.setBolt("PrintOutBolt", new PrintOutBolt(), 2). customGrouping("CdrReader", new CdrGrouper());
рднрд╛рдЧреЛ рдФрд░ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░реЗрдВ рдХрд┐ рдпрд╣ рдЗрд░рд╛рджрд╛ рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ:
рдЫрд┐рдкрд╛ рд╣реБрдЖ рдкрд╛рда OUT >> [80] Cdr {callSource = '78119990007', callDestination = '3314931472251135073'
callTime = 17632, clientId = 0, рдореВрд▓реНрдп = 0}
OUT >> [80] Cdr {callSource = '78119990007', callDestination = '4182885669941386786'
рдХреЙрд▓рдЯрд╛рдЗрдо = 31533, рдХреНрд▓рд╛рдЗрдВрдЯрдЖрдИрдбреА = 0, рдореВрд▓реНрдп = 0}
рдЕрдЧрд▓рд╛, рдкрд░рд┐рдпреЛрдЬрдирд╛ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ:
ClientIdBolt - рд╕реЛрд░реНрд╕ рдирдВрдмрд░ рджреНрд╡рд╛рд░рд╛ рдХреНрд▓рд╛рдЗрдВрдЯ рдЖрдИрдбреА рдХреА рдкрд╣рдЪрд╛рди рдХрд░рддрд╛ рд╣реИред
ClientIdGrouper - рдХреНрд▓рд╛рдЗрдВрдЯ рдЖрдИрдбреА рджреНрд╡рд╛рд░рд╛
рд╕рдореВрд╣ ред
RaterBolt - рдмрд┐рд▓рд┐рдВрдЧ рдореЗрдВ рд▓рдЧреЗ рд╣реБрдП рд╣реИрдВред
CalcApp рдХрд╛рд░реНрдпрдХреНрд░рдо рдХрд╛ рдЕрдВрддрд┐рдо рд╕рдВрд╕реНрдХрд░рдг рд╣реИред
рдпрджрд┐ рд╡рд┐рд╖рдп рджрд┐рд▓рдЪрд╕реНрдк рд╣реИ, рддреЛ рдЕрдЧрд▓реЗ рднрд╛рдЧ рдореЗрдВ рдореБрдЭреЗ рдбреЗрдЯрд╛ рд╣рд╛рдирд┐ рдХреЗ рдЦрд┐рд▓рд╛рдл рд╕реБрд░рдХреНрд╖рд╛ рддрдВрддреНрд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░рдиреЗ рдХреА рдЙрдореНрдореАрдж рд╣реИ рдФрд░ рдПрдХ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдХреНрд▓рд╕реНрдЯрд░ рдкрд░ рдЪрд▓ рд░рд╣рд╛ рд╣реИред рдХреЛрдб
GitHub рдкрд░ рдЙрдкрд▓рдмреНрдз
рд╣реИ ред
рдкреБрдирд╢реНрдЪред рдмреЗрд╢рдХ, рдЖрдкрдиреЗ рдЧреАрдд рд╕реЗ рд╢рдмреНрджреЛрдВ рдХреЛ рдирд╣реАрдВ рдирд┐рдХрд╛рд▓рд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдбреЗрдЯрд╛ рдкреНрд░реЛрд╕реЗрд╕рд░ "рдмреЛрд▓реНрдЯ" рдХрд╛ рдирд╛рдо рдХреБрдЫ рднреНрд░рд╛рдордХ рд╣реИ :)
рдпреБрдкреАрдбреАред рд▓реЗрдЦ рдХрд╛
рджреВрд╕рд░рд╛ рднрд╛рдЧ рдкреНрд░рдХрд╛рд╢рд┐рдд рд╣реБрдЖ рд╣реИред