āĻĨāĻŋāĻŽ āĻāĻ¨ā§āĻ¨āĻ¯āĻŧāĻ¨
āĻŦā§āĻ¯āĻŦāĻšā§āĻ¤ āĻā§āĻļāĻ˛āĻāĻŋ "āĻĄāĻžāĻāĻžāĻŦā§āĻ¸ā§ āĻŦā§āĻ¯āĻŦāĻ¸āĻžāĻ¯āĻŧāĻŋāĻ āĻ¯ā§āĻā§āĻ¤āĻŋ" āĻ§āĻžāĻ°āĻŖāĻžāĻ° āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻĄāĻŧāĻŋāĻ¤, āĻ¯āĻž āĻāĻāĻžāĻ¨ā§ āĻāĻ°āĻ āĻŦāĻŋāĻļāĻĻā§ āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻāĻ°āĻž āĻšāĻ¯āĻŧā§āĻā§ -
āĻ¤āĻžāĻ¤ā§āĻ¤ā§āĻŦāĻŋāĻ āĻ
āĻāĻļāĻāĻŋ āĻĄāĻā§āĻŽā§āĻ¨ā§āĻā§āĻļāĻ¨ā§ āĻāĻžāĻ˛āĻāĻžāĻŦā§ āĻŦāĻ°ā§āĻŖāĻ¨āĻž āĻāĻ°āĻž āĻšāĻ¯āĻŧā§āĻā§
āĻ¨āĻŋāĻŦāĻ¨ā§āĻ§ā§ āĻ¨āĻ¤ā§āĻ¨ āĻāĻŋāĻā§ āĻ¨ā§āĻ, āĻā§āĻ¨ āĻā§āĻĒāĻ¨ āĻ āĻ°ā§āĻĨ āĻŦāĻž āĻā§āĻĒāĻ¨ āĻā§āĻāĻžāĻ¨ āĻ¨ā§āĻāĨ¤ āĻāĻāĻāĻŋ āĻ¤āĻžāĻ¤ā§āĻ¤ā§āĻŦāĻŋāĻ āĻ§āĻžāĻ°āĻŖāĻžāĻ° āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻŋāĻ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻā§ āĻļā§āĻ§ā§ āĻāĻāĻāĻŋ āĻ¸ā§āĻā§āĻāĨ¤ āĻā§āĻ āĻāĻā§āĻ°āĻšā§ āĻšāĻ˛ā§ āĻĒāĻĄāĻŧā§āĻ¨āĨ¤ āĻāĻĒāĻ¨āĻŋ āĻ¯āĻĻāĻŋ āĻāĻā§āĻ°āĻšā§ āĻ¨āĻž āĻšāĻ¨ āĻ¤āĻŦā§ āĻāĻĒāĻ¨āĻžāĻ° āĻ¸āĻŽāĻ¯āĻŧ āĻ¨āĻˇā§āĻ āĻāĻ°āĻŦā§āĻ¨ āĻ¨āĻžāĨ¤
āĻ¸āĻŽāĻ¸ā§āĻ¯āĻž āĻāĻ āĻ¨
āĻ ā§āĻ¯āĻžāĻĒā§āĻ˛āĻŋāĻā§āĻļāĻ¨ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻāĻžāĻ°ā§āĻ° āĻā§āĻŽāĻŋāĻāĻž āĻ āĻ¨ā§āĻ¸āĻžāĻ°ā§ āĻāĻāĻāĻŋ āĻ¨āĻĨāĻŋ āĻĻā§āĻāĻž/āĻĸā§āĻāĻžāĻ¨ā§/āĻĒāĻ°āĻŋāĻŦāĻ°ā§āĻ¤āĻ¨/āĻŽā§āĻā§ āĻĢā§āĻ˛āĻžāĻ° āĻ ā§āĻ¯āĻžāĻā§āĻ¸ā§āĻ¸ āĻ¸ā§āĻŽāĻžāĻŦāĻĻā§āĻ§ āĻāĻ°āĻž āĻĒā§āĻ°āĻ¯āĻŧā§āĻāĻ¨āĨ¤ āĻā§āĻŽāĻŋāĻāĻž āĻāĻāĻāĻŋ āĻā§āĻŦāĻŋāĻ˛ā§ āĻāĻāĻāĻŋ āĻāĻ¨ā§āĻā§āĻ°āĻŋ āĻŦā§āĻāĻžāĻ¯āĻŧ āĻā§āĻŽāĻŋāĻāĻž āĻāĻāĻāĻŋ āĻā§āĻŦāĻŋāĻ˛ā§āĻ° āĻ¸āĻžāĻĨā§ āĻŦāĻšā§-āĻĨā§āĻā§-āĻ āĻ¨ā§āĻ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻā§āĻ° āĻ¸āĻžāĻĨā§ āĻ¯ā§āĻā§āĻ¤ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ°āĻāĻžāĻ°ā§. āĻ¤ā§āĻā§āĻāĻ¤āĻžāĻ° āĻāĻžāĻ°āĻŖā§ āĻā§āĻŦāĻŋāĻ˛ā§āĻ° āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ā§āĻ° āĻŦāĻŋāĻŦāĻ°āĻŖ āĻŦāĻžāĻĻ āĻĻā§āĻāĻ¯āĻŧāĻž āĻšāĻ¯āĻŧā§āĻā§āĨ¤ āĻŦāĻŋāĻˇāĻ¯āĻŧ āĻāĻ˛āĻžāĻāĻžāĻ° āĻ¸āĻžāĻĨā§ āĻ¸āĻŽā§āĻĒāĻ°ā§āĻāĻŋāĻ¤ āĻ¸ā§āĻ¨āĻŋāĻ°ā§āĻĻāĻŋāĻˇā§āĻ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ā§āĻ° āĻŦāĻŋāĻŦāĻ°āĻŖāĻ āĻŦāĻžāĻĻ āĻĻā§āĻāĻ¯āĻŧāĻž āĻšāĻ¯āĻŧā§āĻā§āĨ¤
āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨
āĻā§āĻŽāĻŋāĻāĻž, āĻ¸ā§āĻāĻŋāĻŽāĻž, āĻā§āĻŦāĻŋāĻ˛ āĻ¤ā§āĻ°āĻŋ āĻāĻ°ā§āĻ¨
āĻĄāĻžāĻāĻžāĻŦā§āĻ¸ āĻ āĻŦāĻā§āĻā§āĻ āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻž
CREATE ROLE store;
CREATE SCHEMA store AUTHORIZATION store;
CREATE TABLE store.docs
(
id integer , --id Đ´ĐžĐēŅĐŧĐĩĐŊŅĐ°
man_id integer , --id ĐŧĐĩĐŊĐĩĐ´ĐļĐĩŅĐ° Đ´ĐžĐēŅĐŧĐĩĐŊŅĐ°
stat_id integer , --id ŅŅĐ°ŅŅŅĐ° Đ´ĐžĐēŅĐŧĐĩĐŊŅĐ°
...
is_del BOOLEAN DEFAULT FALSE
);
ALTER TABLE store.docs ADD CONSTRAINT doc_pk PRIMARY KEY (id);
ALTER TABLE store.docs OWNER TO store ;
RLS āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻĢāĻžāĻāĻļāĻ¨ āĻ¤ā§āĻ°āĻŋ āĻāĻ°āĻž
SELECT āĻ¸āĻžāĻ°āĻŋ āĻ¸āĻŽā§āĻĒāĻžāĻĻāĻ¨ āĻāĻ°āĻžāĻ° āĻā§āĻˇāĻŽāĻ¤āĻž āĻĒāĻ°ā§āĻā§āĻˇāĻž āĻāĻ°āĻž āĻšāĻā§āĻā§
āĻā§āĻ_āĻ¸āĻŋāĻ˛ā§āĻā§āĻ āĻāĻ°ā§āĻ¨
CREATE OR REPLACE FUNCTION store.check_select ( current_id store.docs.id%TYPE ) RETURNS boolean AS $$
DECLARE
result boolean ;
curr_pid integer ;
curr_stat_id integer ;
doc_man_id integer ;
BEGIN
-- DBA иĐŧĐĩĐĩŅ Đ´ĐžŅŅŅĐŋ ĐēĐž вŅĐĩĐŧ Đ´ĐžĐēŅĐŧĐĩĐŊŅĐ°Đŧ
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
--ĐŅĐģи Đ´ĐžĐēŅĐŧĐĩĐŊŅ иĐŧĐĩĐĩŅ ĐŧĐĩŅĐēŅ 'ŅĐ´Đ°ĐģĐĩĐŊ' - ĐŊĐĩ ĐŋĐžĐēаСŅваŅŅ в вŅйОŅĐēĐĩ
SELECT
is_del
INTO
result
FROM
store.docs
WHERE
id = current_id ;
IF result = TRUE
THEN
RETURN FALSE ;
END IF ;
--------------------------------
--ĐĐžĐģŅŅиŅŅ id ŅĐĩĐēŅŅĐĩĐŗĐž ĐŋĐžĐģŅСОваŅĐĩĐģŅ
SELECT
service_function.get_curr_pid ()
INTO
curr_pid ;
--------------------------------
--ĐĐžĐģŅŅиŅŅ id ĐŧĐĩĐŊĐĩĐ´ĐļĐĩŅĐ° Đ´ĐžĐēŅĐŧĐĩĐŊŅĐ°
SELECT
man_id
INTO
doc_man_id
FROM
store.docs
WHERE
id = current_id ;
--------------------------------
--ĐŅĐģи ĐŧĐĩĐŊĐĩĐ´ĐļĐĩŅ Đ´ĐžĐēŅĐŧĐĩĐŊŅĐ° ĐŊĐĩ ŅĐĩĐēŅŅиК ĐŋĐžĐģŅСОваŅĐĩĐģŅ иĐģи ĐŧĐĩĐŊĐĩĐ´ĐļĐĩŅ ĐŊĐĩ ĐŊаСĐŊĐ°ŅĐĩĐŊ
--дОйавиŅŅ Đ´ĐžĐēŅĐŧĐĩĐŊŅ в вŅйОŅĐēŅ
IF doc_man_id != curr_pid OR doc_man_id IS NULL
THEN
RETURN TRUE ;
ELSE
--ĐĐžĐģŅŅиŅŅ ŅĐĩĐēŅŅиК ŅŅĐ°ŅŅŅ Đ´ĐžĐēŅĐŧĐĩĐŊŅĐ°
SELECT
stat_id
INTO
curr_statid
FROM
store.docs
WHERE
id = current_id ;
--ĐŅĐģи ŅŅĐ°ŅŅŅ ĐŋОСвОĐģŅĐĩŅ ĐŋŅĐžŅĐŧĐžŅŅĐĩŅŅ Đ´ĐžĐēŅĐŧĐĩĐŊŅ - дОйавиŅŅ Đ´ĐžĐēŅĐŧĐĩĐŊŅ в вŅйОŅĐēŅ
IF curr_statid = 4 OR curr_statid = 9
THEN
RETURN TRUE ;
ELSE
--ĐĐŊĐ°ŅĐĩ - иŅĐēĐģŅŅиŅŅ Đ´ĐžĐēŅĐŧĐĩĐŊŅ иС вŅйОŅĐēи
RETURN FALSE ;
END IF ;
END IF ;
--------------------------------
RETURN FALSE ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.check_select( store.docs.id%TYPE ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.check_select( store.docs.id%TYPE ) FROM public;
GRANT EXECUTE ON FUNCTION store.check_select( store.docs.id%TYPE ) TO service_functions;
āĻ¸āĻžāĻ°āĻŋ āĻĸā§āĻāĻžāĻ¨ā§āĻ° āĻā§āĻˇāĻŽāĻ¤āĻž āĻĒāĻ°ā§āĻā§āĻˇāĻž āĻāĻ°āĻž āĻšāĻā§āĻā§
check_insert
CREATE OR REPLACE FUNCTION store.check_insert ( current_id store.docs.id%TYPE ) RETURNS boolean AS $$
DECLARE
curr_role_id integer ;
BEGIN
--DBA ĐŧĐžĐļĐĩŅ дОйавĐģŅŅŅ ŅŅŅĐžĐēŅ в ĐģŅйОĐŧ ŅĐģŅŅĐ°Đĩ
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
--ĐĐžĐģŅŅиŅŅ id ŅĐžĐģи ŅĐĩĐēŅŅĐĩĐŗĐž ĐŋĐžĐģŅСОваŅĐĩĐģŅ
SELECT
service_functions.current_rid()
INTO
curr_role_id ;
--------------------------------
--ĐŅĐģи ŅĐžĐģŅ Đ´ĐžĐŋŅŅĐēĐ°ĐĩŅ вОСĐŧĐžĐļĐŊĐžŅŅŅ ŅОСдаĐŊиŅ ĐŊОвОĐŗĐž Đ´ĐžĐēŅĐŧĐĩĐŊŅĐ°
--ŅаСŅĐĩŅиŅŅ
IF curr_role_id = 3 OR curr_role_id = 5
THEN
RETURN TRUE ;
END IF ;
--------------------------------
RETURN FALSE ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.check_insert( store.docs.id%TYPE ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.check_insert( store.docs.id%TYPE ) FROM public;
GRANT EXECUTE ON FUNCTION store.check_insert( store.docs.id%TYPE ) TO service_functions;
āĻāĻāĻāĻŋ āĻ¸āĻžāĻ°āĻŋ āĻŽā§āĻā§ āĻĢā§āĻ˛āĻžāĻ° āĻā§āĻˇāĻŽāĻ¤āĻž āĻĒāĻ°ā§āĻā§āĻˇāĻž āĻāĻ°āĻž āĻšāĻā§āĻā§
check_delete
CREATE OR REPLACE FUNCTION store.check_delete ( current_id store.docs.id%TYPE )
RETURNS boolean AS $$
BEGIN
--ĐĸĐžĐģŅĐēĐž DBA ĐŧĐžĐļĐĩŅ ŅĐ´Đ°ĐģŅŅŅ ŅŅŅĐžĐēŅ
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
RETURN FALSE ;
END
$$ LANGUAGE plpgsql
SECURITY DEFINER;
ALTER FUNCTION store.check_delete( store.docs.id%TYPE ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.check_delete( store.docs.id%TYPE ) FROM public;
āĻāĻāĻāĻŋ āĻ¸āĻžāĻ°āĻŋ āĻāĻĒāĻĄā§āĻ āĻāĻ°āĻžāĻ° āĻā§āĻˇāĻŽāĻ¤āĻž āĻĒāĻ°ā§āĻā§āĻˇāĻž āĻāĻ°āĻž āĻšāĻā§āĻā§āĨ¤
update_using
CREATE OR REPLACE FUNCTION store.update_using ( current_id store.docs.id%TYPE , is_del boolean )
RETURNS boolean AS $$
BEGIN
--ĐĐžĐēŅĐŧĐĩĐŊŅŅ иĐŧĐĩŅŅиĐĩ ŅŅĐ°ŅŅŅ 'ŅĐ´Đ°ĐģĐĩĐŊ' - ĐŊĐĩ ŅĐĩĐ´Đ°ĐēŅиŅŅŅŅŅŅ
IF is_del
THEN
RETURN FALSE ;
ELSE
RETURN TRUE ;
END IF ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.update_using( store.docs.id%TYPE , boolean ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.update_using( store.docs.id%TYPE , boolean ) FROM public;
GRANT EXECUTE ON FUNCTION store.update_using( store.docs.id%TYPE ) TO service_functions;
āĻāĻĒāĻĄā§āĻ āĻā§āĻ
CREATE OR REPLACE FUNCTION store.update_with_check ( current_id store.docs.id%TYPE , is_del boolean )
RETURNS boolean AS $$
DECLARE
current_rid integer ;
current_statid integer ;
BEGIN
--DBA ĐŧĐžĐļĐĩŅ ĐŋŅĐžŅĐŧĐ°ŅŅиваŅŅ ŅŅŅĐžĐēŅ
IF SESSION_USER = 'curr_dba'
THEN
RETURN TRUE ;
END IF ;
--------------------------------
--ĐĐžĐģŅŅиŅŅ id ŅĐžĐģи ŅĐĩĐēŅŅĐĩĐŗĐž ĐŋĐžĐģŅСОваŅĐĩĐģŅ
SELECT
service_functions.current_rid()
INTO
curr_role_id ;
--------------------------------
--ĐŖĐ´Đ°ĐģĐĩĐŊиĐĩ Đ´ĐžĐēŅĐŧĐĩĐŊŅĐ° - иСĐŧĐĩĐŊĐĩĐŊиĐĩ ĐŋŅиСĐŊĐ°ĐēĐ°
IF is_deleted
THEN
--ĐŅĐģи ŅĐžĐģŅ ĐŋĐžĐģŅСОваŅĐĩĐģŅ ***
IF current_role_id = 3
THEN
SELECT
stat_id
INTO
curr_statid
FROM
store.docs
WHERE
id = current_id ;
--ĐĐžĐēŅĐŧĐĩĐŊŅ в ŅŅĐ°ŅŅŅĐĩ *** ĐŊĐĩĐģŅСŅ ŅĐ´Đ°ĐģиŅŅ
IF current_status_id = 11
THEN
RETURN FALSE ;
ELSE
--ĐĐžĐļĐŊĐž ŅĐ´Đ°ĐģиŅŅ Đ´ĐžĐēŅĐŧĐĩĐŊŅ в Đ´ŅŅĐŗиŅ
ŅŅĐ°ŅŅŅĐ°Ņ
RETURN TRUE ;
END IF ;
--ĐĐŊĐ°ŅĐĩ , ĐĩŅĐģи ŅĐžĐģŅ ĐŋĐžĐģŅСОваŅĐĩĐģŅ ***
ELSIF current_role_id = 5
THEN
--ĐŅĐĩ ŅŅĐ°ŅŅŅŅ Đ´ĐžĐēŅĐŧĐĩĐŊŅĐ°
RETURN TRUE ;
ELSE
--ĐŅŅĐŗиĐĩ ĐŋĐžĐģŅСОваŅĐĩĐģи ĐŊĐĩ ĐŧĐžĐŗŅŅ ŅĐ´Đ°ĐģŅŅŅ Đ´ĐžĐēŅĐŧĐĩĐŊŅŅ
RETURN FALSE ;
END IF ;
ELSE
--ĐĐąĐŊОвĐģĐĩĐŊиĐĩ Đ´ĐžĐēŅĐŧĐĩĐŊŅĐ° ŅаСŅĐĩŅĐĩĐŊĐž
RETURN TRUE ;
END IF ;
RETURN FALSE ;
END
$$ LANGUAGE plpgsql SECURITY DEFINER;
ALTER FUNCTION store.update_with_check( storg.docs.id%TYPE , boolean ) OWNER TO store ;
REVOKE EXECUTE ON FUNCTION store.update_with_check( storg.docs.id%TYPE , boolean ) FROM public;
GRANT EXECUTE ON FUNCTION store.update_with_check( store.docs.id%TYPE ) TO service_functions;
āĻāĻāĻāĻŋ āĻā§āĻŦāĻŋāĻ˛ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻ¸āĻžāĻ°āĻŋ āĻ¸ā§āĻ¤āĻ°ā§āĻ° āĻ¨āĻŋāĻ°āĻžāĻĒāĻ¤ā§āĻ¤āĻž āĻ¨ā§āĻ¤āĻŋ āĻ¸āĻā§āĻ°āĻŋāĻ¯āĻŧ āĻāĻ°ā§āĻ¨āĨ¤
āĻ¸āĻžāĻ°āĻŋ āĻ¸ā§āĻ¤āĻ°ā§āĻ° āĻ¨āĻŋāĻ°āĻžāĻĒāĻ¤ā§āĻ¤āĻž āĻ¸āĻā§āĻˇāĻŽ āĻāĻ°ā§āĻ¨
ALTER TABLE store.docs ENABLE ROW LEVEL SECURITY ;
CREATE POLICY doc_select ON store.docs FOR SELECT TO service_functions USING ( (SELECT store.check_select(id)) );
CREATE POLICY doc_insert ON store.docs FOR INSERT TO service_functions WITH CHECK ( (SELECT store.check_insert(id)) );
CREATE POLICY docs_delete ON store.docs FOR DELETE TO service_functions USING ( (SELECT store.check_delete(id)) );
CREATE POLICY doc_update_using ON store.docs FOR UPDATE TO service_functions USING ( (SELECT store.update_using(id , is_del )) );
CREATE POLICY doc_update_check ON store.docs FOR UPDATE TO service_functions WITH CHECK ( (SELECT store.update_with_check(id , is_del )) );
āĻĢāĻ˛āĻžāĻĢāĻ˛
āĻāĻāĻž āĻāĻžāĻ āĻāĻ°ā§āĨ¤
āĻĒā§āĻ°āĻ¸ā§āĻ¤āĻžāĻŦāĻŋāĻ¤ āĻā§āĻļāĻ˛āĻāĻŋ āĻŦā§āĻ¯āĻŦāĻ¸āĻžāĻ¯āĻŧāĻŋāĻ āĻĢāĻžāĻāĻļāĻ¨ā§āĻ° āĻ¸ā§āĻ¤āĻ° āĻĨā§āĻā§ āĻĄā§āĻāĻž āĻ¸ā§āĻā§āĻ°ā§āĻ āĻ¸ā§āĻ¤āĻ°ā§ āĻ°ā§āĻ˛ āĻŽāĻĄā§āĻ˛ā§āĻ° āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ āĻ¸ā§āĻĨāĻžāĻ¨āĻžāĻ¨ā§āĻ¤āĻ° āĻāĻ°āĻž āĻ¸āĻŽā§āĻāĻŦ āĻāĻ°ā§āĻā§āĨ¤
āĻŦā§āĻ¯āĻŦāĻ¸āĻžāĻ¯āĻŧā§āĻ° āĻĒā§āĻ°āĻ¯āĻŧā§āĻāĻ¨ā§āĻ¯āĻŧāĻ¤āĻžāĻā§āĻ˛āĻŋāĻ° āĻĒā§āĻ°āĻ¯āĻŧā§āĻāĻ¨ āĻšāĻ˛ā§ āĻĢāĻžāĻāĻļāĻ¨āĻā§āĻ˛āĻŋāĻā§ āĻāĻ°āĻ āĻĒāĻ°āĻŋāĻļā§āĻ˛āĻŋāĻ¤ āĻĄā§āĻāĻž āĻ˛ā§āĻāĻžāĻ¨ā§āĻ° āĻŽāĻĄā§āĻ˛āĻā§āĻ˛āĻŋ āĻŦāĻžāĻ¸ā§āĻ¤āĻŦāĻžāĻ¯āĻŧāĻ¨ā§āĻ° āĻāĻ¨ā§āĻ¯ āĻāĻāĻāĻŋ āĻā§āĻŽāĻĒā§āĻ˛ā§āĻ āĻšāĻŋāĻ¸āĻžāĻŦā§ āĻŦā§āĻ¯āĻŦāĻšāĻžāĻ° āĻāĻ°āĻž āĻ¯ā§āĻ¤ā§ āĻĒāĻžāĻ°ā§āĨ¤
āĻāĻ¤ā§āĻ¸: www.habr.com