ml.ruby-lang.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

ruby-core

Thread Start a new thread
Download
Threads by month
  • ----- 2025 -----
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
ruby-core@ml.ruby-lang.org

December 2022

  • 10 participants
  • 244 discussions
[ruby-core:111138] [Ruby master Bug#19169] Kernel#freeze doesn't propagate to singleton class when the singleton class has prepended modules
by alanwu (Alan Wu) 02 Dec '22

02 Dec '22
Issue #19169 has been reported by alanwu (Alan Wu). ---------------------------------------- Bug #19169: Kernel#freeze doesn't propagate to singleton class when the singleton class has prepended modules https://bugs.ruby-lang.org/issues/19169 * Author: alanwu (Alan Wu) * Status: Open * Priority: Normal * ruby -v: ruby 3.2.0dev (2022-12-01T16:50:48Z master 9da2a5204f) [arm64-darwin22] * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- ```ruby a = [] singleton = a.singleton_class a.freeze p singleton.frozen? # => true a = [] singleton = a.singleton_class.tap { |klass| klass.prepend(Module.new) } a.freeze p singleton.frozen? # => false ``` It's because of this function: ```c void rb_freeze_singleton_class(VALUE x) { /* should not propagate to meta-meta-class, and so on */ if (!(RBASIC(x)->flags & FL_SINGLETON)) { VALUE klass = RBASIC_CLASS(x); if (klass && (klass = RCLASS_ORIGIN(klass)) != 0 && FL_TEST(klass, (FL_SINGLETON|FL_FREEZE)) == FL_SINGLETON) { OBJ_FREEZE_RAW(klass); } } } ``` It freezes the origin class of the singleton class, but I'm not sure why. When there is no prepended modules `RCLASS_ORIGIN(klass)` just returns `klass`. It's old code, so maybe the meaning of `RCLASS_ORIGIN` has changed? Practically speaking not a big deal because each time one calls `.singleton_class` it copies the frozen bit of the attached object to the singleton class. -- https://bugs.ruby-lang.org/
2 1
0 0
[ruby-core:111142] [Ruby master Feature#19000] Data: Add "Copy with changes method" [Follow-on to #16122 Data: simple immutable value object]
by mame (Yusuke Endoh) 01 Dec '22

01 Dec '22
Issue #19000 has been updated by mame (Yusuke Endoh). Discussed at the dev meeting. Regarding method names, @matz likes `Data#update`. However, @ko1 objects because "update" is used as a destructive vocabulary in `Hash#update`. @matz said Data#with` is acceptable; Data#dup` is not acceptable. ---------------------------------------- Feature #19000: Data: Add "Copy with changes method" [Follow-on to #16122 Data: simple immutable value object] https://bugs.ruby-lang.org/issues/19000#change-100422 * Author: RubyBugs (A Nonymous) * Status: Open * Priority: Normal ---------------------------------------- *As requested: extracted a follow-up to #16122 Data: simple immutable value object from [this comment](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/109815)* # Proposal: Add a "Copy with changes" method to Data Assume the proposed `Data.define` exists. Seeing examples from the [[Values gem]](https://github.com/ms-ati/Values): ```ruby require "values" # A new class Point = Value.new(:x, :y) # An immutable instance Origin = Point.with(x: 0, y: 0) # Q: How do we make copies that change 1 or more values? right = Origin.with(x: 1.0) up = Origin.with(y: 1.0) up_and_right = right.with(y: up.y) # In loops movements = [ [ :x, +0.5 ], [ :x, +0.5 ], [ :y, -1.0 ], [ :x, +0.5 ], ] # position = Point(x: 1.5, y: -1.0) position = movements.inject(Origin) do |p, (field, delta)| p.with(field => p.send(field) + delta) end ``` ## Proposed detail: Call this method: `#with` ```ruby Money = Data.define(:amount, :currency) account = Money.new(amount: 100, currency: 'USD') transactions = [+10, -5, +15] account = transactions.inject(account) { |a, t| a.with(amount: a.amount + t) } #=> Money(amount: 120, currency: "USD") ``` ## Why add this "Copy with changes" method to the Data simple immutable value class? Called on an instance, it returns a new instance with only the provided parameters changed. This API affordance is now **widely adopted across many languages** for its usefulness. Why is it so useful? Because copying immutable value object instances, with 1 or more discrete changes to specific fields, is the proper and ubiquitous pattern that takes the place of mutation when working with immutable value objects. **Other languages** C# Records: “immutable record structs — Non-destructive mutation” — is called `with { ... }` https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-t… Scala Case Classes — is called `#copy` https://docs.scala-lang.org/tour/case-classes.html Java 14+ Records — Brian Goetz at Oracle is working on adding a with copy constructor inspired by C# above as we speak, likely to be called `#with` https://mail.openjdk.org/pipermail/amber-spec-experts/2022-June/003461.html Rust “Struct Update Syntax” via `..` syntax in constructor https://doc.rust-lang.org/book/ch05-01-defining-structs.html#creating-insta… ## Alternatives Without a copy-with-changes method, one must construct entirely new instances using the constructor. This can either be (a) fully spelled out as boilerplate code, or (b) use a symmetrical `#to_h` to feed the keyword-args constructor. **(a) Boilerplate using constructor** ```ruby Point = Data.define(:x, :y, :z) Origin = Point.new(x: 0.0, y: 0.0, z: 0.0) change = { z: -1.5 } # Have to use full constructor -- does this even work? point = Point.new(x: Origin.x, y: Origin.y, **change) ``` **(b) Using a separately proposed `#to_h` method and constructor symmetry** ```ruby Point = Data.define(:x, :y, :z) Origin = Point.new(x: 0.0, y: 0.0, z: 0.0) change = { z: -1.5 } # Have to use full constructor -- does this even work? point = Point.new(**(Origin.to_h.merge(change))) ``` Notice that the above are not ergonomic -- leading so many of our peer language communities to adopt the `#with` method to copy an instance with discrete changes. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111141] [Ruby master Feature#19000] Data: Add "Copy with changes method" [Follow-on to #16122 Data: simple immutable value object]
by mame (Yusuke Endoh) 01 Dec '22

01 Dec '22
Issue #19000 has been updated by mame (Yusuke Endoh). RubyBugs (A Nonymous) wrote in #note-21: > How is this? Thanks for the update. Now I have a question. Do you really want to write `p.with(field => p.send(field) + delta)`? I don't think it is very elegant. It is not very convincing (at least, to me) as a first motivation example. Also, do you need the ability to update multiple fields at once? Both motivation examples only update a single field. This may be the result of simplifying the motivation example, though. Looking at these motivation examples, there may be room to consider an API like `p.with(field) {|old_value| old_value + delta }` or something. ---------------------------------------- Feature #19000: Data: Add "Copy with changes method" [Follow-on to #16122 Data: simple immutable value object] https://bugs.ruby-lang.org/issues/19000#change-100421 * Author: RubyBugs (A Nonymous) * Status: Open * Priority: Normal ---------------------------------------- *As requested: extracted a follow-up to #16122 Data: simple immutable value object from [this comment](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/109815)* # Proposal: Add a "Copy with changes" method to Data Assume the proposed `Data.define` exists. Seeing examples from the [[Values gem]](https://github.com/ms-ati/Values): ```ruby require "values" # A new class Point = Value.new(:x, :y) # An immutable instance Origin = Point.with(x: 0, y: 0) # Q: How do we make copies that change 1 or more values? right = Origin.with(x: 1.0) up = Origin.with(y: 1.0) up_and_right = right.with(y: up.y) # In loops movements = [ [ :x, +0.5 ], [ :x, +0.5 ], [ :y, -1.0 ], [ :x, +0.5 ], ] # position = Point(x: 1.5, y: -1.0) position = movements.inject(Origin) do |p, (field, delta)| p.with(field => p.send(field) + delta) end ``` ## Proposed detail: Call this method: `#with` ```ruby Money = Data.define(:amount, :currency) account = Money.new(amount: 100, currency: 'USD') transactions = [+10, -5, +15] account = transactions.inject(account) { |a, t| a.with(amount: a.amount + t) } #=> Money(amount: 120, currency: "USD") ``` ## Why add this "Copy with changes" method to the Data simple immutable value class? Called on an instance, it returns a new instance with only the provided parameters changed. This API affordance is now **widely adopted across many languages** for its usefulness. Why is it so useful? Because copying immutable value object instances, with 1 or more discrete changes to specific fields, is the proper and ubiquitous pattern that takes the place of mutation when working with immutable value objects. **Other languages** C# Records: “immutable record structs — Non-destructive mutation” — is called `with { ... }` https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-t… Scala Case Classes — is called `#copy` https://docs.scala-lang.org/tour/case-classes.html Java 14+ Records — Brian Goetz at Oracle is working on adding a with copy constructor inspired by C# above as we speak, likely to be called `#with` https://mail.openjdk.org/pipermail/amber-spec-experts/2022-June/003461.html Rust “Struct Update Syntax” via `..` syntax in constructor https://doc.rust-lang.org/book/ch05-01-defining-structs.html#creating-insta… ## Alternatives Without a copy-with-changes method, one must construct entirely new instances using the constructor. This can either be (a) fully spelled out as boilerplate code, or (b) use a symmetrical `#to_h` to feed the keyword-args constructor. **(a) Boilerplate using constructor** ```ruby Point = Data.define(:x, :y, :z) Origin = Point.new(x: 0.0, y: 0.0, z: 0.0) change = { z: -1.5 } # Have to use full constructor -- does this even work? point = Point.new(x: Origin.x, y: Origin.y, **change) ``` **(b) Using a separately proposed `#to_h` method and constructor symmetry** ```ruby Point = Data.define(:x, :y, :z) Origin = Point.new(x: 0.0, y: 0.0, z: 0.0) change = { z: -1.5 } # Have to use full constructor -- does this even work? point = Point.new(**(Origin.to_h.merge(change))) ``` Notice that the above are not ergonomic -- leading so many of our peer language communities to adopt the `#with` method to copy an instance with discrete changes. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111140] [Ruby master Feature#19117] Include the method owner in backtraces, not just the method name
by mame (Yusuke Endoh) 01 Dec '22

01 Dec '22
Issue #19117 has been updated by mame (Yusuke Endoh). Discussed at the dev meeting. @matz was basically positive for this proposal. But there is still much to discuss and experiment, so it was decided to discuss for Ruby 3.3. * How much impact does exception generation have on performance? (Each frame of the backtrace needs to maintain self) * What notation to use (not discussed at this dev meeting due to priority on Ruby 3.2 issues) ---------------------------------------- Feature #19117: Include the method owner in backtraces, not just the method name https://bugs.ruby-lang.org/issues/19117#change-100420 * Author: byroot (Jean Boussier) * Status: Open * Priority: Normal ---------------------------------------- ``` module Foo class Bar def inspect 1 + '1' end end end p Foo::Bar.new ``` This code produce the following backtrace: ``` /tmp/foo.rb:4:in `+': String can't be coerced into Integer (TypeError) from /tmp/foo.rb:4:in `inspect' from /tmp/foo.rb:9:in `p' from /tmp/foo.rb:9:in `<main>' ``` This works, but on large codebases and large backtraces the method name isn't always all that revealing, most of the time you need to open many of the locations listed in the backtrace to really understand what is going on. I propose that we also include the owner name: ``` /tmp/foo.rb:4:in `Integer#+': String can't be coerced into Integer (TypeError) from /tmp/foo.rb:4:in `Foo::Bar#inspect' from /tmp/foo.rb:9:in `Kernel#p' from /tmp/foo.rb:9:in `<main>' ``` I believe that in many case it would allow to much better understand the backtrace without having to jump back and forth between it and the source code. This is inspired by @ivoanjo 's `backtracie` gem: https://github.com/ivoanjo/backtracie -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111139] [Ruby master Bug#19012] BasicSocket#recv* methods return an empty packet instead of nil on closed connections
by mame (Yusuke Endoh) 01 Dec '22

01 Dec '22
Issue #19012 has been updated by mame (Yusuke Endoh). This is what @akr said at the dev meeting. (My understanding) > The proposed behavior might be possible for stream. On the other hand, for datagram, the current behavior is better. I am not sure if there is a portable way to determine if the file descriptor behind an IO object is stream or datagram. ---------------------------------------- Bug #19012: BasicSocket#recv* methods return an empty packet instead of nil on closed connections https://bugs.ruby-lang.org/issues/19012#change-100419 * Author: byroot (Jean Boussier) * Status: Open * Priority: Normal * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- `man recvmsg(2)` states: > Return Value > These calls return the number of bytes received, or -1 if an error occurred. The return value will be 0 when the peer has performed an orderly shutdown. But somehow the entire `receiv` family of methods in Ruby seem to interpret `0` as empty string instead of "EOF". ```ruby require 'socket' puts "=== pipes ===" r, w = IO.pipe r.read_nonblock(1, exception: false) # => :wait_readable w.close r.read_nonblock(1, exception: false) # => nil (EOF) puts "=== sockets ====" r, w = UNIXSocket.socketpair r.read_nonblock(1, exception: false) # => :wait_readable r.recvmsg_nonblock(1, exception: false) # => :wait_readable r.recv_nonblock(1, exception: false) # => :wait_readable w.close r.read_nonblock(1, exception: false) # => nil (EOF) r.recvmsg_nonblock(1, exception: false) # => ["", #<Addrinfo: empty-sockaddr SOCK_STREAM>, 128]] r.recvmsg # => ["", #<Addrinfo: empty-sockaddr SOCK_STREAM>, 0]] r.recv_nonblock(1, exception: false) # => "" ``` ### Expected behavior I would expect `recvmsg_nonblock`, `recvmsg`, `recv_nonblock` and `recv` to return `nil` when the connection is closed. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111134] [Ruby master Bug#19145] TestException#test_exception_in_message timeouts
by vo.x (Vit Ondruch) 01 Dec '22

01 Dec '22
Issue #19145 has been updated by vo.x (Vit Ondruch). Thx for the fix. With commit:git|0436f1e15a, I don't observe the timeout anymore. ---------------------------------------- Bug #19145: TestException#test_exception_in_message timeouts https://bugs.ruby-lang.org/issues/19145#change-100413 * Author: vo.x (Vit Ondruch) * Status: Closed * Priority: Normal * Assignee: nobu (Nobuyoshi Nakada) * ruby -v: ruby 3.2.0dev (2022-11-24 master 66e5200ba4) [x86_64-linux] * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- Testing with 66e5200ba4, I observe following error: ~~~ $ make -C redhat-linux-build test-all 'TESTS=-v -n /TestException#test_exception_in_message/' 'MSPECOPT=-fs ' make: Entering directory '/builddir/build/BUILD/ruby-3.2.0-66e5200ba4/redhat-linux-build' Run options: --seed=50244 "--ruby=./miniruby -I/builddir/build/BUILD/ruby-3.2.0-66e5200ba4/lib -I. -I.ext/common /builddir/build/BUILD/ruby-3.2.0-66e5200ba4/tool/runruby.rb --extout=.ext -- --disable-gems" --excludes-dir=/builddir/build/BUILD/ruby-3.2.0-66e5200ba4/test/excludes --name=!/memory_leak/ -v -n /TestException#test_exception_in_message/ # Running tests: [1/0] TestException#test_exception_in_message = 3.10 sT 1) Timeout: TestException#test_exception_in_message Finished tests in 6.405179s, 0.1561 tests/s, 0.3122 assertions/s. 1 tests, 2 assertions, 0 failures, 1 errors, 0 skips ruby -v: ruby 3.2.0dev (2022-11-24 master 66e5200ba4) [x86_64-linux] make: *** [uncommon.mk:855: yes-test-all] Error 1 make: Leaving directory '/builddir/build/BUILD/ruby-3.2.0-66e5200ba4/redhat-linux-build' ~~~ Last time I was testing with 4b1504ae0a beginning of November and there was not issue -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111133] [Ruby master Bug#19147] `TestFileExhaustive#test_expand_path_for_existent_username` and `TestDir#test_home` fails on i686
by vo.x (Vit Ondruch) 01 Dec '22

01 Dec '22
Issue #19147 has been updated by vo.x (Vit Ondruch). Interestingly, testing with commit:git|0436f1e15a, there are now additional spec failures which appears to be the same issue: ~~~ 1) File.expand_path expands ~ENV['USER'] to the user's home directory ERROR RuntimeError: can't set length of shared string /builddir/build/BUILD/ruby-3.2.0-0436f1e15a/spec/ruby/core/file/expand_path_spec.rb:99:in `expand_path' /builddir/build/BUILD/ruby-3.2.0-0436f1e15a/spec/ruby/core/file/expand_path_spec.rb:99:in `block (3 levels) in <top (required)>' /builddir/build/BUILD/ruby-3.2.0-0436f1e15a/spec/ruby/core/file/expand_path_spec.rb:7:in `<top (required)>' 2) File.expand_path expands ~ENV['USER']/a to a in the user's home directory ERROR RuntimeError: can't set length of shared string /builddir/build/BUILD/ruby-3.2.0-0436f1e15a/spec/ruby/core/file/expand_path_spec.rb:103:in `expand_path' /builddir/build/BUILD/ruby-3.2.0-0436f1e15a/spec/ruby/core/file/expand_path_spec.rb:103:in `block (3 levels) in <top (required)>' /builddir/build/BUILD/ruby-3.2.0-0436f1e15a/spec/ruby/core/file/expand_path_spec.rb:7:in `<top (required)>' ~~~ ---------------------------------------- Bug #19147: `TestFileExhaustive#test_expand_path_for_existent_username` and `TestDir#test_home` fails on i686 https://bugs.ruby-lang.org/issues/19147#change-100412 * Author: vo.x (Vit Ondruch) * Status: Open * Priority: Normal * ruby -v: ruby 3.2.0dev (2022-11-24 master 66e5200ba4) [i386-linux] * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- Testing with commit:git|66e5200ba4 on Fedora Rawhide, I observe following error just on i686 (other platforms are passing just fine): ~~~ 1) Error: TestFileExhaustive#test_expand_path_for_existent_username: RuntimeError: can't set length of shared string /builddir/build/BUILD/ruby-3.2.0-66e5200ba4/test/ruby/test_file_exhaustive.rb:1122:in `expand_path' /builddir/build/BUILD/ruby-3.2.0-66e5200ba4/test/ruby/test_file_exhaustive.rb:1122:in `test_expand_path_for_existent_username' 2) Error: TestDir#test_home: RuntimeError: can't set length of shared string /builddir/build/BUILD/ruby-3.2.0-66e5200ba4/test/ruby/test_dir.rb:537:in `expand_path' /builddir/build/BUILD/ruby-3.2.0-66e5200ba4/test/ruby/test_dir.rb:537:in `block in test_home' ~~~ Previously testing with commit:git|4b1504ae0a, the tests were passing just fine. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111132] [Ruby master Bug#19079] Modules included in a DelegateClass cannot override delegate methods
by jonathanhefner (Jonathan Hefner) 01 Dec '22

01 Dec '22
Issue #19079 has been updated by jonathanhefner (Jonathan Hefner). This issue occurred for a private module in Rails: https://github.com/rails/rails/pull/46189#discussion_r991440668. Using `include` in a subclass works. Using `prepend` also works, and is the workaround I used for the Rails module. However, my proposed solution for this issue (https://github.com/ruby/delegate/pull/14) also solves #19079 with a performance improvement. I opened this issue and #19079 because the current behavior seemed surprising to me. In particular, I expected the `DelegateClass` block to behave just like a `Class.new` block. I feel like that is a reasonable assumption based on [the documentation](https://github.com/ruby/delegate/blob/2e1272cadbf86a02a0084d…. But, if my assumption is wrong, then I understand the decision. ---------------------------------------- Bug #19079: Modules included in a DelegateClass cannot override delegate methods https://bugs.ruby-lang.org/issues/19079#change-100411 * Author: jonathanhefner (Jonathan Hefner) * Status: Rejected * Priority: Normal * ruby -v: ruby 3.1.2p20 * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- Because `DelegateClass` defines delegate methods on the class itself, those delegate methods come first in the method lookup chain. This prevents included modules from overriding delegate methods: ```ruby Base = Class.new do def foo "base" end end Helper = Module.new do def foo "helper" end end WithHelper = DelegateClass(Base) { include Helper } WithHelper.new(Base.new).foo # => "base" ``` One possible solution would be to define the delegate methods in a separate module. That way, other modules could come before it in the method lookup chain. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111131] [Ruby master Bug#19166] Module#remove_method can change frozen modules when there is a prepended module
by alanwu (Alan Wu) 01 Dec '22

01 Dec '22
Issue #19166 has been reported by alanwu (Alan Wu). ---------------------------------------- Bug #19166: Module#remove_method can change frozen modules when there is a prepended module https://bugs.ruby-lang.org/issues/19166 * Author: alanwu (Alan Wu) * Status: Open * Priority: Normal * ruby -v: 2.7, 3.0, 3.1, dev * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- ```ruby module A prepend Module.new # remove this line and you'd get FrozenError as expected def foo; end freeze remove_method :foo # remove works even though module is frozen! p instance_methods(false) # => [] end ``` Old bug, reproduces in 2.7 through 3.1 and on master. Found while investigating #19164. -- https://bugs.ruby-lang.org/
1 0
0 0
[ruby-core:111130] [Ruby master Bug#19143] Windows - bundled extension gems compile, but don't copy *.so files to lib folder
by MSP-Greg (Greg L) 01 Dec '22

01 Dec '22
Issue #19143 has been updated by MSP-Greg (Greg L). @nobu Yes, I agree, it might be very helpful when one has more than one platform installed and uses `--user-install`. As in `Gem.install_extension_in_lib`, also [Gem::Ext::ExtConfBuilder](https://github.com/ruby/ruby/blob/master/lib/ruby…. I overwrite my Windows Ruby master installs daily, so I always use `--user-install`. Maybe issues with existing extension gems that load with `require_relative`, and also pre-compiled gems? ---------------------------------------- Bug #19143: Windows - bundled extension gems compile, but don't copy *.so files to lib folder https://bugs.ruby-lang.org/issues/19143#change-100408 * Author: MSP-Greg (Greg L) * Status: Closed * Priority: Normal * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- Just finished updating ruby-loco's mswin build to use a system similar to the ucrt & mingw builds. Confirmed something I noticed previously, and also occurs with the RubyInstaller2 head build. On Windows, bundled extension gems (debug, rbs) compile their extension in the `ext` folder, but do not copy them to the `lib` folder. So, the *.so file is created, but not copied. I think this was working correctly on Ruby 3.1? -- https://bugs.ruby-lang.org/
1 0
0 0
  • ← Newer
  • 1
  • ...
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.