āĻŦā§āĻ¯āĻžāĻš āĻ•ā§‹āĻ¯āĻŧā§‡āĻ°āĻŋ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖā§‡āĻ° āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž āĻāĻŦāĻ‚ āĻ¤āĻžāĻĻā§‡āĻ° āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ (āĻĒāĻ°ā§āĻŦ 1)

āĻŦā§āĻ¯āĻžāĻš āĻ•ā§‹āĻ¯āĻŧā§‡āĻ°āĻŋ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖā§‡āĻ° āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž āĻāĻŦāĻ‚ āĻ¤āĻžāĻĻā§‡āĻ° āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ (āĻĒāĻ°ā§āĻŦ 1)āĻĒā§āĻ°āĻžāĻ¯āĻŧ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ†āĻ§ā§āĻ¨āĻŋāĻ• āĻ¸āĻĢā§āĻŸāĻ“āĻ¯āĻŧā§āĻ¯āĻžāĻ° āĻĒāĻŖā§āĻ¯ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻž āĻ¨āĻŋāĻ¯āĻŧā§‡ āĻ—āĻ āĻŋāĻ¤āĨ¤ āĻĒā§āĻ°āĻžāĻ¯āĻŧāĻļāĻ‡, āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻ¸āĻžāĻ°ā§āĻ­āĻŋāĻ¸ āĻšā§āĻ¯āĻžāĻ¨ā§‡āĻ˛āĻ—ā§āĻ˛āĻŋāĻ° āĻĻā§€āĻ°ā§āĻ˜ āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻ¸āĻŽāĻ¯āĻŧāĻ—ā§āĻ˛āĻŋ āĻ•āĻ°ā§āĻŽāĻ•ā§āĻˇāĻŽāĻ¤āĻž āĻ¸āĻŽāĻ¸ā§āĻ¯āĻžāĻ° āĻ‰āĻ¤ā§āĻ¸ āĻšāĻ¯āĻŧā§‡ āĻ“āĻ ā§‡āĨ¤ āĻāĻ‡ āĻ§āĻ°āĻ¨ā§‡āĻ° āĻ¸āĻŽāĻ¸ā§āĻ¯āĻžāĻ° āĻ†āĻĻāĻ°ā§āĻļ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻšāĻ˛ āĻāĻ•āĻžāĻ§āĻŋāĻ• āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻ¸āĻžāĻ°ā§āĻ­āĻŋāĻ¸ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻĒā§āĻ¯āĻžāĻ•ā§‡āĻœā§‡ āĻĒā§āĻ¯āĻžāĻ• āĻ•āĻ°āĻž, āĻ¯āĻžāĻ•ā§‡ āĻŦā§āĻ¯āĻžāĻšāĻŋāĻ‚ āĻŦāĻ˛āĻž āĻšāĻ¯āĻŧāĨ¤

āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ āĻŦā§āĻ¯āĻžāĻš āĻĒā§āĻ°āĻ¸ā§‡āĻ¸āĻŋāĻ‚ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡āĻ¨, āĻ¤āĻžāĻšāĻ˛ā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻ•āĻ°ā§āĻŽāĻ•ā§āĻˇāĻŽāĻ¤āĻž āĻŦāĻž āĻ•ā§‹āĻĄ āĻ¸ā§āĻĒāĻˇā§āĻŸāĻ¤āĻžāĻ° āĻĒāĻ°āĻŋāĻĒā§āĻ°ā§‡āĻ•ā§āĻˇāĻŋāĻ¤ā§‡ āĻĢāĻ˛āĻžāĻĢāĻ˛ā§‡ āĻ–ā§āĻļāĻŋ āĻ¨āĻžāĻ“ āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤ āĻāĻ‡ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻŸāĻŋ āĻ•āĻ˛āĻžāĻ°ā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ¤āĻ¤āĻŸāĻž āĻ¸āĻšāĻœ āĻ¨āĻ¯āĻŧ āĻ¯āĻ¤āĻŸāĻž āĻ†āĻĒāĻ¨āĻŋ āĻ­āĻžāĻŦāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻ‰āĻĻā§āĻĻā§‡āĻļā§āĻ¯ā§‡ āĻāĻŦāĻ‚ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻĒāĻ°āĻŋāĻ¸ā§āĻĨāĻŋāĻ¤āĻŋāĻ¤ā§‡, āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨āĻ—ā§āĻ˛āĻŋ āĻŦā§āĻ¯āĻžāĻĒāĻ•āĻ­āĻžāĻŦā§‡ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻŋāĻ¤ āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ‰āĻĻāĻžāĻšāĻ°āĻŖ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡, āĻ†āĻŽāĻŋ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ° āĻ¸ā§āĻŦāĻŋāĻ§āĻž āĻāĻŦāĻ‚ āĻ…āĻ¸ā§āĻŦāĻŋāĻ§āĻž āĻĻā§‡āĻ–āĻžāĻŦāĨ¤

āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ā§€ āĻĒā§āĻ°āĻ•āĻ˛ā§āĻĒ

āĻ¸ā§āĻĒāĻˇā§āĻŸāĻ¤āĻžāĻ° āĻœāĻ¨ā§āĻ¯, āĻ†āĻŽāĻŋ āĻŦāĻ°ā§āĻ¤āĻŽāĻžāĻ¨ā§‡ āĻ¯ā§‡ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋāĻ¤ā§‡ āĻ•āĻžāĻœ āĻ•āĻ°āĻ›āĻŋ āĻ¤āĻžāĻ° āĻāĻ•āĻŸāĻŋ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ° āĻ‰āĻĻāĻžāĻšāĻ°āĻŖ āĻĻā§‡āĻ–āĻŋāĨ¤

āĻ‰āĻĻāĻžāĻšāĻ°āĻŖā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻĒā§āĻ˛ā§āĻ¯āĻžāĻŸāĻĢāĻ°ā§āĻŽ āĻ¨āĻŋāĻ°ā§āĻŦāĻžāĻšāĻ¨ā§‡āĻ° āĻŦā§āĻ¯āĻžāĻ–ā§āĻ¯āĻžāĻĻā§āĻ°ā§āĻŦāĻ˛ āĻĒāĻžāĻ°āĻĢāĻ°āĻŽā§āĻ¯āĻžāĻ¨ā§āĻ¸ā§‡āĻ° āĻ¸āĻŽāĻ¸ā§āĻ¯āĻžāĻŸāĻŋ āĻŦā§‡āĻļ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻāĻŦāĻ‚ āĻ•ā§‹āĻ¨āĻ“ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ­āĻžāĻˇāĻž āĻŦāĻž āĻĒā§āĻ˛ā§āĻ¯āĻžāĻŸāĻĢāĻ°ā§āĻŽāĻ•ā§‡ āĻĒā§āĻ°āĻ­āĻžāĻŦāĻŋāĻ¤ āĻ•āĻ°ā§‡ āĻ¨āĻžāĨ¤ āĻāĻ‡ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§āĻŸāĻŋ āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž āĻāĻŦāĻ‚ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻĒā§āĻ°āĻĻāĻ°ā§āĻļāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻ¸ā§āĻĒā§āĻ°āĻŋāĻ‚ + āĻ•ā§‹āĻŸāĻ˛āĻŋāĻ¨ āĻ•ā§‹āĻĄ āĻ‰āĻĻāĻžāĻšāĻ°āĻŖ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦā§‡āĨ¤ Kotlin āĻœāĻžāĻ­āĻž āĻāĻŦāĻ‚ C# āĻĄā§‡āĻ­ā§‡āĻ˛āĻĒāĻžāĻ°āĻĻā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ¸āĻŽāĻžāĻ¨āĻ­āĻžāĻŦā§‡ āĻŦā§‹āĻ§āĻ—āĻŽā§āĻ¯ (āĻŦāĻž āĻŦā§‹āĻ§āĻ—āĻŽā§āĻ¯), āĻ‰āĻĒāĻ°āĻ¨ā§āĻ¤ā§, āĻ•ā§‹āĻĄ āĻœāĻžāĻ­āĻžāĻ° āĻ¤ā§āĻ˛āĻ¨āĻžāĻ¯āĻŧ āĻ†āĻ°ā§‹ āĻ•āĻŽāĻĒā§āĻ¯āĻžāĻ•ā§āĻŸ āĻāĻŦāĻ‚ āĻŦā§‹āĻ§āĻ—āĻŽā§āĻ¯āĨ¤ āĻ–āĻžāĻāĻŸāĻŋ āĻœāĻžāĻ­āĻž āĻĄā§‡āĻ­ā§‡āĻ˛āĻĒāĻžāĻ°āĻĻā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŦā§‹āĻāĻž āĻ¸āĻšāĻœ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯, āĻ†āĻŽāĻŋ āĻ•ā§‹āĻŸāĻ˛āĻŋāĻ¨ā§‡āĻ° āĻ•āĻžāĻ˛ā§‹ āĻœāĻžāĻĻā§ āĻāĻĄāĻŧāĻžāĻŦ āĻāĻŦāĻ‚ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ¸āĻžāĻĻāĻž āĻœāĻžāĻĻā§ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦ (āĻ˛āĻŽā§āĻŦāĻ•ā§‡āĻ° āĻšā§‡āĻ¤āĻ¨āĻžāĻ¯āĻŧ)āĨ¤ āĻ•āĻ¯āĻŧā§‡āĻ•āĻŸāĻŋ āĻāĻ•ā§āĻ¸āĻŸā§‡āĻ¨āĻļāĻ¨ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻĨāĻžāĻ•āĻŦā§‡, āĻ¤āĻŦā§‡ āĻ¤āĻžāĻ°āĻž āĻĒā§āĻ°āĻ•ā§ƒāĻ¤āĻĒāĻ•ā§āĻˇā§‡ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻœāĻžāĻ­āĻž āĻĒā§āĻ°ā§‹āĻ—ā§āĻ°āĻžāĻŽāĻžāĻ°āĻĻā§‡āĻ° āĻ•āĻžāĻ›ā§‡ āĻ¸ā§āĻŸā§āĻ¯āĻžāĻŸāĻŋāĻ• āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻšāĻŋāĻ¸āĻžāĻŦā§‡ āĻĒāĻ°āĻŋāĻšāĻŋāĻ¤, āĻ¤āĻžāĻ‡ āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻ›ā§‹āĻŸ āĻšāĻŋāĻ¨āĻŋ āĻ¯āĻž āĻ–āĻžāĻŦāĻžāĻ°ā§‡āĻ° āĻ¸ā§āĻŦāĻžāĻĻ āĻ¨āĻˇā§āĻŸ āĻ•āĻ°āĻŦā§‡ āĻ¨āĻžāĨ¤
āĻāĻ•āĻŸāĻŋ āĻ¨āĻĨāĻŋ āĻ…āĻ¨ā§āĻŽā§‹āĻĻāĻ¨ āĻ¸ā§‡āĻŦāĻž āĻ†āĻ›ā§‡. āĻ•ā§‡āĻ‰ āĻāĻ•āĻŸāĻŋ āĻ¨āĻĨāĻŋ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§‡ āĻāĻŦāĻ‚ āĻ†āĻ˛ā§‹āĻšāĻ¨āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻœāĻŽāĻž āĻĻā§‡āĻ¯āĻŧ, āĻ¯āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨āĻž āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ, āĻāĻŦāĻ‚ āĻļā§‡āĻˇ āĻĒāĻ°ā§āĻ¯āĻ¨ā§āĻ¤ āĻ¨āĻĨāĻŋāĻ¤ā§‡ āĻ¸āĻŽā§āĻŽāĻ¤ āĻšāĻ¯āĻŧāĨ¤ āĻ…āĻ¨ā§āĻŽā§‹āĻĻāĻ¨ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻž āĻ¨āĻŋāĻœā§‡āĻ‡ āĻ¨āĻĨāĻŋ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ•āĻŋāĻ›ā§āĻ‡ āĻœāĻžāĻ¨ā§‡ āĻ¨āĻž: āĻāĻŸāĻŋ āĻ•ā§‡āĻŦāĻ˛āĻŽāĻžāĻ¤ā§āĻ° āĻ›ā§‹āĻŸ āĻ…āĻ¤āĻŋāĻ°āĻŋāĻ•ā§āĻ¤ āĻĢāĻžāĻ‚āĻļāĻ¨ āĻ¸āĻš āĻ…āĻ¨ā§āĻŽā§‹āĻĻāĻ¨āĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻšā§āĻ¯āĻžāĻŸ āĻ¯āĻž āĻ†āĻŽāĻ°āĻž āĻāĻ–āĻžāĻ¨ā§‡ āĻŦāĻŋāĻŦā§‡āĻšāĻ¨āĻž āĻ•āĻ°āĻŦ āĻ¨āĻžāĨ¤

āĻ¸ā§āĻ¤āĻ°āĻžāĻ‚, āĻ¤āĻžāĻĻā§‡āĻ° āĻĒā§āĻ°āĻ¤ā§āĻ¯ā§‡āĻ•āĻŸāĻŋāĻ¤ā§‡ āĻ…āĻ‚āĻļāĻ—ā§āĻ°āĻšāĻŖāĻ•āĻžāĻ°ā§€āĻĻā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻĒā§‚āĻ°ā§āĻŦāĻ¨āĻŋāĻ°ā§āĻ§āĻžāĻ°āĻŋāĻ¤ āĻ¸ā§‡āĻŸ āĻ¸āĻš āĻšā§āĻ¯āĻžāĻŸ āĻ°ā§āĻŽ (āĻ¨āĻĨāĻŋāĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•āĻŋāĻ¤) āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤ āĻ¨āĻŋāĻ¯āĻŧāĻŽāĻŋāĻ¤ āĻšā§āĻ¯āĻžāĻŸā§‡āĻ° āĻŽāĻ¤ā§‹, āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻĒāĻžāĻ ā§āĻ¯ āĻāĻŦāĻ‚ āĻĢāĻžāĻ‡āĻ˛ āĻĨāĻžāĻ•ā§‡ āĻāĻŦāĻ‚ āĻ‰āĻ¤ā§āĻ¤āĻ° āĻŦāĻž āĻĢāĻ°ā§‹āĻ¯āĻŧāĻžāĻ°ā§āĻĄ āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡:

data class ChatMessage(
  // nullable Ņ‚Đ°Đē ĐēĐ°Đē ĐŋĐžŅĐ˛ĐģŅĐĩŅ‚ŅŅ Ņ‚ĐžĐģŅŒĐēĐž ĐŋĐžŅĐģĐĩ persist
  val id: Long? = null,
  /** ĐĄŅŅ‹ĐģĐēĐ° ĐŊĐ° Đ°Đ˛Ņ‚ĐžŅ€Đ° */
  val author: UserReference,
  /** ĐĄĐžĐžĐąŅ‰ĐĩĐŊиĐĩ */
  val message: String,
  /** ĐĄŅŅ‹ĐģĐēи ĐŊĐ° Đ°Ņ‚Ņ‚Đ°Ņ‡Đ¸ */
  // Đ¸Đˇ-Са ĐžŅĐžĐąĐĩĐŊĐŊĐžŅŅ‚ĐĩĐš ŅĐ˛ŅĐˇĐēи JPA+ĐĄĐŖБД ĐŋŅ€ĐžŅ‰Đĩ ĐŋОддĐĩŅ€ĐļиваŅ‚ŅŒ Đ¸ null, Đ¸ ĐŋŅƒŅŅ‚Ņ‹Đĩ ŅĐŋиŅĐēи
  val files: List<FileReference>? = null,
  /** Đ•ŅĐģи ŅĐ˛ĐģŅĐĩŅ‚ŅŅ ĐžŅ‚вĐĩŅ‚ĐžĐŧ, Ņ‚Đž ĐˇĐ´ĐĩŅŅŒ ĐąŅƒĐ´ĐĩŅ‚ ĐžŅ€Đ¸ĐŗиĐŊĐ°Đģ */
  val replyTo: ChatMessage? = null,
  /** Đ•ŅĐģи ŅĐ˛ĐģŅĐĩŅ‚ŅŅ ĐŋĐĩŅ€ĐĩŅŅ‹ĐģĐēОК, Ņ‚Đž ĐˇĐ´ĐĩŅŅŒ ĐąŅƒĐ´ĐĩŅ‚ ĐžŅ€Đ¸ĐŗиĐŊĐ°Đģ */
  val forwardFrom: ChatMessage? = null
)

āĻĢāĻžāĻ‡āĻ˛ āĻāĻŦāĻ‚ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻ˛āĻŋāĻ™ā§āĻ•āĻ—ā§āĻ˛āĻŋ āĻ…āĻ¨ā§āĻ¯āĻžāĻ¨ā§āĻ¯ āĻĄā§‹āĻŽā§‡āĻ¨ā§‡āĻ° āĻ˛āĻŋāĻ™ā§āĻ•āĨ¤ āĻāĻ–āĻžāĻ¨ā§‡ āĻ†āĻŽāĻ°āĻž āĻāĻ‡ āĻŽāĻ¤ āĻŦāĻžāĻ¸ āĻ•āĻ°āĻŋ:

typealias FileReference Long
typealias UserReference Long

āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ° āĻĄā§‡āĻŸāĻž āĻ•ā§€āĻ•ā§āĻ˛ā§‹āĻ•ā§‡ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ āĻāĻŦāĻ‚ REST āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻĒā§āĻ¨āĻ°ā§āĻĻā§āĻ§āĻžāĻ° āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĨ¤ āĻĢāĻžāĻ‡āĻ˛āĻ—ā§āĻ˛āĻŋāĻ° āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡āĻ“ āĻāĻ•āĻ‡ āĻ°āĻ•āĻŽ āĻšāĻ¯āĻŧ: āĻĢāĻžāĻ‡āĻ˛ āĻāĻŦāĻ‚ āĻ¸ā§‡āĻ—ā§āĻ˛āĻŋāĻ° āĻ¸āĻŽā§āĻĒāĻ°ā§āĻ•ā§‡ āĻ¤āĻĨā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻĒā§ƒāĻĨāĻ• āĻĢāĻžāĻ‡āĻ˛ āĻ¸ā§āĻŸā§‹āĻ°ā§‡āĻœ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ¤ā§‡ āĻĨāĻžāĻ•ā§‡ā§ˇ

āĻāĻ‡ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ•āĻ˛ āĻšāĻ¯āĻŧ āĻ­āĻžāĻ°ā§€ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§. āĻāĻ° āĻŽāĻžāĻ¨ā§‡ āĻšāĻ˛ āĻ¯ā§‡ āĻāĻ‡ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻ—ā§āĻ˛āĻŋ āĻĒāĻ°āĻŋāĻŦāĻšāĻ¨ā§‡āĻ° āĻ“āĻ­āĻžāĻ°āĻšā§‡āĻĄ āĻāĻ•āĻŸāĻŋ āĻ¤ā§ƒāĻ¤ā§€āĻ¯āĻŧ āĻĒāĻ•ā§āĻˇā§‡āĻ° āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻž āĻĻā§āĻŦāĻžāĻ°āĻž āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ¯ā§‡ āĻ¸āĻŽāĻ¯āĻŧ āĻ˛āĻžāĻ—ā§‡ āĻ¤āĻžāĻ° āĻšā§‡āĻ¯āĻŧā§‡ āĻ…āĻ¨ā§‡āĻ• āĻŦā§‡āĻļāĻŋāĨ¤ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻĒāĻ°ā§€āĻ•ā§āĻˇāĻžāĻ° āĻŦā§‡āĻžā§āĻšāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡, āĻāĻ‡ āĻ§āĻ°āĻ¨ā§‡āĻ° āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ—ā§āĻ˛āĻŋāĻ° āĻœāĻ¨ā§āĻ¯ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻ•āĻ˛ āĻŸāĻžāĻ‡āĻŽ āĻšāĻ˛ 100 ms, āĻ¤āĻžāĻ‡ āĻ†āĻŽāĻ°āĻž āĻ­āĻŦāĻŋāĻˇā§āĻ¯āĻ¤ā§‡ āĻāĻ‡ āĻ¨āĻŽā§āĻŦāĻ°āĻ—ā§āĻ˛āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦā§ˇ

āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧ āĻ¤āĻĨā§āĻ¯ āĻ¸āĻš āĻļā§‡āĻˇ āĻāĻ¨ āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻ—ā§āĻ˛āĻŋ āĻĒā§‡āĻ¤ā§‡ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ REST āĻ•āĻ¨ā§āĻŸā§āĻ°ā§‹āĻ˛āĻžāĻ° āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻ…āĻ°ā§āĻĨāĻžā§Ž, āĻ†āĻŽāĻ°āĻž āĻŦāĻŋāĻļā§āĻŦāĻžāĻ¸ āĻ•āĻ°āĻŋ āĻ¯ā§‡ āĻĢā§āĻ°āĻ¨ā§āĻŸāĻāĻ¨ā§āĻĄā§‡āĻ° āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻŽāĻĄā§‡āĻ˛ āĻĒā§āĻ°āĻžāĻ¯āĻŧ āĻāĻ•āĻ‡ āĻāĻŦāĻ‚ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻĄā§‡āĻŸāĻž āĻĒāĻžāĻ āĻžāĻ¨ā§‹ āĻĻāĻ°āĻ•āĻžāĻ°āĨ¤ āĻĢā§āĻ°āĻ¨ā§āĻŸ-āĻāĻ¨ā§āĻĄ āĻŽāĻĄā§‡āĻ˛ā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻĒāĻžāĻ°ā§āĻĨāĻ•ā§āĻ¯ āĻšāĻ˛ āĻ¯ā§‡ āĻĢāĻžāĻ‡āĻ˛ āĻāĻŦāĻ‚ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€āĻ•ā§‡ āĻ¤āĻžāĻĻā§‡āĻ° āĻ˛āĻŋāĻ™ā§āĻ• āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ āĻ¸āĻžāĻŽāĻžāĻ¨ā§āĻ¯ āĻĄāĻŋāĻ•ā§āĻ°āĻŋāĻĒā§āĻŸ āĻ•āĻ°āĻž āĻĢāĻ°ā§āĻŽā§‡ āĻ‰āĻĒāĻ¸ā§āĻĨāĻžāĻĒāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡:

/** Đ’ Ņ‚Đ°ĐēĐžĐŧ Đ˛Đ¸Đ´Đĩ ĐžŅ‚Đ´Đ°ŅŽŅ‚ŅŅ ŅŅŅ‹ĐģĐēи ĐŊĐ° ŅŅƒŅ‰ĐŊĐžŅŅ‚и Đ´ĐģŅ Ņ„Ņ€ĐžĐŊŅ‚Đ° */
data class ReferenceUI(
  /** Đ˜Đ´ĐĩĐŊŅ‚иŅ„иĐēĐ°Ņ‚ĐžŅ€ Đ´ĐģŅ url */
  val ref: String,
  /** Đ’идиĐŧĐžĐĩ ĐŋĐžĐģŅŒĐˇĐžĐ˛Đ°Ņ‚ĐĩĐģŅŽ ĐŊаСваĐŊиĐĩ ŅŅŅ‹ĐģĐēи */
  val name: String
)
data class ChatMessageUI(
  val id: Long,
  /** ĐĄŅŅ‹ĐģĐēĐ° ĐŊĐ° Đ°Đ˛Ņ‚ĐžŅ€Đ° */
  val author: ReferenceUI,
  /** ĐĄĐžĐžĐąŅ‰ĐĩĐŊиĐĩ */
  val message: String,
  /** ĐĄŅŅ‹ĐģĐēи ĐŊĐ° Đ°Ņ‚Ņ‚Đ°Ņ‡Đ¸ */
  val files: List<ReferenceUI>,
  /** Đ•ŅĐģи ŅĐ˛ĐģŅŅ‚ŅŅ ĐžŅ‚вĐĩŅ‚ĐžĐŧ, Ņ‚Đž ĐˇĐ´ĐĩŅŅŒ ĐąŅƒĐ´ĐĩŅ‚ ĐžŅ€Đ¸ĐŗиĐŊĐ°Đģ */
  val replyTo: ChatMessageUI? = null,
  /** Đ•ŅĐģи ŅĐ˛ĐģŅŅ‚ŅŅ ĐŋĐĩŅ€ĐĩŅŅ‹ĐģĐēОК, Ņ‚Đž ĐˇĐ´ĐĩŅŅŒ ĐąŅƒĐ´ĐĩŅ‚ ĐžŅ€Đ¸ĐŗиĐŊĐ°Đģ */
  val forwardFrom: ChatMessageUI? = null
)

āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ¨āĻŋāĻŽā§āĻ¨āĻ˛āĻŋāĻ–āĻŋāĻ¤āĻ—ā§āĻ˛āĻŋ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡:

interface ChatRestApi {
  fun getLast(nInt): List<ChatMessageUI>
}

UI āĻĒā§‹āĻ¸ā§āĻŸāĻĢāĻŋāĻ•ā§āĻ¸ āĻŽāĻžāĻ¨ā§‡ āĻĢā§āĻ°āĻ¨ā§āĻŸāĻāĻ¨ā§āĻĄā§‡āĻ° āĻœāĻ¨ā§āĻ¯ DTO āĻŽāĻĄā§‡āĻ˛, āĻ…āĻ°ā§āĻĨāĻžā§Ž REST āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ¯āĻž āĻĒāĻ°āĻŋāĻŦā§‡āĻļāĻ¨ āĻ•āĻ°āĻž āĻ‰āĻšāĻŋāĻ¤āĨ¤

āĻāĻ–āĻžāĻ¨ā§‡ āĻ†āĻļā§āĻšāĻ°ā§āĻ¯ā§‡āĻ° āĻŦāĻŋāĻˇāĻ¯āĻŧ āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ āĻ¯ā§‡ āĻ†āĻŽāĻ°āĻž āĻ•ā§‹āĻ¨ā§‹ āĻšā§āĻ¯āĻžāĻŸ āĻ†āĻ‡āĻĄāĻŋ āĻĒāĻžāĻ¸ āĻ•āĻ°āĻ›āĻŋ āĻ¨āĻž āĻāĻŽāĻ¨āĻ•āĻŋ ChatMessage/ChatMessageUI āĻŽāĻĄā§‡āĻ˛ā§‡āĻ° āĻāĻ•āĻŸāĻŋāĻ“ āĻ¨ā§‡āĻ‡āĨ¤ āĻ†āĻŽāĻŋ āĻ‡āĻšā§āĻ›āĻžāĻ•ā§ƒāĻ¤āĻ­āĻžāĻŦā§‡ āĻāĻŸāĻŋ āĻ•āĻ°ā§‡āĻ›āĻŋ āĻ¯āĻžāĻ¤ā§‡ āĻ‰āĻĻāĻžāĻšāĻ°āĻŖāĻ—ā§āĻ˛āĻŋāĻ° āĻ•ā§‹āĻĄ āĻŦāĻŋāĻļā§ƒāĻ™ā§āĻ–āĻ˛ āĻ¨āĻž āĻšāĻ¯āĻŧ (āĻšā§āĻ¯āĻžāĻŸāĻ—ā§āĻ˛āĻŋ āĻŦāĻŋāĻšā§āĻ›āĻŋāĻ¨ā§āĻ¨, āĻ¤āĻžāĻ‡ āĻ†āĻŽāĻ°āĻž āĻ§āĻ°ā§‡ āĻ¨āĻŋāĻ¤ā§‡ āĻĒāĻžāĻ°āĻŋ āĻ¯ā§‡ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ•ā§‡āĻŦāĻ˛ āĻāĻ•āĻŸāĻŋāĻ‡ āĻ†āĻ›ā§‡)āĨ¤

āĻĻāĻžāĻ°ā§āĻļāĻ¨āĻŋāĻ• āĻĄāĻŋāĻ—ā§āĻ°ā§‡āĻļāĻ¨ChatMessageUI āĻ•ā§āĻ˛āĻžāĻ¸ āĻāĻŦāĻ‚ ChatRestApi.getLast āĻ‰āĻ­āĻ¯āĻŧ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ‡ āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻĄā§‡āĻŸāĻž āĻŸāĻžāĻ‡āĻĒ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ¯āĻ–āĻ¨ āĻĒā§āĻ°āĻ•ā§ƒāĻ¤āĻĒāĻ•ā§āĻˇā§‡ āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻ…āĻ°ā§āĻĄāĻžāĻ° āĻ•āĻ°āĻž āĻ¸ā§‡āĻŸāĨ¤ āĻāĻŸāĻŋ JDK-āĻ¤ā§‡ āĻ–āĻžāĻ°āĻžāĻĒ, āĻ¤āĻžāĻ‡ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻĢā§‡āĻ¸ āĻ¸ā§āĻ¤āĻ°ā§‡ āĻ‰āĻĒāĻžāĻĻāĻžāĻ¨āĻ—ā§āĻ˛āĻŋāĻ° āĻ•ā§āĻ°āĻŽ āĻ˜ā§‹āĻˇāĻŖāĻž āĻ•āĻ°āĻž (āĻ¸āĻ‚āĻ¯ā§‹āĻœāĻ¨ āĻāĻŦāĻ‚ āĻ¸āĻ°āĻžāĻ¨ā§‹āĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ•ā§āĻ°āĻŽ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻž) āĻ•āĻžāĻœ āĻ•āĻ°āĻŦā§‡ āĻ¨āĻžāĨ¤ āĻ¸ā§āĻ¤āĻ°āĻžāĻ‚ āĻ…āĻ°ā§āĻĄāĻžāĻ° āĻ•āĻ°āĻž āĻ¸ā§‡āĻŸā§‡āĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻšāĻ¯āĻŧ āĻāĻŽāĻ¨ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻ…āĻ­ā§āĻ¯āĻžāĻ¸ āĻšāĻ¯āĻŧā§‡ āĻ‰āĻ ā§‡āĻ›ā§‡ (āĻāĻ•āĻŸāĻŋ āĻ˛āĻŋāĻ™ā§āĻ•āĻĄāĻšā§āĻ¯āĻžāĻļāĻ¸ā§‡āĻŸāĻ“ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡, āĻ¤āĻŦā§‡ āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻĢā§‡āĻ¸ āĻ¨āĻ¯āĻŧ)āĨ¤
āĻ—ā§āĻ°ā§āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖ āĻ¸ā§€āĻŽāĻžāĻŦāĻĻā§āĻ§āĻ¤āĻž: āĻ†āĻŽāĻ°āĻž āĻ…āĻ¨ā§āĻŽāĻžāĻ¨ āĻ•āĻ°āĻŦ āĻ¯ā§‡ āĻ‰āĻ¤ā§āĻ¤āĻ° āĻŦāĻž āĻ¸ā§āĻĨāĻžāĻ¨āĻžāĻ¨ā§āĻ¤āĻ°ā§‡āĻ° āĻ•ā§‹āĻ¨ āĻĻā§€āĻ°ā§āĻ˜ āĻšā§‡āĻ‡āĻ¨ āĻ¨ā§‡āĻ‡āĨ¤ āĻ…āĻ°ā§āĻĨāĻžā§Ž, āĻ¤āĻžāĻ°āĻž āĻŦāĻŋāĻĻā§āĻ¯āĻŽāĻžāĻ¨, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻ¤āĻžāĻĻā§‡āĻ° āĻĻā§ˆāĻ°ā§āĻ˜ā§āĻ¯ āĻ¤āĻŋāĻ¨āĻŸāĻŋ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻ…āĻ¤āĻŋāĻ•ā§āĻ°āĻŽ āĻ•āĻ°ā§‡ āĻ¨āĻžāĨ¤ āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻ—ā§āĻ˛āĻŋāĻ° āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻšā§‡āĻ‡āĻ¨āĻŸāĻŋ āĻ…āĻŦāĻļā§āĻ¯āĻ‡ āĻĢā§āĻ°āĻ¨ā§āĻŸāĻāĻ¨ā§āĻĄā§‡ āĻĒā§āĻ°ā§‡āĻ°āĻŖ āĻ•āĻ°āĻž āĻ‰āĻšāĻŋāĻ¤āĨ¤

āĻŦāĻžāĻšā§āĻ¯āĻŋāĻ• āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ—ā§āĻ˛āĻŋ āĻĨā§‡āĻ•ā§‡ āĻĄā§‡āĻŸāĻž āĻ—ā§āĻ°āĻšāĻŖ āĻ•āĻ°āĻ¤ā§‡ āĻ¨āĻŋāĻŽā§āĻ¨āĻ˛āĻŋāĻ–āĻŋāĻ¤ APIāĻ—ā§āĻ˛āĻŋ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡:

interface ChatMessageRepository {
  fun findLast(nInt): List<ChatMessage>
}
data class FileHeadRemote(
  val id: FileReference,
  val name: String
)
interface FileRemoteApi {
  fun getHeadById(idFileReference): FileHeadRemote
  fun getHeadsByIds(idSet<FileReference>): Set<FileHeadRemote>
  fun getHeadsByIds(idList<FileReference>): List<FileHeadRemote>
  fun getHeadsByChat(): List<FileHeadRemote>
}
data class UserRemote(
  val id: UserReference,
  val name: String
)
interface UserRemoteApi {
  fun getUserById(idUserReference): UserRemote
  fun getUsersByIds(idSet<UserReference>): Set<UserRemote>
  fun getUsersByIds(idList<UserReference>): List<UserRemote>
}

āĻāĻŸāĻŋ āĻĻā§‡āĻ–āĻž āĻ¯āĻžāĻ¯āĻŧ āĻ¯ā§‡ āĻŦāĻšāĻŋāĻ°āĻžāĻ—āĻ¤ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ—ā§āĻ˛āĻŋ āĻĒā§āĻ°āĻžāĻĨāĻŽāĻŋāĻ•āĻ­āĻžāĻŦā§‡ āĻŦā§āĻ¯āĻžāĻš āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ¸āĻ°āĻŦāĻ°āĻžāĻš āĻ•āĻ°ā§‡ āĻāĻŦāĻ‚ āĻ‰āĻ­āĻ¯āĻŧ āĻ¸āĻ‚āĻ¸ā§āĻ•āĻ°āĻŖā§‡: āĻ¸ā§‡āĻŸā§‡āĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ (āĻ‰āĻĒāĻžāĻĻāĻžāĻ¨ā§‡āĻ° āĻ•ā§āĻ°āĻŽ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ¨āĻž āĻ•āĻ°ā§‡, āĻ…āĻ¨āĻ¨ā§āĻ¯ āĻ•ā§€ āĻ¸āĻš) āĻāĻŦāĻ‚ āĻ¤āĻžāĻ˛āĻŋāĻ•āĻžāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ (āĻ¸āĻĻā§ƒāĻļ āĻšāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ - āĻ…āĻ°ā§āĻĄāĻžāĻ°āĻŸāĻŋ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ)āĨ¤

āĻ¸āĻšāĻœ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨

āĻ¨āĻŋāĻˇā§āĻĒāĻžāĻĒ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨

āĻ†āĻŽāĻžāĻĻā§‡āĻ° REST āĻ•āĻ¨ā§āĻŸā§āĻ°ā§‹āĻ˛āĻžāĻ°ā§‡āĻ° āĻĒā§āĻ°āĻĨāĻŽ āĻ¨āĻŋāĻ°ā§āĻŦā§‹āĻ§ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ āĻŦā§‡āĻļāĻŋāĻ°āĻ­āĻžāĻ— āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡ āĻāĻ‡āĻ°āĻ•āĻŽ āĻ•āĻŋāĻ›ā§ āĻĻā§‡āĻ–āĻžāĻŦā§‡:

class ChatRestController(
  private val messageRepository: ChatMessageRepository,
  private val userRepository: UserRemoteApi,
  private val fileRepository: FileRemoteApi
) : ChatRestApi {
  override fun getLast(nInt) =
    messageRepository.findLast(n)
      .map it.toFrontModel() }
  
  private fun ChatMessage.toFrontModel(): ChatMessageUI =
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = userRepository.getUserById(author).toFrontReference(),
      message = message,
      files = files?.let files ->
        fileRepository.getHeadsByIds(files)
          .map it.toFrontReference() }
      } ?: listOf(),
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
}

āĻ¸āĻŦāĻ•āĻŋāĻ›ā§ āĻ–ā§āĻŦ āĻĒāĻ°āĻŋāĻˇā§āĻ•āĻžāĻ°, āĻāĻŦāĻ‚ āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻŦāĻĄāĻŧ āĻĒā§āĻ˛āĻžāĻ¸āĨ¤

āĻ†āĻŽāĻ°āĻž āĻŦā§āĻ¯āĻžāĻš āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŋ āĻāĻŦāĻ‚ āĻŦā§āĻ¯āĻžāĻšāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻāĻ•āĻŸāĻŋ āĻŦāĻšāĻŋāĻ°āĻžāĻ—āĻ¤ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻž āĻĨā§‡āĻ•ā§‡ āĻĄā§‡āĻŸāĻž āĻ—ā§āĻ°āĻšāĻŖ āĻ•āĻ°āĻŋāĨ¤ āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ‰ā§ŽāĻĒāĻžāĻĻāĻ¨āĻļā§€āĻ˛āĻ¤āĻžāĻ° āĻ•āĻŋ āĻšāĻŦā§‡?

āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻ° āĻœāĻ¨ā§āĻ¯, āĻ˛ā§‡āĻ–āĻ• āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡āĻ° āĻĄā§‡āĻŸāĻž āĻĒā§‡āĻ¤ā§‡ UserRemoteApi-āĻ āĻāĻ•āĻŸāĻŋ āĻ•āĻ˛ āĻ•āĻ°āĻž āĻšāĻŦā§‡ āĻāĻŦāĻ‚ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻ¸āĻ‚āĻ¯ā§āĻ•ā§āĻ¤ āĻĢāĻžāĻ‡āĻ˛ āĻĒā§‡āĻ¤ā§‡ FileRemoteApi-āĻ āĻāĻ•āĻŸāĻŋ āĻ•āĻ˛ āĻ•āĻ°āĻž āĻšāĻŦā§‡āĨ¤ āĻŽāĻ¨ā§‡ āĻšāĻšā§āĻ›ā§‡ āĻāĻŸāĻžāĻ‡āĨ¤ āĻ§āĻ°āĻž āĻ¯āĻžāĻ• āĻ¯ā§‡ ChatMessage-āĻāĻ° ForwardFrom āĻāĻŦāĻ‚ replyTo āĻĢāĻŋāĻ˛ā§āĻĄāĻ—ā§āĻ˛āĻŋ āĻāĻŽāĻ¨āĻ­āĻžāĻŦā§‡ āĻĒā§āĻ°āĻžāĻĒā§āĻ¤ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧā§‡āĻ›ā§‡ āĻ¯āĻžāĻ¤ā§‡ āĻ…āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧ āĻ•āĻ˛ā§‡āĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻšāĻ¯āĻŧ āĻ¨āĻžāĨ¤ āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻ¸ā§‡āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ ChatMessageUI-āĻ¤ā§‡ āĻĒāĻ°āĻŋāĻŖāĻ¤ āĻ•āĻ°āĻ˛ā§‡ āĻ¤āĻž āĻĒā§āĻ¨āĻ°āĻžāĻŦā§ƒāĻ¤ā§āĻ¤āĻŋ āĻ˜āĻŸāĻŦā§‡, āĻ…āĻ°ā§āĻĨāĻžā§Ž āĻ•āĻ˛ āĻ•āĻžāĻ‰āĻ¨ā§āĻŸāĻžāĻ°āĻ—ā§āĻ˛āĻŋ āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ–āĻ¯ā§‹āĻ—ā§āĻ¯āĻ­āĻžāĻŦā§‡ āĻŦā§ƒāĻĻā§āĻ§āĻŋ āĻĒā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡ā§ˇ āĻ¯ā§‡āĻŽāĻ¨āĻŸāĻŋ āĻ†āĻŽāĻ°āĻž āĻ†āĻ—ā§‡ āĻ‰āĻ˛ā§āĻ˛ā§‡āĻ– āĻ•āĻ°ā§‡āĻ›āĻŋ, āĻ†āĻ¸ā§āĻ¨ āĻ§āĻ°ā§‡ āĻ¨āĻŋāĻ‡ āĻ¯ā§‡ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ…āĻ¨ā§‡āĻ• āĻ¨ā§‡āĻ¸ā§āĻŸāĻŋāĻ‚ āĻ¨ā§‡āĻ‡ āĻāĻŦāĻ‚ āĻšā§‡āĻ‡āĻ¨āĻŸāĻŋ āĻ¤āĻŋāĻ¨āĻŸāĻŋ āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻ¸ā§€āĻŽāĻžāĻŦāĻĻā§āĻ§āĨ¤

āĻĢāĻ˛āĻ¸ā§āĻŦāĻ°ā§‚āĻĒ, āĻ†āĻŽāĻ°āĻž āĻĒā§āĻ°āĻ¤āĻŋ āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻ¯āĻŧ āĻŦāĻžāĻšā§āĻ¯āĻŋāĻ• āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻĻā§āĻ‡ āĻĨā§‡āĻ•ā§‡ āĻ›āĻ¯āĻŧāĻŸāĻŋ āĻ•āĻ˛ āĻāĻŦāĻ‚ āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻ—ā§āĻ˛āĻŋāĻ° āĻ¸āĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻĒā§āĻ¯āĻžāĻ•ā§‡āĻœā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻāĻ•āĻŸāĻŋ JPA āĻ•āĻ˛ āĻĒāĻžāĻŦāĨ¤ āĻŽā§‹āĻŸ āĻ•āĻ˛ā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž 2*N+1 āĻĨā§‡āĻ•ā§‡ 6*N+1 āĻĒāĻ°ā§āĻ¯āĻ¨ā§āĻ¤ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻŋāĻ¤ āĻšāĻŦā§‡āĨ¤ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦ āĻ‡āĻ‰āĻ¨āĻŋāĻŸā§‡ āĻāĻŸāĻŋ āĻ•āĻ¤? āĻ§āĻ°āĻž āĻ¯āĻžāĻ• āĻāĻ•āĻŸāĻŋ āĻĒā§ƒāĻˇā§āĻ āĻž āĻ°ā§‡āĻ¨ā§āĻĄāĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ 20āĻŸāĻŋ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻ˛āĻžāĻ—ā§‡āĨ¤ āĻ¸ā§‡āĻ—ā§āĻ˛āĻŋ āĻĒā§‡āĻ¤ā§‡, āĻāĻŸāĻŋ 4 āĻ¸ā§‡āĻ•ā§‡āĻ¨ā§āĻĄ āĻĨā§‡āĻ•ā§‡ 10 āĻ¸ā§‡āĻ•ā§‡āĻ¨ā§āĻĄ āĻĒāĻ°ā§āĻ¯āĻ¨ā§āĻ¤ āĻ˛āĻžāĻ—āĻŦā§‡āĨ¤ āĻ­āĻ¯āĻŧāĻžāĻ¨āĻ•! āĻ†āĻŽāĻŋ āĻāĻŸāĻŋ 500 ms āĻāĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻ°āĻžāĻ–āĻ¤ā§‡ āĻšāĻžāĻ‡āĨ¤ āĻāĻŦāĻ‚ āĻ¯ā§‡āĻšā§‡āĻ¤ā§ āĻ¤āĻžāĻ°āĻž āĻĢā§āĻ°āĻ¨ā§āĻŸāĻāĻ¨ā§āĻĄā§‡ āĻ¨āĻŋāĻ°ā§āĻŦāĻŋāĻ˜ā§āĻ¨ āĻ¸ā§āĻ•ā§āĻ°āĻ˛āĻŋāĻ‚ āĻ•āĻ°āĻžāĻ° āĻ¸ā§āĻŦāĻĒā§āĻ¨ āĻĻā§‡āĻ–ā§‡āĻ›āĻŋāĻ˛, āĻ¤āĻžāĻ‡ āĻāĻ‡ āĻļā§‡āĻˇ āĻĒāĻ¯āĻŧā§‡āĻ¨ā§āĻŸā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻ•āĻ°ā§āĻŽāĻ•ā§āĻˇāĻŽāĻ¤āĻž āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧāĻ¤āĻž āĻĻā§āĻŦāĻŋāĻ—ā§āĻŖ āĻ•āĻ°āĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĨ¤

āĻĒā§‡āĻļāĻžāĻĻāĻžāĻ°āĻ°āĻž:

  1. āĻ•ā§‹āĻĄāĻŸāĻŋ āĻ¸āĻ‚āĻ•ā§āĻˇāĻŋāĻĒā§āĻ¤ āĻāĻŦāĻ‚ āĻ¸ā§āĻŦ-āĻĄāĻ•ā§āĻŽā§‡āĻ¨ā§āĻŸāĻŋāĻ‚ (āĻāĻ•āĻŸāĻŋ āĻ¸āĻŽāĻ°ā§āĻĨāĻ¨ āĻĻāĻ˛ā§‡āĻ° āĻ¸ā§āĻŦāĻĒā§āĻ¨)āĨ¤
  2. āĻ•ā§‹āĻĄāĻŸāĻŋ āĻ¸āĻšāĻœ, āĻ¤āĻžāĻ‡ āĻ¨āĻŋāĻœā§‡āĻ•ā§‡ āĻĒāĻžāĻ¯āĻŧā§‡ āĻ—ā§āĻ˛āĻŋ āĻ•āĻ°āĻžāĻ° āĻĒā§āĻ°āĻžāĻ¯āĻŧ āĻ•ā§‹āĻ¨ āĻ¸ā§āĻ¯ā§‹āĻ— āĻ¨ā§‡āĻ‡āĨ¤
  3. āĻŦā§āĻ¯āĻžāĻš āĻĒā§āĻ°āĻ¸ā§‡āĻ¸āĻŋāĻ‚ āĻ•āĻŋāĻ›ā§ āĻĒāĻ°āĻ• āĻŽāĻ¤ āĻĻā§‡āĻ–āĻžāĻ¯āĻŧ āĻ¨āĻž āĻāĻŦāĻ‚ āĻœā§ˆāĻŦāĻ­āĻžāĻŦā§‡ āĻ¯ā§āĻ•ā§āĻ¤āĻŋāĻ¤ā§‡ āĻāĻ•āĻ¤ā§āĻ°āĻŋāĻ¤ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ.
  4. āĻ¯ā§āĻ•ā§āĻ¤āĻŋ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ¸āĻšāĻœā§‡ āĻ•āĻ°āĻž āĻšāĻŦā§‡ āĻāĻŦāĻ‚ āĻ¸ā§āĻĨāĻžāĻ¨ā§€āĻ¯āĻŧ āĻšāĻŦā§‡.

āĻ•āĻŽ:

āĻ–ā§āĻŦ āĻ›ā§‹āĻŸ āĻĒā§āĻ¯āĻžāĻ•ā§‡āĻŸā§‡āĻ° āĻ•āĻžāĻ°āĻŖā§‡ āĻ­āĻ¯āĻŧāĻ™ā§āĻ•āĻ° āĻ•āĻ°ā§āĻŽāĻ•ā§āĻˇāĻŽāĻ¤āĻžāĨ¤

āĻāĻ‡ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻŸāĻŋ āĻĒā§āĻ°āĻžāĻ¯āĻŧāĻļāĻ‡ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻŦāĻž āĻĒā§āĻ°ā§‹āĻŸā§‹āĻŸāĻžāĻ‡āĻĒāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻĻā§‡āĻ–āĻž āĻ¯āĻžāĻ¯āĻŧāĨ¤ āĻ¯āĻĻāĻŋ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻžāĻ° āĻ—āĻ¤āĻŋ āĻ—ā§āĻ°ā§āĻ¤ā§āĻŦāĻĒā§‚āĻ°ā§āĻŖ āĻšāĻ¯āĻŧ, āĻ¤āĻŦā§‡ āĻāĻŸāĻŋ āĻ¸āĻŋāĻ¸ā§āĻŸā§‡āĻŽāĻ•ā§‡ āĻœāĻŸāĻŋāĻ˛ āĻ•āĻ°ā§‡ āĻ¤ā§‹āĻ˛āĻžāĻ° āĻĒāĻ•ā§āĻˇā§‡ āĻ–ā§āĻŦ āĻ•āĻŽāĻ‡ āĻ‰āĻĒāĻ¯ā§āĻ•ā§āĻ¤āĨ¤ āĻāĻ•āĻ‡ āĻ¸āĻŽāĻ¯āĻŧā§‡, āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ–ā§āĻŦ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ•āĻ°ā§āĻŽāĻ•ā§āĻˇāĻŽāĻ¤āĻž āĻ­āĻ¯āĻŧāĻžāĻ¨āĻ•, āĻ¤āĻžāĻ‡ āĻāĻ‡ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻ—ā§‡āĻ° āĻ¸ā§āĻ¯ā§‹āĻ— āĻ–ā§āĻŦ āĻ¸āĻ‚āĻ•ā§€āĻ°ā§āĻŖāĨ¤

āĻ¨āĻŋāĻˇā§āĻĒāĻžāĻĒ āĻ¸āĻŽāĻžāĻ¨ā§āĻ¤āĻ°āĻžāĻ˛ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖ

āĻ†āĻĒāĻ¨āĻŋ āĻ¸āĻŽāĻžāĻ¨ā§āĻ¤āĻ°āĻžāĻ˛āĻ­āĻžāĻŦā§‡ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖ āĻļā§āĻ°ā§ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ - āĻāĻŸāĻŋ āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻŦāĻžāĻ°ā§āĻ¤āĻžāĻ—ā§āĻ˛āĻŋāĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻžāĻ° āĻ‰āĻĒāĻ° āĻ¨āĻŋāĻ°ā§āĻ­āĻ° āĻ•āĻ°ā§‡ āĻ¸āĻŽāĻ¯āĻŧā§‡āĻ° āĻ°ā§ˆāĻ–āĻŋāĻ• āĻŦā§ƒāĻĻā§āĻ§āĻŋ āĻĨā§‡āĻ•ā§‡ āĻĒāĻ°āĻŋāĻ¤ā§āĻ°āĻžāĻŖ āĻĒā§‡āĻ¤ā§‡ āĻĻā§‡āĻ¯āĻŧāĨ¤ āĻāĻŸāĻŋ āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻļā§‡āĻˇāĻ­āĻžāĻŦā§‡ āĻ­āĻžāĻ˛ āĻĒāĻĨ āĻ¨āĻ¯āĻŧ āĻ•āĻžāĻ°āĻŖ āĻāĻ° āĻĢāĻ˛ā§‡ āĻŦāĻšāĻŋāĻ°āĻžāĻ—āĻ¤ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ° āĻ‰āĻĒāĻ° āĻāĻ•āĻŸāĻŋ āĻŦāĻĄāĻŧ āĻĒāĻŋāĻ• āĻ˛ā§‹āĻĄ āĻšāĻŦā§‡ā§ˇ

āĻ¸āĻŽāĻžāĻ¨ā§āĻ¤āĻ°āĻžāĻ˛ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ āĻ•āĻ°āĻž āĻ–ā§āĻŦāĻ‡ āĻ¸āĻšāĻœ:

override fun getLast(nInt) =
  messageRepository.findLast(n).parallelStream()
    .map it.toFrontModel() }
    .collect(toList())

āĻ¸āĻŽāĻžāĻ¨ā§āĻ¤āĻ°āĻžāĻ˛ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡, āĻ†āĻŽāĻ°āĻž āĻ†āĻĻāĻ°ā§āĻļāĻ­āĻžāĻŦā§‡ 300-700 ms āĻĒāĻžāĻ‡, āĻ¯āĻž āĻāĻ•āĻŸāĻŋ āĻ¨āĻŋāĻˇā§āĻĒāĻžāĻĒ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ā§‡āĻ° āĻ¤ā§āĻ˛āĻ¨āĻžāĻ¯āĻŧ āĻ…āĻ¨ā§‡āĻ• āĻ­āĻžāĻ˛ā§‹, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻāĻ–āĻ¨āĻ“ āĻ¯āĻĨā§‡āĻˇā§āĻŸ āĻĻā§āĻ°ā§āĻ¤ āĻ¨āĻ¯āĻŧāĨ¤

āĻāĻ‡ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ° āĻ¸āĻžāĻĨā§‡, userRepository āĻāĻŦāĻ‚ fileRepository-āĻāĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻ—ā§āĻ˛āĻŋ āĻ¸āĻŋāĻ™ā§āĻ•ā§āĻ°ā§‹āĻ¨āĻžāĻ¸āĻ­āĻžāĻŦā§‡ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ•āĻ°āĻž āĻšāĻŦā§‡, āĻ¯āĻž āĻ–ā§āĻŦ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ¨āĻ¯āĻŧāĨ¤ āĻāĻŸāĻŋ āĻ āĻŋāĻ• āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯, āĻ†āĻĒāĻ¨āĻžāĻ•ā§‡ āĻ•āĻ˛ āĻ˛āĻœāĻŋāĻ• āĻ…āĻ¨ā§‡āĻ• āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡āĨ¤ āĻ‰āĻĻāĻžāĻšāĻ°āĻŖāĻ¸ā§āĻŦāĻ°ā§‚āĻĒ, CompletionStage āĻāĻ° āĻŽāĻžāĻ§ā§āĻ¯āĻŽā§‡ (āĻ“āĻ°āĻĢā§‡ Completable Future):

private fun ChatMessage.toFrontModel(): ChatMessageUI =
  CompletableFuture.supplyAsync {
    userRepository.getUserById(author).toFrontReference()
  }.thenCombine(
    files?.let {
      CompletableFuture.supplyAsync {
        fileRepository.getHeadsByIds(files).map it.toFrontReference() }
      }
    } ?: CompletableFuture.completedFuture(listOf())
  ) authorfiles ->
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = author,
      message = message,
      files = files,
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
  }.get()!!

āĻāĻŸāĻŋ āĻĻā§‡āĻ–āĻž āĻ¯āĻžāĻ¯āĻŧ āĻ¯ā§‡ āĻĒā§āĻ°āĻžāĻĨāĻŽāĻŋāĻ•āĻ­āĻžāĻŦā§‡ āĻ¸āĻšāĻœ āĻŽā§āĻ¯āĻžāĻĒāĻŋāĻ‚ āĻ•ā§‹āĻĄ āĻ•āĻŽ āĻŦā§‹āĻ§āĻ—āĻŽā§āĻ¯ āĻšāĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤ āĻāĻ° āĻ•āĻžāĻ°āĻŖ āĻšāĻ˛ āĻ¯ā§‡ āĻĢāĻ˛āĻžāĻĢāĻ˛āĻ—ā§āĻ˛āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ āĻ¸ā§‡āĻ–āĻžāĻ¨ āĻĨā§‡āĻ•ā§‡ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻŦāĻšāĻŋāĻ°āĻžāĻ—āĻ¤ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻ•āĻ˛āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻ†āĻ˛āĻžāĻĻāĻž āĻ•āĻ°āĻ¤ā§‡ āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛ā§ˇ āĻāĻŸāĻŋ āĻ¨āĻŋāĻœā§‡āĻ‡ āĻ–āĻžāĻ°āĻžāĻĒ āĻ¨āĻ¯āĻŧāĨ¤ āĻ¤āĻŦā§‡ āĻ•āĻ˛āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻāĻ•āĻ¤ā§āĻ°āĻŋāĻ¤ āĻ•āĻ°āĻž āĻ–ā§āĻŦ āĻŽāĻžāĻ°ā§āĻœāĻŋāĻ¤ āĻĻā§‡āĻ–āĻžāĻ¯āĻŧ āĻ¨āĻž āĻāĻŦāĻ‚ āĻāĻ•āĻŸāĻŋ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻĒā§āĻ°āĻ¤āĻŋāĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻļā§€āĻ˛ "āĻ¨ā§āĻĄāĻ˛" āĻāĻ° āĻŽāĻ¤ā§‹āĨ¤

āĻ†āĻĒāĻ¨āĻŋ coroutines āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ˛ā§‡, āĻ¸āĻŦāĻ•āĻŋāĻ›ā§ āĻ†āĻ°ā§‹ āĻļāĻžāĻ˛ā§€āĻ¨ āĻĻā§‡āĻ–āĻžāĻŦā§‡:

private fun ChatMessage.toFrontModel(): ChatMessageUI =
  join(
    userRepository.getUserById(author).toFrontReference() },
    files?.let fileRepository.getHeadsByIds(files)
      .map it.toFrontReference() } } ?: listOf() }
  ).let (author, files) ->
    ChatMessageUI(
      id = id ?: throw IllegalStateException("$this must be persisted"),
      author = author,
      message = message,
      files = files,
      forwardFrom = forwardFrom?.toFrontModel(),
      replyTo = replyTo?.toFrontModel()
    )
  }

āĻ¯ā§‡āĻ–āĻžāĻ¨ā§‡:

fun <ABjoin(a: () -> Ab: () -> B) =
  runBlocking(IO{
    awaitAll(async a() }async b() })
  }.let {
    it[0as to it[1as B
  }

āĻ¤āĻžāĻ¤ā§āĻ¤ā§āĻŦāĻŋāĻ•āĻ­āĻžāĻŦā§‡, āĻāĻ‡ āĻ§āĻ°āĻ¨ā§‡āĻ° āĻ¸āĻŽāĻžāĻ¨ā§āĻ¤āĻ°āĻžāĻ˛ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡, āĻ†āĻŽāĻ°āĻž 200-400 ms āĻĒāĻžāĻŦ, āĻ¯āĻž āĻ‡āĻ¤āĻŋāĻŽāĻ§ā§āĻ¯ā§‡āĻ‡ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻĒā§āĻ°āĻ¤ā§āĻ¯āĻžāĻļāĻžāĻ° āĻ•āĻžāĻ›āĻžāĻ•āĻžāĻ›āĻŋāĨ¤

āĻĻā§āĻ°ā§āĻ­āĻžāĻ—ā§āĻ¯āĻŦāĻļāĻ¤, āĻāĻ‡ āĻ§āĻ°āĻ¨ā§‡āĻ° āĻ­āĻžāĻ˛ āĻ¸āĻŽāĻžāĻ¨ā§āĻ¤āĻ°āĻžāĻ˛āĻ•āĻ°āĻŖ āĻŦāĻŋāĻĻā§āĻ¯āĻŽāĻžāĻ¨ āĻ¨ā§‡āĻ‡, āĻāĻŦāĻ‚ āĻĒā§āĻ°āĻĻāĻžāĻ¨ā§‡āĻ° āĻŽā§‚āĻ˛ā§āĻ¯ āĻŦā§‡āĻļ āĻ¨āĻŋāĻˇā§āĻ ā§āĻ°: āĻāĻ•āĻ‡ āĻ¸āĻŽāĻ¯āĻŧā§‡ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ•āĻ¯āĻŧā§‡āĻ•āĻœāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ•āĻžāĻ°ā§€ āĻ•āĻžāĻœ āĻ•āĻ°āĻžāĻ° āĻ¸āĻžāĻĨā§‡, āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻŦā§āĻ¯āĻžāĻ°ā§‡āĻœ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻĒāĻĄāĻŧāĻŦā§‡, āĻ¯āĻž āĻ¯āĻžāĻ‡āĻšā§‹āĻ• āĻ¸āĻŽāĻžāĻ¨ā§āĻ¤āĻ°āĻžāĻ˛āĻ­āĻžāĻŦā§‡ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻ•āĻ°āĻž āĻšāĻŦā§‡ āĻ¨āĻž, āĻ¤āĻžāĻ‡ āĻ†āĻŽāĻ°āĻž āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻĻā§āĻƒāĻ–āĻœāĻ¨āĻ• 4 āĻ¸ā§‡āĻ•ā§‡āĻ¨ā§āĻĄā§‡ āĻĢāĻŋāĻ°ā§‡ āĻ†āĻ¸āĻŦā§‡āĨ¤

āĻāĻ‡ āĻ§āĻ°āĻ¨ā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻž āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ†āĻŽāĻžāĻ° āĻĢāĻ˛āĻžāĻĢāĻ˛ āĻšāĻ˛ 1300āĻŸāĻŋ āĻŦāĻžāĻ°ā§āĻ¤āĻž āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖā§‡āĻ° āĻœāĻ¨ā§āĻ¯ 1700-20 msāĨ¤ āĻāĻŸāĻŋ āĻĒā§āĻ°āĻĨāĻŽ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ā§‡āĻ° āĻ¤ā§āĻ˛āĻ¨āĻžāĻ¯āĻŧ āĻĻā§āĻ°ā§āĻ¤, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻāĻ–āĻ¨āĻ“ āĻ¸āĻŽāĻ¸ā§āĻ¯āĻžāĻ° āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻ•āĻ°ā§‡ āĻ¨āĻžāĨ¤

āĻ¸āĻŽāĻžāĻ¨ā§āĻ¤āĻ°āĻžāĻ˛ āĻĒā§āĻ°āĻļā§āĻ¨ā§‡āĻ° āĻŦāĻŋāĻ•āĻ˛ā§āĻĒ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻ¯āĻĻāĻŋ āĻ¤ā§ƒāĻ¤ā§€āĻ¯āĻŧ āĻĒāĻ•ā§āĻˇā§‡āĻ° āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ—ā§āĻ˛āĻŋ āĻŦā§āĻ¯āĻžāĻš āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻ¨āĻž āĻ•āĻ°ā§‡? āĻ‰āĻĻāĻžāĻšāĻ°āĻŖāĻ¸ā§āĻŦāĻ°ā§‚āĻĒ, āĻ†āĻĒāĻ¨āĻŋ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻĢā§‡āĻ¸ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ° āĻ­āĻŋāĻ¤āĻ°ā§‡ āĻŦā§āĻ¯āĻžāĻš āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ā§‡āĻ° āĻ…āĻ­āĻžāĻŦ āĻ˛ā§āĻ•āĻžāĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨:

interface UserRemoteApi {
  fun getUserById(idUserReference): UserRemote
  fun getUsersByIds(idSet<UserReference>): Set<UserRemote> =
    id.parallelStream()
      .map getUserById(it}.collect(toSet())
  fun getUsersByIds(idList<UserReference>): List<UserRemote> =
    id.parallelStream()
      .map getUserById(it}.collect(toList())
}

āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ āĻ­āĻŦāĻŋāĻˇā§āĻ¯āĻ¤ā§‡āĻ° āĻ¸āĻ‚āĻ¸ā§āĻ•āĻ°āĻŖāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻŦā§āĻ¯āĻžāĻš āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖ āĻĻā§‡āĻ–āĻ¤ā§‡ āĻ†āĻļāĻž āĻ•āĻ°ā§‡āĻ¨ āĻ¤āĻŦā§‡ āĻāĻŸāĻŋ āĻŦā§‹āĻāĻž āĻ¯āĻžāĻ¯āĻŧāĨ¤
āĻĒā§‡āĻļāĻžāĻĻāĻžāĻ°āĻ°āĻž:

  1. āĻ¸āĻšāĻœā§‡ āĻŦāĻžāĻ°ā§āĻ¤āĻž-āĻ­āĻŋāĻ¤ā§āĻ¤āĻŋāĻ• āĻ¸āĻŽāĻžāĻ¨ā§āĻ¤āĻ°āĻžāĻ˛ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨.
  2. āĻ­āĻžāĻ˛ āĻŽāĻžāĻĒāĻ¯ā§‹āĻ—ā§āĻ¯āĻ¤āĻž.

āĻ•āĻ¨āĻ¸:

  1. āĻ¸āĻŽāĻžāĻ¨ā§āĻ¤āĻ°āĻžāĻ˛āĻ­āĻžāĻŦā§‡ āĻŦāĻŋāĻ­āĻŋāĻ¨ā§āĻ¨ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ° āĻ…āĻ¨ā§āĻ°ā§‹āĻ§āĻ—ā§āĻ˛āĻŋ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻž āĻ•āĻ°āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻāĻ° āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖ āĻĨā§‡āĻ•ā§‡ āĻĄā§‡āĻŸāĻž āĻ…āĻ§āĻŋāĻ—ā§āĻ°āĻšāĻŖāĻ•ā§‡ āĻ†āĻ˛āĻžāĻĻāĻž āĻ•āĻ°āĻžāĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨āĨ¤
  2. āĻ¤ā§ƒāĻ¤ā§€āĻ¯āĻŧ āĻĒāĻ•ā§āĻˇā§‡āĻ° āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻŦāĻ°ā§āĻ§āĻŋāĻ¤ āĻ˛ā§‹āĻĄāĨ¤

āĻāĻŸāĻž āĻĻā§‡āĻ–āĻž āĻ¯āĻžāĻ¯āĻŧ āĻ¯ā§‡ āĻĒā§āĻ°āĻ¯ā§‹āĻœā§āĻ¯āĻ¤āĻžāĻ° āĻ¸ā§āĻ¯ā§‹āĻ— āĻĒā§āĻ°āĻžāĻ¯āĻŧ āĻ¨āĻŋāĻ°ā§āĻŦā§‹āĻ§ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ° āĻŽāĻ¤ā§‹āĻ‡āĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ āĻ…āĻ¨ā§āĻ¯āĻĻā§‡āĻ° āĻ¨āĻŋāĻ°ā§āĻĻāĻ¯āĻŧ āĻļā§‹āĻˇāĻŖā§‡āĻ° āĻ•āĻžāĻ°āĻŖā§‡ āĻ†āĻĒāĻ¨āĻžāĻ° āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ° āĻ•āĻ°ā§āĻŽāĻ•ā§āĻˇāĻŽāĻ¤āĻž āĻ•āĻ¯āĻŧā§‡āĻ•āĻ—ā§āĻŖ āĻŦāĻžāĻĄāĻŧāĻžāĻ¤ā§‡ āĻšāĻžāĻ¨ āĻ¤āĻŦā§‡ āĻ¸āĻŽāĻžāĻ¨ā§āĻ¤āĻ°āĻžāĻ˛ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻŦā§‹āĻ§āĻ—āĻŽā§āĻ¯āĨ¤ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ‰āĻĻāĻžāĻšāĻ°āĻŖā§‡, āĻ•āĻ°ā§āĻŽāĻ•ā§āĻˇāĻŽāĻ¤āĻž 2,5 āĻ—ā§āĻŖ āĻŦā§‡āĻĄāĻŧā§‡āĻ›ā§‡, āĻ¤āĻŦā§‡ āĻāĻŸāĻŋ āĻ¸ā§āĻĒāĻˇā§āĻŸāĻ¤āĻ‡ āĻ¯āĻĨā§‡āĻˇā§āĻŸ āĻ¨āĻ¯āĻŧāĨ¤

āĻ•ā§āĻ¯āĻžāĻļāĻŋāĻ‚

āĻ†āĻĒāĻ¨āĻŋ āĻŦāĻžāĻšā§āĻ¯āĻŋāĻ• āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ—ā§āĻ˛āĻŋāĻ° āĻœāĻ¨ā§āĻ¯ JPA-āĻāĻ° āĻ¸ā§āĻĒāĻŋāĻ°āĻŋāĻŸā§‡ āĻ•ā§āĻ¯āĻžāĻļāĻŋāĻ‚ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨, āĻ…āĻ°ā§āĻĨāĻžā§Ž, āĻĒā§āĻ°āĻžāĻĒā§āĻ¤ āĻŦāĻ¸ā§āĻ¤ā§āĻ—ā§āĻ˛āĻŋāĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¸ā§‡āĻļāĻ¨ā§‡āĻ° āĻŽāĻ§ā§āĻ¯ā§‡ āĻ¸āĻ‚āĻ°āĻ•ā§āĻˇāĻŖ āĻ•āĻ°ā§āĻ¨ āĻ¯āĻžāĻ¤ā§‡ āĻ¸ā§‡āĻ—ā§āĻ˛āĻŋ āĻ†āĻŦāĻžāĻ° āĻ¨āĻž āĻĒāĻžāĻ“āĻ¯āĻŧāĻž āĻ¯āĻžāĻ¯āĻŧ (āĻŦā§āĻ¯āĻžāĻš āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖā§‡āĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ¸āĻš)āĨ¤ āĻ†āĻĒāĻ¨āĻŋ āĻ¨āĻŋāĻœā§‡ āĻāĻ‡ āĻ§āĻ°āĻ¨ā§‡āĻ° āĻ•ā§āĻ¯āĻžāĻļā§‡ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨, āĻ†āĻĒāĻ¨āĻŋ āĻ¸ā§āĻĒā§āĻ°āĻŋāĻ‚āĻ•ā§‡ āĻāĻ° @Cacheable āĻĻāĻŋāĻ¯āĻŧā§‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨, āĻāĻ›āĻžāĻĄāĻŧāĻžāĻ“ āĻ†āĻĒāĻ¨āĻŋ āĻ¸āĻŦāĻ¸āĻŽāĻ¯āĻŧ EhCache-āĻāĻ° āĻŽāĻ¤ā§‹ āĻ¤ā§ˆāĻ°āĻŋ āĻ•ā§āĻ¯āĻžāĻļā§‡ āĻŽā§āĻ¯āĻžāĻ¨ā§āĻ¯āĻŧāĻžāĻ˛āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨āĨ¤

āĻāĻ•āĻŸāĻŋ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž āĻš'āĻ˛ āĻ•ā§āĻ¯āĻžāĻļā§‡āĻ—ā§āĻ˛āĻŋ āĻ•ā§‡āĻŦāĻ˛ āĻ¤āĻ–āĻ¨āĻ‡ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻ° āĻ¯āĻĻāĻŋ āĻ¤āĻžāĻĻā§‡āĻ° āĻšāĻŋāĻŸ āĻĨāĻžāĻ•ā§‡āĨ¤ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡, āĻ˛ā§‡āĻ–āĻ• āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡āĻ° āĻšāĻŋāĻŸ āĻ–ā§āĻŦ āĻ¸āĻŽā§āĻ­āĻŦāĻ¤ (āĻ†āĻ¸ā§āĻ¨, 50%) āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻĢāĻžāĻ‡āĻ˛āĻ—ā§āĻ˛āĻŋāĻ¤ā§‡ āĻ•ā§‹āĻ¨āĻ“ āĻšāĻŋāĻŸ āĻšāĻŦā§‡ āĻ¨āĻžāĨ¤ āĻāĻ‡ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ° āĻ•āĻŋāĻ›ā§ āĻ‰āĻ¨ā§āĻ¨āĻ¤āĻŋ āĻšāĻŦā§‡, āĻ•āĻŋāĻ¨ā§āĻ¤ā§ āĻāĻŸāĻŋ āĻ•āĻ°ā§āĻŽāĻ•ā§āĻˇāĻŽāĻ¤āĻžāĻ•ā§‡ āĻ†āĻŽā§‚āĻ˛ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻŦā§‡ āĻ¨āĻž (āĻāĻŦāĻ‚ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻāĻ•āĻŸāĻŋ āĻ…āĻ—ā§āĻ°āĻ—āĻ¤āĻŋ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨)āĨ¤

āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻ¸ā§‡āĻ¸āĻ¨ (āĻĻā§€āĻ°ā§āĻ˜) āĻ•ā§āĻ¯āĻžāĻļā§‡ āĻœāĻŸāĻŋāĻ˛ āĻ…āĻŦā§ˆāĻ§āĻ•āĻ°āĻŖ āĻ¯ā§āĻ•ā§āĻ¤āĻŋ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨āĨ¤ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖāĻ­āĻžāĻŦā§‡, āĻ†āĻĒāĻ¨āĻŋ āĻ¯āĻ¤ āĻĒāĻ°ā§‡ āĻ‡āĻ¨ā§āĻŸāĻžāĻ°āĻ¸ā§‡āĻļāĻ¨ āĻ•ā§āĻ¯āĻžāĻļā§‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻĒāĻžāĻ°āĻĢāĻ°āĻŽā§āĻ¯āĻžāĻ¨ā§āĻ¸ āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ā§‡ āĻ¨āĻžāĻŽāĻŦā§‡āĻ¨, āĻ¤āĻ¤āĻ‡ āĻ­āĻžāĻ˛ā§‹āĨ¤

āĻĒā§‡āĻļāĻžāĻĻāĻžāĻ°āĻ°āĻž:

  1. āĻ•ā§‹āĻĄ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ¨āĻž āĻ•āĻ°ā§‡ āĻ•ā§āĻ¯āĻžāĻļāĻŋāĻ‚ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻ— āĻ•āĻ°ā§āĻ¨āĨ¤
  2. āĻ‰āĻ¤ā§āĻĒāĻžāĻĻāĻ¨āĻļā§€āĻ˛āĻ¤āĻž āĻ•āĻ¯āĻŧā§‡āĻ•āĻŦāĻžāĻ° āĻŦā§ƒāĻĻā§āĻ§āĻŋ āĻĒā§‡āĻ¯āĻŧā§‡āĻ›ā§‡ (āĻ•āĻŋāĻ›ā§ āĻ•ā§āĻˇā§‡āĻ¤ā§āĻ°ā§‡)āĨ¤

āĻ•āĻ¨āĻ¸:

  1. āĻ­ā§āĻ˛āĻ­āĻžāĻŦā§‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻšāĻ˛ā§‡ āĻ•āĻ°ā§āĻŽāĻ•ā§āĻˇāĻŽāĻ¤āĻž āĻšā§āĻ°āĻžāĻ¸ā§‡āĻ° āĻ¸āĻŽā§āĻ­āĻžāĻŦāĻ¨āĻžāĨ¤
  2. āĻŦāĻĄāĻŧ āĻŽā§‡āĻŽāĻ°āĻŋ āĻ“āĻ­āĻžāĻ°āĻšā§‡āĻĄ, āĻŦāĻŋāĻļā§‡āĻˇ āĻ•āĻ°ā§‡ āĻĻā§€āĻ°ā§āĻ˜ āĻ•ā§āĻ¯āĻžāĻļā§‡ āĻ¸āĻšāĨ¤
  3. āĻœāĻŸāĻŋāĻ˛ āĻ…āĻŦā§ˆāĻ§āĻ¤āĻž, āĻ¤ā§āĻ°ā§āĻŸāĻŋ āĻ¯āĻž āĻ°āĻžāĻ¨āĻŸāĻžāĻ‡āĻŽā§‡ āĻšāĻžāĻ°ā§āĻĄ-āĻŸā§-āĻ°āĻŋāĻĒā§āĻ°ā§‹āĻĄāĻŋāĻ‰āĻ¸ āĻ¸āĻŽāĻ¸ā§āĻ¯āĻžāĻ° āĻĻāĻŋāĻ•ā§‡ āĻĒāĻ°āĻŋāĻšāĻžāĻ˛āĻŋāĻ¤ āĻ•āĻ°āĻŦā§‡āĨ¤

āĻ–ā§āĻŦ āĻĒā§āĻ°āĻžāĻ¯āĻŧāĻ‡, āĻ•ā§āĻ¯āĻžāĻļā§‡ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ¨āĻ•āĻļāĻž āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž āĻĻā§āĻ°ā§āĻ¤ āĻĒā§āĻ¯āĻžāĻš āĻ†āĻĒ āĻ•āĻ°āĻ¤ā§‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ. āĻāĻ° āĻ…āĻ°ā§āĻĨ āĻāĻ‡ āĻ¨āĻ¯āĻŧ āĻ¯ā§‡ āĻ¤āĻžāĻĻā§‡āĻ° āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻž āĻ‰āĻšāĻŋāĻ¤ āĻ¨āĻ¯āĻŧāĨ¤ āĻ¯āĻžāĻ‡āĻšā§‹āĻ•, āĻ†āĻĒāĻ¨āĻžāĻ° āĻ¸āĻ°ā§āĻŦāĻĻāĻž āĻ¤āĻžāĻĻā§‡āĻ° āĻ¸āĻžāĻĨā§‡ āĻ¸āĻžāĻŦāĻ§āĻžāĻ¨āĻ¤āĻžāĻ° āĻ¸āĻžāĻĨā§‡ āĻ†āĻšāĻ°āĻŖ āĻ•āĻ°āĻž āĻ‰āĻšāĻŋāĻ¤ āĻāĻŦāĻ‚ āĻĒā§āĻ°āĻĨāĻŽā§‡ āĻĢāĻ˛āĻžāĻĢāĻ˛ā§‡āĻ° āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻžāĻ°āĻŋāĻ¤āĻž āĻ˛āĻžāĻ­ā§‡āĻ° āĻŽā§‚āĻ˛ā§āĻ¯āĻžāĻ¯āĻŧāĻ¨ āĻ•āĻ°āĻž āĻ‰āĻšāĻŋāĻ¤ āĻāĻŦāĻ‚ āĻļā§āĻ§ā§āĻŽāĻžāĻ¤ā§āĻ° āĻ¤āĻžāĻ°āĻĒāĻ° āĻāĻ•āĻŸāĻŋ āĻ¸āĻŋāĻĻā§āĻ§āĻžāĻ¨ā§āĻ¤ āĻ¨ā§‡āĻ“āĻ¯āĻŧāĻž āĻ‰āĻšāĻŋāĻ¤āĨ¤

āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ‰āĻĻāĻžāĻšāĻ°āĻŖā§‡, āĻ•ā§āĻ¯āĻžāĻļā§‡ āĻĒā§āĻ°āĻžāĻ¯āĻŧ 25% āĻ•āĻžāĻ°ā§āĻ¯āĻ•ā§āĻˇāĻŽāĻ¤āĻž āĻŦā§ƒāĻĻā§āĻ§āĻŋ āĻĒā§āĻ°āĻĻāĻžāĻ¨ āĻ•āĻ°āĻŦā§‡āĨ¤ āĻāĻ•āĻ‡ āĻ¸āĻŽāĻ¯āĻŧā§‡, āĻ•ā§āĻ¯āĻžāĻļā§‡āĻ—ā§āĻ˛āĻŋāĻ° āĻ…āĻ¨ā§‡āĻ• āĻ…āĻ¸ā§āĻŦāĻŋāĻ§āĻž āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡, āĻ¤āĻžāĻ‡ āĻ†āĻŽāĻŋ āĻ¸ā§‡āĻ—ā§āĻ˛āĻŋ āĻāĻ–āĻžāĻ¨ā§‡ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°āĻŦ āĻ¨āĻžāĨ¤

āĻĢāĻ˛āĻžāĻĢāĻ˛

āĻ¸ā§āĻ¤āĻ°āĻžāĻ‚, āĻ†āĻŽāĻ°āĻž āĻŦā§āĻ¯āĻžāĻš āĻĒā§āĻ°āĻ¸ā§‡āĻ¸āĻŋāĻ‚ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻāĻŽāĻ¨ āĻāĻ•āĻŸāĻŋ āĻĒāĻ°āĻŋāĻˇā§‡āĻŦāĻžāĻ° āĻ¨āĻŋāĻˇā§āĻĒāĻžāĻĒ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ā§‡āĻ° āĻĻāĻŋāĻ•ā§‡ āĻ¤āĻžāĻ•āĻŋāĻ¯āĻŧā§‡āĻ›āĻŋ āĻāĻŦāĻ‚ āĻāĻŸāĻŋāĻ•ā§‡ āĻ—āĻ¤āĻŋ āĻŦāĻžāĻĄāĻŧāĻžāĻ¨ā§‹āĻ° āĻ•āĻŋāĻ›ā§ āĻ¸āĻšāĻœ āĻ‰āĻĒāĻžāĻ¯āĻŧāĨ¤

āĻāĻ‡ āĻ¸āĻŽāĻ¸ā§āĻ¤ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ° āĻĒā§āĻ°āĻ§āĻžāĻ¨ āĻ¸ā§āĻŦāĻŋāĻ§āĻž āĻšāĻ˛ āĻ¸āĻ°āĻ˛āĻ¤āĻž, āĻ¯āĻž āĻĨā§‡āĻ•ā§‡ āĻ…āĻ¨ā§‡āĻ• āĻ†āĻ¨āĻ¨ā§āĻĻāĻĻāĻžāĻ¯āĻŧāĻ• āĻĒāĻ°āĻŋāĻŖāĻ¤āĻŋ āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡āĨ¤

āĻāĻ‡ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻ—ā§āĻ˛āĻŋāĻ° āĻāĻ•āĻŸāĻŋ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž āĻšāĻ˛ āĻĻā§āĻ°ā§āĻŦāĻ˛ āĻ•āĻ°ā§āĻŽāĻ•ā§āĻˇāĻŽāĻ¤āĻž, āĻĒā§āĻ°āĻžāĻĨāĻŽāĻŋāĻ•āĻ­āĻžāĻŦā§‡ āĻĒā§āĻ¯āĻžāĻ•ā§‡āĻŸā§‡āĻ° āĻ†āĻ•āĻžāĻ°ā§‡āĻ° āĻ•āĻžāĻ°āĻŖā§‡āĨ¤ āĻ…āĻ¤āĻāĻŦ, āĻ¯āĻĻāĻŋ āĻāĻ‡ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨āĻ—ā§āĻ˛āĻŋ āĻ†āĻĒāĻ¨āĻžāĻ° āĻ‰āĻĒāĻ¯ā§āĻ•ā§āĻ¤ āĻ¨āĻž āĻšāĻ¯āĻŧ, āĻ¤āĻŦā§‡ āĻāĻŸāĻŋ āĻ†āĻ°āĻ“ āĻ°ā§āĻ¯āĻžāĻĄāĻŋāĻ•āĻžāĻ˛ āĻĒāĻĻā§āĻ§āĻ¤āĻŋ āĻŦāĻŋāĻŦā§‡āĻšāĻ¨āĻž āĻ•āĻ°āĻž āĻŽā§‚āĻ˛ā§āĻ¯āĻŦāĻžāĻ¨āĨ¤

āĻĻā§āĻŸāĻŋ āĻĒā§āĻ°āĻ§āĻžāĻ¨ āĻĻāĻŋāĻ• āĻ°āĻ¯āĻŧā§‡āĻ›ā§‡ āĻ¯ā§‡āĻ–āĻžāĻ¨ā§‡ āĻ†āĻĒāĻ¨āĻŋ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨āĻ—ā§āĻ˛āĻŋ āĻ¸āĻ¨ā§āĻ§āĻžāĻ¨ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨:

  • āĻĄā§‡āĻŸāĻž āĻ¸āĻš āĻ…ā§āĻ¯āĻžāĻ¸āĻŋāĻ™ā§āĻ•ā§āĻ°ā§‹āĻ¨āĻžāĻ¸ āĻ•āĻžāĻœ (āĻāĻ•āĻŸāĻŋ āĻĒā§āĻ¯āĻžāĻ°āĻžāĻĄāĻžāĻ‡āĻŽ āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ā§‡āĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨, āĻ¤āĻžāĻ‡ āĻāĻ‡ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§ā§‡ āĻ†āĻ˛ā§‹āĻšāĻ¨āĻž āĻ•āĻ°āĻž āĻšāĻ¯āĻŧāĻ¨āĻŋ);
  • āĻ¸āĻŋāĻ™ā§āĻ•ā§āĻ°ā§‹āĻ¨āĻžāĻ¸ āĻĒā§āĻ°āĻ•ā§āĻ°āĻŋāĻ¯āĻŧāĻžāĻ•āĻ°āĻŖ āĻŦāĻœāĻžāĻ¯āĻŧ āĻ°āĻžāĻ–āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻŦā§āĻ¯āĻžāĻšā§‡āĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ§āĻ¨āĨ¤

āĻŦā§āĻ¯āĻžāĻš āĻŦāĻ°ā§āĻ§āĻŋāĻ¤ āĻ•āĻ°āĻž āĻŦāĻžāĻšā§āĻ¯āĻŋāĻ• āĻ•āĻ˛ā§‡āĻ° āĻ¸āĻ‚āĻ–ā§āĻ¯āĻž āĻ…āĻ¨ā§‡āĻ• āĻ•āĻŽāĻŋāĻ¯āĻŧā§‡ āĻĻā§‡āĻŦā§‡ āĻāĻŦāĻ‚ āĻāĻ•āĻ‡ āĻ¸āĻžāĻĨā§‡ āĻ•ā§‹āĻĄāĻŸāĻŋ āĻ¸āĻŋāĻ™ā§āĻ•ā§āĻ°ā§‹āĻ¨āĻžāĻ¸ āĻ°āĻžāĻ–āĻŦā§‡āĨ¤ āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§ā§‡āĻ° āĻĒāĻ°āĻŦāĻ°ā§āĻ¤ā§€ āĻ…āĻ‚āĻļ āĻāĻ‡ āĻŦāĻŋāĻˇāĻ¯āĻŧā§‡ āĻ¨āĻŋāĻŦā§‡āĻĻāĻŋāĻ¤ āĻ•āĻ°āĻž āĻšāĻŦā§‡.

āĻ‰āĻ¤ā§āĻ¸: www.habr.com

āĻāĻ•āĻŸāĻŋ āĻŽāĻ¨ā§āĻ¤āĻŦā§āĻ¯ āĻœā§āĻĄāĻŧā§āĻ¨