Ce diaporama a bien été signalé.
Le téléchargement de votre SlideShare est en cours. ×

Metaprogramming

Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Publicité
Prochain SlideShare
Metaprogramming in Ruby
Metaprogramming in Ruby
Chargement dans…3
×

Consultez-les par la suite

1 sur 133 Publicité

Plus De Contenu Connexe

Diaporamas pour vous (20)

Publicité

Plus récents (20)

Metaprogramming

  1. 1. Metaprogramming in Ruby
  2. 2. Things I Wish I Knew When I Started Ruby
  3. 3. Who? Joshua Hull @jj https://github.com/joshbuddy
  4. 4. What?
  5. 5. What? Writing programs that write programs.
  6. 6. What? Writing programs that write programs. NOT code generation!
  7. 7. Why? We all do it.
  8. 8. Why? We all do it. Ruby attr_accessor :my_attribute
  9. 9. Why? We all do it. Ruby attr_accessor :my_attribute def my_attribute @my_attribute end def my_attribute=(my_attribute) @my_attribute = my_attribute end
  10. 10. Why? We all do it. Ruby attr_accessor :my_attribute Java public int getAttribute() { return attribute; } public void setAttribute(int newAttribute) { attribute = newAttribute; }
  11. 11. Why? We all do it. ner in Ruby W attr_accessor :my_attribute Java public int getAttribute() { return attribute; } public void setAttribute(int newAttribute) { attribute = newAttribute; }
  12. 12. Why? def age @age || 'not set' end def gender @gender || 'not set' end def name @name || 'not set' end
  13. 13. Why? def age @age || 'not set' end def gender @gender || 'not set' end def name @name || 'not set' end [:age, :gender, :name].each do |attr| define_method(attr) do instance_variable_get(:"@#{attr}") || 'not set' end end
  14. 14. Drawbacks
  15. 15. Drawbacks You can write some difficult-to-understand code.
  16. 16. Drawbacks You can write some difficult-to-understand code.
  17. 17. Method dispatch
  18. 18. Method dispatch class MyObject attr_accessor :name def say_hello puts "hello" puts name end end
  19. 19. Method dispatch class MyObject attr_accessor :name def say_hello puts "hello" puts name end end This is a method call, but who receives it?
  20. 20. Method dispatch class MyObject attr_accessor :name def say_hello puts "hello" puts self.name end end
  21. 21. Method dispatch class MyObject attr_accessor :name def say_hello puts "hello" puts self.name end end self is always the implied receiver!
  22. 22. Method dispatch class MyObject attr_accessor :name def say_hello puts "hello" puts name end end
  23. 23. Method dispatch class MyObject self.attr_accessor :name def say_hello puts "hello" puts name end end
  24. 24. Method dispatch class MyObject Who is self self.attr_accessor :name here? def say_hello puts "hello" puts name end end
  25. 25. Method dispatch class MyObject Who is self self.attr_accessor :name here? def say_hello puts "hello" The class puts name end is! end
  26. 26. Method dispatch Module#attr Who is self here? The class is!
  27. 27. Ruby classes
  28. 28. Ruby classes class NewClass def hey puts 'hello!' end end
  29. 29. Ruby classes class NewClass { def hey puts 'hello!' end end This is normal code!
  30. 30. Ruby classes class NewClass def hey puts 'hello!' end end is the same as NewClass = Class.new do def hey puts 'hello!' end end
  31. 31. Ruby classes class ParsingError < RuntimeError end
  32. 32. Ruby classes class ParsingError < RuntimeError end is the same as ParsingError = Class.new(RuntimeError)
  33. 33. Ruby classes def class_with_accessors(*attributes) Class.new do attr_accessor *attributes end end
  34. 34. Ruby classes def class_with_accessors(*attributes) Class.new do attr_accessor *attributes end end Returns a new class!
  35. 35. Ruby classes def class_with_accessors(*attributes) Class.new do attr_accessor *attributes end end Returns a new class! class Person < class_with_accessors(:name, :age, :sex) # ... end
  36. 36. eval, instance_eval, class_eval
  37. 37. eval, instance_eval, class_eval Method eval instance_eval class_eval
  38. 38. eval, instance_eval, class_eval Method Context eval your current context instance_eval the object class_eval the object’s class
  39. 39. eval, instance_eval, class_eval eval eval "puts 'hello'" # hello
  40. 40. eval, instance_eval, class_eval instance_eval class MyClass end MyClass.instance_eval("def hi; 'hi'; end")
  41. 41. eval, instance_eval, class_eval instance_eval class MyClass end MyClass.instance_eval("def hi; 'hi'; end") MyClass.hi # 'hi'
  42. 42. eval, instance_eval, class_eval instance_eval class MyClass end MyClass.instance_eval("def hi; 'hi' end") obj = MyClass.new # <MyClass:0x10178aff8> obj.hi # NoMethodError: undefined method `hi' for #<MyClass>
  43. 43. eval, instance_eval, class_eval class_eval class MyClass end MyClass.class_eval("def hi; 'hi' end")
  44. 44. eval, instance_eval, class_eval class_eval class MyClass end MyClass.class_eval("def hi; 'hi' end") MyClass.hi # NoMethodError: undefined method `hi' for MyClass:Class
  45. 45. eval, instance_eval, class_eval class_eval class MyClass end MyClass.class_eval("def hi; 'hi' end") obj = MyClass.new # <MyClass:0x101849688> obj.hi # "hi"
  46. 46. eval, instance_eval, class_eval class_eval instance_eval class MyClass class MyClass end end MyClass.class_eval("def hi; 'hi'; end") MyClass.instance_eval("def hi; 'hi'; end") obj = MyClass.new MyClass.hi # <MyClass:0x101849688> # 'hi' obj.hi # "hi"
  47. 47. eval, instance_eval, class_eval Ninja’s will attack you if ... you don’t use __FILE__, __LINE__
  48. 48. eval, instance_eval, class_eval class HiThere end HiThere.class_eval "def hi; raise; end" HiThere.class_eval "def hi_with_niceness; raise; end", __FILE__, __LINE__ HiThere.new.hi HiThere.new.hi_with_niceness
  49. 49. eval, instance_eval, class_eval class HiThere end HiThere.class_eval "def hi; raise; end" HiThere.class_eval "def hi_with_niceness; raise; end", __FILE__, __LINE__ HiThere.new.hi HiThere.new.hi_with_niceness (eval):1:in `hi': unhandled exception from my_file.rb:7 my_file.rb:5:in `hi_with_niceness': unhandled exception from my_file.rb:7
  50. 50. eval, instance_eval, class_eval class HiThere end HiThere.class_eval "def hi; raise; end" HiThere.class_eval "def hi_with_niceness; raise; end", __FILE__, __LINE__ HiThere.new.hi HiThere.new.hi_with_niceness (eval):1:in `hi': unhandled exception from my_file.rb:7 So nice. <3 my_file.rb:5:in `hi_with_niceness': unhandled exception from my_file.rb:7
  51. 51. eval, instance_eval, class_eval Implement attr_accessor!
  52. 52. eval, instance_eval, class_eval class Module def create_attr(attribute) class_eval("def #{attribute}; @#{attribute}; end") end end
  53. 53. eval, instance_eval, class_eval class Module def create_attr(attribute) class_eval("def #{attribute}; @#{attribute}; end") end end class M create_attr :hi end
  54. 54. eval, instance_eval, class_eval class Module def create_attr(attribute) class_eval("def #{attribute}; @#{attribute}; end") end end def M class M def hi create_attr :hi @hi end end end
  55. 55. Defining methods
  56. 56. Defining methods For an object o = Object.new o.instance_eval("def just_this_object; end") o.just_this_object
  57. 57. Defining methods For an object o = Object.new o.instance_eval("def just_this_object; end") o.just_this_object Object.new.just_this_object # NoMethodError: undefined method `just_this_object'
  58. 58. Defining methods For an object o = Object.new o.instance_eval("def just_this_object; end") o.just_this_object Object.new.just_this_object # NoMethodError: undefined method `just_this_object' o = Object.new o.instance_eval { def just_this_object end }
  59. 59. Defining methods For an object o = Object.new o.extend(Module.new { def just_this_object end })
  60. 60. Defining methods For a class MyClass = Class.new class MyClass def new_method end end MyClass.new.respond_to?(:new_method) # true
  61. 61. Defining methods For a class MyClass = Class.new MyClass.class_eval " MyClass.class_eval do def new_method def new_method end end " end MyClass.send(:define_method, :new_method) { # your method body }
  62. 62. Defining methods Aliasing Module#alias_method
  63. 63. Scoping
  64. 64. Scoping module Project class Main def run # ... end end end
  65. 65. Scoping module Project class Main def run # ... end end end Class definitions Module definitions Method definitions
  66. 66. Scoping a = 'hello' module Project class Main def run puts a end end end Project::Main.new.run
  67. 67. Scoping a = 'hello' module Project class Main def run puts a end end end Project::Main.new.run # undefined local variable or method `a' for #<Project::Main> (NameError)
  68. 68. Scoping module Project class Main end end a = 'hello' Project::Main.class_eval do define_method(:run) do puts a end end Project::Main.new.run # => hello
  69. 69. Scoping Example: Connection Sharing module AddConnections def self.add_connection_methods(cls, host, port) cls.class_eval do define_method(:get_connection) do puts "Getting connection for #{host}:#{port}" end define_method(:host) { host } define_method(:port) { port } end end end
  70. 70. Scoping Example: Connection Sharing module AddConnections def self.add_connection_methods(cls, host, port) cls.class_eval do define_method(:get_connection) do puts "Getting connection for #{host}:#{port}" end define_method(:host) { host } define_method(:port) { port } end end end Client = Class.new AddConnections.add_connection_methods(Client, 'localhost', 8080) Client.new.get_connection # Getting connection for localhost:8080 Client.new.host # localhost Client.new.port # 8080
  71. 71. Scoping Kernel#binding Let’s you leak the current “bindings”
  72. 72. Scoping Kernel#binding Let’s you leak the current “bindings” def create_connection(bind) eval ' connection = "I am a connection" ', bind end connection = nil create_connection(binding) connection # => I am a connection
  73. 73. Scoping Kernel#binding Let’s you leak the current “bindings” def create_connection(bind) eval ' connection = "I am a connection" ', bind end Calls connection = nil with the create_connection(binding) current connection # => I am a connection state
  74. 74. Scoping Kernel#binding Let’s you leak the current “bindings” def create_connection(bind) eval ' connection = "I am a connection" ', bind end Calls connection = nil with the create_connection(binding) current connection # => I am a connection state MAGIC!
  75. 75. Scoping Kernel#binding Let’s you leak the current “bindings” def create_connection(bind) eval ' connection = "I am a connection" ', bind end # connection = nil create_connection(binding) connection # undefined local variable or method `connection'
  76. 76. Scoping Kernel#binding Let’s you leak the current “bindings” def create_connection(bind) eval ' connection = "I am a connection" ', bind end # connection = nil create_connection(binding) connection # undefined local variable or method `connection' You can’t add to the local variables via binding
  77. 77. Scoping Kernel#binding Let’s you leak the current “bindings” def create_connection(bind) eval ' connection = "I am a connection" ', bind end eval "connection = nil" create_connection(binding) connection # undefined local variable or method `connection' You can’t add to the local variables via eval
  78. 78. Scoping Kernel#binding TOPLEVEL_BINDING
  79. 79. Scoping Kernel#binding TOPLEVEL_BINDING a = 'hello' module Program class Main def run puts eval("a", TOPLEVEL_BINDING) end end end Program::Main.new.run # => hello
  80. 80. Interception! (aka lazy magic)
  81. 81. Interception! method_missing(method, *args, &blk)
  82. 82. Interception! method_missing(method, *args, &blk) class MethodMissing def method_missing(m, *args, &blk) puts "method_missing #{m} #{args.inspect} #{blk.inspect}" super end end
  83. 83. Interception! method_missing(method, *args, &blk) class MethodMissing def method_missing(m, *args, &blk) puts "method_missing #{m} #{args.inspect} #{blk.inspect}" super end end mm = MethodMissing.new mm.i_dont_know_this(1, 2, 3) # method_missing i_dont_know_this [1, 2, 3] nil # NoMethodError: undefined method `i_dont_know_this' for #<MethodMissing>
  84. 84. Interception! Example: Timing module MethodsWithTiming def method_missing(m, *args, &blk) if timed_method = m.to_s[/^(.*)_with_timing$/, 1] and respond_to?(timed_method) respond = nil measurement = Benchmark.measure { respond = send(timed_method, *args, &blk) } puts "Method #{m} took #{measurement}" respond else super end end end
  85. 85. Interception! Example: Timing module MethodsWithTiming def method_missing(m, *args, &blk) if timed_method = m.to_s[/^(.*)_with_timing$/, 1] and respond_to?(timed_method) respond = nil measurement = Benchmark.measure { respond = send(timed_method, *args, &blk) } puts "Method #{m} took #{measurement}" respond else super end end end sc = SlowClass.new class SlowClass sc.slow include MethodsWithTiming def slow sleep 1 sc.slow_with_timing end # Method slow_with_timing took 0.000000 0.000000 0.000000 ( 1.000088) end
  86. 86. Interception! Example: Proxy class Proxy def initialize(backing) @backing = backing end def method_missing(m, *args, &blk) @backing.send(m, *args, &blk) end end
  87. 87. Interception! Example: Proxy class LoggingProxy def initialize(backing) @backing = backing end def method_missing(m, *args, &blk) puts "Calling method #{m} with #{args.inspect}" @backing.send(m, *args, &blk) end end
  88. 88. Interception! Example: Simple DSL class NameCollector attr_reader :names def initialize @names = [] end def method_missing(method, *args, &blk) args.empty? ? @names.push(method.to_s.capitalize) : super end end nc = NameCollector.new nc.josh nc.bob nc.jane nc.names.join(' ') # => Josh Bob Jane
  89. 89. Interception! Object#respond_to?(sym)
  90. 90. Interception! Object#respond_to?(sym) Example: Timing module MethodsWithTiming alias_method :original_respond_to?, :respond_to? def method_missing(m, *args, &blk) if timed_method = m.to_s[/^(.*)_with_timing$/, 1] and original_respond_to?(timed_method) respond = nil measurement = Benchmark.measure { respond = send(timed_method, *args, &blk) } puts "Method #{m} took #{measurement}" respond else super end end def respond_to?(sym) (timed_method = sym.to_s[/^(.*)_with_timing$/, 1]) ? original_respond_to?(timed_method.to_sym) : original_respond_to?(sym) end end
  91. 91. Interception! Object#respond_to?(sym) Example: Timing module MethodsWithTiming ge ts alias_method :original_respond_to?, :respond_to? It def method_missing(m, *args, &blk) r! if timed_method = m.to_s[/^(.*)_with_timing$/, 1] and original_respond_to?(timed_method) te respond = nil et measurement = Benchmark.measure { b respond = send(timed_method, *args, &blk) } puts "Method #{m} took #{measurement}" respond else super end end def respond_to?(sym) (timed_method = sym.to_s[/^(.*)_with_timing$/, 1]) ? original_respond_to?(timed_method.to_sym) : original_respond_to?(sym) end end
  92. 92. Interception! Object#respond_to_missing?(sym) (1.9 only) Example: Timing module MethodsWithTiming def method_missing(m, *args, &blk) if timed_method = m.to_s[/^(.*)_with_timing$/, 1] and respond_to?(timed_method) respond = nil measurement = Benchmark.measure { respond = send(timed_method, *args, &blk) } puts "Method #{m} took #{measurement}" respond else super end end def respond_to_missing?(sym) (timed_method = sym.to_s[/^(.*)_with_timing$/, 1]) ? respond_to?(timed_method.to_sym) : super end end
  93. 93. Interception! const_missing(sym)
  94. 94. Interception! const_missing(sym) MyClass::MyOtherClass # MyClass.const_missing(:MyOtherClass)
  95. 95. Interception! const_missing(sym) MyClass::MyOtherClass # MyClass.const_missing(:MyOtherClass) Example: Loader class Loader def self.const_missing(sym) file = File.join(File.dirname(__FILE__), "#{sym.to_s.downcase}.rb") if File.exist?(file) require file Object.const_defined?(sym) ? Object.const_get(sym) : super else puts "can't find #{file}, sorry!" super end end end
  96. 96. Interception! Example: Loader class Loader def self.const_missing(sym) file = File.join(File.dirname(__FILE__), "#{sym.to_s.downcase}.rb") if File.exist?(file) require file Object.const_defined?(sym) ? Object.const_get(sym) : super else puts "can't find #{file}, sorry!" super end end end
  97. 97. Interception! Example: Loader class Loader def self.const_missing(sym) file = File.join(File.dirname(__FILE__), "#{sym.to_s.downcase}.rb") if File.exist?(file) require file Object.const_defined?(sym) ? Object.const_get(sym) : super else puts "can't find #{file}, sorry!" super end end end Loader::Auto # can't find ./auto.rb, sorry! # NameError: uninitialized constant Loader::Auto # or, if you have an ./auto.rb Loader::Auto # => Auto
  98. 98. Callbacks
  99. 99. Callbacks Module#method_added
  100. 100. Callbacks Module#method_added
  101. 101. Callbacks Module#method_added class MyClass def self.method_added(m) puts "adding #{m}" end puts "defining my method" def my_method 'two' end puts "done defining my method" end
  102. 102. Callbacks Module#method_added class MyClass defining my method def self.method_added(m) adding my_method puts "adding #{m}" done defining my method end puts "defining my method" def my_method 'two' end puts "done defining my method" end
  103. 103. Callbacks Module#method_added Example: Thor! class Tasks def self.desc(desc) @desc = desc end def self.method_added(m) (@method_descs ||= {})[m] = @desc @desc = nil end def self.method_description(m) method_defined?(m) ? @method_descs[m] || "This action isn't documented" : "This action doesn't exist" end desc "Start server" def start end def stop end end
  104. 104. Callbacks Module#method_added Example: Thor! Record the description class Tasks def self.desc(desc) @desc = desc When a method is added, end record the description associated def self.method_added(m) with that method (@method_descs ||= {})[m] = @desc @desc = nil end Provide the description for a def self.method_description(m) method, or, if not found, some method_defined?(m) ? default string. @method_descs[m] || "This action isn't documented" : "This action doesn't exist" end desc "Start server" def start end def stop end end
  105. 105. Callbacks Module#method_added Example: Thor! Record the description class Tasks def self.desc(desc) @desc = desc When a method is added, end record the description associated def self.method_added(m) with that method (@method_descs ||= {})[m] = @desc @desc = nil end Provide the description for a def self.method_description(m) method, or, if not found, some method_defined?(m) ? default string. @method_descs[m] || "This action isn't documented" : "This action doesn't exist" end desc "Start server" def start end Described! def stop end end
  106. 106. Callbacks Module#method_added Example: Thor! Query your methods! class Tasks puts Tasks.method_description(:start) def self.desc(desc) # => Start server @desc = desc puts Tasks.method_description(:stop) end # => This action isn't documented def self.method_added(m) puts Tasks.method_description(:restart) (@method_descs ||= {})[m] = @desc # => This action doesn't exist @desc = nil end def self.method_description(m) method_defined?(m) ? @method_descs[m] || "This action isn't documented" : "This action doesn't exist" end desc "Start server" def start end def stop end end
  107. 107. Callbacks Object#singleton_method_added
  108. 108. Callbacks Object#singleton_method_added class ClassWithMethods def self.singleton_method_added(m) puts "ADDING! #{m}" end def self.another end end
  109. 109. Callbacks Object#singleton_method_added class ClassWithMethods def self.singleton_method_added(m) puts "ADDING! #{m}" end def self.another end end # ADDING! singleton_method_added # ADDING! another
  110. 110. Callbacks Object#singleton_method_added class ClassWithMethods def self.singleton_method_added(m) puts "ADDING! #{m}" end def self.another end end Holy meta! # ADDING! singleton_method_added # ADDING! another
  111. 111. Callbacks Module#included module Logger def self.included(m) puts "adding logging to #{m}" end end class Server include Logger end # adding logging to Server
  112. 112. Callbacks Module#included Example: ClassMethods pattern module Logger class Server def self.included(m) include Logger puts "adding logging to #{m}" end def self.create log("Creating server!") def self.log(message) end puts "LOG: #{message}" end end end Server.create # `create': undefined method `log' for Server:Class (NoMethodError)
  113. 113. Callbacks Module#included Example: ClassMethods pattern module Logger class Server def self.included(m) include Logger m.extend(ClassMethods) end def self.create log("Creating server!") module ClassMethods end def log(message) end puts "LOG: #{message}" end end end Server.create # LOG: Creating server!
  114. 114. Callbacks Module#extended module One def self.extended(obj) puts "#{self} has been extended by #{obj}" end end Object.new.extend(One) # One has been extended by #<Object:0x1019614a8>
  115. 115. Callbacks Class#inherited class Parent def self.inherited(o) puts "#{self} was inherited by #{o}" end end class Child < Parent end # Parent was inherited by Child
  116. 116. Callbacks Guarding callbacks Module#append_features include Module#extend_object extend def self.extend_object(o) super end def self.append_features(o) super end
  117. 117. Callbacks Guarding callbacks Module#append_features include Module#extend_object extend def self.append_features(o) o.instance_method(:<=>) ? super : warn('you no can uze') end
  118. 118. Callbacks Kernel#caller def one two end def two method name three file name line (optional) end def three p caller end # ["method.rb:156:in `two'", "method.rb:152:in `one'", "method.rb:163"] https://github.com/joshbuddy/callsite
  119. 119. Callbacks Module#nesting module A module B module C p Module.nesting end end end # [A::B::C, A::B, A]
  120. 120. There and back again, a parsing tale
  121. 121. There and back again, a parsing tale gem install ruby_parser gem install sexp_processor gem install ruby2ruby Let’s go!
  122. 122. There and back again, a parsing tale Parsing require 'rubygems' require 'ruby_parser' RubyParser.new.process("'string'") s(:str, "string") Type Arguments...
  123. 123. There and back again, a parsing tale Parsing require 'rubygems' require 'ruby_parser' RubyParser.new.process("'string'") s(:str, "string") [:str, "string"] # Sexp Sexp.superclass # Array
  124. 124. There and back again, a parsing tale Parsing RubyParser.new.process("'string' + 'string'") s(:call, s(:str, "string"), :+, s(:arglist, s(:str, "string"))) Method Method Receiver Arguments call name
  125. 125. There and back again, a parsing tale Parsing RubyParser.new.process("'string' + 'string'") s(:call, nil, :puts, s(:arglist, s(:str, "hello world"))) Method Receiver Method Arguments call name
  126. 126. There and back again, a parsing tale And, back again... require 'rubygems' require 'ruby2ruby' Ruby2Ruby.new.process [:str, "hello"] # => "hello"
  127. 127. There and back again, a parsing tale And, back again... require 'rubygems' require 'ruby2ruby' Ruby2Ruby.new.process [:str, "hello"] # => "hello" Ruby2Ruby.new.process [:lit, :symbol] # => :symbol
  128. 128. There and back again, a parsing tale Roundtrip require 'sexp_processor' require 'ruby2ruby' require 'ruby_parser' class JarJarify < SexpProcessor def initialize self.strict = false super end def process_str(str) new_string = "YOUZA GONNA SAY #{str[-1]}" str.clear s(:str, new_string) end end
  129. 129. There and back again, a parsing tale Roundtrip class JarJarify < SexpProcessor def initialize self.strict = false super end def process_str(str) new_string = "YOUZA GONNA SAY #{str[-1]}" str.clear s(:str, new_string) end end ast = RubyParser.new.process('puts "hello"') Ruby2Ruby.new.process(JarJarify.new.process(ast)) # => puts("YOUZA GONNA SAY hello")
  130. 130. There and back again, a parsing tale Roundtrip class JarJarify < SexpProcessor def initialize self.strict = false Process type :str super end def process_str(str) new_string = "YOUZA GONNA SAY #{str[-1]}" str.clear s(:str, new_string) Consume the current sexp end end Return a new one ast = RubyParser.new.process('puts "hello"') Ruby2Ruby.new.process(JarJarify.new.process(ast)) # => puts("YOUZA GONNA SAY hello")
  131. 131. IT’S OVER!

Notes de l'éditeur

  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n

×