āĻĢā§āĻ˛āĻžāĻ‡āĻ¤ā§‡ āĻšāĻŋāĻ¤ā§āĻ°ā§‡āĻ° āĻ†āĻ•āĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ āĻ•āĻ°āĻž āĻšāĻšā§āĻ›ā§‡

āĻ‡āĻŽā§‡āĻœ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻāĻŽāĻ¨ āĻĒā§āĻ°āĻžāĻ¯āĻŧ āĻ¯ā§‡āĻ•ā§‹āĻ¨ā§‹ āĻ“āĻ¯āĻŧā§‡āĻŦ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ā§‡, āĻāĻ‡ āĻ‡āĻŽā§‡āĻœāĻ—ā§āĻ˛āĻŋāĻ° āĻ›ā§‹āĻŸ āĻ•āĻĒāĻŋ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻŦā§‡, āĻāĻŦāĻ‚ āĻĒā§āĻ°āĻžāĻ¯āĻŧāĻļāĻ‡ āĻ…āĻ¤āĻŋāĻ°āĻŋāĻ•ā§āĻ¤ āĻ‡āĻŽā§‡āĻœā§‡āĻ° āĻœāĻ¨ā§āĻ¯ āĻŦā§‡āĻļ āĻ•āĻŋāĻ›ā§ āĻĢāĻ°āĻŽā§āĻ¯āĻžāĻŸ āĻĨāĻžāĻ•ā§‡āĨ¤
āĻāĻ•āĻŸāĻŋ āĻŦāĻŋāĻĻā§āĻ¯āĻŽāĻžāĻ¨ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ā§‡ āĻ¨āĻ¤ā§āĻ¨ āĻŽāĻžāĻ¤ā§āĻ°āĻž āĻ¯ā§‹āĻ— āĻ•āĻ°āĻžāĻ° āĻĢāĻ˛ā§‡ āĻ•āĻŋāĻ›ā§ āĻŽāĻžāĻĨāĻžāĻŦā§āĻ¯āĻĨāĻžāĻ“ āĻšāĻ¯āĻŧāĨ¤ āĻ¤āĻžāĻ‡ āĻ•āĻžāĻœ:

āĻ•āĻžāĻœā§‡āĻ°

āĻ†āĻ¸ā§āĻ¨ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧāĻ¤āĻžāĻ° āĻ¤āĻžāĻ˛āĻŋāĻ•āĻž āĻŦā§‹āĻāĻžāĻ‡:

  • āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻžāĻ¨ā§‡āĻ° āĻ…āĻ¸ā§āĻ¤āĻŋāĻ¤ā§āĻŦā§‡āĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ¯ā§‡ āĻ•ā§‹āĻ¨āĻ“ āĻ¸āĻŽāĻ¯āĻŧā§‡ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨āĻŸāĻŋāĻ¤ā§‡ āĻ…āĻ¤āĻŋāĻ°āĻŋāĻ•ā§āĻ¤ āĻ•āĻžāĻ°ā§āĻ¯āĻ•āĻžāĻ°āĻŋāĻ¤āĻž āĻĒā§āĻ°āĻŦāĻ°ā§āĻ¤āĻ¨ āĻ¨āĻž āĻ•āĻ°ā§‡ āĻ‰āĻĄāĻŧāĻ¤ā§‡ āĻĨāĻžāĻ•āĻž āĻ¯ā§‡āĻ•ā§‹āĻ¨ā§‹ āĻŦāĻŋāĻ¨ā§āĻ¯āĻžāĻ¸ā§‡āĻ° āĻ…āĻ¤āĻŋāĻ°āĻŋāĻ•ā§āĻ¤ āĻšāĻŋāĻ¤ā§āĻ° āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°ā§āĻ¨;
  • āĻĒā§āĻ°āĻ¤āĻŋāĻŸāĻŋ āĻ…āĻ¨ā§āĻ°ā§‹āĻ§ā§‡ āĻ…āĻ¤āĻŋāĻ°āĻŋāĻ•ā§āĻ¤ āĻ›āĻŦāĻŋ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻžāĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ āĻ¨ā§‡āĻ‡;
  • āĻ…āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻĢāĻ°āĻŽā§āĻ¯āĻžāĻŸā§‡āĻ° āĻ…āĻ¤āĻŋāĻ°āĻŋāĻ•ā§āĻ¤ āĻ›āĻŦāĻŋ āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻžāĻ° āĻ•ā§āĻˇāĻŽāĻ¤āĻž āĻ…āĻ•ā§āĻˇāĻŽ āĻ•āĻ°ā§āĻ¨āĨ¤

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

nginx āĻ‡āĻ¨āĻ¸ā§āĻŸāĻ˛ā§‡āĻļāĻ¨ āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨

āĻ‰āĻĒāĻ°ā§‡āĻ° āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨ā§€āĻ¯āĻŧāĻ¤āĻžāĻ—ā§āĻ˛āĻŋ āĻ¸āĻŽāĻžāĻ§āĻžāĻ¨ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯ āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻ¨āĻŋāĻŽā§āĻ¨āĻ˛āĻŋāĻ–āĻŋāĻ¤ nginx āĻŽāĻĄāĻŋāĻ‰āĻ˛āĻ—ā§āĻ˛āĻŋāĻ° āĻ¸ā§‡āĻŸ āĻĒā§āĻ°āĻ¯āĻŧā§‹āĻœāĻ¨:

  • ngx_http_image_filter_module - āĻšāĻŋāĻ¤ā§āĻ°ā§‡āĻ° āĻ†āĻ•āĻžāĻ° āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨ā§‡āĻ° āĻœāĻ¨ā§āĻ¯;
  • ngx_http_proxy_module - āĻ•ā§āĻ¯āĻžāĻļā§‡ āĻ•āĻ°āĻžāĻ° āĻœāĻ¨ā§āĻ¯;
  • ngx_http_secure_link_module - āĻ¸ā§āĻĒā§āĻ¯āĻžāĻŽ āĻĨā§‡āĻ•ā§‡ āĻ°āĻ•ā§āĻˇāĻž āĻ•āĻ°āĻ¤ā§‡;

МодŅƒĐģи ngx_http_image_filter_module и ngx_http_secure_link_module āĻĄāĻŋāĻĢāĻ˛ā§āĻŸāĻ°ā§‚āĻĒā§‡ āĻ‡āĻ¨āĻ¸ā§āĻŸāĻ˛ āĻ•āĻ°āĻž āĻšāĻ¯āĻŧ āĻ¨āĻž, āĻ¤āĻžāĻ‡ āĻ¸ā§‡āĻ—ā§āĻ˛āĻŋ āĻ…āĻŦāĻļā§āĻ¯āĻ‡ āĻ‡āĻ¨āĻ¸ā§āĻŸāĻ˛ā§‡āĻļāĻ¨ āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨ āĻĒāĻ°ā§āĻ¯āĻžāĻ¯āĻŧā§‡ āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻŸ āĻ•āĻ°āĻž āĻ†āĻŦāĻļā§āĻ¯āĻ• nginx:

phoinix@phoinix-work:~/src/nginx-0.8.29
$ ./configure --with-http_secure_link_module --with-http_image_filter_module

nginx āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨

āĻ†āĻŽāĻ°āĻž āĻ†āĻŽāĻžāĻĻā§‡āĻ° āĻšā§‹āĻ¸ā§āĻŸ āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻ¯ā§‹āĻ— āĻ•āĻ°āĻŋ āĻ…āĻŦāĻ¸ā§āĻĨāĻžāĻ¨ āĻāĻŦāĻ‚ āĻ¸āĻžāĻ§āĻžāĻ°āĻŖ āĻ•ā§āĻ¯āĻžāĻļā§‡ āĻĒāĻ°āĻžāĻŽāĻŋāĻ¤āĻŋ:

...
    proxy_cache_path /www/myprojects/cache levels=1:2 keys_zone=image-preview:10m;
...
    server {
...
        location ~ ^/preview/([cir])/(.+) {
        # ĐĸиĐŋ ĐžĐŋĐĩŅ€Đ°Ņ†Đ¸Đ¸
            set                         $oper $1;
        # ПаŅ€Đ°ĐŧĐĩŅ‚Ņ€Ņ‹ иСОйŅ€Đ°ĐļĐĩĐŊиŅ и ĐŋŅƒŅ‚ŅŒ Đē Ņ„Đ°ĐšĐģŅƒ
            set                         $remn $2;
        # ПŅ€ĐžĐēŅĐ¸Ņ€ŅƒĐĩĐŧ ĐŊĐ° ĐžŅ‚Đ´ĐĩĐģŅŒĐŊŅ‹Đš Ņ…ĐžŅŅ‚
            proxy_pass                  http://myproject.ru:81/$oper/$remn;
            proxy_intercept_errors      on;
            error_page                  404 = /preview/404;
        # КĐĩŅˆĐ¸Ņ€ĐžĐ˛Đ°ĐŊиĐĩ
            proxy_cache                 image-preview;
            proxy_cache_key             "$host$document_uri";
        # 200 ĐžŅ‚вĐĩŅ‚Ņ‹ ĐēĐĩŅˆĐ¸Ņ€ŅƒĐĩĐŧ ĐŊĐ° 1 Đ´ĐĩĐŊŅŒ
            proxy_cache_valid           200 1d;
        # ĐžŅŅ‚Đ°ĐģŅŒĐŊŅ‹Đĩ ĐžŅ‚вĐĩŅ‚Ņ‹ ĐēĐĩŅˆĐ¸Ņ€ŅƒĐĩĐŧ ĐŊĐ° 1 ĐŧиĐŊŅƒŅ‚Ņƒ
            proxy_cache_valid           any 1m;
        }
        
        # ВозвŅ€Đ°Ņ‰Đ°ĐĩĐŧ ĐžŅˆĐ¸ĐąĐēŅƒ
        location = /preview/404 {
            internal;
            default_type                image/gif;
            alias                       /www/myprojects/image/noimage.gif;
        }
...
    }
...

āĻ†āĻŽāĻ°āĻž āĻ•āĻ¨āĻĢāĻŋāĻ—āĻžāĻ°ā§‡āĻļāĻ¨ā§‡ āĻāĻ•āĻŸāĻŋ āĻ¨āĻ¤ā§āĻ¨ āĻšā§‹āĻ¸ā§āĻŸ āĻ¯ā§‹āĻ— āĻ•āĻ°āĻŋ:

server {
    server_name                     myproject.ru;
    listen                          81;

    access_log                      /www/myproject.ru/logs/nginx.preview.access_log;
    error_log                       /www/myproject.ru/logs/nginx.preview.error_log info;

    # ĐŖĐēаСŅ‹Đ˛Đ°ĐĩĐŧ ŅĐĩĐēŅ€ĐĩŅ‚ĐŊĐžĐĩ ŅĐģОвО Đ´ĐģŅ md5
    secure_link_secret              secret;

    # ОŅˆĐ¸ĐąĐēи ĐžŅ‚ĐŋŅ€Đ°Đ˛ĐģŅĐĩĐŧ ĐžĐŊĐ° ĐžŅ‚Đ´ĐĩĐģŅŒĐŊŅ‹Đš location
    error_page                      403 404 415 500 502 503 504 = @404;

    # location ДĐģŅ Ņ„иĐģŅŒŅ‚Ņ€Đ° size
    location ~ ^/i/[^/]+/(.+) {
        
        # ĐŗŅ€ŅĐˇĐŊŅ‹Đš Ņ…Đ°Đē ĐžŅ‚ ИĐŗĐžŅ€Ņ ĐĄŅ‹ŅĐžĐĩва *
        alias                       /www/myproject.ru/images/$1;
        try_files                   "" @404;
    
        # ПŅ€ĐžĐ˛ĐĩŅ€ŅĐĩĐŧ ĐŋŅ€Đ°Đ˛Đ¸ĐģŅŒĐŊĐžŅŅ‚ŅŒ ŅŅŅ‹ĐģĐēи и md5
        if ($secure_link = "") { return 404; }
        
        # ИŅĐŋĐžĐģŅŒĐˇŅƒĐĩĐŧ ŅĐžĐžŅ‚вĐĩŅ‚ŅĐ˛ŅƒŅŽŅ‰Đ¸Đš Ņ„иĐģŅŒŅ‚Ņ€
        image_filter                size;
    }

    # По Đ°ĐŊĐ°ĐģĐžĐŗии ĐžŅŅ‚Đ°ĐģŅŒĐŊŅ‹Đĩ location Đ´ĐģŅ Đ´Ņ€ŅƒĐŗиŅ… Ņ„иĐģŅŒŅ‚Ņ€ĐžĐ˛
    location ~ ^/c/[^/]+/(d+|-)x(d+|-)/(.+) {
        set                         $width  $1;
        set                         $height $2;
        
        alias                       /www/myproject.ru/images/$3;
        try_files                   "" @404;
    
        if ($secure_link = "") { return 404; }
    
        image_filter                crop  $width  $height;
    }
    
    location ~ ^/r/[^/]+/(d+|-)x(d+|-)/(.+) {
        set                         $width  $1;
        set                         $height $2;

        alias                       /www/myproject.ru/images/$3;
        try_files                   "" @404;

        if ($secure_link = "") { return 404; }

        image_filter                resize  $width  $height;
    }

    location @404 { return 404; }
}

āĻĢāĻ˛āĻ¸ā§āĻŦāĻ°ā§‚āĻĒ, āĻ¨āĻŋāĻŽā§āĻ¨āĻ˛āĻŋāĻ–āĻŋāĻ¤ āĻ˛āĻŋāĻ™ā§āĻ•āĻ—ā§āĻ˛āĻŋ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§‡ āĻ…āĻ¤āĻŋāĻ°āĻŋāĻ•ā§āĻ¤ āĻšāĻŋāĻ¤ā§āĻ°āĻ—ā§āĻ˛āĻŋ āĻĒāĻžāĻ“āĻ¯āĻŧāĻž āĻ¯ā§‡āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡:

* try_files — āĻ¸ā§āĻĒā§‡āĻ¸ āĻāĻŦāĻ‚ āĻ°āĻžāĻļāĻŋāĻ¯āĻŧāĻžāĻ¨ āĻ…āĻ•ā§āĻˇāĻ°ā§‡āĻ° āĻĒā§āĻ°āĻ¤āĻŋ āĻ¸āĻ‚āĻŦā§‡āĻĻāĻ¨āĻļā§€āĻ˛, āĻ¤āĻžāĻ‡ āĻ†āĻŽāĻžāĻ•ā§‡ āĻāĻ•āĻŸāĻŋ āĻ•ā§āĻ°āĻžāĻš āĻ¤ā§ˆāĻ°āĻŋ āĻ•āĻ°āĻ¤ā§‡ āĻšāĻ¯āĻŧā§‡āĻ›āĻŋāĻ˛ āĻ‰āĻĒāĻ¨āĻžāĻŽ.

āĻāĻ•āĻŸāĻŋ āĻ“āĻ¯āĻŧā§‡āĻŦ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻ•āĻ°ā§āĻ¨

āĻ“āĻ¯āĻŧā§‡āĻŦ āĻ…ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻ•ā§‡āĻļāĻ¨ āĻ¸ā§āĻ¤āĻ°ā§‡, āĻ†āĻĒāĻ¨āĻŋ āĻ¨āĻŋāĻŽā§āĻ¨āĻ˛āĻŋāĻ–āĻŋāĻ¤ āĻĒāĻĻā§āĻ§āĻ¤āĻŋāĻŸāĻŋ āĻ•āĻ°āĻ¤ā§‡ āĻĒāĻžāĻ°ā§‡āĻ¨ (āĻĒāĻžāĻ°ā§āĻ˛):

sub proxy_image {
    use Digest::MD5     qw /md5_hex/;
    my %params = @_;
    my $filter = {
                    size    => 'i',
                    resize  => 'r',
                    crop    => 'c'            
                  }->{$params{filter}} || 'r';
    my $path = ($filter ne 'i' ?
                    ( $params{height} || '_' ) . 'x' . ( $params{width} || '_' ) . '/' :
                    ()
               ) . $params{source};
    my $md5 = md5_hex( $path . 'secret' );
    $path = '/preview/' . $filter . '/' . $md5 . '/' . $path;
    return $path;
}

my $preview_path = &proxy_image(
                    source  => 'image1.jpg',
                    height  => 100,
                    width   => 100,
                    filter  => 'resize'
                );

āĻ¯āĻĻāĻŋāĻ“ āĻ†āĻŽāĻŋ āĻŽāĻžāĻĒ āĻ—āĻŖāĻ¨āĻž āĻ•āĻ°āĻžāĻ° āĻ¸ā§āĻĒāĻžāĻ°āĻŋāĻļ āĻ•āĻ°āĻŦ āĻĒā§āĻ°āĻŋāĻ­āĻŋāĻ‰.

āĻŽāĻ‡ āĻĻāĻŋāĻ¯āĻŧāĻž āĻ†āĻšāĻ°āĻŖ āĻ•āĻ°āĻž

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

ĐžŅ€Đ¸ĐŗиĐŊĐ°Đģ

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

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