зеркало из https://github.com/github/ruby.git
* time.c (time_load): restore instance variables (if any) before
loading from marshaled data. * time.c (time_mdump): new marshal dumper. _dump is still available for compatibility. * time.c (time_mload): new marshal loader. * marshal.c (w_object): preserve instance variables for objects with marshal_dump. * marshal.c (r_object0): restore instance variables before calling marshal_load. * error.c (rb_warn_m): always return nil. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4651 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
Родитель
a70a430f83
Коммит
10c4bb29b2
20
ChangeLog
20
ChangeLog
|
@ -1,3 +1,8 @@
|
|||
Thu Oct 2 17:22:37 2003 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||
|
||||
* time.c (time_load): restore instance variables (if any) before
|
||||
loading from marshaled data.
|
||||
|
||||
Thu Oct 2 14:19:15 2003 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* ext/iconv/iconv.c (iconv_fail): now yield erred substring, and
|
||||
|
@ -37,6 +42,21 @@ Thu Oct 2 03:25:01 2003 NAKAMURA Usaku <usa@ruby-lang.org>
|
|||
|
||||
* eval.c (rb_thread_raise): prototype; avoid VC++ warning.
|
||||
|
||||
Thu Oct 2 01:37:34 2003 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||
|
||||
* time.c (time_mdump): new marshal dumper. _dump is still
|
||||
available for compatibility.
|
||||
|
||||
* time.c (time_mload): new marshal loader.
|
||||
|
||||
* marshal.c (w_object): preserve instance variables for objects
|
||||
with marshal_dump.
|
||||
|
||||
* marshal.c (r_object0): restore instance variables before calling
|
||||
marshal_load.
|
||||
|
||||
* error.c (rb_warn_m): always return nil.
|
||||
|
||||
Thu Oct 2 01:32:46 2003 Yukihiro Matsumoto <matz@ruby-lang.org>
|
||||
|
||||
* eval.c (rb_f_block_given_p): real required condition is
|
||||
|
|
9
error.c
9
error.c
|
@ -166,10 +166,11 @@ static VALUE
|
|||
rb_warn_m(self, mesg)
|
||||
VALUE self, mesg;
|
||||
{
|
||||
if (NIL_P(ruby_verbose)) return;
|
||||
rb_io_write(rb_stderr, mesg);
|
||||
rb_io_write(rb_stderr, rb_default_rs);
|
||||
return mesg;
|
||||
if (!NIL_P(ruby_verbose)) {
|
||||
rb_io_write(rb_stderr, mesg);
|
||||
rb_io_write(rb_stderr, rb_default_rs);
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
14
eval.c
14
eval.c
|
@ -10187,7 +10187,19 @@ rb_catch(tag, func, data)
|
|||
VALUE (*func)();
|
||||
VALUE data;
|
||||
{
|
||||
return rb_iterate((VALUE(*)_((VALUE)))catch_i, ID2SYM(rb_intern(tag)), func, data);
|
||||
int state;
|
||||
VALUE val = Qnil; /* OK */
|
||||
|
||||
PUSH_TAG(PROT_NONE);
|
||||
PUSH_SCOPE();
|
||||
if ((state = EXEC_TAG()) == 0) {
|
||||
val = rb_iterate((VALUE(*)_((VALUE)))catch_i, ID2SYM(rb_intern(tag)), func, data);
|
||||
}
|
||||
POP_SCOPE();
|
||||
POP_TAG();
|
||||
if (state) JUMP_TAG(state);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
|
73
marshal.c
73
marshal.c
|
@ -482,11 +482,15 @@ w_object(obj, arg, limit)
|
|||
if (rb_respond_to(obj, s_mdump)) {
|
||||
VALUE v;
|
||||
|
||||
if (TYPE(obj) == T_OBJECT) {
|
||||
w_byte(TYPE_IVAR, arg);
|
||||
ivtbl = ROBJECT(obj)->iv_tbl;
|
||||
}
|
||||
v = rb_funcall(obj, s_mdump, 0, 0);
|
||||
w_byte(TYPE_USRMARSHAL, arg);
|
||||
w_unique(rb_class2name(CLASS_OF(obj)), arg);
|
||||
w_object(v, arg, limit);
|
||||
if (ivtbl) w_ivar(0, &c_arg); /* do not dump generic_ivar */
|
||||
if (ivtbl) w_ivar(ivtbl, &c_arg);
|
||||
return;
|
||||
}
|
||||
if (rb_respond_to(obj, s_dump)) {
|
||||
|
@ -498,7 +502,7 @@ w_object(obj, arg, limit)
|
|||
}
|
||||
w_class(TYPE_USERDEF, obj, arg);
|
||||
w_bytes(RSTRING(v)->ptr, RSTRING(v)->len, arg);
|
||||
if (ivtbl) w_ivar(0, &c_arg);
|
||||
if (ivtbl) w_ivar(ivtbl, &c_arg);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -897,7 +901,7 @@ r_string(arg)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
r_regist(v, arg)
|
||||
r_entry(v, arg)
|
||||
VALUE v;
|
||||
struct load_arg *arg;
|
||||
{
|
||||
|
@ -948,9 +952,10 @@ path2module(path)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
r_object0(arg, proc)
|
||||
r_object0(arg, proc, ivp)
|
||||
struct load_arg *arg;
|
||||
VALUE proc;
|
||||
int *ivp;
|
||||
{
|
||||
VALUE v = Qnil;
|
||||
int type = r_byte(arg);
|
||||
|
@ -966,15 +971,19 @@ r_object0(arg, proc)
|
|||
return v;
|
||||
|
||||
case TYPE_IVAR:
|
||||
v = r_object0(arg, 0);
|
||||
r_ivar(v, arg);
|
||||
{
|
||||
int ivar = Qtrue;
|
||||
|
||||
v = r_object0(arg, 0, &ivar);
|
||||
if (ivar) r_ivar(v, arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_EXTENDED:
|
||||
{
|
||||
VALUE m = path2module(r_unique(arg));
|
||||
|
||||
v = r_object0(arg, 0);
|
||||
v = r_object0(arg, 0, 0);
|
||||
rb_extend_object(v, m);
|
||||
}
|
||||
break;
|
||||
|
@ -986,7 +995,7 @@ r_object0(arg, proc)
|
|||
if (FL_TEST(c, FL_SINGLETON)) {
|
||||
rb_raise(rb_eTypeError, "singleton can't be loaded");
|
||||
}
|
||||
v = r_object0(arg, 0);
|
||||
v = r_object0(arg, 0, 0);
|
||||
if (rb_special_const_p(v) || TYPE(v) == T_OBJECT || TYPE(v) == T_CLASS) {
|
||||
format_error:
|
||||
rb_raise(rb_eArgError, "dump format error (user class)");
|
||||
|
@ -1040,7 +1049,7 @@ r_object0(arg, proc)
|
|||
d = load_mantissa(d, e, RSTRING(str)->len - (e - ptr));
|
||||
}
|
||||
v = rb_float_new(d);
|
||||
r_regist(v, arg);
|
||||
r_entry(v, arg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1085,19 +1094,19 @@ r_object0(arg, proc)
|
|||
len--;
|
||||
}
|
||||
v = rb_big_norm((VALUE)big);
|
||||
r_regist(v, arg);
|
||||
r_entry(v, arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_STRING:
|
||||
v = r_regist(r_string(arg), arg);
|
||||
v = r_entry(r_string(arg), arg);
|
||||
break;
|
||||
|
||||
case TYPE_REGEXP:
|
||||
{
|
||||
volatile VALUE str = r_bytes(arg);
|
||||
int options = r_byte(arg);
|
||||
v = r_regist(rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, options), arg);
|
||||
v = r_entry(rb_reg_new(RSTRING(str)->ptr, RSTRING(str)->len, options), arg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1106,7 +1115,7 @@ r_object0(arg, proc)
|
|||
volatile long len = r_long(arg); /* gcc 2.7.2.3 -O2 bug?? */
|
||||
|
||||
v = rb_ary_new2(len);
|
||||
r_regist(v, arg);
|
||||
r_entry(v, arg);
|
||||
while (len--) {
|
||||
rb_ary_push(v, r_object(arg));
|
||||
}
|
||||
|
@ -1119,7 +1128,7 @@ r_object0(arg, proc)
|
|||
long len = r_long(arg);
|
||||
|
||||
v = rb_hash_new();
|
||||
r_regist(v, arg);
|
||||
r_entry(v, arg);
|
||||
while (len--) {
|
||||
VALUE key = r_object(arg);
|
||||
VALUE value = r_object(arg);
|
||||
|
@ -1150,7 +1159,7 @@ r_object0(arg, proc)
|
|||
rb_ary_push(values, Qnil);
|
||||
}
|
||||
v = rb_struct_alloc(klass, values);
|
||||
r_regist(v, arg);
|
||||
r_entry(v, arg);
|
||||
for (i=0; i<len; i++) {
|
||||
slot = r_symbol(arg);
|
||||
|
||||
|
@ -1168,27 +1177,39 @@ r_object0(arg, proc)
|
|||
case TYPE_USERDEF:
|
||||
{
|
||||
VALUE klass = path2class(r_unique(arg));
|
||||
VALUE data;
|
||||
|
||||
if (!rb_respond_to(klass, s_load)) {
|
||||
rb_raise(rb_eTypeError, "class %s needs to have method `_load'",
|
||||
rb_class2name(klass));
|
||||
}
|
||||
v = rb_funcall(klass, s_load, 1, r_string(arg));
|
||||
r_regist(v, arg);
|
||||
data = r_string(arg);
|
||||
if (ivp) {
|
||||
r_ivar(data, arg);
|
||||
*ivp = Qfalse;
|
||||
}
|
||||
v = rb_funcall(klass, s_load, 1, data);
|
||||
r_entry(v, arg);
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_USRMARSHAL:
|
||||
{
|
||||
VALUE klass = path2class(r_unique(arg));
|
||||
VALUE data;
|
||||
|
||||
v = rb_obj_alloc(klass);
|
||||
if (!rb_respond_to(v, s_mload)) {
|
||||
rb_raise(rb_eTypeError, "instance of %s needs to have method `marshal_load'",
|
||||
rb_class2name(klass));
|
||||
}
|
||||
r_regist(v, arg);
|
||||
rb_funcall(v, s_mload, 1, r_object(arg));
|
||||
r_entry(v, arg);
|
||||
data = r_object(arg);
|
||||
if (ivp) {
|
||||
r_ivar(v, arg);
|
||||
*ivp = Qfalse;
|
||||
}
|
||||
rb_funcall(v, s_mload, 1, data);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1200,7 +1221,7 @@ r_object0(arg, proc)
|
|||
if (TYPE(v) != T_OBJECT) {
|
||||
rb_raise(rb_eArgError, "dump format error");
|
||||
}
|
||||
r_regist(v, arg);
|
||||
r_entry(v, arg);
|
||||
r_ivar(v, arg);
|
||||
}
|
||||
break;
|
||||
|
@ -1222,13 +1243,13 @@ r_object0(arg, proc)
|
|||
if (TYPE(v) != T_DATA) {
|
||||
rb_raise(rb_eArgError, "dump format error");
|
||||
}
|
||||
r_regist(v, arg);
|
||||
r_entry(v, arg);
|
||||
if (!rb_respond_to(v, s_load_data)) {
|
||||
rb_raise(rb_eTypeError,
|
||||
"class %s needs to have instance method `_load_data'",
|
||||
rb_class2name(klass));
|
||||
}
|
||||
rb_funcall(v, s_load_data, 1, r_object0(arg, 0));
|
||||
rb_funcall(v, s_load_data, 1, r_object0(arg, 0, 0));
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1237,7 +1258,7 @@ r_object0(arg, proc)
|
|||
volatile VALUE str = r_bytes(arg);
|
||||
|
||||
v = rb_path2class(RSTRING(str)->ptr);
|
||||
r_regist(v, arg);
|
||||
r_entry(v, arg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1246,7 +1267,7 @@ r_object0(arg, proc)
|
|||
volatile VALUE str = r_bytes(arg);
|
||||
|
||||
v = path2class(RSTRING(str)->ptr);
|
||||
r_regist(v, arg);
|
||||
r_entry(v, arg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1255,7 +1276,7 @@ r_object0(arg, proc)
|
|||
volatile VALUE str = r_bytes(arg);
|
||||
|
||||
v = path2module(RSTRING(str)->ptr);
|
||||
r_regist(v, arg);
|
||||
r_entry(v, arg);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -1280,7 +1301,7 @@ static VALUE
|
|||
r_object(arg)
|
||||
struct load_arg *arg;
|
||||
{
|
||||
return r_object0(arg, arg->proc);
|
||||
return r_object0(arg, arg->proc, 0);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
|
|
@ -685,15 +685,18 @@ The variable ruby-indent-level controls the amount of indentation.
|
|||
(setq bol (point))
|
||||
(end-of-line)
|
||||
(skip-chars-backward " \t")
|
||||
(let ((pos (point)))
|
||||
(while (and (re-search-backward "#" bol t)
|
||||
(ruby-special-char-p))
|
||||
(forward-char -1))
|
||||
(let (end (pos (point)))
|
||||
(beginning-of-line)
|
||||
(while (and (re-search-forward "#" pos t)
|
||||
(setq end (1- (point)))
|
||||
(ruby-special-char-p end))
|
||||
(setq end nil))
|
||||
(goto-char (or end pos))
|
||||
(skip-chars-backward " \t")
|
||||
(and
|
||||
(setq state (ruby-parse-region parse-start (point)))
|
||||
(nth 0 state)
|
||||
(setq begin (nth 1 state))
|
||||
(setq begin (cdr (nth 1 state)))
|
||||
(goto-char pos)))
|
||||
(or (bobp) (forward-char -1))
|
||||
(and
|
||||
|
|
140
time.c
140
time.c
|
@ -51,32 +51,47 @@ time_s_alloc(klass)
|
|||
|
||||
obj = Data_Make_Struct(klass, struct time_object, 0, time_free, tobj);
|
||||
tobj->tm_got=0;
|
||||
if (gettimeofday(&tobj->tv, 0) < 0) {
|
||||
rb_sys_fail("gettimeofday");
|
||||
}
|
||||
tobj->tv.tv_sec = 0;
|
||||
tobj->tv.tv_usec = 0;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
time_s_now(klass)
|
||||
VALUE klass;
|
||||
static void
|
||||
time_modify(time)
|
||||
VALUE time;
|
||||
{
|
||||
return rb_obj_alloc(klass);
|
||||
rb_check_frozen(time);
|
||||
if (!OBJ_TAINTED(time) && rb_safe_level() >= 4)
|
||||
rb_raise(rb_eSecurityError, "Insecure: can't modify Time");
|
||||
}
|
||||
|
||||
static VALUE
|
||||
time_init(time)
|
||||
VALUE time;
|
||||
{
|
||||
struct time_object *tobj;
|
||||
|
||||
time_modify(time);
|
||||
GetTimeval(time, tobj);
|
||||
tobj->tm_got=0;
|
||||
tobj->tv.tv_sec = 0;
|
||||
tobj->tv.tv_usec = 0;
|
||||
if (gettimeofday(&tobj->tv, 0) < 0) {
|
||||
rb_sys_fail("gettimeofday");
|
||||
}
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
#define NDIV(x,y) (-(-((x)+1)/(y))-1)
|
||||
#define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
|
||||
|
||||
static VALUE
|
||||
time_new_internal(klass, sec, usec)
|
||||
VALUE klass;
|
||||
void
|
||||
time_overflow_p(sec, usec)
|
||||
time_t sec, usec;
|
||||
{
|
||||
VALUE obj;
|
||||
time_t tmp;
|
||||
struct time_object *tobj;
|
||||
|
||||
if (usec >= 1000000) { /* usec positive overflow */
|
||||
tmp = sec + usec / 1000000;
|
||||
|
@ -98,13 +113,22 @@ time_new_internal(klass, sec, usec)
|
|||
if (sec < 0 || (sec == 0 && usec < 0))
|
||||
rb_raise(rb_eArgError, "time must be positive");
|
||||
#endif
|
||||
}
|
||||
|
||||
obj = Data_Make_Struct(klass, struct time_object, 0, time_free, tobj);
|
||||
tobj->tm_got = 0;
|
||||
static VALUE
|
||||
time_new_internal(klass, sec, usec)
|
||||
VALUE klass;
|
||||
time_t sec, usec;
|
||||
{
|
||||
VALUE time = time_s_alloc(klass);
|
||||
struct time_object *tobj;
|
||||
|
||||
GetTimeval(time, tobj);
|
||||
time_overflow_p(sec, usec);
|
||||
tobj->tv.tv_sec = sec;
|
||||
tobj->tv.tv_usec = usec;
|
||||
|
||||
return obj;
|
||||
return time;
|
||||
}
|
||||
|
||||
VALUE
|
||||
|
@ -757,15 +781,6 @@ time_hash(time)
|
|||
return LONG2FIX(hash);
|
||||
}
|
||||
|
||||
static void
|
||||
time_modify(time)
|
||||
VALUE time;
|
||||
{
|
||||
rb_check_frozen(time);
|
||||
if (!OBJ_TAINTED(time) && rb_safe_level() >= 4)
|
||||
rb_raise(rb_eSecurityError, "Insecure: can't modify Time");
|
||||
}
|
||||
|
||||
static VALUE
|
||||
time_init_copy(copy, time)
|
||||
VALUE copy, time;
|
||||
|
@ -1293,12 +1308,9 @@ time_s_times(obj)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
time_dump(argc, argv, time)
|
||||
int argc;
|
||||
VALUE *argv;
|
||||
time_mdump(time)
|
||||
VALUE time;
|
||||
{
|
||||
VALUE dummy;
|
||||
struct time_object *tobj;
|
||||
struct tm *tm;
|
||||
unsigned long p, s;
|
||||
|
@ -1306,7 +1318,6 @@ time_dump(argc, argv, time)
|
|||
time_t t;
|
||||
int i;
|
||||
|
||||
rb_scan_args(argc, argv, "01", &dummy);
|
||||
GetTimeval(time, tobj);
|
||||
|
||||
t = tobj->tv.tv_sec;
|
||||
|
@ -1337,15 +1348,29 @@ time_dump(argc, argv, time)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
time_load(klass, str)
|
||||
VALUE klass, str;
|
||||
time_dump(argc, argv, time)
|
||||
int argc;
|
||||
VALUE *argv;
|
||||
VALUE time;
|
||||
{
|
||||
VALUE dummy;
|
||||
|
||||
rb_scan_args(argc, argv, "01", &dummy);
|
||||
return time_mdump(time);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
time_mload(time, str)
|
||||
VALUE time, str;
|
||||
{
|
||||
struct time_object *tobj;
|
||||
unsigned long p, s;
|
||||
time_t sec, usec;
|
||||
unsigned char *buf;
|
||||
struct tm tm;
|
||||
int i;
|
||||
|
||||
time_modify(time);
|
||||
StringValue(str);
|
||||
buf = (unsigned char *)RSTRING(str)->ptr;
|
||||
if (RSTRING(str)->len != 8) {
|
||||
|
@ -1361,21 +1386,43 @@ time_load(klass, str)
|
|||
}
|
||||
|
||||
if ((p & (1<<31)) == 0) {
|
||||
return time_new_internal(klass, p, s);
|
||||
sec = p;
|
||||
usec = s;
|
||||
}
|
||||
p &= ~(1<<31);
|
||||
tm.tm_year = (p >> 14) & 0x1ffff;
|
||||
tm.tm_mon = (p >> 10) & 0xf;
|
||||
tm.tm_mday = (p >> 5) & 0x1f;
|
||||
tm.tm_hour = p & 0x1f;
|
||||
tm.tm_min = (s >> 26) & 0x3f;
|
||||
tm.tm_sec = (s >> 20) & 0x3f;
|
||||
tm.tm_isdst = 0;
|
||||
else {
|
||||
p &= ~(1<<31);
|
||||
tm.tm_year = (p >> 14) & 0x1ffff;
|
||||
tm.tm_mon = (p >> 10) & 0xf;
|
||||
tm.tm_mday = (p >> 5) & 0x1f;
|
||||
tm.tm_hour = p & 0x1f;
|
||||
tm.tm_min = (s >> 26) & 0x3f;
|
||||
tm.tm_sec = (s >> 20) & 0x3f;
|
||||
tm.tm_isdst = 0;
|
||||
|
||||
sec = make_time_t(&tm, Qtrue);
|
||||
usec = (time_t)(s & 0xfffff);
|
||||
sec = make_time_t(&tm, Qtrue);
|
||||
usec = (time_t)(s & 0xfffff);
|
||||
}
|
||||
time_overflow_p(sec, usec);
|
||||
|
||||
return time_new_internal(klass, sec, usec);
|
||||
GetTimeval(time, tobj);
|
||||
tobj->tm_got = 0;
|
||||
tobj->tv.tv_sec = sec;
|
||||
tobj->tv.tv_usec = usec;
|
||||
return time;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
time_load(klass, str)
|
||||
VALUE klass, str;
|
||||
{
|
||||
VALUE time = time_s_alloc(klass);
|
||||
|
||||
if (FL_TEST(str, FL_EXIVAR)) {
|
||||
rb_copy_generic_ivar(time, str);
|
||||
FL_SET(time, FL_EXIVAR);
|
||||
}
|
||||
time_mload(time, str);
|
||||
return time;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1384,8 +1431,8 @@ Init_Time()
|
|||
rb_cTime = rb_define_class("Time", rb_cObject);
|
||||
rb_include_module(rb_cTime, rb_mComparable);
|
||||
|
||||
rb_define_singleton_method(rb_cTime, "now", time_s_now, 0);
|
||||
rb_define_alloc_func(rb_cTime, time_s_alloc);
|
||||
rb_define_singleton_method(rb_cTime, "now", rb_class_new_instance, -1);
|
||||
rb_define_singleton_method(rb_cTime, "at", time_s_at, -1);
|
||||
rb_define_singleton_method(rb_cTime, "utc", time_s_mkutc, -1);
|
||||
rb_define_singleton_method(rb_cTime, "gm", time_s_mkutc, -1);
|
||||
|
@ -1446,4 +1493,9 @@ Init_Time()
|
|||
/* methods for marshaling */
|
||||
rb_define_method(rb_cTime, "_dump", time_dump, -1);
|
||||
rb_define_singleton_method(rb_cTime, "_load", time_load, 1);
|
||||
#if 0
|
||||
/* Time will support marshal_dump and marshal_load in the future (1.9 maybe) */
|
||||
rb_define_method(rb_cTime, "marshal_dump", time_mdump, 0);
|
||||
rb_define_method(rb_cTime, "marshal_load", time_mload, 1);
|
||||
#endif
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче