mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
sync ev
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/v1_1r@280 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
3b0fec9a5f
commit
2562004338
13 changed files with 182 additions and 58 deletions
21
ChangeLog
21
ChangeLog
|
|
@ -1,3 +1,22 @@
|
|||
Tue Jul 28 13:03:25 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
|
||||
|
||||
* array.c (ary_s_new): argument to specify initial value is added.
|
||||
|
||||
* array.c (ary_s_new): specifies size, not capacity.
|
||||
|
||||
Mon Jul 27 12:39:34 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
|
||||
|
||||
* string.c (str_replace): zero fill for expansion gap.
|
||||
|
||||
* regex.c (mbctab_euc): set flags on for 0xA1-0xFE. suggested by
|
||||
<inaba@st.rim.or.jp>.
|
||||
|
||||
* string.c (str_inspect): consider current_mbctype.
|
||||
|
||||
Sun Jul 26 15:37:11 1998 Tadayoshi Funaba <tadf@kt.rim.or.jp>
|
||||
|
||||
* array.c (ary_s_new): Array.new(1<<30) dumps core.
|
||||
|
||||
Fri Jul 24 13:40:19 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
|
||||
|
||||
* version 1.1c1 released.
|
||||
|
|
@ -14,7 +33,7 @@ Fri Jul 24 02:10:22 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
|
|||
|
||||
Thu Jul 23 13:11:32 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
|
||||
|
||||
* eval.c (rb_attr): argument should be symbol or a string.
|
||||
* eval.c (rb_attr): argument should be symbol or string.
|
||||
|
||||
Wed Jul 22 11:59:34 1998 Yukihiro Matsumoto <matz@netlab.co.jp>
|
||||
|
||||
|
|
|
|||
23
array.c
23
array.c
|
|
@ -27,6 +27,17 @@ memclear(mem, size)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
memfill(mem, size, val)
|
||||
register VALUE *mem;
|
||||
register int size;
|
||||
register VALUE val;
|
||||
{
|
||||
while (size--) {
|
||||
*mem++ = val;
|
||||
}
|
||||
}
|
||||
|
||||
#define ARY_FREEZE FL_USER1
|
||||
|
||||
static void
|
||||
|
|
@ -131,9 +142,6 @@ ary_new4(n, elts)
|
|||
if (elts) {
|
||||
MEMCPY(RARRAY(ary)->ptr, elts, VALUE, n);
|
||||
}
|
||||
else {
|
||||
memclear(RARRAY(ary)->ptr, n);
|
||||
}
|
||||
RARRAY(ary)->len = n;
|
||||
|
||||
return ary;
|
||||
|
|
@ -159,13 +167,13 @@ ary_s_new(argc, argv, klass)
|
|||
VALUE *argv;
|
||||
VALUE klass;
|
||||
{
|
||||
VALUE size;
|
||||
VALUE size, val;
|
||||
NEWOBJ(ary, struct RArray);
|
||||
OBJSETUP(ary, klass, T_ARRAY);
|
||||
|
||||
ary->len = 0;
|
||||
ary->ptr = 0;
|
||||
if (rb_scan_args(argc, argv, "01", &size) == 0) {
|
||||
if (rb_scan_args(argc, argv, "02", &size, &val) == 0) {
|
||||
ary->capa = ARY_DEFAULT_SIZE;
|
||||
}
|
||||
else {
|
||||
|
|
@ -174,13 +182,14 @@ ary_s_new(argc, argv, klass)
|
|||
if (capa < 0) {
|
||||
ArgError("negative array size");
|
||||
}
|
||||
if (capa*sizeof(VALUE) < 0) {
|
||||
if (capa > 0 && capa*sizeof(VALUE) <= 0) {
|
||||
ArgError("array size too big");
|
||||
}
|
||||
ary->capa = capa;
|
||||
ary->len = capa;
|
||||
}
|
||||
ary->ptr = ALLOC_N(VALUE, ary->capa);
|
||||
memclear(ary->ptr, ary->capa);
|
||||
memfill(ary->ptr, ary->len, val);
|
||||
obj_call_init((VALUE)ary);
|
||||
|
||||
return (VALUE)ary;
|
||||
|
|
|
|||
21
configure.in
21
configure.in
|
|
@ -539,6 +539,9 @@ rb_cv_missing_fconvert=yes, rb_cv_missing_fconvert=no)])
|
|||
setup=Setup
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
|
||||
AC_SUBST(binsuffix)
|
||||
AC_SUBST(setup)
|
||||
|
||||
|
|
@ -547,7 +550,7 @@ if test "$prefix" = NONE; then
|
|||
fi
|
||||
|
||||
if test "$fat_binary" = yes ; then
|
||||
CFLAGS="$CFLAGS -pipe $ARCH_FLAG"
|
||||
CFLAGS="$CFLAGS $ARCH_FLAG"
|
||||
fi
|
||||
|
||||
LIBRUBY='libruby.a'
|
||||
|
|
@ -575,9 +578,19 @@ if test "$enable_shared" = 'yes'; then
|
|||
LIBRUBYARG='-L./ -lruby'
|
||||
fi
|
||||
|
||||
if test "$host_os" = "rhapsody" ; then
|
||||
CFLAGS="$CFLAGS -no-precomp"
|
||||
fi
|
||||
case "$host_os" in
|
||||
nextstep*)
|
||||
CFLAGS="$CFLAGS -pipe"
|
||||
;;
|
||||
openstep*)
|
||||
CFLAGS="$CFLAGS -pipe"
|
||||
;;
|
||||
rhasody*)
|
||||
CFLAGS="$CFLAGS -pipe -no-precomp"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
AC_SUBST(LIBRUBY)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#ifdef NeXT
|
||||
#define DYNAMIC_ENDIAN /* determine endian at runtime */
|
||||
#ifndef __Apple__
|
||||
#ifndef __APPLE__
|
||||
#define S_IXUSR _S_IXUSR /* execute/search permission, owner */
|
||||
#endif
|
||||
#define S_IXGRP 0000010 /* execute/search permission, group */
|
||||
|
|
|
|||
43
dln.c
43
dln.c
|
|
@ -1088,7 +1088,11 @@ dln_sym(name)
|
|||
#endif
|
||||
|
||||
#ifdef NeXT
|
||||
/*#include <mach-o/rld.h>*/
|
||||
#if NS_TARGET_MAJOR < 4
|
||||
#include <mach-o/rld.h>
|
||||
#else
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
@ -1316,6 +1320,7 @@ dln_load(file)
|
|||
Mi hisho@tasihara.nest.or.jp,
|
||||
and... Miss ARAI Akino(^^;)
|
||||
----------------------------------------------------*/
|
||||
#if NS_TARGET_MAJOR < 4 /* NeXTSTEP rld functions */
|
||||
{
|
||||
unsigned long init_address;
|
||||
char *object_files[2] = {NULL, NULL};
|
||||
|
|
@ -1341,6 +1346,42 @@ dln_load(file)
|
|||
(*init_fct)();
|
||||
return ;
|
||||
}
|
||||
#else/* OPENSTEP dyld functions */
|
||||
{
|
||||
int dyld_result ;
|
||||
NSObjectFileImage obj_file ; /* handle, but not use it */
|
||||
/* "file" is module file name .
|
||||
"buf" is initial function name with "_" . */
|
||||
|
||||
void (*init_fct)();
|
||||
|
||||
|
||||
dyld_result = NSCreateObjectFileImageFromFile( file, &obj_file );
|
||||
|
||||
if (dyld_result != NSObjectFileImageSuccess)
|
||||
{
|
||||
LoadError("Failed to load %.200s", file);
|
||||
}
|
||||
|
||||
NSLinkModule(obj_file, file, TRUE);
|
||||
|
||||
|
||||
/* lookup the initial function */
|
||||
/*NSIsSymbolNameDefined require function name without "_" */
|
||||
if( NSIsSymbolNameDefined( buf + 1 ) )
|
||||
{
|
||||
LoadError("Failed to lookup Init function %.200s",file);
|
||||
}
|
||||
|
||||
/* NSLookupAndBindSymbol require function name with "_" !! */
|
||||
|
||||
init_fct = NSAddressOfSymbol( NSLookupAndBindSymbol( buf ) );
|
||||
(*init_fct)();
|
||||
|
||||
|
||||
return ;
|
||||
}
|
||||
#endif /* rld or dyld */
|
||||
#endif
|
||||
|
||||
#ifdef __BEOS__
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ libdir = prefix + "/lib/" + ruby_install_name
|
|||
archdir = libdir+"/"+CONFIG["arch"]
|
||||
mandir = CONFIG["mandir"] + "/man1"
|
||||
|
||||
File.makedirs bindir, TRUE
|
||||
File.install "ruby#{binsuffix}",
|
||||
"#{bindir}/#{ruby_install_name}#{binsuffix}", 0755, TRUE
|
||||
for dll in Dir['*.dll']
|
||||
|
|
|
|||
|
|
@ -17,41 +17,44 @@ class Tempfile < SimpleDelegator
|
|||
|
||||
def Tempfile.callback(path)
|
||||
lambda{
|
||||
print "removing ", path, "..."
|
||||
print "removing ", path, "..." if $DEBUG
|
||||
if File.exist?(path)
|
||||
File.unlink(path)
|
||||
end
|
||||
if File.exist?(path + '.lock')
|
||||
File.unlink(path + '.lock')
|
||||
File.rmdir(path + '.lock')
|
||||
end
|
||||
print "done\n"
|
||||
print "done\n" if $DEBUG
|
||||
}
|
||||
end
|
||||
|
||||
def initialize(basename, tmpdir = '/tmp')
|
||||
umask = File.umask(0177)
|
||||
tmpname = lock = nil
|
||||
begin
|
||||
n = 0
|
||||
while true
|
||||
begin
|
||||
@tmpname = sprintf('%s/%s.%d.%d', tmpdir, basename, $$, n)
|
||||
unless File.exist?(@tmpname)
|
||||
File.symlink(tmpdir, @tmpname + '.lock')
|
||||
tmpname = sprintf('%s/%s.%d.%d', tmpdir, basename, $$, n)
|
||||
lock = tmpname + '.lock'
|
||||
unless File.exist?(lock)
|
||||
Dir.mkdir(lock)
|
||||
break
|
||||
end
|
||||
rescue
|
||||
raise "cannot generate tmpfile `%s'" % @tmpname if n >= Max_try
|
||||
raise "cannot generate tmpfile `%s'" % tmpname if n >= Max_try
|
||||
#sleep(1)
|
||||
end
|
||||
n += 1
|
||||
end
|
||||
|
||||
@clean_files = Tempfile.callback(@tmpname)
|
||||
@clean_files = Tempfile.callback(tmpname)
|
||||
ObjectSpace.define_finalizer(self, @clean_files)
|
||||
|
||||
@tmpfile = File.open(@tmpname, 'w+')
|
||||
@tmpname = tmpname
|
||||
@tmpfile = File.open(tmpname, 'w+')
|
||||
super(@tmpfile)
|
||||
File.unlink(@tmpname + '.lock')
|
||||
Dir.rmdir(lock)
|
||||
ensure
|
||||
File.umask(umask)
|
||||
end
|
||||
|
|
@ -78,6 +81,7 @@ class Tempfile < SimpleDelegator
|
|||
end
|
||||
|
||||
if __FILE__ == $0
|
||||
# $DEBUG = true
|
||||
f = Tempfile.new("foo")
|
||||
f.print("foo\n")
|
||||
f.close
|
||||
|
|
|
|||
37
lib/tk.rb
37
lib/tk.rb
|
|
@ -548,6 +548,19 @@ module Tk
|
|||
tk_call 'bell'
|
||||
end
|
||||
|
||||
def Tk.focus(display=nil)
|
||||
if display == nil
|
||||
r = tk_call('focus')
|
||||
else
|
||||
r = tk_call('focus', '-displayof', display)
|
||||
end
|
||||
tk_tcl2ruby(r)
|
||||
end
|
||||
|
||||
def Tk.focus_lastfor(win)
|
||||
tk_tcl2ruby(tk_call('focus', '-lastfor', win))
|
||||
end
|
||||
|
||||
def toUTF8(str,encoding)
|
||||
INTERP._toUTF8(str,encoding)
|
||||
end
|
||||
|
|
@ -636,9 +649,15 @@ module Tk
|
|||
def positionfrom(*args)
|
||||
tk_call 'wm', 'positionfrom', path, *args
|
||||
end
|
||||
def protocol(name, func=None)
|
||||
func = install_cmd(func) if not func == None
|
||||
tk_call 'wm', 'command', path, name, func
|
||||
def protocol(name=nil, cmd=nil)
|
||||
if cmd
|
||||
tk_call('wm', 'protocol', path, name, cmd)
|
||||
elsif name
|
||||
result = tk_call('wm', 'protocol', path, name)
|
||||
(result == "")? nil : tk_tcl2ruby(result)
|
||||
else
|
||||
tk_split_simplelist(tk_call('wm', 'protocol', path))
|
||||
end
|
||||
end
|
||||
def resizable(*args)
|
||||
w = tk_call('wm', 'resizable', path, *args)
|
||||
|
|
@ -1402,8 +1421,8 @@ module TkOption
|
|||
def clear
|
||||
tk_call 'option', 'clear'
|
||||
end
|
||||
def get win, classname, name
|
||||
tk_call 'option', 'get', classname, name
|
||||
def get win, name, klass
|
||||
tk_call 'option', 'get', win ,name, klass
|
||||
end
|
||||
def readfile file, pri=None
|
||||
tk_call 'option', 'readfile', file, pri
|
||||
|
|
@ -1735,8 +1754,12 @@ class TkWindow<TkObject
|
|||
list(tk_call('place', 'slaves', epath))
|
||||
end
|
||||
|
||||
def focus
|
||||
tk_call 'focus', path
|
||||
def focus(force=false)
|
||||
if force
|
||||
tk_call 'focus', '-force', path
|
||||
else
|
||||
tk_call 'focus', path
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -310,7 +310,7 @@ class TkCanvas<TkWindow
|
|||
|| key == 'latinfont' || key == 'asciifont' )
|
||||
tagfont_configure(tagid(tagOrId), {key=>value})
|
||||
else
|
||||
tk_call 'itemconfigure', tagid(tagOrId), "-#{key}", value
|
||||
tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class TkFont
|
|||
r | []
|
||||
|
||||
when /^8\.*/
|
||||
list(tk_call('font', 'names'))
|
||||
tk_split_simplelist(tk_call('font', 'names'))
|
||||
|
||||
end
|
||||
end
|
||||
|
|
@ -89,10 +89,14 @@ class TkFont
|
|||
if fnt == []
|
||||
TkFont.new(nil, nil).call_font_configure(path, *(args + [{}]))
|
||||
else
|
||||
compound = Hash[*list(tk_call('font', 'configure',
|
||||
fnt))].collect{|key,value|
|
||||
[key[1..-1], value]
|
||||
}.assoc('compound')[1]
|
||||
begin
|
||||
compound = Hash[*list(tk_call('font', 'configure',
|
||||
fnt))].collect{|key,value|
|
||||
[key[1..-1], value]
|
||||
}.assoc('compound')[1]
|
||||
rescue
|
||||
compound = []
|
||||
end
|
||||
if compound == []
|
||||
TkFont.new(fnt, DEFAULT_KANJI_FONT_NAME) \
|
||||
.call_font_configure(path, *(args + [{}]))
|
||||
|
|
@ -156,14 +160,19 @@ class TkFont
|
|||
elsif font.kind_of? Array
|
||||
finfo = {}
|
||||
finfo['family'] = font[0].to_s
|
||||
if font[1] && font[1] != '0' && font[1] =~ /^(|\+|-)([0-9]+)$/
|
||||
if $1 == '-'
|
||||
finfo['pixels'] = font[1].to_s
|
||||
if font[1]
|
||||
fsize = font[1].to_s
|
||||
if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/
|
||||
if $1 == '-'
|
||||
finfo['pixels'] = $2
|
||||
else
|
||||
finfo['points'] = $2
|
||||
end
|
||||
else
|
||||
finfo['points'] = font[1].to_s
|
||||
finfo['points'] = '13'
|
||||
end
|
||||
end
|
||||
finfo[2..-1].each{|style|
|
||||
font[2..-1].each{|style|
|
||||
case (style)
|
||||
when 'normal'
|
||||
finfo['weight'] = style
|
||||
|
|
@ -199,16 +208,19 @@ class TkFont
|
|||
elsif font.kind_of? Array
|
||||
finfo = {}
|
||||
finfo['family'] = font[0].to_s
|
||||
if font[1] && font[1] != '0' && font[1] =~ /^(|\+|-)([0-9]+)$/
|
||||
if $1 == '-'
|
||||
finfo['pixels'] = $2
|
||||
if font[1]
|
||||
fsize = font[1].to_s
|
||||
if fsize != '0' && fsize =~ /^(|\+|-)([0-9]+)$/
|
||||
if $1 == '-'
|
||||
finfo['pixels'] = $2
|
||||
else
|
||||
finfo['points'] = $2
|
||||
end
|
||||
else
|
||||
finfo['points'] = $2
|
||||
finfo['points'] = '13'
|
||||
end
|
||||
else
|
||||
finfo['points'] = '13'
|
||||
end
|
||||
finfo[2..-1].each{|style|
|
||||
font[2..-1].each{|style|
|
||||
case (style)
|
||||
when 'normal'
|
||||
finfo['weight'] = style
|
||||
|
|
|
|||
11
regex.c
11
regex.c
|
|
@ -4081,7 +4081,7 @@ static const unsigned char mbctab_ascii[] = {
|
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
static const unsigned char mbctab_euc[] = {
|
||||
static const unsigned char mbctab_euc[] = { /* 0xA1-0xFE */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
|
@ -4090,17 +4090,16 @@ static const unsigned char mbctab_euc[] = {
|
|||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
|
||||
};
|
||||
|
||||
static const unsigned char mbctab_sjis[] = {
|
||||
static const unsigned char mbctab_sjis[] = { /* 0x80-0x9f,0xE0-0xFF */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@
|
|||
(modify-syntax-entry ?# "<" ruby-mode-syntax-table)
|
||||
(modify-syntax-entry ?\n ">" ruby-mode-syntax-table)
|
||||
(modify-syntax-entry ?\\ "\\" ruby-mode-syntax-table)
|
||||
(modify-syntax-entry ?$ "." ruby-mode-syntax-table)
|
||||
(modify-syntax-entry ?$ "/" ruby-mode-syntax-table)
|
||||
(modify-syntax-entry ?? "_" ruby-mode-syntax-table)
|
||||
(modify-syntax-entry ?_ "_" ruby-mode-syntax-table)
|
||||
(modify-syntax-entry ?< "." ruby-mode-syntax-table)
|
||||
|
|
@ -652,7 +652,7 @@ An end of a defun is found by moving forward from the beginning of one."
|
|||
'("\\(^\\|[^_]\\)\\b\\(nil\\|self\\|true\\|false\\)\\b\\([^_]\\|$\\)"
|
||||
2 font-lock-variable-name-face)
|
||||
;; variables
|
||||
'("\\[$@].\\([a-zA-Z0-9_]\\)"
|
||||
'("[$@].[a-zA-Z0-9_]*"
|
||||
0 font-lock-variable-name-face)
|
||||
;; constants
|
||||
'("\\(^\\|[^_]\\)\\b\\([A-Z]+[a-zA-Z0-9_]*\\)"
|
||||
|
|
|
|||
5
string.c
5
string.c
|
|
@ -851,6 +851,9 @@ str_replace(str, beg, len, val)
|
|||
RSTRING(str)->ptr+beg+len,
|
||||
RSTRING(str)->len-(beg+len));
|
||||
}
|
||||
if (RSTRING(str)->len < beg && len < 0) {
|
||||
MEMZERO(RSTRING(str)->ptr+RSTRING(str)->len, char, -len);
|
||||
}
|
||||
memcpy(RSTRING(str)->ptr+beg, RSTRING(val)->ptr, RSTRING(val)->len);
|
||||
RSTRING(str)->len += RSTRING(val)->len - len;
|
||||
RSTRING(str)->ptr[RSTRING(str)->len] = '\0';
|
||||
|
|
@ -1407,7 +1410,7 @@ str_inspect(str)
|
|||
*b++ = c;
|
||||
*b++ = *p++;
|
||||
}
|
||||
else if (c & 0x80) {
|
||||
else if ((c & 0x80) && current_mbctype != MBCTYPE_EUC) {
|
||||
CHECK(1);
|
||||
*b++ = c;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue