DIY рдЯреВрд▓реАрдВрдЧ рдкреНрд░реЛрдлрд╛рдЗрд▓рд░

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

рдореБрдЦреНрдп рдЖрд╡рд╢реНрдпрдХрддрд╛рдПрдВ рд╕рд╛рджрдЧреА, рдкрд╛рда рдореЛрдб рдореЗрдВ рдЪрд▓рд╛рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдФрд░ рд╡рд╛рд╕реНрддреБрдХрд▓рд╛ рд╕реЗ рд╕реНрд╡рддрдВрддреНрд░рддрд╛ рд╣реИрдВред


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

рдЗрдВрд╕реНрдЯреНрд░реВрдореЗрдВрдЯреЗрд╢рди (рдЗрдВрдЯрд╕реНрдЯреЗрдбреЗрд╢рди) рдмрд╛рдпрдЯреЗрдХреЛрдб рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рдХреЛ рдмрдирд╛рдП рд░рдЦрддрд╛ рд╣реИред
рдорд╛рдирдХ рдкреИрдХреЗрдЬ java.lang.instrument рдЖрдкрдХреЛ рдордХреНрдЦреА рдкрд░ рдЗрд╕реЗ рдмрджрд▓рдиреЗ рдХреА рд╕рдВрднрд╛рд╡рдирд╛ рдХреЗ рд╕рд╛рде рдмрд╛рдпрдЯреЗрдХреЛрдб рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░рдиреЗ рдХреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдореЗрдВ рд╣рд╕реНрддрдХреНрд╖реЗрдк рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред

рдпрд╣ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:
рдЬрд╛рд╡рд╛ рдорд╢реАрди рд╢реБрд░реВ рдХрд░рддреЗ рд╕рдордп, -рдЬреЗрд╡рд╛рдЧреЗрдВрдЯ рд╕реНрд╡рд┐рдЪ рдХреЛ рдЗрдВрдЧрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ: рдЬрд╛рд░-рдлрд╛рдЗрд▓-рдирд╛рдо = рдкреИрд░рд╛рдореАрдЯрд░,
рдЬрд╣рд╛рдБ jar-file-name рдПрдЬреЗрдВрдЯ рдХреА jar рдлрд╝рд╛рдЗрд▓ рдХрд╛ рдкреВрд░реНрдг рдкрде рд╣реИ, рдкреИрд░рд╛рдореАрдЯрд░ рдПрдЬреЗрдВрдЯ рдХреЗ рд▓рд┐рдП рджрд┐рдП рдЧрдП рдкреИрд░рд╛рдореАрдЯрд░ рд╣реИрдВред

рдЬрд╛рд░ рдлрд╝рд╛рдЗрд▓ рдХреЗ рдкреНрд░рдХрдЯрди рдореЗрдВ, рд╡рд┐рдзрд┐ рдпреБрдХреНрдд рд╡рд░реНрдЧ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╣реИ
public static void premain(String args, Instrumentation instrumentation) 

рдПрдЬреЗрдВрдЯ рд▓реЛрдб рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рдХреМрди рд╕реА jvm рдХреЙрд▓ рдХрд░реЗрдЧрд╛ред
рдЗрд╕ рддрдВрддреНрд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╡рд┐рд╡рд░рдг рдпрд╣рд╛рдБ рдкрд╛рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ ред

рд╣рдорд╛рд░реЗ рдПрдЬреЗрдВрдЯ рдХрд╛ рдХрд╛рдо рдЗрд╕ рддрд░рд╣ рд╕реЗ рд▓реЛрдб рдХрд░рдиреЗ рдпреЛрдЧреНрдп рд╡рд░реНрдЧреЛрдВ рдХреЗ рддрд░реАрдХреЛрдВ рдХреЛ рдмрджрд▓рдирд╛ рд╣реИ
рддрд╛рдХрд┐ рдЬрдм рд╣рдо рдкреНрд░рд╡реЗрд╢ рдХрд░реЗрдВ рдФрд░ рдЗрд╕ рд╡рд┐рдзрд┐ рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓реЗрдВ, рддреЛ рд╣рдорд╛рд░реЗ TracerAgent рд╡рд░реНрдЧ рдХреЗ рддрд░реАрдХреЗ рдХрд╣рд▓рд╛рддреЗ рд╣реИрдВ :
  @SuppressWarnings("unused") public static void methodEnter(MethodInfo methodInfo) { methodCallProcessor.methodEnter(methodInfo); } @SuppressWarnings("unused") public static void methodExit() { methodCallProcessor.methodExit(); } 

MethodInfo рд╡рд░реНрдЧ рдХреЗ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рд╡рд┐рдзрд┐ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬрд╛рдирдХрд╛рд░реА рд╣реИред
рдкреНрд░рддреНрдпреЗрдХ рд╕рд╛рдзрди рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдП MethodInfo рдХреЛ рд╕реНрдЯреЛрд░ рдХрд░рдирд╛ рдХрд╣реАрдВ рди рдХрд╣реАрдВ рдЖрд╡рд╢реНрдпрдХ рд╣реИред
рдЗрд╕рдХреЗ рд▓рд┐рдП, рдкреНрд░рддреНрдпреЗрдХ рд╡рд░реНрдЧ рдХреЗ рд▓рд┐рдП рдирд┐рдореНрди рдкреНрд░рдкрддреНрд░ рдХреА рдПрдХ рдЫрд╛рдпрд╛ рд╡рд░реНрдЧ рдмрдирд╛рдИ рдЧрдИ рд╣реИ:
 public class ShadowClassXXX { public static MethodInfo m1 = agent.TracerAgent.getMethodInfo(1L); // MethodInfo   /* .. */ public static MethodInfo m99 = agent.TracerAgent.getMethodInfo(99L); // MethodInfo   } 

рдЪреВрдВрдХрд┐ рд╡рд░реНрдЧ рдХреЗ рдЫрд╛рдпрд╛ рдХреНрд╖реЗрддреНрд░ рд╕реНрдерд┐рд░ рд╣реЛрддреЗ рд╣реИрдВ, рдЗрд╕рд▓рд┐рдП рд╡реЗ рд▓реЛрдб рд╣реЛрдиреЗ рдкрд░ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЖрд░рдВрдн рд╣реЛрддреЗ рд╣реИрдВред рдкреНрд░рддреНрдпреЗрдХ рдЙрддреНрдкрд░рд┐рд╡рд░реНрддрдиреАрдп рд╡рд┐рдзрд┐ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЛрдб рдЬреЛрдбрд╝рд╛ рдЧрдпрд╛ рд╣реИ:
 TracerAgent.methodEnter(ShadowClass.mXXX); 

рдЖрдЦрд┐рд░ рдореЗрдВ
 TracerAgent.methodExit(); 

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

рдЕрдм рдЬрдм рдЖрдк рджрд░реНрдЬ рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рд╡рд┐рдзрд┐ рд╕реЗ рдмрд╛рд╣рд░ рдирд┐рдХрд▓рддреЗ рд╣реИрдВ, рддреЛ рдирд┐рдпрдВрддреНрд░рдг рдХреЛ рд░реЛрдХ рджрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдФрд░
MethodCallProcessor рд╡рд░реНрдЧ рдХреЗ рд╕рдВрдЧрдд рддрд░реАрдХреЛрдВ рдХреЛ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ред

MethodCallProcessor рдереНрд░реЗрдбрд▓реЛрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдереНрд░реЗрдб рдХреЗ рд▓рд┐рдП рдХреЙрд▓ рд╕реНрдЯреИрдХ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд░рддрд╛ рд╣реИред
MethodEnter рдХреЙрд▓ рд╕рдордп рдХреЗ рд╕рд╛рде рд╕реНрдЯреИрдХ рдХреЗ рд▓рд┐рдП MethodCallMarker рдХреЛ рдмрдЪрд╛рддрд╛ рд╣реИ рдФрд░ рдХреЙрд▓ рдХрд╛рдЙрдВрдЯрд░ рдХреЛ рдмрдврд╝рд╛рддрд╛ рд╣реИред
рдпрджрд┐ рд╡рд┐рдзрд┐ рдХреЙрд▓ рдХреЛ рдЯреНрд░реЗрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рддреЛ рдХреЙрд▓ рд╕реНрдЯреИрдХ рдкреНрд░рджрд░реНрд╢рд┐рдд рд╣реЛрддрд╛ рд╣реИред
MethodExit MethodCallMarker рд╕реНрдЯреИрдХ рд╕реЗ рдЪрдпрди рдХрд░рддрд╛ рд╣реИ, рдФрд░ рд╡рд┐рдзрд┐ рдореЗрдВ рдмрд┐рддрд╛рдП рд╕рдордп рдХреЛ рдЕрдкрдиреЗ MethodInfo рдореЗрдВ рдЬреЛрдбрд╝рддрд╛ рд╣реИред

рдзрд╛рдЧрд╛ TracerAgent рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдореЗрдВ рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдФрд░ рд╢рдЯрдбрд╛рдЙрдирд╣реВрдХ рдХреЗ рд╕рд╛рде рдкрдВрдЬреАрдХреГрдд рд╣реИред рдЗрд╕ рдереНрд░реЗрдб рдХреЛ рд╢рдЯрдбрд╛рдЙрди рдЕрдиреБрдХреНрд░рдо jvm рдХреЗ рджреМрд░рд╛рди рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдФрд░ рдПрдХрддреНрд░рд┐рдд рдЖрдБрдХрдбрд╝реЛрдВ рдХреЛ рдкреНрд░рд┐рдВрдЯ рдХрд░реЗрдЧрд╛ред рд╡рд╣рд╛рдВ, рдереНрд░реЗрдб рдХреЛ рд╕рдордп-рд╕рдордп рдкрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдЖрдВрдХрдбрд╝реЗ рдмрдирд╛рдП рдФрд░ рд▓реЙрдиреНрдЪ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред
 рд╡рд┐рдХрд▓реНрдк:
 -рд╡рд╛рдЬреЗрдВрдЯ: <рдПрдЬреЗрдВрдЯ рдХреА рдкреВрд░реА рдлрд╝рд╛рдЗрд▓ jar рдлрд╝рд╛рдЗрд▓> = p: regexp [#t: regexp] [# d: number] [# i: number]
 рдкреА - рдЗрдВрд╕реНрдЯреНрд░реВрдореЗрдВрдЯреЗрдб рдХреНрд▓рд╛рд╕реЗрд╕ (рдкреВрд░рд╛ рдореИрдЪ - рдореИрдЪ)
 рдЯреА - рдЯреНрд░реЗрд╕ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рд╡рд┐рдзрд┐рдпрд╛рдБ (рдЖрдВрд╢рд┐рдХ рдорд┐рд▓рд╛рди - рдЦреЛрдЬреЗрдВ)
 рдбреА - рдбрд┐рдмрдЧ рд╕реНрддрд░ 
 i - рд╕реЗрдХрдВрдб рдореЗрдВ рд╕рд╛рдВрдЦреНрдпрд┐рдХреА рдЙрддреНрдкрд╛рджрди рдХреА рдЕрд╡рдзрд┐ (0 рдЖрд╡рдзрд┐рдХ рдЙрддреНрдкрд╛рджрди рдЕрдХреНрд╖рдо рдХрд░рддрд╛ рд╣реИ)

рд▓реЗрдЦ рд╕реЗ рдХреЛрдб рдХреЗ рд▓рд┐рдП рдЙрджрд╛рд╣рд░рдг рд░рди:
 java -version java version "1.7.0_21" Java(TM) SE Runtime Environment (build 1.7.0_21-b11) Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode) java -XX:-UseSplitVerifier -javaagent:D:\traceragent\target\traceragent-1.0-SNAPSHOT-complete.jar=p:examples.*#d:1#i:5 

javassist рдЕрднреА рднреА рд╣рдореЗрд╢рд╛ рдирдП рд╕рдВрд╕реНрдХрд░рдг 51 рд╡рд░реНрдЧ рдмрд╛рдЗрдЯрдХреЛрдб рдкреНрд░рд╛рд░реВрдк рдХреЗ рд╕рд╛рде рд╕рд╛рдордирд╛ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред
рд╕реНрд╡рд┐рдЪ -XX: -UseSplitVerifier JVM7, рд╡рд┐рд╡рд░рдг рдореЗрдВ рдкреЗрд╢ рдХрд┐рдП рдЧрдП рдирдП рдмрд╛рдЗрдЯрдХреЛрдб рд╕рддреНрдпрд╛рдкрдирдХрд░реНрддрд╛ рдХреЛ рдирд┐рд╖реНрдХреНрд░рд┐рдп рдХрд░рддрд╛ рд╣реИред
рдкрд░рд┐рдгрд╛рдо
 [рдПрдЬреЗрдВрдЯ +] *** рдкреНрд░рджрд░реНрд╢рди рд░рд┐рдкреЛрд░реНрдЯ ***

 рд╢реАрд░реНрд╖ 5 рд╕рдордп рд▓реЗрдиреЗ рд╡рд╛рд▓реЗ рддрд░реАрдХреЗ (рдорд╛рдЗрдХреНрд░реЛрд╕реЗрдХрдВрдб):
           965050 example.data.CashAccountRow $ рдорд╛рд╕реНрдХред рдЕрддрд┐рд░рд┐рдХреНрдд $ 100 (example.data.CashAccountRow $ рдорд╛рд╕реНрдХ)
           779944 example.data.CashAccountRow.setAge (int)
           766023 example.data.CashAccountRow.setGender (int)
           764292 example.data.CashAccountRow.setHeight (int)
           763387 example.data.CashAccountRow.setAmount (int)

 рд╢реАрд░реНрд╖ 5 рдирд╛рдордХ рд╡рд┐рдзрд┐рдпрд╛рдБ:
         22805261 рдЙрджрд╛рд╣рд░рдг.data.CashAccountRow $ рдорд╛рд╕реНрдХред рдЕрддрд┐рд░рд┐рдХреНрдд $ 100 (example.data.CashAccountRow $ рдорд╛рд╕реНрдХ)
          9122242 example.data.CashAccountRow $ shifts.access $ 000 (example.data.CashAccountRow $ shifts)
          2280592 example.data.CashAccountRow.setAge (int)
          2280623 example.data.CashAccountRow.setBitStorage (рд▓рдВрдмреА)
          2280653 example.data.CashAccountRow.setGender (int)

 рд╢реАрд░реНрд╖ 5 рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг:
                1 example.data.CashAccountStore
                1 example.data.CashAccountRow

 [AGENT-] рдкреНрд░рджрд░реНрд╢рди рд░рд┐рдкреЛрд░реНрдЯ рдХрд╛ *** рдЕрдВрдд

 --- рдЫреЛрдбрд╝реЗрдВ ---

 рдорд┐рд▓рд╛рди рдХрд┐рдП рдЧрдП рд░рд┐рдХреЙрд░реНрдб рдХреА рд╕рдВрдЦреНрдпрд╛: 38
 рдмреАрддрд╛ рд╕рдордп: 7707 рдореА
 рдкреНрд░рдпреБрдХреНрдд рдореЗрдореЛрд░реА: 91MB

 [рдПрдЬреЗрдВрдЯ +] *** рдкреНрд░рджрд░реНрд╢рди рд░рд┐рдкреЛрд░реНрдЯ ***

 рд╢реАрд░реНрд╖ 10 рд╕рдордп рд▓реЗрдиреЗ рд╡рд╛рд▓реЗ рддрд░реАрдХреЗ (рдорд╛рдЗрдХреНрд░реЛрд╕реЗрдХрдВрдб):
         36081913 рдЙрджрд╛рд╣рд░рдг .App.main (java.lang.String [])
         20606259 example.data.CashAccountStore ()
         15428502 example.data.CashAccountStore.find2 (example.data.CashAccountStore $ CashAccountFinder)
         12439241 example.data.GenMatcherAMOUNTHEIGHTGENDER.c (example.data.CashAccountRow)
          9469502 example.data.CashAccountRow.getAmount ()
          5928018 example.data.CashAccountRow $ рдорд╛рд╕реНрдХред рдЕрддрд┐рд░рд┐рдХреНрдд $ 100 (example.data.CashAccountRow $ рдорд╛рд╕реНрдХ)
          3392146 example.data.CashAccountRow $ shifts.access $ 000 (example.data.CashAccountRow $ рдкрд╛рд▓реА)
          3279163 example.data.CashAccountRow.setAge (int)
          3271959 example.data.CashAccountRow.setHeight (int)
          3267890 example.data.CashAccountRow.setAmount (int)

 рд╢реАрд░реНрд╖ 10 рдирд╛рдордХ рд╡рд┐рдзрд┐рдпрд╛рдБ:
        140079808 example.data.CashAccountRow $ рдорд╛рд╕реНрдХред рдЕрддрд┐рд░рд┐рдХреНрдд $ 100 (example.data.CashAccountRow $ рдорд╛рд╕реНрдХ)
         80079812 example.data.CashAccountRow $ shifts.access $ 000 (example.data.CashAccountRow $ рдкрд╛рд▓реА)
         40000000 example.data.CashAccountRow.getAmount ()
         30000000 example.data.CashAccountRow.setBitStorage (рд▓рдВрдмреА)
         20,000,000 example.data.GenMatcherAMOUNTHEIGHTGENDER.c (example.data.CashAccountGow)
         10000000 example.data.CashAccountRow.setGender (int)
         10000000 example.data.CashAccountRow.setAge (int)
         10000000 example.data.CashAccountRow.setAmount (int)
         10000000 example.data.CashAccountRow.setHeight (int)
         10000000 example.data.CashAccountRow.getBitStorage ()

 рд╢реАрд░реНрд╖ 10 рд╡рд╕реНрддреБрдУрдВ рдХрд╛ рдирд┐рд░реНрдорд╛рдг:
                3 example.data.CashAccountStore $ CashAccountFinder $ FieldGetter
                3 example.data.CashAccountStore $ CashAccountFinder $ PredicateHolder
                3 example.data.CashAccountRow
                1 example.data.GenMatcherAMOUNTHEIGHTGENDER
                1 example.data.GenMatcherBase
                1 example.data.CashAccountStore $ CashAccountFinder $ HeightFieldGetter
                1 example.data.CashAccountStore $ CashAccountFinder
                1 example.data.CashAccountStore
                1 example.data.CashAccountStore $ CashAccountFinder $ AmountFieldGetter
                1 example.data.CashAccountStore $ CashAccountFinder $ GenderFieldGetter

 [AGENT-] рдкреНрд░рджрд░реНрд╢рди рд░рд┐рдкреЛрд░реНрдЯ рдХрд╛ *** рдЕрдВрдд


рд╕реНрд╡рд╛рднрд╛рд╡рд┐рдХ рд░реВрдк рд╕реЗ, рдХреЙрд▓рд┐рдВрдЧ рдПрдЬреЗрдВрдЯ рддрд░реАрдХреЗ рдкреНрд░рджрд░реНрд╢рди рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред
рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдСрдкрд░реЗрдЯрд┐рдВрдЧ рд╕рдордп рд▓рдЧрднрдЧ 500 рдЧреБрдирд╛ рдмрдврд╝ рдЧрдпрд╛ рд╣реИред
рд▓реЗрдХрд┐рди рдпрд╣ рдПрдХ рдЪрд░рдо рдорд╛рдорд▓рд╛ рд╣реИ рдЬрд╣рд╛рдВ рд▓рдЧрднрдЧ рдЦрд╛рд▓реА рд╢рд░реАрд░ рд╡рд╛рд▓реЗ рддрд░реАрдХреЛрдВ рдХреЛ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╕рд╛рдорд╛рдиреНрдп рдЬреАрд╡рди рдореЗрдВ рдЖрдк рдУрд╡рд░рд╣реЗрдб рдХреЗ рд╕рд╛рде рд░рдЦ рд╕рдХрддреЗ рд╣реИрдВред

рд▓рдХреНрд╖реНрдп рдЗрддрдирд╛ рд╕рдЯреАрдХ рд╕рдордп рдкреНрд░реЛрдлрд╛рдЗрд▓рд┐рдВрдЧ рдирд╣реАрдВ рд╣реИ рдЬрд┐рддрдирд╛ рдХрд┐ рд╕рдЯреАрдХ рдХреЙрд▓,
рдирд┐рд░реНрдорд┐рдд рд╡рд╕реНрддреБрдУрдВ рдФрд░ рдЯреНрд░реЗрд╕ рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ред рдХреЛрдб GitHub рдкрд░ рдЙрдкрд▓рдмреНрдз рд╣реИ ред

рдкреБрдирд╢реНрдЪред рдЖрдкрдХреЛ рдкрд░рд┐рдгрд╛рдореА рдХреЛрдб рдХреЛ рдПрдХ рддреИрдпрд╛рд░-рдХрд┐рдП рдЧрдП рд╡рд╛рдгрд┐рдЬреНрдпрд┐рдХ-рд╕реНрддрд░реАрдп рдкреНрд░реЛрдлрд╛рдЗрд▓рд░ рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ рд╕рдордЭрдирд╛ рдЪрд╛рд╣рд┐рдПред рдпрд╣ рдПрдХ рдкреНрд░рдпреЛрдЧ рд╕реЗ рдЕрдзрд┐рдХ рдХреБрдЫ рдирд╣реАрдВ рд╣реИ, рдЬреЗрд╡реАрдПрдо рдХреЗ рдПрдХ рдЕрдиреНрдп рддрдВрддреНрд░ рдХрд╛ рдЦреБрд▓рд╛рд╕рд╛ рдХрд░рддрд╛ рд╣реИред

Source: https://habr.com/ru/post/In185010/


All Articles